diff options
author | jacopograndi <jacopo.grandi@outlook.it> | 2022-01-04 13:35:02 +0100 |
---|---|---|
committer | jacopograndi <jacopo.grandi@outlook.it> | 2022-01-04 13:35:02 +0100 |
commit | bb16c32bde58cba70e4877aa2d3ebd04332eb575 (patch) | |
tree | de3d82cca043c26cbaa64837a3b2c18efc6ddb64 /game | |
parent | 411d2f6d6a6e5370d33f0f54b2f2de7147a9d977 (diff) |
linux compile and imgs
Diffstat (limited to 'game')
-rw-r--r-- | game/ai/action.cpp | 150 | ||||
-rw-r--r-- | game/ai/action.h | 102 | ||||
-rw-r--r-- | game/ai/engine.h | 130 | ||||
-rw-r--r-- | game/ai/evaluator.h | 58 | ||||
-rw-r--r-- | game/ai/generator.h | 202 | ||||
-rw-r--r-- | game/ai/performer.h | 96 | ||||
-rw-r--r-- | game/ai/tactic.h | 62 | ||||
-rw-r--r-- | game/constants.h | 32 | ||||
-rw-r--r-- | game/entity.cpp | 20 | ||||
-rw-r--r-- | game/entity.h | 162 | ||||
-rw-r--r-- | game/ground.cpp | 262 | ||||
-rw-r--r-- | game/ground.h | 72 | ||||
-rw-r--r-- | game/gst.cpp | 1208 | ||||
-rw-r--r-- | game/gst.h | 248 | ||||
-rw-r--r-- | game/load.cpp | 298 | ||||
-rw-r--r-- | game/load.h | 14 | ||||
-rw-r--r-- | game/menu.cpp | 152 | ||||
-rw-r--r-- | game/menu.h | 178 | ||||
-rw-r--r-- | game/player.h | 90 | ||||
-rw-r--r-- | game/playercontrol.cpp | 896 | ||||
-rw-r--r-- | game/playercontrol.h | 182 | ||||
-rw-r--r-- | game/tech.cpp | 2 | ||||
-rw-r--r-- | game/tech.h | 262 | ||||
-rw-r--r-- | game/tile.h | 44 | ||||
-rw-r--r-- | game/view.cpp | 412 | ||||
-rw-r--r-- | game/view.h | 78 |
26 files changed, 2706 insertions, 2706 deletions
diff --git a/game/ai/action.cpp b/game/ai/action.cpp index 63218ba..d85eb4d 100644 --- a/game/ai/action.cpp +++ b/game/ai/action.cpp @@ -1,76 +1,76 @@ -#include "action.h" - -bool ai::compare_action(ai::action a, ai::action b) { - return (a.heuristic < b.heuristic); -} - -std::string ai::action::to_string () { - if (type == actype::attack) { - if (abs(x-mx)+abs(y-my) != 0) { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " move " + - "[" + std::to_string(mx) + ", " + std::to_string(my) + "]" - + " attack " + - "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]"; - } else { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " attack " + - "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]"; - } - } - if (type == actype::heal) { - if (abs(x-mx)+abs(y-my) != 0) { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " move " + - "[" + std::to_string(mx) + ", " + std::to_string(my) + "]" - + " heal " + - "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]"; - } else { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " heal " + - "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]"; - } - } - if (type == actype::convert) { - if (abs(x-mx)+abs(y-my) != 0) { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " move " + - "[" + std::to_string(mx) + ", " + std::to_string(my) + "]" - + " convert " + - "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]"; - } else { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " convert " + - "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]"; - } - } - if (type == actype::move) { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" - + " move " + - "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"; - } - if (type == actype::build) { - if (abs(x-mx)+abs(y-my) != 0) { - return "[" + std::to_string(x) + ", " + std::to_string(y) - + "]" + " move " + - "[" + std::to_string(mx) + ", " + std::to_string(my) - + "]" + " build " + - std::to_string(v); - } else { - return "[" + std::to_string(mx) + ", " + std::to_string(my) - + "]" + " build " + - std::to_string(v); - } - } - if (type == actype::train) { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" + - " train " + std::to_string(v); - } - if (type == actype::trade) { - return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" + - " trade " + std::to_string(v); - } - if (type == actype::tech) { - return "tech " + std::to_string(v); - } +#include "action.h"
+
+bool ai::compare_action(ai::action a, ai::action b) {
+ return (a.heuristic < b.heuristic);
+}
+
+std::string ai::action::to_string () {
+ if (type == actype::attack) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
+ + " attack " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ } else {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " attack " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ }
+ }
+ if (type == actype::heal) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
+ + " heal " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ } else {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " heal " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ }
+ }
+ if (type == actype::convert) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
+ + " convert " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ } else {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " convert " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ }
+ }
+ if (type == actype::move) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]";
+ }
+ if (type == actype::build) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y)
+ + "]" + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my)
+ + "]" + " build " +
+ std::to_string(v);
+ } else {
+ return "[" + std::to_string(mx) + ", " + std::to_string(my)
+ + "]" + " build " +
+ std::to_string(v);
+ }
+ }
+ if (type == actype::train) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" +
+ " train " + std::to_string(v);
+ }
+ if (type == actype::trade) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" +
+ " trade " + std::to_string(v);
+ }
+ if (type == actype::tech) {
+ return "tech " + std::to_string(v);
+ }
}
\ No newline at end of file diff --git a/game/ai/action.h b/game/ai/action.h index 12da451..6b631ca 100644 --- a/game/ai/action.h +++ b/game/ai/action.h @@ -1,52 +1,52 @@ -#ifndef ACTION_H -#define ACTION_H - -#include <string> -#include <vector> - -namespace ai { - -enum actype { - attack, heal, convert, build, train, trade, move, tech -}; - -class action { - public: - action (actype type, int v) : - type(type), v(v) {} - action (actype type, int x, int y, int v) : - type(type), x(x), y(y), v(v) {} - action (actype type, int x, int y, int mx, int my) : - type(type), x(x), y(y), mx(mx), my(my) {} - action (actype type, int x, int y, int mx, int my, int v) : - type(type), x(x), y(y), mx(mx), my(my), v(v) {} - action (actype type, int x, int y, int mx, int my, int tx, int ty) : - type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty) {} - action (actype type, int x, int y, int mx, int my, int tx, int ty, int v) : - type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty), v(v) {} - - action (const action& rhs) { - type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my; - tx = rhs.tx; ty = rhs.ty; v = rhs.v; - } - action& operator=(const action& rhs) { - type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my; - tx = rhs.tx; ty = rhs.ty; v = rhs.v; - } - - actype type; - int x, y; // start - int mx, my; // moved - int tx, ty; // target - int v; // value (id of trainee, building or f/g trade, or tech id) - - float heuristic { 0 }; - - std::string to_string (); -}; - -bool compare_action(action a, action b); - -} - +#ifndef ACTION_H
+#define ACTION_H
+
+#include <string>
+#include <vector>
+
+namespace ai {
+
+enum actype {
+ attack, heal, convert, build, train, trade, move, tech
+};
+
+class action {
+ public:
+ action (actype type, int v) :
+ type(type), v(v) {}
+ action (actype type, int x, int y, int v) :
+ type(type), x(x), y(y), v(v) {}
+ action (actype type, int x, int y, int mx, int my) :
+ type(type), x(x), y(y), mx(mx), my(my) {}
+ action (actype type, int x, int y, int mx, int my, int v) :
+ type(type), x(x), y(y), mx(mx), my(my), v(v) {}
+ action (actype type, int x, int y, int mx, int my, int tx, int ty) :
+ type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty) {}
+ action (actype type, int x, int y, int mx, int my, int tx, int ty, int v) :
+ type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty), v(v) {}
+
+ action (const action& rhs) {
+ type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my;
+ tx = rhs.tx; ty = rhs.ty; v = rhs.v;
+ }
+ action& operator=(const action& rhs) {
+ type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my;
+ tx = rhs.tx; ty = rhs.ty; v = rhs.v;
+ }
+
+ actype type;
+ int x, y; // start
+ int mx, my; // moved
+ int tx, ty; // target
+ int v; // value (id of trainee, building or f/g trade, or tech id)
+
+ float heuristic { 0 };
+
+ std::string to_string ();
+};
+
+bool compare_action(action a, action b);
+
+}
+
#endif
\ No newline at end of file diff --git a/game/ai/engine.h b/game/ai/engine.h index d3755e1..584cb11 100644 --- a/game/ai/engine.h +++ b/game/ai/engine.h @@ -1,66 +1,66 @@ -#ifndef ENGINE_H -#define ENGINE_H - -#include <iostream> - -#include <string> -#include <vector> -#include <limits> -#include <cmath> - -#include "../ground.h" -#include "../gst.h" - -#include "action.h" -#include "tactic.h" -#include "generator.h" -#include "evaluator.h" -#include "performer.h" - -namespace ai { - -class engine { - public: - engine (Gst &gst) : init(gst) {} - Gst &init; - - tactic get_best () { - tactic t { search(init, 4) }; - std::cout << t.to_string(); - return t; - } - - tactic search (Gst &gst, int depth) { - generator gen { gst }; - std::vector<tactic> tactics = gen.tactics(); - tactic best; best.eval = std::numeric_limits<float>::lowest(); - for (tactic t : tactics) { - performer perf { gst }; - Gst next { perf.apply(t) }; - t.eval = negamax(next, depth, gst.turn); - std::cout << "depth " << depth << " eval " << t.eval << "\n"; - if (t.eval > best.eval) best = t; - } - return best; - } - - float negamax (Gst gst, int depth, int player) { - //for (int i=0; i<3-depth; i++) std::cout << " "; std::cout << depth << "\n"; - if (depth == 0) { - evaluator eval { gst }; - return eval.eval(player); - } - float value = std::numeric_limits<float>::lowest(); - generator gen { gst }; - auto tactics = gen.tactics(); - for (tactic t : tactics) { - performer perf { gst }; - Gst next { perf.apply(t) }; - value = fmax(value, negamax(next, depth-1, -player)); - } - return -value; - } -}; - -} +#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+#include <limits>
+#include <cmath>
+
+#include "../ground.h"
+#include "../gst.h"
+
+#include "action.h"
+#include "tactic.h"
+#include "generator.h"
+#include "evaluator.h"
+#include "performer.h"
+
+namespace ai {
+
+class engine {
+ public:
+ engine (Gst &gst) : init(gst) {}
+ Gst &init;
+
+ tactic get_best () {
+ tactic t { search(init, 4) };
+ std::cout << t.to_string();
+ return t;
+ }
+
+ tactic search (Gst &gst, int depth) {
+ generator gen { gst };
+ std::vector<tactic> tactics = gen.tactics();
+ tactic best; best.eval = std::numeric_limits<float>::lowest();
+ for (tactic t : tactics) {
+ performer perf { gst };
+ Gst next { perf.apply(t) };
+ t.eval = negamax(next, depth, gst.turn);
+ std::cout << "depth " << depth << " eval " << t.eval << "\n";
+ if (t.eval > best.eval) best = t;
+ }
+ return best;
+ }
+
+ float negamax (Gst gst, int depth, int player) {
+ //for (int i=0; i<3-depth; i++) std::cout << " "; std::cout << depth << "\n";
+ if (depth == 0) {
+ evaluator eval { gst };
+ return eval.eval(player);
+ }
+ float value = std::numeric_limits<float>::lowest();
+ generator gen { gst };
+ auto tactics = gen.tactics();
+ for (tactic t : tactics) {
+ performer perf { gst };
+ Gst next { perf.apply(t) };
+ value = fmax(value, negamax(next, depth-1, -player));
+ }
+ return -value;
+ }
+};
+
+}
#endif
\ No newline at end of file diff --git a/game/ai/evaluator.h b/game/ai/evaluator.h index 75684de..b288076 100644 --- a/game/ai/evaluator.h +++ b/game/ai/evaluator.h @@ -1,30 +1,30 @@ -#ifndef EVALUATOR_H -#define EVALUATOR_H - -#include <iostream> - -#include <string> -#include <vector> - -#include "../ground.h" -#include "../gst.h" - -namespace ai { - -class evaluator { - public: - evaluator (Gst gst) : gst(gst) {} - Gst gst; - - float eval (int player) { - float val = 0; - for (Entity &ent : gst.entities) { - int own = (int)(ent.owner != player)*2-1; - val += own*(ent.info->cost[0] + ent.info->cost[1])*(ent.hp/100.0f); - } - return val; - } -}; - -} +#ifndef EVALUATOR_H
+#define EVALUATOR_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#include "../ground.h"
+#include "../gst.h"
+
+namespace ai {
+
+class evaluator {
+ public:
+ evaluator (Gst gst) : gst(gst) {}
+ Gst gst;
+
+ float eval (int player) {
+ float val = 0;
+ for (Entity &ent : gst.entities) {
+ int own = (int)(ent.owner != player)*2-1;
+ val += own*(ent.info->cost[0] + ent.info->cost[1])*(ent.hp/100.0f);
+ }
+ return val;
+ }
+};
+
+}
#endif
\ No newline at end of file diff --git a/game/ai/generator.h b/game/ai/generator.h index c6cb288..39bde4f 100644 --- a/game/ai/generator.h +++ b/game/ai/generator.h @@ -1,102 +1,102 @@ -#ifndef GENERATOR_H -#define GENERATOR_H - -#include <iostream> - -#include <string> -#include <vector> - -#include "../ground.h" -#include "../gst.h" -#include "action.h" -#include "tactic.h" -#include "performer.h" - -namespace ai { - -const int maxiter = 100000; - - -class generator { - public: - generator (Gst &gst) : init(gst) {} - Gst &init; - - std::vector<action> valid_actions (Gst &gst) { - Ground &gr = gst.inv->ground; - std::vector<action> acts; - for (Entity &ent : gst.entities) { - if (ent.done) continue; - if (ent.owner != gst.turn) continue; - - std::vector<action> ent_acts; - - std::vector<int> moves = gr.move_area(gst, ent); - for (auto move : moves) { - int mx = move%gr.sizex, my = move/gr.sizex; - action act { actype::move, ent.x, ent.y, mx, my }; - - performer perf { gst }; - Gst next { gst }; - next = perf.act(next, act); - Entity &matk = next.get_at(mx, my); - std::vector<int> atks = gr.attack_targets(next, matk); - for (auto atk : atks) { - int tx = atk%gr.sizex, ty = atk/gr.sizex; - action act_atk { actype::attack, ent.x, ent.y, - mx, my, tx, ty }; - Entity &mdef = next.get_at(tx, ty); - - BattleResult res = gst.battle_res(matk, mdef); - float heur = (mdef.hp-res.def_hp); - heur *= (mdef.info->cost[0] + mdef.info->cost[1]); - act_atk.heuristic = heur; - ent_acts.push_back(act_atk); - } - - int dist = 999999; - int pos = gst.get_nearest_enemy(ent, dist); - float heur = 1.0f/dist; - act.heuristic = heur; - ent_acts.push_back(act); - } - std::sort(ent_acts.begin(), ent_acts.end(), compare_action); - for (int i=0; i<3 && i<ent_acts.size(); i++) { - acts.push_back(ent_acts[i]); - } - } - std::sort(acts.begin(), acts.end(), compare_action); - return acts; - } - - tactic valid_tactic (int &n) { - tactic t; - Gst gst { init }; - for (int i=0; i<ai::maxiter; i++) { - std::vector<action> acts { valid_actions(gst) }; - if (acts.size() == 0) break; - performer perf { gst }; - int j = n % (acts.size()); - n /= acts.size(); - action &act = acts[j]; - gst = perf.act(gst, act); - t.acts.push_back(act); - //std::cout << act.to_string() << std::endl; - } - return t; - } - - std::vector<tactic> tactics () { - std::vector<tactic> ts; - for (int i=0; i<3; i++) { - int n = i; - tactic t = valid_tactic(n); - if (n > 0) break; - ts.push_back(t); - } - return ts; - } -}; - -} +#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#include "../ground.h"
+#include "../gst.h"
+#include "action.h"
+#include "tactic.h"
+#include "performer.h"
+
+namespace ai {
+
+const int maxiter = 100000;
+
+
+class generator {
+ public:
+ generator (Gst &gst) : init(gst) {}
+ Gst &init;
+
+ std::vector<action> valid_actions (Gst &gst) {
+ Ground &gr = gst.inv->ground;
+ std::vector<action> acts;
+ for (Entity &ent : gst.entities) {
+ if (ent.done) continue;
+ if (ent.owner != gst.turn) continue;
+
+ std::vector<action> ent_acts;
+
+ std::vector<int> moves = gr.move_area(gst, ent);
+ for (auto move : moves) {
+ int mx = move%gr.sizex, my = move/gr.sizex;
+ action act { actype::move, ent.x, ent.y, mx, my };
+
+ performer perf { gst };
+ Gst next { gst };
+ next = perf.act(next, act);
+ Entity &matk = next.get_at(mx, my);
+ std::vector<int> atks = gr.attack_targets(next, matk);
+ for (auto atk : atks) {
+ int tx = atk%gr.sizex, ty = atk/gr.sizex;
+ action act_atk { actype::attack, ent.x, ent.y,
+ mx, my, tx, ty };
+ Entity &mdef = next.get_at(tx, ty);
+
+ BattleResult res = gst.battle_res(matk, mdef);
+ float heur = (mdef.hp-res.def_hp);
+ heur *= (mdef.info->cost[0] + mdef.info->cost[1]);
+ act_atk.heuristic = heur;
+ ent_acts.push_back(act_atk);
+ }
+
+ int dist = 999999;
+ int pos = gst.get_nearest_enemy(ent, dist);
+ float heur = 1.0f/dist;
+ act.heuristic = heur;
+ ent_acts.push_back(act);
+ }
+ std::sort(ent_acts.begin(), ent_acts.end(), compare_action);
+ for (int i=0; i<3 && i<ent_acts.size(); i++) {
+ acts.push_back(ent_acts[i]);
+ }
+ }
+ std::sort(acts.begin(), acts.end(), compare_action);
+ return acts;
+ }
+
+ tactic valid_tactic (int &n) {
+ tactic t;
+ Gst gst { init };
+ for (int i=0; i<ai::maxiter; i++) {
+ std::vector<action> acts { valid_actions(gst) };
+ if (acts.size() == 0) break;
+ performer perf { gst };
+ int j = n % (acts.size());
+ n /= acts.size();
+ action &act = acts[j];
+ gst = perf.act(gst, act);
+ t.acts.push_back(act);
+ //std::cout << act.to_string() << std::endl;
+ }
+ return t;
+ }
+
+ std::vector<tactic> tactics () {
+ std::vector<tactic> ts;
+ for (int i=0; i<3; i++) {
+ int n = i;
+ tactic t = valid_tactic(n);
+ if (n > 0) break;
+ ts.push_back(t);
+ }
+ return ts;
+ }
+};
+
+}
#endif
\ No newline at end of file diff --git a/game/ai/performer.h b/game/ai/performer.h index 472773b..17be028 100644 --- a/game/ai/performer.h +++ b/game/ai/performer.h @@ -1,49 +1,49 @@ -#ifndef PERFORMER_H -#define PERFORMER_H - -#include <iostream> - -#include <string> -#include <vector> - -#include "../ground.h" -#include "../gst.h" -#include "action.h" -#include "tactic.h" - -namespace ai { - -class performer { - public: - performer (Gst &gst) : init(gst) {} - Gst &init; - - Gst apply (tactic t) { - Gst next { init }; - for (action a : t.acts) { - next = act(next, a); - } - next.end_day(); - return next; - } - - Gst& act (Gst &gst, action a) { - if (a.type == actype::move) { - Entity &ent = gst.get_at(a.x, a.y); - ent.x = a.mx; ent.y = a.my; - ent.moved = 1; ent.done = true; - } - if (a.type == actype::attack) { - Entity &ent = gst.get_at(a.x, a.y); - ent.x = a.mx; ent.y = a.my; - ent.moved = 1; - Entity &def = gst.get_at(a.tx, a.ty); - gst.battle(ent, def); - ent.done = true; - } - return gst; - } -}; - -} +#ifndef PERFORMER_H
+#define PERFORMER_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#include "../ground.h"
+#include "../gst.h"
+#include "action.h"
+#include "tactic.h"
+
+namespace ai {
+
+class performer {
+ public:
+ performer (Gst &gst) : init(gst) {}
+ Gst &init;
+
+ Gst apply (tactic t) {
+ Gst next { init };
+ for (action a : t.acts) {
+ next = act(next, a);
+ }
+ next.end_day();
+ return next;
+ }
+
+ Gst& act (Gst &gst, action a) {
+ if (a.type == actype::move) {
+ Entity &ent = gst.get_at(a.x, a.y);
+ ent.x = a.mx; ent.y = a.my;
+ ent.moved = 1; ent.done = true;
+ }
+ if (a.type == actype::attack) {
+ Entity &ent = gst.get_at(a.x, a.y);
+ ent.x = a.mx; ent.y = a.my;
+ ent.moved = 1;
+ Entity &def = gst.get_at(a.tx, a.ty);
+ gst.battle(ent, def);
+ ent.done = true;
+ }
+ return gst;
+ }
+};
+
+}
#endif
\ No newline at end of file diff --git a/game/ai/tactic.h b/game/ai/tactic.h index 7eefef9..ec2e382 100644 --- a/game/ai/tactic.h +++ b/game/ai/tactic.h @@ -1,32 +1,32 @@ -#ifndef TACTIC_H -#define TACTIC_H - -#include <string> -#include <vector> - -#include "action.h" - -namespace ai { - -class tactic { - public: - tactic () { } - - std::vector<action> acts; - float eval = 0; - - // copy constructor - tactic (const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; } - tactic& operator=(const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; } - - std::string to_string () { - std::string str = "tactic eval= " + std::to_string(eval) + "\n"; - for (action act : acts) { - str += act.to_string() + "\n"; - } - return str; - } -}; - -} +#ifndef TACTIC_H
+#define TACTIC_H
+
+#include <string>
+#include <vector>
+
+#include "action.h"
+
+namespace ai {
+
+class tactic {
+ public:
+ tactic () { }
+
+ std::vector<action> acts;
+ float eval = 0;
+
+ // copy constructor
+ tactic (const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; }
+ tactic& operator=(const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; }
+
+ std::string to_string () {
+ std::string str = "tactic eval= " + std::to_string(eval) + "\n";
+ for (action act : acts) {
+ str += act.to_string() + "\n";
+ }
+ return str;
+ }
+};
+
+}
#endif
\ No newline at end of file diff --git a/game/constants.h b/game/constants.h index 2ba343a..ef6a477 100644 --- a/game/constants.h +++ b/game/constants.h @@ -1,17 +1,17 @@ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -namespace constants { - const int col_gud_r = 40; - const int col_gud_g = 120; - const int col_gud_b = 0; - const int col_bad_r = 255; - const int col_bad_g = 120; - const int col_bad_b = 0; - - const float menu_attack_margin_amt = 60; - const float menu_attack_margin_arrow = 80; - const float menu_attack_margin_mod = 93; -} - +#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+namespace constants {
+ const int col_gud_r = 40;
+ const int col_gud_g = 120;
+ const int col_gud_b = 0;
+ const int col_bad_r = 255;
+ const int col_bad_g = 120;
+ const int col_bad_b = 0;
+
+ const float menu_attack_margin_amt = 60;
+ const float menu_attack_margin_arrow = 80;
+ const float menu_attack_margin_mod = 93;
+}
+
#endif
\ No newline at end of file diff --git a/game/entity.cpp b/game/entity.cpp index f127150..8539045 100644 --- a/game/entity.cpp +++ b/game/entity.cpp @@ -1,11 +1,11 @@ -#include "entity.h" -#include <iostream> - - -int EntityClass::from_string (std::string str) { - if (str == "inf") return EntityInfo::Class::inf; - if (str == "cav") return EntityInfo::Class::cav; - if (str == "ran") return EntityInfo::Class::ran; - if (str == "sie") return EntityInfo::Class::sie; - if (str == "bld") return EntityInfo::Class::bld; +#include "entity.h"
+#include <iostream>
+
+
+int EntityClass::from_string (std::string str) {
+ if (str == "inf") return EntityInfo::Class::inf;
+ if (str == "cav") return EntityInfo::Class::cav;
+ if (str == "ran") return EntityInfo::Class::ran;
+ if (str == "sie") return EntityInfo::Class::sie;
+ if (str == "bld") return EntityInfo::Class::bld;
}
\ No newline at end of file diff --git a/game/entity.h b/game/entity.h index a15ebdb..f9f6781 100644 --- a/game/entity.h +++ b/game/entity.h @@ -1,82 +1,82 @@ -#ifndef ENTITIES_H -#define ENTITIES_H - -#include <vector> -#include <string> - -#include <iostream> - -#include "../umath/vec2.h" - - -class EntityInfo { - public: - EntityInfo() { spritebounds = vec2 { 16*6, 16 }; } - - enum Class { inf, cav, ran, sie, bld }; - Class ent_class; - - std::string name; - - int id; - int level; - - float hp; - float attack; - float defence; - int range; - float sight; - int move; - int unit; - std::vector<int> abilities; - std::vector<int> build; - std::vector<int> train_id; - std::vector<Class> train_class; - - std::vector<float> prod { 0, 0 }; - std::vector<float> cost { 0, 0 }; - - std::vector<int> adjacent; - std::vector<int> diagonal; - float defence_bonus { 0 }; - int upgrade { -1 }; - - vec2 spritebounds; -}; - -namespace EntityClass { - int from_string(std::string str); -} - -class Entity { - public: - Entity (int x, int y, EntityInfo *info, int owner) - : x(x), y(y), info(info), owner(owner) { moved = 0; hp = 100; } - - // copy constructor - Entity (const Entity& rhs) { - building = rhs.building; hp = rhs.hp; x = rhs.x; y = rhs.y; - done = rhs.done; moved = rhs.moved; info = rhs.info; - fights = rhs.fights; owner = rhs.owner; - } - Entity& operator=(const Entity& rhs) { - building = rhs.building; hp = rhs.hp; x = rhs.x; y = rhs.y; - done = rhs.done; moved = rhs.moved; info = rhs.info; - fights = rhs.fights; owner = rhs.owner; - }; - - bool operator==(Entity oth) { - return x == oth.x && y == oth.y && info->unit == oth.info->unit; - } - - int building { 0 }; - float hp; - int x, y; - bool done = false; - int moved; - EntityInfo *info; - int fights { 0 }; - int owner; -}; - +#ifndef ENTITIES_H
+#define ENTITIES_H
+
+#include <vector>
+#include <string>
+
+#include <iostream>
+
+#include "../umath/vec2.h"
+
+
+class EntityInfo {
+ public:
+ EntityInfo() { spritebounds = vec2 { 16*6, 16 }; }
+
+ enum Class { inf, cav, ran, sie, bld };
+ Class ent_class;
+
+ std::string name;
+
+ int id;
+ int level;
+
+ float hp;
+ float attack;
+ float defence;
+ int range;
+ float sight;
+ int move;
+ int unit;
+ std::vector<int> abilities;
+ std::vector<int> build;
+ std::vector<int> train_id;
+ std::vector<Class> train_class;
+
+ std::vector<float> prod { 0, 0 };
+ std::vector<float> cost { 0, 0 };
+
+ std::vector<int> adjacent;
+ std::vector<int> diagonal;
+ float defence_bonus { 0 };
+ int upgrade { -1 };
+
+ vec2 spritebounds;
+};
+
+namespace EntityClass {
+ int from_string(std::string str);
+}
+
+class Entity {
+ public:
+ Entity (int x, int y, EntityInfo *info, int owner)
+ : x(x), y(y), info(info), owner(owner) { moved = 0; hp = 100; }
+
+ // copy constructor
+ Entity (const Entity& rhs) {
+ building = rhs.building; hp = rhs.hp; x = rhs.x; y = rhs.y;
+ done = rhs.done; moved = rhs.moved; info = rhs.info;
+ fights = rhs.fights; owner = rhs.owner;
+ }
+ Entity& operator=(const Entity& rhs) {
+ building = rhs.building; hp = rhs.hp; x = rhs.x; y = rhs.y;
+ done = rhs.done; moved = rhs.moved; info = rhs.info;
+ fights = rhs.fights; owner = rhs.owner;
+ };
+
+ bool operator==(Entity oth) {
+ return x == oth.x && y == oth.y && info->unit == oth.info->unit;
+ }
+
+ int building { 0 };
+ float hp;
+ int x, y;
+ bool done = false;
+ int moved;
+ EntityInfo *info;
+ int fights { 0 };
+ int owner;
+};
+
#endif
\ No newline at end of file diff --git a/game/ground.cpp b/game/ground.cpp index cd67751..610b096 100644 --- a/game/ground.cpp +++ b/game/ground.cpp @@ -1,132 +1,132 @@ -#include "ground.h" -#include "gst.h" - -#include <iostream> -#include <algorithm> - -void Ground::build (int sx, int sy) { - sizex = sx; sizey = sy; - tiles = new int[sx*sy]; - for (int i=0; i<sx*sy; i++) tiles[i] = 0; -} - -int Ground::at(int x, int y) { - return x+y*sizex; -} - - -// areas -std::vector<int> Ground::star (int pos) { - std::vector<int> fs; - int x = pos % sizex, y = pos / sizex; - if (x-1 >= 0) { fs.push_back(at(x-1, y)); } - if (x+1 < sizex) { fs.push_back(at(x+1, y)); } - if (y-1 >= 0) { fs.push_back(at(x, y-1)); } - if (y+1 < sizey) { fs.push_back(at(x, y+1)); } - return fs; -} - -class step { public: - step(int pos, int m) : pos(pos), m(m) {}; - bool operator==(step oth) { return pos==oth.pos && m==oth.m; } - bool operator==(int p) { return pos==p; } - int pos, m; -}; - -std::vector<int> Ground::move_area (Gst &gst, Entity &ent) { - Player &player = gst.players[ent.owner]; - int move_num = ent.info->move; - move_num += player.tech_lookup.id(ent.info->id).move; - - std::vector<int> moves; - std::vector<int> visited { at(ent.x, ent.y) }; - std::vector<step> frontier { step { at(ent.x, ent.y), move_num } }; - - int maxcost = 99; - if (gst.inv->info_has_ability(ent.info, "Scout")) maxcost = 2; - - int iter=0; - for (; iter<10000; iter++) { - - if (frontier.size() == 0) break; - step maxf {-1, -1}; - for (step t : frontier) { - if (t.m > maxf.m) { - maxf.pos = t.pos; - maxf.m = t.m; - } - } - frontier.erase(std::remove(frontier.begin(), frontier.end(), maxf), - frontier.end()); - auto forward_star = star(maxf.pos); - for (int t : forward_star) { - if (!(std::find(visited.begin(), visited.end(), t) != visited.end()) - && !(std::find(frontier.begin(), frontier.end(), t) != frontier.end())) { - int movecost = gst.inv->tiles[tiles[t]].move_cost; - if (movecost > maxcost) movecost = maxcost; - int walkedm = maxf.m - movecost; - bool obs_enemy = false, obs_friend = false; - for (Entity &e : gst.entities) { - if (at(e.x, e.y) == t) { - if (e.owner != ent.owner) obs_enemy = true; - else obs_friend = true; - break; - } - } - if (walkedm >= 0 && !obs_enemy) { - frontier.emplace_back(t, walkedm); - if (!obs_friend) { - moves.push_back(t); - } - } - } - } - visited.push_back(maxf.pos); - } - - - return moves; -} - -std::vector<int> Ground::attack_targets (Gst &gst, Entity &ent) { - std::vector<int> attacks; - int range = gst.get_range(ent); - bool builds = !gst.inv->info_has_ability(ent.info, "Units Only"); - bool units = !gst.inv->info_has_ability(ent.info, "Buildings Only"); - for (Entity &e : gst.entities) { - if (!units && e.info->unit == 1) continue; - if (!builds && e.info->unit == 0) continue; - int dist = abs(e.x-ent.x)+abs(e.y-ent.y); - if (dist > 0 && e.owner != ent.owner && dist <= range) { - attacks.push_back(at(e.x, e.y)); - } - } - return attacks; -} - -std::vector<int> Ground::heal_targets (Gst &gst, Entity &ent) { - std::vector<int> heals; - int range = gst.get_range(ent); - for (Entity &e : gst.entities) { - if (e.info->unit == 0) continue; - if (e.info->ent_class == EntityInfo::Class::sie) continue; - int dist = abs(e.x-ent.x)+abs(e.y-ent.y); - if (dist > 0 && e.owner == ent.owner && dist <= range) { - heals.push_back(at(e.x, e.y)); - } - } - return heals; -} - -std::vector<int> Ground::convert_targets (Gst &gst, Entity &ent) { - std::vector<int> converts; - int range = gst.get_range(ent); - for (Entity &e : gst.entities) { - if (e.info->unit == 0) continue; - int dist = abs(e.x-ent.x)+abs(e.y-ent.y); - if (dist > 0 && e.owner != ent.owner && dist <= range) { - converts.push_back(at(e.x, e.y)); - } - } - return converts; +#include "ground.h"
+#include "gst.h"
+
+#include <iostream>
+#include <algorithm>
+
+void Ground::build (int sx, int sy) {
+ sizex = sx; sizey = sy;
+ tiles = new int[sx*sy];
+ for (int i=0; i<sx*sy; i++) tiles[i] = 0;
+}
+
+int Ground::at(int x, int y) {
+ return x+y*sizex;
+}
+
+
+// areas
+std::vector<int> Ground::star (int pos) {
+ std::vector<int> fs;
+ int x = pos % sizex, y = pos / sizex;
+ if (x-1 >= 0) { fs.push_back(at(x-1, y)); }
+ if (x+1 < sizex) { fs.push_back(at(x+1, y)); }
+ if (y-1 >= 0) { fs.push_back(at(x, y-1)); }
+ if (y+1 < sizey) { fs.push_back(at(x, y+1)); }
+ return fs;
+}
+
+class step { public:
+ step(int pos, int m) : pos(pos), m(m) {};
+ bool operator==(step oth) { return pos==oth.pos && m==oth.m; }
+ bool operator==(int p) { return pos==p; }
+ int pos, m;
+};
+
+std::vector<int> Ground::move_area (Gst &gst, Entity &ent) {
+ Player &player = gst.players[ent.owner];
+ int move_num = ent.info->move;
+ move_num += player.tech_lookup.id(ent.info->id).move;
+
+ std::vector<int> moves;
+ std::vector<int> visited { at(ent.x, ent.y) };
+ std::vector<step> frontier { step { at(ent.x, ent.y), move_num } };
+
+ int maxcost = 99;
+ if (gst.inv->info_has_ability(ent.info, "Scout")) maxcost = 2;
+
+ int iter=0;
+ for (; iter<10000; iter++) {
+
+ if (frontier.size() == 0) break;
+ step maxf {-1, -1};
+ for (step t : frontier) {
+ if (t.m > maxf.m) {
+ maxf.pos = t.pos;
+ maxf.m = t.m;
+ }
+ }
+ frontier.erase(std::remove(frontier.begin(), frontier.end(), maxf),
+ frontier.end());
+ auto forward_star = star(maxf.pos);
+ for (int t : forward_star) {
+ if (!(std::find(visited.begin(), visited.end(), t) != visited.end())
+ && !(std::find(frontier.begin(), frontier.end(), t) != frontier.end())) {
+ int movecost = gst.inv->tiles[tiles[t]].move_cost;
+ if (movecost > maxcost) movecost = maxcost;
+ int walkedm = maxf.m - movecost;
+ bool obs_enemy = false, obs_friend = false;
+ for (Entity &e : gst.entities) {
+ if (at(e.x, e.y) == t) {
+ if (e.owner != ent.owner) obs_enemy = true;
+ else obs_friend = true;
+ break;
+ }
+ }
+ if (walkedm >= 0 && !obs_enemy) {
+ frontier.emplace_back(t, walkedm);
+ if (!obs_friend) {
+ moves.push_back(t);
+ }
+ }
+ }
+ }
+ visited.push_back(maxf.pos);
+ }
+
+
+ return moves;
+}
+
+std::vector<int> Ground::attack_targets (Gst &gst, Entity &ent) {
+ std::vector<int> attacks;
+ int range = gst.get_range(ent);
+ bool builds = !gst.inv->info_has_ability(ent.info, "Units Only");
+ bool units = !gst.inv->info_has_ability(ent.info, "Buildings Only");
+ for (Entity &e : gst.entities) {
+ if (!units && e.info->unit == 1) continue;
+ if (!builds && e.info->unit == 0) continue;
+ int dist = abs(e.x-ent.x)+abs(e.y-ent.y);
+ if (dist > 0 && e.owner != ent.owner && dist <= range) {
+ attacks.push_back(at(e.x, e.y));
+ }
+ }
+ return attacks;
+}
+
+std::vector<int> Ground::heal_targets (Gst &gst, Entity &ent) {
+ std::vector<int> heals;
+ int range = gst.get_range(ent);
+ for (Entity &e : gst.entities) {
+ if (e.info->unit == 0) continue;
+ if (e.info->ent_class == EntityInfo::Class::sie) continue;
+ int dist = abs(e.x-ent.x)+abs(e.y-ent.y);
+ if (dist > 0 && e.owner == ent.owner && dist <= range) {
+ heals.push_back(at(e.x, e.y));
+ }
+ }
+ return heals;
+}
+
+std::vector<int> Ground::convert_targets (Gst &gst, Entity &ent) {
+ std::vector<int> converts;
+ int range = gst.get_range(ent);
+ for (Entity &e : gst.entities) {
+ if (e.info->unit == 0) continue;
+ int dist = abs(e.x-ent.x)+abs(e.y-ent.y);
+ if (dist > 0 && e.owner != ent.owner && dist <= range) {
+ converts.push_back(at(e.x, e.y));
+ }
+ }
+ return converts;
}
\ No newline at end of file diff --git a/game/ground.h b/game/ground.h index d1a4f34..fcded29 100644 --- a/game/ground.h +++ b/game/ground.h @@ -1,37 +1,37 @@ -#ifndef GROUND_H -#define GROUND_H - -#include "entity.h" - -class Gst; - -class Resource { - public: - Resource (int pos, int kind) : pos(pos), kind(kind) {} - - enum Type { gold, food }; - - int pos, kind; -}; - -class Ground { - public: - Ground () {} - - int *tiles; - - std::vector<Resource> resources; - - void build (int sx, int sy); - - int sizex; - int sizey; - int at (int x, int y); - std::vector<int> star (int pos); - std::vector<int> move_area (Gst &gst, Entity &ent); - std::vector<int> attack_targets (Gst &gst, Entity &ent); - std::vector<int> heal_targets (Gst &gst, Entity &ent); - std::vector<int> convert_targets (Gst &gst, Entity &ent); -}; - +#ifndef GROUND_H
+#define GROUND_H
+
+#include "entity.h"
+
+class Gst;
+
+class Resource {
+ public:
+ Resource (int pos, int kind) : pos(pos), kind(kind) {}
+
+ enum Type { gold, food };
+
+ int pos, kind;
+};
+
+class Ground {
+ public:
+ Ground () {}
+
+ int *tiles;
+
+ std::vector<Resource> resources;
+
+ void build (int sx, int sy);
+
+ int sizex;
+ int sizey;
+ int at (int x, int y);
+ std::vector<int> star (int pos);
+ std::vector<int> move_area (Gst &gst, Entity &ent);
+ std::vector<int> attack_targets (Gst &gst, Entity &ent);
+ std::vector<int> heal_targets (Gst &gst, Entity &ent);
+ std::vector<int> convert_targets (Gst &gst, Entity &ent);
+};
+
#endif
\ No newline at end of file diff --git a/game/gst.cpp b/game/gst.cpp index 334844a..35f2b44 100644 --- a/game/gst.cpp +++ b/game/gst.cpp @@ -1,605 +1,605 @@ -#include "gst.h" - -#include <map> -#include <iostream> - - -Tech* Inv::get_tech (int id) { - for (auto &tech : techs) { - if (id == tech.id) return &tech; - } -} - -EntityInfo* Inv::get_info (std::string name) { - for (EntityInfo &info : infos) { - if (name == info.name) return &info; - } -} - -EntityInfo* Inv::get_info (int id) { - for (EntityInfo &info : infos) { - if (id == info.id) return &info; - } -} - -bool Inv::info_has_ability (EntityInfo* info, std::string name) { - for (int ab : info->abilities) { - if (abilities[ab].name == name) return true; - } - return false; -} - - - -Player& Gst::get_player (int id) { - for (auto &player : players) { - if (id == player.id) return player; - } -} - -Entity& Gst::get_at (int x, int y) { - for (Entity &e : entities) { - if (e.x ==x && e.y == y) return e; - } -} - -std::vector<float> Gst::get_cost (EntityInfo *info, Player &player) { - std::vector<float> cost = info->cost; - - std::cout << "cost : " << player.tech_lookup.id(info->id).cost[0] << " " << player.tech_lookup.id(info->id).cost[1] << "\n"; - for (int i=0; i<info->cost.size(); i++) { - cost[i] *= 1+player.tech_lookup.id(info->id).cost[i]; - cost[i] += player.tech_lookup.id(info->id).cost_abs[i]; - } - return cost; -} - -float Gst::get_trade_rate (Player &player) { - float rate = 250; - rate -= player.tech_lookup.id(0).trade * 25; - return rate; -} - -float Gst::get_type_bonus (Entity &atk, Entity &def) { - float b = 0; - switch(atk.info->ent_class) { - case EntityInfo::Class::inf: - if (def.info->ent_class == EntityInfo::Class::bld) b += 1.0f/3.0f; - if (def.info->ent_class == EntityInfo::Class::sie) b += 1.0f/3.0f; - break; - - case EntityInfo::Class::cav: - if (def.info->ent_class == EntityInfo::Class::bld) b += -0.5; - if (def.info->ent_class == EntityInfo::Class::inf) b += 1.0f/3.0f; - if (def.info->ent_class == EntityInfo::Class::ran) b += 1.0f/3.0f; - break; - - case EntityInfo::Class::ran: - if (def.info->ent_class == EntityInfo::Class::bld) b += -0.5f; - break; - - case EntityInfo::Class::sie: - if (def.info->ent_class == EntityInfo::Class::bld) b += +0.5f; - break; - } - return b; -} - -int Gst::get_vet_level (Entity &ent) { return std::min(3, ent.fights/3); } - -std::vector<Bonus> Gst::get_bonuses (Entity &atk, Entity &def) { - auto &tiles = inv->tiles; - auto &ground = inv->ground; - std::vector<Bonus> bs; - if (tiles[ground.tiles[ground.at(atk.x, atk.y)]].attack_bonus != 0) { - - bs.emplace_back( - tiles[ground.tiles[ground.at(atk.x, atk.y)]].attack_bonus, - Bonus::Id::ground, true); - } - if (tiles[ground.tiles[ground.at(def.x, def.y)]].defence_bonus != 0) { - bs.emplace_back( - tiles[ground.tiles[ground.at(def.x, def.y)]].defence_bonus, - Bonus::Id::ground, false); - } - - if (check_obstructed(def)) { - for (Entity &e : entities) { - if (&def != &e && e.x == def.x && def.y == e.y) { - bs.emplace_back(e.info->defence_bonus, - Bonus::Id::on_bld, false); - } - } - } - - if (get_type_bonus(atk, def) != 0) { - bs.emplace_back(get_type_bonus(atk, def), Bonus::Id::type, true); - } - /* only attack bonuses - if (get_type_bonus(def, atk) != 0) { - bs.emplace_back(get_type_bonus(def, atk), Bonus::Id::type, false); - }*/ - - if (inv->info_has_ability(atk.info, "Causes Fear")) - bs.emplace_back(-1.0f/3, Bonus::Id::ability, false); - if (inv->info_has_ability(def.info, "Causes Fear")) - bs.emplace_back(-1.0f/3, Bonus::Id::ability, true); - - if (inv->info_has_ability(atk.info, "Anti-Cavalry")) - bs.emplace_back(4.0f/3, Bonus::Id::ability, true); - if (inv->info_has_ability(def.info, "Anti-Cavalry")) - bs.emplace_back(4.0f/3, Bonus::Id::ability, false); - - if (inv->info_has_ability(atk.info, "Desert Charge") - && !inv->info_has_ability(def.info, "Desert Charge") - && tiles[ground.tiles[ground.at(def.x, def.y)]].name == "Desert") - bs.emplace_back(1.0f/3, Bonus::Id::ability, true); - - if (inv->info_has_ability(atk.info, "Plains Charge") - && !inv->info_has_ability(def.info, "Plains Charge") - && tiles[ground.tiles[ground.at(def.x, def.y)]].name == "Plains") - bs.emplace_back(1.0f/3, Bonus::Id::ability, true); - - if (inv->info_has_ability(atk.info, "Woodsman") - && !inv->info_has_ability(def.info, "Woodsman") - && tiles[ground.tiles[ground.at(def.x, def.y)]].name == "Forest") - bs.emplace_back(1.0f/3, Bonus::Id::ability, true); - - if (inv->info_has_ability(atk.info, "Volley") && atk.hp >= 50) - bs.emplace_back(1.0f/3, Bonus::Id::ability, true); - - if (inv->info_has_ability(atk.info, "Frenzy")) - bs.emplace_back(1/atk.hp, Bonus::Id::ability, true); - - Player &player_atk = players[atk.owner]; - Player &player_def = players[def.owner]; - float tech_attack = player_atk.tech_lookup.id(atk.info->id).attack; - if (tech_attack != 0) - bs.emplace_back(tech_attack, Bonus::Id::tech, true); - float tech_defence = player_def.tech_lookup.id(def.info->id).defence; - if (tech_defence != 0) - bs.emplace_back(tech_defence, Bonus::Id::tech, false); - - float atk_vet = get_vet_level(atk) * 0.15f; - if (atk_vet > 0) - bs.emplace_back(atk_vet, Bonus::Id::veteran, true); - float def_vet = get_vet_level(def) * 0.15f; - if (def_vet > 0) - bs.emplace_back(def_vet, Bonus::Id::veteran, false); - - return bs; -} - -float Gst::get_damage (Entity &atk, Entity &def, float atk_hp) { - float atkmul = 1; - float defmul = 1; - - auto bonuses = get_bonuses(atk, def); - for (auto bonus : bonuses) { - if (bonus.atk) { atkmul += bonus.amt; } - else { defmul += bonus.amt; } - } - - float dam = (atk.info->attack * atk_hp * atkmul) - / (2.0f*def.info->defence * defmul); - - return dam; -} - -float Gst::get_damage (Entity &atk, Entity &def) { - return get_damage(atk, def, atk.hp); -} - -bool Gst::get_first_strike (Entity &atk, Entity &def) { - bool fs { false }; - fs = inv->info_has_ability(atk.info, "First Strike"); - return fs; -} - -float clamp_hp (float hp) { - if (hp > 100) hp = 100; - if (hp < 0) hp = 0; - return hp; -} - -BattleResult Gst::battle_res (Entity &atk, Entity &def) { - BattleResult result { atk.hp, def.hp }; - bool first_strike_atk = inv->info_has_ability(atk.info, "First Strike"); - bool first_strike_def = inv->info_has_ability(def.info, "First Strike"); - bool skirmish_atk = inv->info_has_ability(atk.info, "Skirmish"); - bool skirmish_def = inv->info_has_ability(def.info, "Skirmish"); - bool anticav_atk = inv->info_has_ability(atk.info, "Anti-Cavalry"); - bool anticav_def = inv->info_has_ability(def.info, "Anti-Cavalry"); - first_strike_atk = first_strike_atk - || (skirmish_atk && def.info->range == 1); - first_strike_def = first_strike_def - || (skirmish_def && atk.info->range == 1); - first_strike_atk = first_strike_atk - || (anticav_atk && def.info->ent_class == EntityInfo::Class::cav); - first_strike_def = first_strike_def - || (anticav_def && atk.info->ent_class == EntityInfo::Class::cav); - - int dist = abs(atk.x-def.x) + abs(atk.y-def.y); - bool def_inrange = (dist <= get_range(def)) ? true : false; - - bool swap = false; - if (first_strike_def && !first_strike_atk) swap = true; - if (swap) { - if (def_inrange) { - result.atk_hp = clamp_hp( - result.atk_hp - get_damage(def, atk, result.def_hp)); - } - if (!inv->info_has_ability(atk.info, "No Counter")) - if (result.atk_hp > 0) - result.def_hp = clamp_hp( - result.def_hp - get_damage(atk, def, result.atk_hp)); - } else { - result.def_hp = clamp_hp( - result.def_hp - get_damage(atk, def, result.atk_hp)); - if (!inv->info_has_ability(def.info, "No Counter") && def_inrange) - if (result.def_hp > 0) - result.atk_hp = clamp_hp( - result.atk_hp - get_damage(def, atk, result.def_hp)); - } - - if (inv->info_has_ability(atk.info, "Rapid Fire")) - if (result.def_hp > 0) - result.def_hp = clamp_hp( - result.def_hp - get_damage(atk, def, result.def_hp)); - - if (inv->info_has_ability(def.info, "Rapid Fire") && def_inrange) - if (result.atk_hp > 0) - result.atk_hp = clamp_hp( - result.atk_hp - get_damage(def, atk, result.def_hp)); - - if (result.atk_hp > 0 && inv->info_has_ability(atk.info, "Zeal")) - result.atk_hp = clamp_hp(result.atk_hp + 20); - if (result.def_hp > 0 && inv->info_has_ability(def.info, "Zeal")) - result.def_hp = clamp_hp(result.def_hp + 20); - - return result; -} - -void Gst::battle (Entity &atk, Entity &def) { - /*std::cout << "! attack " << atk.info->name << "(hp:" << atk.hp << "), " - << def.info->name << "(hp:" << def.hp << ") \n";*/ - - auto result = battle_res(atk, def); - atk.hp = result.atk_hp; - def.hp = result.def_hp; - - if (atk.info->unit == 1) atk.fights += 1; - if (def.info->unit == 1) def.fights += 1; - - /*std::cout << "! result " << atk.info->name << "(hp:" << atk.hp << "), " - << def.info->name << "(hp:" << def.hp << ") \n";*/ - clear_dead(); -} - -void Gst::clear_dead() { - auto i = std::begin(entities); - while (i != std::end(entities)) { - if (i->hp <= 0) { - entities.erase(i); - } - else i++; - } -} - -int Gst::get_range (Entity &ent) { - int range = ent.info->range; - if (range > 1) { - auto &tiles = inv->tiles; - auto &ground = inv->ground; - range += tiles[ground.tiles[ground.at(ent.x, ent.y)]].range_bonus; - } - if (range < 1) range = 1; - return range; -} - - -void Gst::heal (Entity &atk, Entity &def) { - Player &player = get_player(atk.owner); - float amt = 20; - if (atk.info->level == 3) { amt += 10; } // improved heal - if (player.has_tech(52)) { amt += 10; } // tech illumination - def.hp = clamp_hp(def.hp + amt); -} - -void Gst::convert (Entity &atk, Entity &def) { - Player &player = get_player(atk.owner); - float amt = 0.20f; - if (player.has_tech(53)) { amt += 0.10f; } // tech faith - // caution, randomness - std::uniform_real_distribution<float> odds(0, 1); - float value = odds(inv->engine); - std::cout << value << " / " << amt << " odds\n"; - if (value < amt) { - def.owner = atk.owner; - } -} - - -int Gst::get_nearest_enemy (Entity &ent, int &mindist) { - auto &ground = inv->ground; - int pos = -1; mindist = 9999999; - for (Entity &oth : entities) { - if (oth.owner == ent.owner) continue; - int dist = abs(oth.x-ent.x) + abs(oth.y-ent.y); - if (dist < mindist) { - mindist = dist; - pos = ground.at(oth.x, oth.y); - } - } -} - - -std::vector<int> Gst::get_possible_trains (Entity &ent) { - Player &player = get_player(ent.owner); - auto &cls = ent.info->train_class; - std::vector<int> trains; - if (ent.info->id == 107) { // market special case - std::vector<int> candidates; - for (EntityInfo &info : inv->infos) { - if (info.id == 0) continue; // villager only in train_id - if (info.level > player.level) continue; - if (info.level < player.level && info.upgrade != -1) continue; - if (std::find(cls.begin(), cls.end(), info.ent_class) != cls.end()) - { - candidates.push_back(info.id); - } - } - std::shuffle(candidates.begin(), candidates.end(), inv->engine); - // pick 3 cands at random - for (int i=0; i<3; i++) trains.push_back(candidates[i]); - return trains; - } - - for (int id : ent.info->train_id) { - auto info = inv->get_info(id); - if (info->level > player.level) continue; - if (info->level < player.level && info->upgrade != -1) continue; - trains.push_back(id); - } - /* - // get all train class ids, highest upgrade level - for (EntityInfo &info : infos) { - if (info.id == 0) continue; // villager only in train_id - if (info.level > player.level) continue; - if (info.level < player.level && info.upgrade != -1) continue; - if (std::find(cls.begin(), cls.end(), info.ent_class) != cls.end()) { - if (std::find(trains.begin(), trains.end(), info.id) - != trains.end()) - { - trains.push_back(info.id); - } - } - }*/ - return trains; -} - -std::vector<int> Gst::get_possible_builds (Entity &ent) { - std::vector<int> builds; - for (int id : ent.info->build) { - if (check_req_build(ent, inv->get_info(id))) { - builds.push_back(id); - } - } - return builds; -} - - -bool Gst::check_req_build(Entity &ent, EntityInfo *info) { - auto &ground = inv->ground; - Player &player = players[ent.owner]; - if (player.level < info->level) return false; - for (int id : info->adjacent) { - bool adj = false; - for (Entity &e : entities) { - if (e.info->id == id && ent.owner == e.owner) { - int dist = abs(e.x-ent.x) + abs(e.y-ent.y); - if (dist == 1) { - adj = true; - } - } - } - if (!adj) return false; - } - for (int id : info->diagonal) { - bool diag = false; - for (Entity &e : entities) { - if (e.info->id == id && ent.owner == e.owner) { - int dx = abs(e.x-ent.x), dy = abs(e.y-ent.y); - int dist = dx + dy; - if (dx == 1 && dy == 1) { - diag = true; - } - } - } - if (!diag) return false; - } - if (info->id == 100) { - for (Resource &r : ground.resources) { - if (r.pos == ground.at(ent.x, ent.y)) { - return false; - } - } - int mindist = 9999; - for (Entity &e : entities) { - if (e.info->id == 100 && ent.owner == e.owner) { - int dist = abs(e.x-ent.x) + abs(ent.y-e.y); - if (dist < mindist) { - mindist = dist; - } - } - } - if (mindist < 5) { - return false; - } - return true; - } - if (info->id == 101) { - for (Resource &r : ground.resources) { - if (r.kind == Resource::Type::food - && r.pos == ground.at(ent.x, ent.y)) { - return true; - } - } - return false; - } - if (info->id == 102) { - for (Resource &r : ground.resources) { - if (r.kind == Resource::Type::gold - && r.pos == ground.at(ent.x, ent.y)) { - return true; - } - } - return false; - } - return true; -} - - -bool Gst::check_req_tech (Tech *tech, Player &player) { - if (player.leveling_up == 1) return false; - if (tech->level > player.level) { - return false; - } - if (tech->cost[0] > player.res[0] - || tech->cost[1] > player.res[1] ) - { - return false; - } - if (player.has_tech(tech->id)) { - return false; - } - bool req_id = false; - for (auto &ent : entities) { - if (ent.owner == turn // WARNING: turn is not player.id - && ent.info->id == tech->req_id - && ent.building == 0) - { - req_id = true; - break; - } - } - if (!req_id) { - return false; - } - return true; -} - -bool Gst::check_req_level (Player &player) { - if (player.leveling_up == 1) return false; - - for (float v : player.res) { - if (v <= (player.level+1)*500) return false; - } - - std::map<int, int> lv_techs; - for (int id : player.techs) lv_techs[inv->get_tech(id)->level] ++; - if (player.level == 0) { - if (lv_techs[0] >= 3) return true; - } - if (player.level == 1) { - if (lv_techs[1] >= 7) return true; - } - if (player.level == 2) { - if (lv_techs[2] >= 11) return true; - } - return false; -} - -bool Gst::check_obstructed (Entity &ent) { - for (Entity &e : entities) { - if (&ent != &e && e.x == ent.x && ent.y == e.y) return true; - } - return false; -} - -void Gst::end_day () { - turn++; - if (turn >= players.size()) { - turn = 0; - day++; - } - Player &player = players[turn]; - if (player.leveling_up != -1) { - level_upgrade(player); - player.level ++; - player.leveling_up = -1; - } - for (Entity &e : entities) { - e.done = false; - e.moved = 0; - if (get_player(e.owner) == player) { - for (int i=0; i<player.res.size(); i++) { - player.res[i] += e.info->prod[i] * - (1+player.tech_lookup.id(e.info->id).prod[i]); - } - if (e.building < 0) { - e.building++; - if (e.building == 0) { - e.hp = clamp_hp(e.hp + 50); - } - } - if (e.info->unit == 1 && check_obstructed(e)) { - e.hp = clamp_hp(e.hp + 20); - } - } - } - if (player.researching != -1) { - player.techs.push_back(player.researching); - update_tech_lookup(player); - player.researching = -1; - } -} - -void Gst::level_upgrade (Player &player) { - for (Entity &e : entities) { - if (get_player(e.owner) == player) { - if (e.info->upgrade != -1 && e.info->level == player.level) { - e.info = inv->get_info(e.info->upgrade); - } - } - } -} - - -void Gst::update_tech_lookup (Player &player) { - player.tech_lookup.map_id.clear(); - for (int i : player.techs) { - Tech *tech = inv->get_tech(i); - std::vector<int> ids { }; - bool noaff = true; - if (tech->bonus.aff_id.size() > 0) { - ids = tech->bonus.aff_id; - noaff = false; - } else { - if (tech->bonus.aff_level != -1) { - for (EntityInfo info : inv->infos) { - if (info.level == tech->bonus.aff_level) { - ids.push_back(info.id); - } - } - noaff = false; - } - if (tech->bonus.aff_class.size() > 0) { - for (EntityInfo info : inv->infos) { - auto &cls = tech->bonus.aff_class; - if (std::find(cls.begin(), cls.end(), - info.ent_class) != cls.end()) - { - ids.push_back(info.id); - } - } - noaff = false; - } - } - if (noaff) { for (auto info : inv->infos) ids.push_back(info.id); } - for (int id : ids) { - player.tech_lookup.map_id[id] = - player.tech_lookup.map_id[id] + tech->bonus; - } - } +#include "gst.h"
+
+#include <map>
+#include <iostream>
+
+
+Tech* Inv::get_tech (int id) {
+ for (auto &tech : techs) {
+ if (id == tech.id) return &tech;
+ }
+}
+
+EntityInfo* Inv::get_info (std::string name) {
+ for (EntityInfo &info : infos) {
+ if (name == info.name) return &info;
+ }
+}
+
+EntityInfo* Inv::get_info (int id) {
+ for (EntityInfo &info : infos) {
+ if (id == info.id) return &info;
+ }
+}
+
+bool Inv::info_has_ability (EntityInfo* info, std::string name) {
+ for (int ab : info->abilities) {
+ if (abilities[ab].name == name) return true;
+ }
+ return false;
+}
+
+
+
+Player& Gst::get_player (int id) {
+ for (auto &player : players) {
+ if (id == player.id) return player;
+ }
+}
+
+Entity& Gst::get_at (int x, int y) {
+ for (Entity &e : entities) {
+ if (e.x ==x && e.y == y) return e;
+ }
+}
+
+std::vector<float> Gst::get_cost (EntityInfo *info, Player &player) {
+ std::vector<float> cost = info->cost;
+
+ std::cout << "cost : " << player.tech_lookup.id(info->id).cost[0] << " " << player.tech_lookup.id(info->id).cost[1] << "\n";
+ for (int i=0; i<info->cost.size(); i++) {
+ cost[i] *= 1+player.tech_lookup.id(info->id).cost[i];
+ cost[i] += player.tech_lookup.id(info->id).cost_abs[i];
+ }
+ return cost;
+}
+
+float Gst::get_trade_rate (Player &player) {
+ float rate = 250;
+ rate -= player.tech_lookup.id(0).trade * 25;
+ return rate;
+}
+
+float Gst::get_type_bonus (Entity &atk, Entity &def) {
+ float b = 0;
+ switch(atk.info->ent_class) {
+ case EntityInfo::Class::inf:
+ if (def.info->ent_class == EntityInfo::Class::bld) b += 1.0f/3.0f;
+ if (def.info->ent_class == EntityInfo::Class::sie) b += 1.0f/3.0f;
+ break;
+
+ case EntityInfo::Class::cav:
+ if (def.info->ent_class == EntityInfo::Class::bld) b += -0.5;
+ if (def.info->ent_class == EntityInfo::Class::inf) b += 1.0f/3.0f;
+ if (def.info->ent_class == EntityInfo::Class::ran) b += 1.0f/3.0f;
+ break;
+
+ case EntityInfo::Class::ran:
+ if (def.info->ent_class == EntityInfo::Class::bld) b += -0.5f;
+ break;
+
+ case EntityInfo::Class::sie:
+ if (def.info->ent_class == EntityInfo::Class::bld) b += +0.5f;
+ break;
+ }
+ return b;
+}
+
+int Gst::get_vet_level (Entity &ent) { return std::min(3, ent.fights/3); }
+
+std::vector<Bonus> Gst::get_bonuses (Entity &atk, Entity &def) {
+ auto &tiles = inv->tiles;
+ auto &ground = inv->ground;
+ std::vector<Bonus> bs;
+ if (tiles[ground.tiles[ground.at(atk.x, atk.y)]].attack_bonus != 0) {
+
+ bs.emplace_back(
+ tiles[ground.tiles[ground.at(atk.x, atk.y)]].attack_bonus,
+ Bonus::Id::ground, true);
+ }
+ if (tiles[ground.tiles[ground.at(def.x, def.y)]].defence_bonus != 0) {
+ bs.emplace_back(
+ tiles[ground.tiles[ground.at(def.x, def.y)]].defence_bonus,
+ Bonus::Id::ground, false);
+ }
+
+ if (check_obstructed(def)) {
+ for (Entity &e : entities) {
+ if (&def != &e && e.x == def.x && def.y == e.y) {
+ bs.emplace_back(e.info->defence_bonus,
+ Bonus::Id::on_bld, false);
+ }
+ }
+ }
+
+ if (get_type_bonus(atk, def) != 0) {
+ bs.emplace_back(get_type_bonus(atk, def), Bonus::Id::type, true);
+ }
+ /* only attack bonuses
+ if (get_type_bonus(def, atk) != 0) {
+ bs.emplace_back(get_type_bonus(def, atk), Bonus::Id::type, false);
+ }*/
+
+ if (inv->info_has_ability(atk.info, "Causes Fear"))
+ bs.emplace_back(-1.0f/3, Bonus::Id::ability, false);
+ if (inv->info_has_ability(def.info, "Causes Fear"))
+ bs.emplace_back(-1.0f/3, Bonus::Id::ability, true);
+
+ if (inv->info_has_ability(atk.info, "Anti-Cavalry"))
+ bs.emplace_back(4.0f/3, Bonus::Id::ability, true);
+ if (inv->info_has_ability(def.info, "Anti-Cavalry"))
+ bs.emplace_back(4.0f/3, Bonus::Id::ability, false);
+
+ if (inv->info_has_ability(atk.info, "Desert Charge")
+ && !inv->info_has_ability(def.info, "Desert Charge")
+ && tiles[ground.tiles[ground.at(def.x, def.y)]].name == "Desert")
+ bs.emplace_back(1.0f/3, Bonus::Id::ability, true);
+
+ if (inv->info_has_ability(atk.info, "Plains Charge")
+ && !inv->info_has_ability(def.info, "Plains Charge")
+ && tiles[ground.tiles[ground.at(def.x, def.y)]].name == "Plains")
+ bs.emplace_back(1.0f/3, Bonus::Id::ability, true);
+
+ if (inv->info_has_ability(atk.info, "Woodsman")
+ && !inv->info_has_ability(def.info, "Woodsman")
+ && tiles[ground.tiles[ground.at(def.x, def.y)]].name == "Forest")
+ bs.emplace_back(1.0f/3, Bonus::Id::ability, true);
+
+ if (inv->info_has_ability(atk.info, "Volley") && atk.hp >= 50)
+ bs.emplace_back(1.0f/3, Bonus::Id::ability, true);
+
+ if (inv->info_has_ability(atk.info, "Frenzy"))
+ bs.emplace_back(1/atk.hp, Bonus::Id::ability, true);
+
+ Player &player_atk = players[atk.owner];
+ Player &player_def = players[def.owner];
+ float tech_attack = player_atk.tech_lookup.id(atk.info->id).attack;
+ if (tech_attack != 0)
+ bs.emplace_back(tech_attack, Bonus::Id::tech, true);
+ float tech_defence = player_def.tech_lookup.id(def.info->id).defence;
+ if (tech_defence != 0)
+ bs.emplace_back(tech_defence, Bonus::Id::tech, false);
+
+ float atk_vet = get_vet_level(atk) * 0.15f;
+ if (atk_vet > 0)
+ bs.emplace_back(atk_vet, Bonus::Id::veteran, true);
+ float def_vet = get_vet_level(def) * 0.15f;
+ if (def_vet > 0)
+ bs.emplace_back(def_vet, Bonus::Id::veteran, false);
+
+ return bs;
+}
+
+float Gst::get_damage (Entity &atk, Entity &def, float atk_hp) {
+ float atkmul = 1;
+ float defmul = 1;
+
+ auto bonuses = get_bonuses(atk, def);
+ for (auto bonus : bonuses) {
+ if (bonus.atk) { atkmul += bonus.amt; }
+ else { defmul += bonus.amt; }
+ }
+
+ float dam = (atk.info->attack * atk_hp * atkmul)
+ / (2.0f*def.info->defence * defmul);
+
+ return dam;
+}
+
+float Gst::get_damage (Entity &atk, Entity &def) {
+ return get_damage(atk, def, atk.hp);
+}
+
+bool Gst::get_first_strike (Entity &atk, Entity &def) {
+ bool fs { false };
+ fs = inv->info_has_ability(atk.info, "First Strike");
+ return fs;
+}
+
+float clamp_hp (float hp) {
+ if (hp > 100) hp = 100;
+ if (hp < 0) hp = 0;
+ return hp;
+}
+
+BattleResult Gst::battle_res (Entity &atk, Entity &def) {
+ BattleResult result { atk.hp, def.hp };
+ bool first_strike_atk = inv->info_has_ability(atk.info, "First Strike");
+ bool first_strike_def = inv->info_has_ability(def.info, "First Strike");
+ bool skirmish_atk = inv->info_has_ability(atk.info, "Skirmish");
+ bool skirmish_def = inv->info_has_ability(def.info, "Skirmish");
+ bool anticav_atk = inv->info_has_ability(atk.info, "Anti-Cavalry");
+ bool anticav_def = inv->info_has_ability(def.info, "Anti-Cavalry");
+ first_strike_atk = first_strike_atk
+ || (skirmish_atk && def.info->range == 1);
+ first_strike_def = first_strike_def
+ || (skirmish_def && atk.info->range == 1);
+ first_strike_atk = first_strike_atk
+ || (anticav_atk && def.info->ent_class == EntityInfo::Class::cav);
+ first_strike_def = first_strike_def
+ || (anticav_def && atk.info->ent_class == EntityInfo::Class::cav);
+
+ int dist = abs(atk.x-def.x) + abs(atk.y-def.y);
+ bool def_inrange = (dist <= get_range(def)) ? true : false;
+
+ bool swap = false;
+ if (first_strike_def && !first_strike_atk) swap = true;
+ if (swap) {
+ if (def_inrange) {
+ result.atk_hp = clamp_hp(
+ result.atk_hp - get_damage(def, atk, result.def_hp));
+ }
+ if (!inv->info_has_ability(atk.info, "No Counter"))
+ if (result.atk_hp > 0)
+ result.def_hp = clamp_hp(
+ result.def_hp - get_damage(atk, def, result.atk_hp));
+ } else {
+ result.def_hp = clamp_hp(
+ result.def_hp - get_damage(atk, def, result.atk_hp));
+ if (!inv->info_has_ability(def.info, "No Counter") && def_inrange)
+ if (result.def_hp > 0)
+ result.atk_hp = clamp_hp(
+ result.atk_hp - get_damage(def, atk, result.def_hp));
+ }
+
+ if (inv->info_has_ability(atk.info, "Rapid Fire"))
+ if (result.def_hp > 0)
+ result.def_hp = clamp_hp(
+ result.def_hp - get_damage(atk, def, result.def_hp));
+
+ if (inv->info_has_ability(def.info, "Rapid Fire") && def_inrange)
+ if (result.atk_hp > 0)
+ result.atk_hp = clamp_hp(
+ result.atk_hp - get_damage(def, atk, result.def_hp));
+
+ if (result.atk_hp > 0 && inv->info_has_ability(atk.info, "Zeal"))
+ result.atk_hp = clamp_hp(result.atk_hp + 20);
+ if (result.def_hp > 0 && inv->info_has_ability(def.info, "Zeal"))
+ result.def_hp = clamp_hp(result.def_hp + 20);
+
+ return result;
+}
+
+void Gst::battle (Entity &atk, Entity &def) {
+ /*std::cout << "! attack " << atk.info->name << "(hp:" << atk.hp << "), "
+ << def.info->name << "(hp:" << def.hp << ") \n";*/
+
+ auto result = battle_res(atk, def);
+ atk.hp = result.atk_hp;
+ def.hp = result.def_hp;
+
+ if (atk.info->unit == 1) atk.fights += 1;
+ if (def.info->unit == 1) def.fights += 1;
+
+ /*std::cout << "! result " << atk.info->name << "(hp:" << atk.hp << "), "
+ << def.info->name << "(hp:" << def.hp << ") \n";*/
+ clear_dead();
+}
+
+void Gst::clear_dead() {
+ auto i = std::begin(entities);
+ while (i != std::end(entities)) {
+ if (i->hp <= 0) {
+ entities.erase(i);
+ }
+ else i++;
+ }
+}
+
+int Gst::get_range (Entity &ent) {
+ int range = ent.info->range;
+ if (range > 1) {
+ auto &tiles = inv->tiles;
+ auto &ground = inv->ground;
+ range += tiles[ground.tiles[ground.at(ent.x, ent.y)]].range_bonus;
+ }
+ if (range < 1) range = 1;
+ return range;
+}
+
+
+void Gst::heal (Entity &atk, Entity &def) {
+ Player &player = get_player(atk.owner);
+ float amt = 20;
+ if (atk.info->level == 3) { amt += 10; } // improved heal
+ if (player.has_tech(52)) { amt += 10; } // tech illumination
+ def.hp = clamp_hp(def.hp + amt);
+}
+
+void Gst::convert (Entity &atk, Entity &def) {
+ Player &player = get_player(atk.owner);
+ float amt = 0.20f;
+ if (player.has_tech(53)) { amt += 0.10f; } // tech faith
+ // caution, randomness
+ std::uniform_real_distribution<float> odds(0, 1);
+ float value = odds(inv->engine);
+ std::cout << value << " / " << amt << " odds\n";
+ if (value < amt) {
+ def.owner = atk.owner;
+ }
+}
+
+
+int Gst::get_nearest_enemy (Entity &ent, int &mindist) {
+ auto &ground = inv->ground;
+ int pos = -1; mindist = 9999999;
+ for (Entity &oth : entities) {
+ if (oth.owner == ent.owner) continue;
+ int dist = abs(oth.x-ent.x) + abs(oth.y-ent.y);
+ if (dist < mindist) {
+ mindist = dist;
+ pos = ground.at(oth.x, oth.y);
+ }
+ }
+}
+
+
+std::vector<int> Gst::get_possible_trains (Entity &ent) {
+ Player &player = get_player(ent.owner);
+ auto &cls = ent.info->train_class;
+ std::vector<int> trains;
+ if (ent.info->id == 107) { // market special case
+ std::vector<int> candidates;
+ for (EntityInfo &info : inv->infos) {
+ if (info.id == 0) continue; // villager only in train_id
+ if (info.level > player.level) continue;
+ if (info.level < player.level && info.upgrade != -1) continue;
+ if (std::find(cls.begin(), cls.end(), info.ent_class) != cls.end())
+ {
+ candidates.push_back(info.id);
+ }
+ }
+ std::shuffle(candidates.begin(), candidates.end(), inv->engine);
+ // pick 3 cands at random
+ for (int i=0; i<3; i++) trains.push_back(candidates[i]);
+ return trains;
+ }
+
+ for (int id : ent.info->train_id) {
+ auto info = inv->get_info(id);
+ if (info->level > player.level) continue;
+ if (info->level < player.level && info->upgrade != -1) continue;
+ trains.push_back(id);
+ }
+ /*
+ // get all train class ids, highest upgrade level
+ for (EntityInfo &info : infos) {
+ if (info.id == 0) continue; // villager only in train_id
+ if (info.level > player.level) continue;
+ if (info.level < player.level && info.upgrade != -1) continue;
+ if (std::find(cls.begin(), cls.end(), info.ent_class) != cls.end()) {
+ if (std::find(trains.begin(), trains.end(), info.id)
+ != trains.end())
+ {
+ trains.push_back(info.id);
+ }
+ }
+ }*/
+ return trains;
+}
+
+std::vector<int> Gst::get_possible_builds (Entity &ent) {
+ std::vector<int> builds;
+ for (int id : ent.info->build) {
+ if (check_req_build(ent, inv->get_info(id))) {
+ builds.push_back(id);
+ }
+ }
+ return builds;
+}
+
+
+bool Gst::check_req_build(Entity &ent, EntityInfo *info) {
+ auto &ground = inv->ground;
+ Player &player = players[ent.owner];
+ if (player.level < info->level) return false;
+ for (int id : info->adjacent) {
+ bool adj = false;
+ for (Entity &e : entities) {
+ if (e.info->id == id && ent.owner == e.owner) {
+ int dist = abs(e.x-ent.x) + abs(e.y-ent.y);
+ if (dist == 1) {
+ adj = true;
+ }
+ }
+ }
+ if (!adj) return false;
+ }
+ for (int id : info->diagonal) {
+ bool diag = false;
+ for (Entity &e : entities) {
+ if (e.info->id == id && ent.owner == e.owner) {
+ int dx = abs(e.x-ent.x), dy = abs(e.y-ent.y);
+ int dist = dx + dy;
+ if (dx == 1 && dy == 1) {
+ diag = true;
+ }
+ }
+ }
+ if (!diag) return false;
+ }
+ if (info->id == 100) {
+ for (Resource &r : ground.resources) {
+ if (r.pos == ground.at(ent.x, ent.y)) {
+ return false;
+ }
+ }
+ int mindist = 9999;
+ for (Entity &e : entities) {
+ if (e.info->id == 100 && ent.owner == e.owner) {
+ int dist = abs(e.x-ent.x) + abs(ent.y-e.y);
+ if (dist < mindist) {
+ mindist = dist;
+ }
+ }
+ }
+ if (mindist < 5) {
+ return false;
+ }
+ return true;
+ }
+ if (info->id == 101) {
+ for (Resource &r : ground.resources) {
+ if (r.kind == Resource::Type::food
+ && r.pos == ground.at(ent.x, ent.y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (info->id == 102) {
+ for (Resource &r : ground.resources) {
+ if (r.kind == Resource::Type::gold
+ && r.pos == ground.at(ent.x, ent.y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+
+bool Gst::check_req_tech (Tech *tech, Player &player) {
+ if (player.leveling_up == 1) return false;
+ if (tech->level > player.level) {
+ return false;
+ }
+ if (tech->cost[0] > player.res[0]
+ || tech->cost[1] > player.res[1] )
+ {
+ return false;
+ }
+ if (player.has_tech(tech->id)) {
+ return false;
+ }
+ bool req_id = false;
+ for (auto &ent : entities) {
+ if (ent.owner == turn // WARNING: turn is not player.id
+ && ent.info->id == tech->req_id
+ && ent.building == 0)
+ {
+ req_id = true;
+ break;
+ }
+ }
+ if (!req_id) {
+ return false;
+ }
+ return true;
+}
+
+bool Gst::check_req_level (Player &player) {
+ if (player.leveling_up == 1) return false;
+
+ for (float v : player.res) {
+ if (v <= (player.level+1)*500) return false;
+ }
+
+ std::map<int, int> lv_techs;
+ for (int id : player.techs) lv_techs[inv->get_tech(id)->level] ++;
+ if (player.level == 0) {
+ if (lv_techs[0] >= 3) return true;
+ }
+ if (player.level == 1) {
+ if (lv_techs[1] >= 7) return true;
+ }
+ if (player.level == 2) {
+ if (lv_techs[2] >= 11) return true;
+ }
+ return false;
+}
+
+bool Gst::check_obstructed (Entity &ent) {
+ for (Entity &e : entities) {
+ if (&ent != &e && e.x == ent.x && ent.y == e.y) return true;
+ }
+ return false;
+}
+
+void Gst::end_day () {
+ turn++;
+ if (turn >= players.size()) {
+ turn = 0;
+ day++;
+ }
+ Player &player = players[turn];
+ if (player.leveling_up != -1) {
+ level_upgrade(player);
+ player.level ++;
+ player.leveling_up = -1;
+ }
+ for (Entity &e : entities) {
+ e.done = false;
+ e.moved = 0;
+ if (get_player(e.owner) == player) {
+ for (int i=0; i<player.res.size(); i++) {
+ player.res[i] += e.info->prod[i] *
+ (1+player.tech_lookup.id(e.info->id).prod[i]);
+ }
+ if (e.building < 0) {
+ e.building++;
+ if (e.building == 0) {
+ e.hp = clamp_hp(e.hp + 50);
+ }
+ }
+ if (e.info->unit == 1 && check_obstructed(e)) {
+ e.hp = clamp_hp(e.hp + 20);
+ }
+ }
+ }
+ if (player.researching != -1) {
+ player.techs.push_back(player.researching);
+ update_tech_lookup(player);
+ player.researching = -1;
+ }
+}
+
+void Gst::level_upgrade (Player &player) {
+ for (Entity &e : entities) {
+ if (get_player(e.owner) == player) {
+ if (e.info->upgrade != -1 && e.info->level == player.level) {
+ e.info = inv->get_info(e.info->upgrade);
+ }
+ }
+ }
+}
+
+
+void Gst::update_tech_lookup (Player &player) {
+ player.tech_lookup.map_id.clear();
+ for (int i : player.techs) {
+ Tech *tech = inv->get_tech(i);
+ std::vector<int> ids { };
+ bool noaff = true;
+ if (tech->bonus.aff_id.size() > 0) {
+ ids = tech->bonus.aff_id;
+ noaff = false;
+ } else {
+ if (tech->bonus.aff_level != -1) {
+ for (EntityInfo info : inv->infos) {
+ if (info.level == tech->bonus.aff_level) {
+ ids.push_back(info.id);
+ }
+ }
+ noaff = false;
+ }
+ if (tech->bonus.aff_class.size() > 0) {
+ for (EntityInfo info : inv->infos) {
+ auto &cls = tech->bonus.aff_class;
+ if (std::find(cls.begin(), cls.end(),
+ info.ent_class) != cls.end())
+ {
+ ids.push_back(info.id);
+ }
+ }
+ noaff = false;
+ }
+ }
+ if (noaff) { for (auto info : inv->infos) ids.push_back(info.id); }
+ for (int id : ids) {
+ player.tech_lookup.map_id[id] =
+ player.tech_lookup.map_id[id] + tech->bonus;
+ }
+ }
}
\ No newline at end of file @@ -1,125 +1,125 @@ -#ifndef GST_H -#define GST_H - -#include <iostream> -#include <algorithm> -#include <string> -#include <vector> -#include <functional> - -#include <random> // just for picking market trains - -#include "ground.h" -#include "entity.h" -#include "tile.h" -#include "player.h" -#include "tech.h" - -class Ability { - public: - Ability(std::string name) : name(name) {} - std::string name; -}; - -class Bonus { - public: - Bonus(float amt, int id, bool atk) : amt(amt), id(id), atk(atk) {} - float amt; int id; bool atk; - enum Id { ground, type, ability, tech, veteran, on_bld, adjacency }; - std::string id_string () { - switch (id) { - case ground: return "Ground"; - case type: return "Class"; - case ability: return "Ability"; - case tech: return "Tech"; - case veteran: return "Veteran"; - case on_bld: return "On Building"; - case adjacency: return "Adjacency"; - } - } -}; - -class BattleResult { - public: - BattleResult(float atk_hp, float def_hp) - : atk_hp(atk_hp), def_hp(def_hp) {} - float atk_hp, def_hp; -}; - -class Inv { - public: - Inv () {} - - std::vector<Tech> techs; - std::vector<Ability> abilities; - std::vector<EntityInfo> infos; - std::vector<Tile> tiles; - Ground ground; - - Tech* get_tech (int id); - EntityInfo* get_info (std::string name); - EntityInfo* get_info (int id); - bool info_has_ability (EntityInfo* info, std::string name); - - std::default_random_engine engine = std::default_random_engine{}; -}; - -class Gst { - public: - Gst(Inv *inv) : inv(inv) { } - - // copy constructor - Gst (const Gst& rhs) { - inv = rhs.inv; entities = rhs.entities; players = rhs.players; - turn = rhs.turn; day = rhs.day; - } - Gst& operator=(const Gst& rhs) { - inv = rhs.inv; entities = rhs.entities; players = rhs.players; - turn = rhs.turn; day = rhs.day; - }; - - Inv *inv; - - std::vector<Entity> entities; - std::vector<Player> players; - int turn { 0 }; - int day { 0 }; - - Player& get_player (int id); - - Entity& get_at (int x, int y); - std::vector<float> get_cost (EntityInfo *info, Player &player); - float get_trade_rate (Player &player); - - int get_vet_level (Entity &ent); - float get_type_bonus (Entity &atk, Entity &def); - std::vector<Bonus> get_bonuses (Entity &atk, Entity &def); - float get_damage (Entity &atk, Entity &def); - float get_damage (Entity &atk, Entity &def, float atk_hp); - bool get_first_strike (Entity &atk, Entity &def); - BattleResult battle_res (Entity &atk, Entity &def); - void clear_dead(); - int get_range(Entity &ent); - - void battle (Entity &atk, Entity &def); - - void heal (Entity &atk, Entity &def); - void convert (Entity &atk, Entity &def); - - int get_nearest_enemy (Entity &ent, int &mindist); - - std::vector<int> get_possible_trains (Entity &ent); - std::vector<int> get_possible_builds (Entity &ent); - - bool check_req_build (Entity &ent, EntityInfo *info); - bool check_req_tech (Tech *tech, Player &player); - bool check_req_level (Player &player); - bool check_obstructed (Entity &ent); - - void end_day (); - void level_upgrade (Player &player); - - void update_tech_lookup (Player &player); -}; - +#ifndef GST_H
+#define GST_H
+
+#include <iostream>
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <functional>
+
+#include <random> // just for picking market trains
+
+#include "ground.h"
+#include "entity.h"
+#include "tile.h"
+#include "player.h"
+#include "tech.h"
+
+class Ability {
+ public:
+ Ability(std::string name) : name(name) {}
+ std::string name;
+};
+
+class Bonus {
+ public:
+ Bonus(float amt, int id, bool atk) : amt(amt), id(id), atk(atk) {}
+ float amt; int id; bool atk;
+ enum Id { ground, type, ability, tech, veteran, on_bld, adjacency };
+ std::string id_string () {
+ switch (id) {
+ case ground: return "Ground";
+ case type: return "Class";
+ case ability: return "Ability";
+ case tech: return "Tech";
+ case veteran: return "Veteran";
+ case on_bld: return "On Building";
+ case adjacency: return "Adjacency";
+ }
+ }
+};
+
+class BattleResult {
+ public:
+ BattleResult(float atk_hp, float def_hp)
+ : atk_hp(atk_hp), def_hp(def_hp) {}
+ float atk_hp, def_hp;
+};
+
+class Inv {
+ public:
+ Inv () {}
+
+ std::vector<Tech> techs;
+ std::vector<Ability> abilities;
+ std::vector<EntityInfo> infos;
+ std::vector<Tile> tiles;
+ Ground ground;
+
+ Tech* get_tech (int id);
+ EntityInfo* get_info (std::string name);
+ EntityInfo* get_info (int id);
+ bool info_has_ability (EntityInfo* info, std::string name);
+
+ std::default_random_engine engine = std::default_random_engine{};
+};
+
+class Gst {
+ public:
+ Gst(Inv *inv) : inv(inv) { }
+
+ // copy constructor
+ Gst (const Gst& rhs) {
+ inv = rhs.inv; entities = rhs.entities; players = rhs.players;
+ turn = rhs.turn; day = rhs.day;
+ }
+ Gst& operator=(const Gst& rhs) {
+ inv = rhs.inv; entities = rhs.entities; players = rhs.players;
+ turn = rhs.turn; day = rhs.day;
+ };
+
+ Inv *inv;
+
+ std::vector<Entity> entities;
+ std::vector<Player> players;
+ int turn { 0 };
+ int day { 0 };
+
+ Player& get_player (int id);
+
+ Entity& get_at (int x, int y);
+ std::vector<float> get_cost (EntityInfo *info, Player &player);
+ float get_trade_rate (Player &player);
+
+ int get_vet_level (Entity &ent);
+ float get_type_bonus (Entity &atk, Entity &def);
+ std::vector<Bonus> get_bonuses (Entity &atk, Entity &def);
+ float get_damage (Entity &atk, Entity &def);
+ float get_damage (Entity &atk, Entity &def, float atk_hp);
+ bool get_first_strike (Entity &atk, Entity &def);
+ BattleResult battle_res (Entity &atk, Entity &def);
+ void clear_dead();
+ int get_range(Entity &ent);
+
+ void battle (Entity &atk, Entity &def);
+
+ void heal (Entity &atk, Entity &def);
+ void convert (Entity &atk, Entity &def);
+
+ int get_nearest_enemy (Entity &ent, int &mindist);
+
+ std::vector<int> get_possible_trains (Entity &ent);
+ std::vector<int> get_possible_builds (Entity &ent);
+
+ bool check_req_build (Entity &ent, EntityInfo *info);
+ bool check_req_tech (Tech *tech, Player &player);
+ bool check_req_level (Player &player);
+ bool check_obstructed (Entity &ent);
+
+ void end_day ();
+ void level_upgrade (Player &player);
+
+ void update_tech_lookup (Player &player);
+};
+
#endif
\ No newline at end of file diff --git a/game/load.cpp b/game/load.cpp index ea4e9e7..f9b0135 100644 --- a/game/load.cpp +++ b/game/load.cpp @@ -1,150 +1,150 @@ -#include <iostream> -#include <fstream> -#include <vector> - -#include "load.h" - -#include "nlohmann/json.hpp" -using json = nlohmann::json; - -std::vector<Ability> load_abilities () { - std::vector<Ability> abs; - abs.emplace_back("Anti-Cavalry"); - abs.emplace_back("Skirmish"); - abs.emplace_back("First Strike"); - abs.emplace_back("Rapid Fire"); - abs.emplace_back("Units Only"); - abs.emplace_back("Buildings Only"); - abs.emplace_back("No Counter"); - abs.emplace_back("No Move & Attack"); - abs.emplace_back("Causes Fear"); - abs.emplace_back("Desert Charge"); - abs.emplace_back("Plains Charge"); - abs.emplace_back("Scares Horses"); - abs.emplace_back("Woodsman"); - abs.emplace_back("Volley"); - abs.emplace_back("Frenzy"); - abs.emplace_back("Zeal"); - abs.emplace_back("Scout"); - abs.emplace_back("Convert"); - abs.emplace_back("Heal"); - abs.emplace_back("Seasoned Veteran"); - return abs; -} - -void load_json (Inv &inv) { - inv.abilities = load_abilities(); - - std::ifstream file_tiles("content/tiles.json"); - json j_tiles; file_tiles >> j_tiles; - for (auto it : j_tiles) { - Tile tile; - tile.name = it["name"]; - tile.move_cost = it["move_cost"]; - tile.defence_bonus = it["defence_bonus"]; - tile.range_bonus = it["range_bonus"]; - tile.spritebounds = vec2 { it["spritebounds"][0], it["spritebounds"][1] }; - inv.tiles.push_back(tile); - } - - std::ifstream file_ents("content/entities.json"); - json j_ents; file_ents >> j_ents; - for (auto it : j_ents) { - EntityInfo ent; - ent.id = it["id"]; - ent.name = it["name"]; - ent.level = it["level"]; - ent.range = it["range"]; - ent.move = it["move"]; - ent.attack = it["attack"]; - ent.defence = it["defence"]; - ent.sight = it["sight"]; - ent.unit = it["unit"]; - for (int i=0; i<it["prod"].size(); i++) { - ent.prod[i] = it["prod"][i]; - } - for (int i=0; i<it["cost"].size(); i++) { - ent.cost[i] = it["cost"][i]; - } - for (auto blds : it["build"]) { - ent.build.push_back(blds); - } - for (auto train : it["train_id"]) { - ent.train_id.push_back(train); - } - for (auto train : it["train_class"]) { - ent.train_class.push_back((EntityInfo::Class) - EntityClass::from_string(train.get<std::string>())); - } - for (auto ad : it["adjacent"]) { - ent.adjacent.push_back(ad); - } - for (auto ad : it["diagonal"]) { - ent.diagonal.push_back(ad); - } - ent.ent_class = (EntityInfo::Class) EntityClass::from_string( - it["class"].get<std::string>()); - for (auto ab : it["abilities"]) { - int index = 0; - for (int i=0; i<inv.abilities.size(); i++) { - if (inv.abilities[i].name == ab) { index = i; break; } - } - ent.abilities.push_back(index); - } - ent.spritebounds = vec2 { it["spritebounds"][0], it["spritebounds"][1] }; - if (it.contains("upgrade")) { ent.upgrade = it["upgrade"]; } - if (it.contains("defence_bonus")) { - ent.defence_bonus = it["defence_bonus"]; - } - inv.infos.push_back(ent); - } - - std::ifstream file_techs("content/techs.json"); - json j_techs; file_techs >> j_techs; - for (auto it : j_techs) { - Tech tech; - tech.name = it["name"]; - tech.id = it["id"]; - tech.level = it["level"]; - tech.req_id = it["req_id"]; - for (int i=0; i<it["cost"].size(); i++) { - tech.cost[i] = it["cost"][i]; - } - auto b = it["bonus"]; - if (b != nullptr) { - if (b.contains("attack")) { tech.bonus.attack = b["attack"]; } - if (b.contains("defence")) { tech.bonus.defence = b["defence"]; } - if (b.contains("sight")) { tech.bonus.sight = b["sight"]; } - if (b.contains("move")) { tech.bonus.move = b["move"]; } - if (b.contains("trade")) { tech.bonus.trade = b["trade"]; } - if (b.contains("req_range")) { - tech.bonus.req_range = b["req_range"]; - } - if (b.contains("improved_heal")) { - tech.bonus.improved_heal = b["improved_heal"]; - } - if (b.contains("improved_convert")) { - tech.bonus.improved_convert = b["improved_convert"]; - } - if (b.contains("cost")) tech.bonus.cost.clear(); - for (auto v : b["cost"]) { tech.bonus.cost.push_back(v); } - if (b.contains("cost_abs")) tech.bonus.cost_abs.clear(); - for (auto v : b["cost_abs"]) { tech.bonus.cost_abs.push_back(v); } - if (b.contains("prod")) tech.bonus.prod.clear(); - for (auto v : b["prod"]) { tech.bonus.prod.push_back(v); } - - for (auto v : b["aff_id"]) { tech.bonus.aff_id.push_back(v); } - for (auto v : b["aff_class"]) { - tech.bonus.aff_class.push_back(EntityClass::from_string( - v.get<std::string>())); - } - if (b.contains("aff_level")) { - tech.bonus.aff_level = b["aff_level"]; - } - if (b.contains("aff_all")) { - tech.bonus.aff_all = b["aff_all"]; - } - } - inv.techs.push_back(tech); - } +#include <iostream>
+#include <fstream>
+#include <vector>
+
+#include "load.h"
+
+#include "nlohmann/json.hpp"
+using json = nlohmann::json;
+
+std::vector<Ability> load_abilities () {
+ std::vector<Ability> abs;
+ abs.emplace_back("Anti-Cavalry");
+ abs.emplace_back("Skirmish");
+ abs.emplace_back("First Strike");
+ abs.emplace_back("Rapid Fire");
+ abs.emplace_back("Units Only");
+ abs.emplace_back("Buildings Only");
+ abs.emplace_back("No Counter");
+ abs.emplace_back("No Move & Attack");
+ abs.emplace_back("Causes Fear");
+ abs.emplace_back("Desert Charge");
+ abs.emplace_back("Plains Charge");
+ abs.emplace_back("Scares Horses");
+ abs.emplace_back("Woodsman");
+ abs.emplace_back("Volley");
+ abs.emplace_back("Frenzy");
+ abs.emplace_back("Zeal");
+ abs.emplace_back("Scout");
+ abs.emplace_back("Convert");
+ abs.emplace_back("Heal");
+ abs.emplace_back("Seasoned Veteran");
+ return abs;
+}
+
+void load_json (Inv &inv) {
+ inv.abilities = load_abilities();
+
+ std::ifstream file_tiles("content/tiles.json");
+ json j_tiles; file_tiles >> j_tiles;
+ for (auto it : j_tiles) {
+ Tile tile;
+ tile.name = it["name"];
+ tile.move_cost = it["move_cost"];
+ tile.defence_bonus = it["defence_bonus"];
+ tile.range_bonus = it["range_bonus"];
+ tile.spritebounds = vec2 { it["spritebounds"][0], it["spritebounds"][1] };
+ inv.tiles.push_back(tile);
+ }
+
+ std::ifstream file_ents("content/entities.json");
+ json j_ents; file_ents >> j_ents;
+ for (auto it : j_ents) {
+ EntityInfo ent;
+ ent.id = it["id"];
+ ent.name = it["name"];
+ ent.level = it["level"];
+ ent.range = it["range"];
+ ent.move = it["move"];
+ ent.attack = it["attack"];
+ ent.defence = it["defence"];
+ ent.sight = it["sight"];
+ ent.unit = it["unit"];
+ for (int i=0; i<it["prod"].size(); i++) {
+ ent.prod[i] = it["prod"][i];
+ }
+ for (int i=0; i<it["cost"].size(); i++) {
+ ent.cost[i] = it["cost"][i];
+ }
+ for (auto blds : it["build"]) {
+ ent.build.push_back(blds);
+ }
+ for (auto train : it["train_id"]) {
+ ent.train_id.push_back(train);
+ }
+ for (auto train : it["train_class"]) {
+ ent.train_class.push_back((EntityInfo::Class)
+ EntityClass::from_string(train.get<std::string>()));
+ }
+ for (auto ad : it["adjacent"]) {
+ ent.adjacent.push_back(ad);
+ }
+ for (auto ad : it["diagonal"]) {
+ ent.diagonal.push_back(ad);
+ }
+ ent.ent_class = (EntityInfo::Class) EntityClass::from_string(
+ it["class"].get<std::string>());
+ for (auto ab : it["abilities"]) {
+ int index = 0;
+ for (int i=0; i<inv.abilities.size(); i++) {
+ if (inv.abilities[i].name == ab) { index = i; break; }
+ }
+ ent.abilities.push_back(index);
+ }
+ ent.spritebounds = vec2 { it["spritebounds"][0], it["spritebounds"][1] };
+ if (it.contains("upgrade")) { ent.upgrade = it["upgrade"]; }
+ if (it.contains("defence_bonus")) {
+ ent.defence_bonus = it["defence_bonus"];
+ }
+ inv.infos.push_back(ent);
+ }
+
+ std::ifstream file_techs("content/techs.json");
+ json j_techs; file_techs >> j_techs;
+ for (auto it : j_techs) {
+ Tech tech;
+ tech.name = it["name"];
+ tech.id = it["id"];
+ tech.level = it["level"];
+ tech.req_id = it["req_id"];
+ for (int i=0; i<it["cost"].size(); i++) {
+ tech.cost[i] = it["cost"][i];
+ }
+ auto b = it["bonus"];
+ if (b != nullptr) {
+ if (b.contains("attack")) { tech.bonus.attack = b["attack"]; }
+ if (b.contains("defence")) { tech.bonus.defence = b["defence"]; }
+ if (b.contains("sight")) { tech.bonus.sight = b["sight"]; }
+ if (b.contains("move")) { tech.bonus.move = b["move"]; }
+ if (b.contains("trade")) { tech.bonus.trade = b["trade"]; }
+ if (b.contains("req_range")) {
+ tech.bonus.req_range = b["req_range"];
+ }
+ if (b.contains("improved_heal")) {
+ tech.bonus.improved_heal = b["improved_heal"];
+ }
+ if (b.contains("improved_convert")) {
+ tech.bonus.improved_convert = b["improved_convert"];
+ }
+ if (b.contains("cost")) tech.bonus.cost.clear();
+ for (auto v : b["cost"]) { tech.bonus.cost.push_back(v); }
+ if (b.contains("cost_abs")) tech.bonus.cost_abs.clear();
+ for (auto v : b["cost_abs"]) { tech.bonus.cost_abs.push_back(v); }
+ if (b.contains("prod")) tech.bonus.prod.clear();
+ for (auto v : b["prod"]) { tech.bonus.prod.push_back(v); }
+
+ for (auto v : b["aff_id"]) { tech.bonus.aff_id.push_back(v); }
+ for (auto v : b["aff_class"]) {
+ tech.bonus.aff_class.push_back(EntityClass::from_string(
+ v.get<std::string>()));
+ }
+ if (b.contains("aff_level")) {
+ tech.bonus.aff_level = b["aff_level"];
+ }
+ if (b.contains("aff_all")) {
+ tech.bonus.aff_all = b["aff_all"];
+ }
+ }
+ inv.techs.push_back(tech);
+ }
}
\ No newline at end of file diff --git a/game/load.h b/game/load.h index d9da659..7dce21e 100644 --- a/game/load.h +++ b/game/load.h @@ -1,8 +1,8 @@ -#ifndef LOAD_H -#define LOAD_H - -#include "gst.h" - -void load_json (Inv &inv); - +#ifndef LOAD_H
+#define LOAD_H
+
+#include "gst.h"
+
+void load_json (Inv &inv);
+
#endif
\ No newline at end of file diff --git a/game/menu.cpp b/game/menu.cpp index b5a91b9..6349f29 100644 --- a/game/menu.cpp +++ b/game/menu.cpp @@ -1,77 +1,77 @@ -#include <iostream> - -#include "menu.h" - -void Menu::close () { - active = false; -} - -void Menu::open (vec2 res) { - over = -1; - active = true; - pos = vec2 { (float)res.x, (float)res.y }; - float height = options.size() * 20; - size = vec2 { 150, height+10 }; - pos *= 0.5f; - pos -= size/2; -} - -int Menu::mouse_option (vec2 mouse) { - int i=0; - for (Option opt : options) { - vec2 off { 0, 5.0f + i*20 }; - vec2 sizeopt { 150, 20 }; - off += pos; - if (off.x < mouse.x && mouse.x < off.x+sizeopt.x - && off.y < mouse.y && mouse.y < off.y+sizeopt.y ) { - return opt.id; - } - i++; - } - return -1; -} - - -void Menu_tech::open (vec2 res) { - over = -1; - active = true; - pos = vec2 { (float)res.x, (float)res.y }; - - tech_opt_ordered.clear(); - tech_opt_ordered.emplace_back(); - tech_opt_ordered.emplace_back(); - tech_opt_ordered.emplace_back(); - tech_opt_ordered.emplace_back(); - - for (OptionTech opt : tech_options) { - tech_opt_ordered[opt.tech->level].emplace_back(opt); - } - int maxsize = 0; - for (auto v : tech_opt_ordered) { - maxsize = maxsize < v.size() ? v.size() : maxsize; - } - - float width = 150 * tech_opt_ordered.size(); - float height = maxsize * 10; - size = vec2 { width, height+20 }; - pos *= 0.5f; - pos -= size/2; -} - -int Menu_tech::mouse_option (vec2 mouse) { - float x = 0, y = 0; - for (auto v : tech_opt_ordered) { - for (auto opt : v) { - vec2 off { x*150, 10.0f + y*10 }; - vec2 sizeopt { 150, 10 }; - off += pos; - if (off.x < mouse.x && mouse.x < off.x+sizeopt.x - && off.y < mouse.y && mouse.y < off.y+sizeopt.y ) { - return opt.tech->id; - } - y++; - } - x++; y=0; - } - return -1; +#include <iostream>
+
+#include "menu.h"
+
+void Menu::close () {
+ active = false;
+}
+
+void Menu::open (vec2 res) {
+ over = -1;
+ active = true;
+ pos = vec2 { (float)res.x, (float)res.y };
+ float height = options.size() * 20;
+ size = vec2 { 150, height+10 };
+ pos *= 0.5f;
+ pos -= size/2;
+}
+
+int Menu::mouse_option (vec2 mouse) {
+ int i=0;
+ for (Option opt : options) {
+ vec2 off { 0, 5.0f + i*20 };
+ vec2 sizeopt { 150, 20 };
+ off += pos;
+ if (off.x < mouse.x && mouse.x < off.x+sizeopt.x
+ && off.y < mouse.y && mouse.y < off.y+sizeopt.y ) {
+ return opt.id;
+ }
+ i++;
+ }
+ return -1;
+}
+
+
+void Menu_tech::open (vec2 res) {
+ over = -1;
+ active = true;
+ pos = vec2 { (float)res.x, (float)res.y };
+
+ tech_opt_ordered.clear();
+ tech_opt_ordered.emplace_back();
+ tech_opt_ordered.emplace_back();
+ tech_opt_ordered.emplace_back();
+ tech_opt_ordered.emplace_back();
+
+ for (OptionTech opt : tech_options) {
+ tech_opt_ordered[opt.tech->level].emplace_back(opt);
+ }
+ int maxsize = 0;
+ for (auto v : tech_opt_ordered) {
+ maxsize = maxsize < v.size() ? v.size() : maxsize;
+ }
+
+ float width = 150 * tech_opt_ordered.size();
+ float height = maxsize * 10;
+ size = vec2 { width, height+20 };
+ pos *= 0.5f;
+ pos -= size/2;
+}
+
+int Menu_tech::mouse_option (vec2 mouse) {
+ float x = 0, y = 0;
+ for (auto v : tech_opt_ordered) {
+ for (auto opt : v) {
+ vec2 off { x*150, 10.0f + y*10 };
+ vec2 sizeopt { 150, 10 };
+ off += pos;
+ if (off.x < mouse.x && mouse.x < off.x+sizeopt.x
+ && off.y < mouse.y && mouse.y < off.y+sizeopt.y ) {
+ return opt.tech->id;
+ }
+ y++;
+ }
+ x++; y=0;
+ }
+ return -1;
}
\ No newline at end of file diff --git a/game/menu.h b/game/menu.h index 41348a7..471bfd7 100644 --- a/game/menu.h +++ b/game/menu.h @@ -1,90 +1,90 @@ -#ifndef MENU_H -#define MENU_H - -#include <vector> -#include <string> - -#include "../umath/vec2.h" -#include "tech.h" - -class Option { - public: - Option(std::string name, int id) : name(name), id(id) {} - - std::string name; - int id; - - std::vector<float> cost; -}; - - -class Menu { - public: - bool active { false }; - std::vector<Option> options; - vec2 pos, size; - int over; - - void close (); - virtual void open (vec2 res); - virtual int mouse_option (vec2 mouse); -}; - -class Menu_unit : public Menu { - public: - Menu_unit () {} - - enum Opts { - move, attack, done, build, train, trade, age_up, heal, convert - }; -}; - -class Menu_day : public Menu { - public: - Menu_day () {} - - enum Opts { - end_day, tech, empire_review, scoring - }; -}; - -class Menu_build : public Menu { - public: - Menu_build () {} -}; -class Menu_train : public Menu { - public: - Menu_train () {} -}; -class Menu_trade : public Menu { - public: - Menu_trade () {} - - enum Opts { - food, gold - }; -}; -class Menu_age_up : public Menu { - public: - Menu_age_up () {} -}; - -class OptionTech { - public: - OptionTech(std::string name, Tech *tech) : name(name), tech(tech) {} - - std::string name; - Tech *tech; -}; - -class Menu_tech : public Menu { - public: - Menu_tech () {} - std::vector<OptionTech> tech_options; - std::vector<std::vector<OptionTech>> tech_opt_ordered; - - void open (vec2 res) override; - int mouse_option (vec2 mouse) override; -}; - +#ifndef MENU_H
+#define MENU_H
+
+#include <vector>
+#include <string>
+
+#include "../umath/vec2.h"
+#include "tech.h"
+
+class Option {
+ public:
+ Option(std::string name, int id) : name(name), id(id) {}
+
+ std::string name;
+ int id;
+
+ std::vector<float> cost;
+};
+
+
+class Menu {
+ public:
+ bool active { false };
+ std::vector<Option> options;
+ vec2 pos, size;
+ int over;
+
+ void close ();
+ virtual void open (vec2 res);
+ virtual int mouse_option (vec2 mouse);
+};
+
+class Menu_unit : public Menu {
+ public:
+ Menu_unit () {}
+
+ enum Opts {
+ move, attack, done, build, train, trade, age_up, heal, convert
+ };
+};
+
+class Menu_day : public Menu {
+ public:
+ Menu_day () {}
+
+ enum Opts {
+ end_day, tech, empire_review, scoring
+ };
+};
+
+class Menu_build : public Menu {
+ public:
+ Menu_build () {}
+};
+class Menu_train : public Menu {
+ public:
+ Menu_train () {}
+};
+class Menu_trade : public Menu {
+ public:
+ Menu_trade () {}
+
+ enum Opts {
+ food, gold
+ };
+};
+class Menu_age_up : public Menu {
+ public:
+ Menu_age_up () {}
+};
+
+class OptionTech {
+ public:
+ OptionTech(std::string name, Tech *tech) : name(name), tech(tech) {}
+
+ std::string name;
+ Tech *tech;
+};
+
+class Menu_tech : public Menu {
+ public:
+ Menu_tech () {}
+ std::vector<OptionTech> tech_options;
+ std::vector<std::vector<OptionTech>> tech_opt_ordered;
+
+ void open (vec2 res) override;
+ int mouse_option (vec2 mouse) override;
+};
+
#endif
\ No newline at end of file diff --git a/game/player.h b/game/player.h index cf4146f..c29ea7e 100644 --- a/game/player.h +++ b/game/player.h @@ -1,46 +1,46 @@ -#ifndef PLAYER_H -#define PLAYER_H - -#include <vector> - -#include "tech.h" - - -class Player { - public: - Player (int r, int g, int b, int id) : r(r), g(g), b(b), id(id) { } - - void pay (std::vector<float> cost) { - for (int i=0; i<res.size(); i++) { - res[i] -= cost[i]; - } - } - void gain (std::vector<float> gain) { - for (int i=0; i<res.size(); i++) { - res[i] += gain[i]; - } - } - - bool has_tech (int id) { - if (std::find(techs.begin(), techs.end(), id) != techs.end()) - return true; - return false; - } - - bool operator== (Player &oth) { return id == oth.id; } - - int id; - - std::vector<float> res { 0, 0 }; - std::vector<int> techs; - - TechLookup tech_lookup; - - int researching { -1 }; - int leveling_up { -1 }; - int level { 0 }; - - int r, g, b; -}; - +#ifndef PLAYER_H
+#define PLAYER_H
+
+#include <vector>
+
+#include "tech.h"
+
+
+class Player {
+ public:
+ Player (int r, int g, int b, int id) : r(r), g(g), b(b), id(id) { }
+
+ void pay (std::vector<float> cost) {
+ for (int i=0; i<res.size(); i++) {
+ res[i] -= cost[i];
+ }
+ }
+ void gain (std::vector<float> gain) {
+ for (int i=0; i<res.size(); i++) {
+ res[i] += gain[i];
+ }
+ }
+
+ bool has_tech (int id) {
+ if (std::find(techs.begin(), techs.end(), id) != techs.end())
+ return true;
+ return false;
+ }
+
+ bool operator== (Player &oth) { return id == oth.id; }
+
+ int id;
+
+ std::vector<float> res { 0, 0 };
+ std::vector<int> techs;
+
+ TechLookup tech_lookup;
+
+ int researching { -1 };
+ int leveling_up { -1 };
+ int level { 0 };
+
+ int r, g, b;
+};
+
#endif
\ No newline at end of file diff --git a/game/playercontrol.cpp b/game/playercontrol.cpp index 3fe178a..dad5b2a 100644 --- a/game/playercontrol.cpp +++ b/game/playercontrol.cpp @@ -1,449 +1,449 @@ -#include <iostream> -#include <string> - -#include "playercontrol.h" -#include "entity.h" - -void open_unit_menu (Gst &gst, View &view, Fsm &fsm, int p) { - Entity &ent = gst.entities[view.selected_entity]; - Player &player = gst.players[ent.owner]; - view.menu_unit.options.clear(); - if (ent.info->unit == 1) { - if (gst.inv->ground.move_area(gst, ent).size() > 0 - && ent.moved == 0) - { - view.menu_unit.options.emplace_back("Move", - Menu_unit::Opts::move); - } - if (gst.inv->ground.attack_targets(gst, ent).size() > 0 - && (!gst.inv->info_has_ability(ent.info, "No Move & Attack") - || ent.moved == 0)) { - view.menu_unit.options.emplace_back("Attack", - Menu_unit::Opts::attack); - } - if (ent.info->build.size() > 0 - && !gst.check_obstructed(ent) - && gst.get_possible_builds(ent).size() > 0) - { - view.menu_unit.options.emplace_back("Build", - Menu_unit::Opts::build); - } - if (gst.inv->ground.heal_targets(gst, ent).size() > 0 - && (gst.inv->info_has_ability(ent.info, "Heal"))) - { - view.menu_unit.options.emplace_back("Heal", - Menu_unit::Opts::heal); - } - if (gst.inv->ground.convert_targets(gst, ent).size() > 0 - && (gst.inv->info_has_ability(ent.info, "Convert"))) - { - view.menu_unit.options.emplace_back("Convert", - Menu_unit::Opts::convert); - } - view.menu_unit.options.emplace_back("Done", - Menu_unit::Opts::done); - } else { - if (gst.get_possible_trains(ent).size() - && !gst.check_obstructed(ent)) - { - view.menu_unit.options.emplace_back("Train", - Menu_unit::Opts::train); - } - if (ent.info->id == 100 - || ent.info->id == 101) { - int rate = (int)gst.get_trade_rate(player); - if (player.res[0] >= rate || player.res[1] >= rate) { - view.menu_unit.options.emplace_back("Trade", - Menu_unit::Opts::trade); - } - } - if (ent.info->id == 100) { - view.menu_unit.options.emplace_back("Age Up", - Menu_unit::Opts::age_up); - } - } - view.menu_unit.open(view.res); -} - -Player_control::Player_control () { - fsm.arcs.emplace_back( - select, sel_ground, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.selected_ground = p; - std::cout << "selected ground " << p << "\n"; - view.menu_day.options.clear(); - view.menu_day.options.emplace_back("End Day", - Menu_day::Opts::end_day); - view.menu_day.options.emplace_back("Research", - Menu_day::Opts::tech); - view.menu_day.options.emplace_back("Empire Review", - Menu_day::Opts::empire_review); - view.menu_day.options.emplace_back("Scoring", - Menu_day::Opts::scoring); - view.menu_day.open(view.res); - return menu_day; - } - ); - fsm.arcs.emplace_back( - menu_day, opt, Menu_day::Opts::end_day, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_day.close(); - view.selected_ground = -1; - gst.end_day(); - std::cout << "end day " << p << "\n"; - return select; - } - ); - fsm.arcs.emplace_back( - menu_day, back, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_day.close(); - view.selected_ground = -1; - return select; - } - ); - fsm.arcs.emplace_back( - menu_day, opt, Menu_day::Opts::tech, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_day.close(); - view.menu_tech.tech_options.clear(); - for (Tech &tech : gst.inv->techs) { - view.menu_tech.tech_options.emplace_back(tech.name, &tech); - } - view.menu_tech.open(view.res); - std::cout << "tech screen " << "\n"; - return menu_tech; - } - ); - fsm.arcs.emplace_back( - menu_tech, opt, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - if (p == -1) - return menu_tech; - Player &player = gst.players[gst.turn]; - Tech *tech = gst.inv->get_tech(p); - if (!gst.check_req_tech(tech, player)) { - return menu_tech; - } - if (player.researching != -1) { - player.gain(tech->cost); - } - player.researching = p; - player.pay(tech->cost); - view.menu_tech.close(); - view.selected_ground = -1; - std::cout << "selected tech " << p << "\n"; - return select; - } - ); - fsm.arcs.emplace_back( - menu_tech, back, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_tech.close(); - view.selected_ground = -1; - return select; - } - ); - fsm.arcs.emplace_back( - select, sel_unit, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.selected_entity = p; - open_unit_menu(gst, view, fsm, p); - std::cout << "selected unit " << p << "\n"; - return menu_unit; - } - ); - fsm.arcs.emplace_back( - menu_unit, back, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.selected_entity = -1; - view.menu_unit.close(); - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::train, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_unit.close(); - std::cout << "train " << p << "\n"; - Entity &ent = gst.entities[view.selected_entity]; - Player &player = gst.players[ent.owner]; - view.menu_train.options.clear(); - auto trains = gst.get_possible_trains(ent); - for (int id : trains) { - EntityInfo *info = gst.inv->get_info(id); - Option opt { info->name, id }; - opt.cost = gst.get_cost(info, player); - if (ent.info->id == 107) { // market - // tech.id = 31 -> merc network - opt.cost[1] += 50 - (int)player.has_tech(31)*25; - } - view.menu_train.options.push_back(opt); - } - view.menu_train.open(view.res); - return menu_train; - } - ); - fsm.arcs.emplace_back( - menu_train, opt, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - std::vector<float> cost { -1, -1 }; - for (auto o : view.menu_train.options) { - if (o.id == p) {cost = o.cost; break; } - } - view.menu_train.close(); - Entity &ent = gst.entities[view.selected_entity]; - ent.done = true; - Entity entb { ent.x, ent.y, gst.inv->get_info(p), ent.owner }; - entb.building = -1; - entb.done = true; - entb.hp = 50; - gst.entities.push_back(entb); - Player &player = gst.players[gst.turn]; - player.pay(cost); - view.selected_entity = -1; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::build, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_unit.close(); - std::cout << "build " << p << "\n"; - Entity &ent = gst.entities[view.selected_entity]; - Player &player = gst.players[ent.owner]; - view.menu_build.options.clear(); - for (int id : ent.info->build) { - EntityInfo *info = gst.inv->get_info(id); - if(!gst.check_req_build(ent, info)) continue; - Option opt { info->name, id }; - opt.cost = gst.get_cost(info, player); - view.menu_build.options.push_back(opt); - } - view.menu_build.open(view.res); - return menu_build; - } - ); - fsm.arcs.emplace_back( - menu_build, opt, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_build.close(); - std::cout << "building " << p << "\n"; - Entity &ent = gst.entities[view.selected_entity]; - ent.done = true; - Entity entb { ent.x, ent.y, gst.inv->get_info(p), ent.owner }; - entb.building = -1; - entb.done = true; - entb.hp = 50; - gst.entities.push_back(entb); - Player &player = gst.players[gst.turn]; - player.pay(gst.get_cost(entb.info, player)); - view.selected_entity = -1; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::move, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_unit.close(); - std::cout << "move " << p << "\n"; - Entity &ent = gst.entities[view.selected_entity]; - view.moves = gst.inv->ground.move_area(gst, ent); - return move; - } - ); - fsm.arcs.emplace_back( - move, sel_ground, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - std::cout << "moved to " << p << "\n"; - Entity &ent = gst.entities[view.selected_entity]; - view.moves.clear(); - ent.x = p % gst.inv->ground.sizex; - ent.y = p / gst.inv->ground.sizex; - ent.moved = 1; - open_unit_menu(gst, view, fsm, p); - return menu_unit; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::attack, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_unit.close(); - std::cout << "attack " << p << "\n"; - Entity &ent = gst.entities[view.selected_entity]; - view.attacks = gst.inv->ground.attack_targets(gst, ent); - return attack; - } - ); - fsm.arcs.emplace_back( - attack, sel_ground, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - std::cout << "attacked " << p << "\n"; - Entity &atk = gst.entities[view.selected_entity]; - int x = view.cursor_ground % gst.inv->ground.sizex; - int y = view.cursor_ground / gst.inv->ground.sizex; - std::cout << "selg " << x << " " << y << "\n"; - Entity &def = gst.get_at(x, y); - atk.done = true; - gst.battle(atk, def); - view.attacks.clear(); - view.selected_entity = -1; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::trade, - [](Gst &gst, View &view, Fsm &fsm, int p) { - Player &player = gst.players[gst.turn]; - view.menu_unit.close(); - view.menu_trade.options.clear(); - int rate = (int)gst.get_trade_rate(player); - if (player.res[0] >= rate) { - view.menu_trade.options.emplace_back( - std::to_string(rate) + " Food for 100 Gold", - Menu_trade::Opts::food); - } - if (player.res[1] >= rate) { - view.menu_trade.options.emplace_back( - std::to_string(rate) + " Gold for 100 Food", - Menu_trade::Opts::gold); - } - view.menu_trade.open(view.res); - std::cout << "trade open " << p << "\n"; - return menu_trade; - } - ); - fsm.arcs.emplace_back( - menu_trade, opt, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - Player &player = gst.players[gst.turn]; - view.menu_trade.close(); - int rate = (int)gst.get_trade_rate(player); - int sel = p; - player.pay(std::vector<float> - { (float)rate*(1-sel), (float)rate*sel }); - player.gain(std::vector<float> - { 100.0f*sel, 100.0f*(1-sel) }); - gst.entities[view.selected_entity].done = true; - view.selected_entity = -1; - std::cout << "done trading " << p << "\n"; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::age_up, - [](Gst &gst, View &view, Fsm &fsm, int p) { - Player &player = gst.players[gst.turn]; - view.menu_unit.close(); - view.menu_age_up.options.clear(); - if (gst.check_req_level(player)) { - view.menu_age_up.options.emplace_back("Age Up", 0); - } - view.menu_age_up.open(view.res); - std::cout << "age up open " << p << "\n"; - return menu_age_up; - } - ); - fsm.arcs.emplace_back( - menu_age_up, opt, 0, - [](Gst &gst, View &view, Fsm &fsm, int p) { - Player &player = gst.players[gst.turn]; - player.leveling_up = 1; - float cost = (player.level+1)*500; - player.pay(std::vector<float>{ cost, cost }); - view.menu_age_up.close(); - gst.entities[view.selected_entity].done = true; - view.selected_entity = -1; - std::cout << "aged up " << p << "\n"; - return select; - } - ); - fsm.arcs.emplace_back( - menu_age_up, back, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_age_up.close(); - view.selected_entity = -1; - std::cout << "closed ageup " << p << "\n"; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::heal, - [](Gst &gst, View &view, Fsm &fsm, int p) { - Player &player = gst.players[gst.turn]; - view.menu_unit.close(); - Entity &ent = gst.entities[view.selected_entity]; - view.heals = gst.inv->ground.heal_targets(gst, ent); - std::cout << "heal targeting " << p << "\n"; - return target_heal; - } - ); - fsm.arcs.emplace_back( - target_heal, sel_ground, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - std::cout << "healed " << p << "\n"; - Entity &atk = gst.entities[view.selected_entity]; - int x = view.cursor_ground % gst.inv->ground.sizex; - int y = view.cursor_ground / gst.inv->ground.sizex; - std::cout << "selg " << x << " " << y << "\n"; - Entity &def = gst.get_at(x, y); - atk.done = true; - gst.heal(atk, def); - view.heals.clear(); - view.selected_entity = -1; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::convert, - [](Gst &gst, View &view, Fsm &fsm, int p) { - Player &player = gst.players[gst.turn]; - view.menu_unit.close(); - Entity &ent = gst.entities[view.selected_entity]; - view.converts = gst.inv->ground.convert_targets(gst, ent); - std::cout << "convert targeting " << p << "\n"; - return target_convert; - } - ); - fsm.arcs.emplace_back( - target_convert, sel_ground, -1, - [](Gst &gst, View &view, Fsm &fsm, int p) { - std::cout << "converted " << p << "\n"; - Entity &atk = gst.entities[view.selected_entity]; - int x = view.cursor_ground % gst.inv->ground.sizex; - int y = view.cursor_ground / gst.inv->ground.sizex; - std::cout << "selg " << x << " " << y << "\n"; - Entity &def = gst.get_at(x, y); - atk.done = true; - gst.convert(atk, def); - view.converts.clear(); - view.selected_entity = -1; - return select; - } - ); - fsm.arcs.emplace_back( - menu_unit, opt, Menu_unit::Opts::done, - [](Gst &gst, View &view, Fsm &fsm, int p) { - view.menu_unit.close(); - gst.entities[view.selected_entity].done = true; - view.selected_entity = -1; - std::cout << "done " << p << "\n"; - return select; - } - ); -} - -void Player_control::process (Gst &gst, View &view) { - if (view.cursor_entity != -1) { - fsm.transition(gst, view, fsm, sel_unit, view.cursor_entity); - } - if (view.cursor_ground != -1) { - fsm.transition(gst, view, fsm, sel_ground, view.cursor_ground); - } - if (view.back != -1) { - fsm.transition(gst, view, fsm, back, 0); - } - if (view.opt != -1) { - fsm.transition(gst, view, fsm, opt, view.opt); - } +#include <iostream>
+#include <string>
+
+#include "playercontrol.h"
+#include "entity.h"
+
+void open_unit_menu (Gst &gst, View &view, Fsm &fsm, int p) {
+ Entity &ent = gst.entities[view.selected_entity];
+ Player &player = gst.players[ent.owner];
+ view.menu_unit.options.clear();
+ if (ent.info->unit == 1) {
+ if (gst.inv->ground.move_area(gst, ent).size() > 0
+ && ent.moved == 0)
+ {
+ view.menu_unit.options.emplace_back("Move",
+ Menu_unit::Opts::move);
+ }
+ if (gst.inv->ground.attack_targets(gst, ent).size() > 0
+ && (!gst.inv->info_has_ability(ent.info, "No Move & Attack")
+ || ent.moved == 0)) {
+ view.menu_unit.options.emplace_back("Attack",
+ Menu_unit::Opts::attack);
+ }
+ if (ent.info->build.size() > 0
+ && !gst.check_obstructed(ent)
+ && gst.get_possible_builds(ent).size() > 0)
+ {
+ view.menu_unit.options.emplace_back("Build",
+ Menu_unit::Opts::build);
+ }
+ if (gst.inv->ground.heal_targets(gst, ent).size() > 0
+ && (gst.inv->info_has_ability(ent.info, "Heal")))
+ {
+ view.menu_unit.options.emplace_back("Heal",
+ Menu_unit::Opts::heal);
+ }
+ if (gst.inv->ground.convert_targets(gst, ent).size() > 0
+ && (gst.inv->info_has_ability(ent.info, "Convert")))
+ {
+ view.menu_unit.options.emplace_back("Convert",
+ Menu_unit::Opts::convert);
+ }
+ view.menu_unit.options.emplace_back("Done",
+ Menu_unit::Opts::done);
+ } else {
+ if (gst.get_possible_trains(ent).size()
+ && !gst.check_obstructed(ent))
+ {
+ view.menu_unit.options.emplace_back("Train",
+ Menu_unit::Opts::train);
+ }
+ if (ent.info->id == 100
+ || ent.info->id == 101) {
+ int rate = (int)gst.get_trade_rate(player);
+ if (player.res[0] >= rate || player.res[1] >= rate) {
+ view.menu_unit.options.emplace_back("Trade",
+ Menu_unit::Opts::trade);
+ }
+ }
+ if (ent.info->id == 100) {
+ view.menu_unit.options.emplace_back("Age Up",
+ Menu_unit::Opts::age_up);
+ }
+ }
+ view.menu_unit.open(view.res);
+}
+
+Player_control::Player_control () {
+ fsm.arcs.emplace_back(
+ select, sel_ground, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.selected_ground = p;
+ std::cout << "selected ground " << p << "\n";
+ view.menu_day.options.clear();
+ view.menu_day.options.emplace_back("End Day",
+ Menu_day::Opts::end_day);
+ view.menu_day.options.emplace_back("Research",
+ Menu_day::Opts::tech);
+ view.menu_day.options.emplace_back("Empire Review",
+ Menu_day::Opts::empire_review);
+ view.menu_day.options.emplace_back("Scoring",
+ Menu_day::Opts::scoring);
+ view.menu_day.open(view.res);
+ return menu_day;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_day, opt, Menu_day::Opts::end_day,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_day.close();
+ view.selected_ground = -1;
+ gst.end_day();
+ std::cout << "end day " << p << "\n";
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_day, back, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_day.close();
+ view.selected_ground = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_day, opt, Menu_day::Opts::tech,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_day.close();
+ view.menu_tech.tech_options.clear();
+ for (Tech &tech : gst.inv->techs) {
+ view.menu_tech.tech_options.emplace_back(tech.name, &tech);
+ }
+ view.menu_tech.open(view.res);
+ std::cout << "tech screen " << "\n";
+ return menu_tech;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_tech, opt, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ if (p == -1)
+ return menu_tech;
+ Player &player = gst.players[gst.turn];
+ Tech *tech = gst.inv->get_tech(p);
+ if (!gst.check_req_tech(tech, player)) {
+ return menu_tech;
+ }
+ if (player.researching != -1) {
+ player.gain(tech->cost);
+ }
+ player.researching = p;
+ player.pay(tech->cost);
+ view.menu_tech.close();
+ view.selected_ground = -1;
+ std::cout << "selected tech " << p << "\n";
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_tech, back, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_tech.close();
+ view.selected_ground = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ select, sel_unit, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.selected_entity = p;
+ open_unit_menu(gst, view, fsm, p);
+ std::cout << "selected unit " << p << "\n";
+ return menu_unit;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, back, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.selected_entity = -1;
+ view.menu_unit.close();
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::train,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_unit.close();
+ std::cout << "train " << p << "\n";
+ Entity &ent = gst.entities[view.selected_entity];
+ Player &player = gst.players[ent.owner];
+ view.menu_train.options.clear();
+ auto trains = gst.get_possible_trains(ent);
+ for (int id : trains) {
+ EntityInfo *info = gst.inv->get_info(id);
+ Option opt { info->name, id };
+ opt.cost = gst.get_cost(info, player);
+ if (ent.info->id == 107) { // market
+ // tech.id = 31 -> merc network
+ opt.cost[1] += 50 - (int)player.has_tech(31)*25;
+ }
+ view.menu_train.options.push_back(opt);
+ }
+ view.menu_train.open(view.res);
+ return menu_train;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_train, opt, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ std::vector<float> cost { -1, -1 };
+ for (auto o : view.menu_train.options) {
+ if (o.id == p) {cost = o.cost; break; }
+ }
+ view.menu_train.close();
+ Entity &ent = gst.entities[view.selected_entity];
+ ent.done = true;
+ Entity entb { ent.x, ent.y, gst.inv->get_info(p), ent.owner };
+ entb.building = -1;
+ entb.done = true;
+ entb.hp = 50;
+ gst.entities.push_back(entb);
+ Player &player = gst.players[gst.turn];
+ player.pay(cost);
+ view.selected_entity = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::build,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_unit.close();
+ std::cout << "build " << p << "\n";
+ Entity &ent = gst.entities[view.selected_entity];
+ Player &player = gst.players[ent.owner];
+ view.menu_build.options.clear();
+ for (int id : ent.info->build) {
+ EntityInfo *info = gst.inv->get_info(id);
+ if(!gst.check_req_build(ent, info)) continue;
+ Option opt { info->name, id };
+ opt.cost = gst.get_cost(info, player);
+ view.menu_build.options.push_back(opt);
+ }
+ view.menu_build.open(view.res);
+ return menu_build;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_build, opt, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_build.close();
+ std::cout << "building " << p << "\n";
+ Entity &ent = gst.entities[view.selected_entity];
+ ent.done = true;
+ Entity entb { ent.x, ent.y, gst.inv->get_info(p), ent.owner };
+ entb.building = -1;
+ entb.done = true;
+ entb.hp = 50;
+ gst.entities.push_back(entb);
+ Player &player = gst.players[gst.turn];
+ player.pay(gst.get_cost(entb.info, player));
+ view.selected_entity = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::move,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_unit.close();
+ std::cout << "move " << p << "\n";
+ Entity &ent = gst.entities[view.selected_entity];
+ view.moves = gst.inv->ground.move_area(gst, ent);
+ return move;
+ }
+ );
+ fsm.arcs.emplace_back(
+ move, sel_ground, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ std::cout << "moved to " << p << "\n";
+ Entity &ent = gst.entities[view.selected_entity];
+ view.moves.clear();
+ ent.x = p % gst.inv->ground.sizex;
+ ent.y = p / gst.inv->ground.sizex;
+ ent.moved = 1;
+ open_unit_menu(gst, view, fsm, p);
+ return menu_unit;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::attack,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_unit.close();
+ std::cout << "attack " << p << "\n";
+ Entity &ent = gst.entities[view.selected_entity];
+ view.attacks = gst.inv->ground.attack_targets(gst, ent);
+ return attack;
+ }
+ );
+ fsm.arcs.emplace_back(
+ attack, sel_ground, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ std::cout << "attacked " << p << "\n";
+ Entity &atk = gst.entities[view.selected_entity];
+ int x = view.cursor_ground % gst.inv->ground.sizex;
+ int y = view.cursor_ground / gst.inv->ground.sizex;
+ std::cout << "selg " << x << " " << y << "\n";
+ Entity &def = gst.get_at(x, y);
+ atk.done = true;
+ gst.battle(atk, def);
+ view.attacks.clear();
+ view.selected_entity = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::trade,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ Player &player = gst.players[gst.turn];
+ view.menu_unit.close();
+ view.menu_trade.options.clear();
+ int rate = (int)gst.get_trade_rate(player);
+ if (player.res[0] >= rate) {
+ view.menu_trade.options.emplace_back(
+ std::to_string(rate) + " Food for 100 Gold",
+ Menu_trade::Opts::food);
+ }
+ if (player.res[1] >= rate) {
+ view.menu_trade.options.emplace_back(
+ std::to_string(rate) + " Gold for 100 Food",
+ Menu_trade::Opts::gold);
+ }
+ view.menu_trade.open(view.res);
+ std::cout << "trade open " << p << "\n";
+ return menu_trade;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_trade, opt, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ Player &player = gst.players[gst.turn];
+ view.menu_trade.close();
+ int rate = (int)gst.get_trade_rate(player);
+ int sel = p;
+ player.pay(std::vector<float>
+ { (float)rate*(1-sel), (float)rate*sel });
+ player.gain(std::vector<float>
+ { 100.0f*sel, 100.0f*(1-sel) });
+ gst.entities[view.selected_entity].done = true;
+ view.selected_entity = -1;
+ std::cout << "done trading " << p << "\n";
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::age_up,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ Player &player = gst.players[gst.turn];
+ view.menu_unit.close();
+ view.menu_age_up.options.clear();
+ if (gst.check_req_level(player)) {
+ view.menu_age_up.options.emplace_back("Age Up", 0);
+ }
+ view.menu_age_up.open(view.res);
+ std::cout << "age up open " << p << "\n";
+ return menu_age_up;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_age_up, opt, 0,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ Player &player = gst.players[gst.turn];
+ player.leveling_up = 1;
+ float cost = (player.level+1)*500;
+ player.pay(std::vector<float>{ cost, cost });
+ view.menu_age_up.close();
+ gst.entities[view.selected_entity].done = true;
+ view.selected_entity = -1;
+ std::cout << "aged up " << p << "\n";
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_age_up, back, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_age_up.close();
+ view.selected_entity = -1;
+ std::cout << "closed ageup " << p << "\n";
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::heal,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ Player &player = gst.players[gst.turn];
+ view.menu_unit.close();
+ Entity &ent = gst.entities[view.selected_entity];
+ view.heals = gst.inv->ground.heal_targets(gst, ent);
+ std::cout << "heal targeting " << p << "\n";
+ return target_heal;
+ }
+ );
+ fsm.arcs.emplace_back(
+ target_heal, sel_ground, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ std::cout << "healed " << p << "\n";
+ Entity &atk = gst.entities[view.selected_entity];
+ int x = view.cursor_ground % gst.inv->ground.sizex;
+ int y = view.cursor_ground / gst.inv->ground.sizex;
+ std::cout << "selg " << x << " " << y << "\n";
+ Entity &def = gst.get_at(x, y);
+ atk.done = true;
+ gst.heal(atk, def);
+ view.heals.clear();
+ view.selected_entity = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::convert,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ Player &player = gst.players[gst.turn];
+ view.menu_unit.close();
+ Entity &ent = gst.entities[view.selected_entity];
+ view.converts = gst.inv->ground.convert_targets(gst, ent);
+ std::cout << "convert targeting " << p << "\n";
+ return target_convert;
+ }
+ );
+ fsm.arcs.emplace_back(
+ target_convert, sel_ground, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ std::cout << "converted " << p << "\n";
+ Entity &atk = gst.entities[view.selected_entity];
+ int x = view.cursor_ground % gst.inv->ground.sizex;
+ int y = view.cursor_ground / gst.inv->ground.sizex;
+ std::cout << "selg " << x << " " << y << "\n";
+ Entity &def = gst.get_at(x, y);
+ atk.done = true;
+ gst.convert(atk, def);
+ view.converts.clear();
+ view.selected_entity = -1;
+ return select;
+ }
+ );
+ fsm.arcs.emplace_back(
+ menu_unit, opt, Menu_unit::Opts::done,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.menu_unit.close();
+ gst.entities[view.selected_entity].done = true;
+ view.selected_entity = -1;
+ std::cout << "done " << p << "\n";
+ return select;
+ }
+ );
+}
+
+void Player_control::process (Gst &gst, View &view) {
+ if (view.cursor_entity != -1) {
+ fsm.transition(gst, view, fsm, sel_unit, view.cursor_entity);
+ }
+ if (view.cursor_ground != -1) {
+ fsm.transition(gst, view, fsm, sel_ground, view.cursor_ground);
+ }
+ if (view.back != -1) {
+ fsm.transition(gst, view, fsm, back, 0);
+ }
+ if (view.opt != -1) {
+ fsm.transition(gst, view, fsm, opt, view.opt);
+ }
}
\ No newline at end of file diff --git a/game/playercontrol.h b/game/playercontrol.h index c0075d4..d6b1fd7 100644 --- a/game/playercontrol.h +++ b/game/playercontrol.h @@ -1,92 +1,92 @@ -#ifndef PLAYERCONTROL_H -#define PLAYERCONTROL_H - -#include <iostream> - -#include "gst.h" -#include "view.h" -#include <vector> -#include <functional> - - -enum pc_state { - select, - move, - attack, - train, - build, - merge, - trade, - age_up, - heal, - power, - move_target, - attack_target, - menu_train, - menu_build, - target_build, - merge_target, - target_heal, - target_convert, - menu_power, - target_power, - menu_unit, - menu_day, - menu_tech, - menu_trade, - menu_age_up, - end -}; - -enum pc_action { - sel_unit, - sel_ground, - opt, - back -}; - - -class Fsm; -using lambda = std::function<pc_state(Gst&, View&, Fsm&, int p)>; - - -class Arc { - public: - Arc (pc_state from, pc_action act, int p, lambda f) - : from(from), act(act), p(p), f(f) {}; - pc_state from; - pc_action act; - int p; - - lambda f; -}; - -class Fsm { - public: - Fsm() { state = select; } - - void transition (Gst &gst, View &view, Fsm &fsm, pc_action act, int p) { - std::cout << "> transitioning from " << state << " with " << act << std::endl; - for (Arc a : arcs) { - if (a.from == state && a.act == act && (a.p == p || a.p == -1)) { - state = a.f(gst, view, fsm, p); - break; - } - } - } - std::vector<Arc> arcs; - - private: - pc_state state; -}; - - -class Player_control { - public: - Player_control (); - void process (Gst &gst, View &view); - - Fsm fsm; -}; - +#ifndef PLAYERCONTROL_H
+#define PLAYERCONTROL_H
+
+#include <iostream>
+
+#include "gst.h"
+#include "view.h"
+#include <vector>
+#include <functional>
+
+
+enum pc_state {
+ select,
+ move,
+ attack,
+ train,
+ build,
+ merge,
+ trade,
+ age_up,
+ heal,
+ power,
+ move_target,
+ attack_target,
+ menu_train,
+ menu_build,
+ target_build,
+ merge_target,
+ target_heal,
+ target_convert,
+ menu_power,
+ target_power,
+ menu_unit,
+ menu_day,
+ menu_tech,
+ menu_trade,
+ menu_age_up,
+ end
+};
+
+enum pc_action {
+ sel_unit,
+ sel_ground,
+ opt,
+ back
+};
+
+
+class Fsm;
+using lambda = std::function<pc_state(Gst&, View&, Fsm&, int p)>;
+
+
+class Arc {
+ public:
+ Arc (pc_state from, pc_action act, int p, lambda f)
+ : from(from), act(act), p(p), f(f) {};
+ pc_state from;
+ pc_action act;
+ int p;
+
+ lambda f;
+};
+
+class Fsm {
+ public:
+ Fsm() { state = select; }
+
+ void transition (Gst &gst, View &view, Fsm &fsm, pc_action act, int p) {
+ std::cout << "> transitioning from " << state << " with " << act << std::endl;
+ for (Arc a : arcs) {
+ if (a.from == state && a.act == act && (a.p == p || a.p == -1)) {
+ state = a.f(gst, view, fsm, p);
+ break;
+ }
+ }
+ }
+ std::vector<Arc> arcs;
+
+ private:
+ pc_state state;
+};
+
+
+class Player_control {
+ public:
+ Player_control ();
+ void process (Gst &gst, View &view);
+
+ Fsm fsm;
+};
+
#endif
\ No newline at end of file diff --git a/game/tech.cpp b/game/tech.cpp index 848b211..d540236 100644 --- a/game/tech.cpp +++ b/game/tech.cpp @@ -1 +1 @@ -#include "tech.h" +#include "tech.h"
diff --git a/game/tech.h b/game/tech.h index b22b173..d5a9e24 100644 --- a/game/tech.h +++ b/game/tech.h @@ -1,132 +1,132 @@ -#ifndef TECH_H -#define TECH_H - -#include <vector> -#include <unordered_map> -#include <string> - -#include <math.h> - -#include <iostream> - -#include "../umath/vec2.h" - -class TechBonus { - public: - float attack { 0 }; - float defence { 0 }; - int sight { 0 }; - int range { 0 }; - int move { 0 }; - std::vector<float> cost { 0, 0 }; - std::vector<float> cost_abs { 0, 0 }; - std::vector<float> prod { 0, 0 }; - int trade { 0 } ; - int improved_heal { 0 }; - int improved_convert { 0 }; - int req_range { 999 }; - - std::vector<int> aff_id; - std::vector<int> aff_class; - int aff_level { -1 }; - int aff_all { 0 }; - - TechBonus operator+(const TechBonus &rhs) { - TechBonus b; - b.attack = attack + rhs.attack; - b.defence = defence + rhs.defence; - b.sight = sight + rhs.sight; - b.move = move + rhs.move; - for (int i=0; i<cost.size(); i++) { - b.cost[i] = cost[i] + rhs.cost[i]; - b.cost_abs[i] = cost_abs[i] + rhs.cost_abs[i]; - b.prod[i] = prod[i] + rhs.prod[i]; - } - b.trade = trade + rhs.trade; - b.improved_heal = improved_heal + rhs.improved_heal; - b.improved_convert = improved_convert + rhs.improved_convert; - return b; - } - - std::string to_string () { - std::string str = ""; - if (attack != 0) { - int value = (int)roundf(attack*100); - str += "Attack: " + std::to_string(value) + "%\n"; - } - if (defence != 0) { - int value = (int)roundf(defence*100); - str += "Defence: " + std::to_string(value) + "%\n"; - } - if (sight != 0) { - str += "Sight: " + std::to_string(sight) + "\n"; - } - if (range != 0) { - str += "Range: " + std::to_string(range) + "\n"; - } - if (move != 0) { - str += "Range: " + std::to_string(range) + "\n"; - } - if (cost[0] != 0 || cost[1] != 0) { - int vf = (int)roundf(cost[0]*100); - int vg = (int)roundf(cost[1]*100); - str += "Cost f: " + std::to_string(vf); - str += "%, g: " + std::to_string(vg) + "%\n"; - } - if (cost_abs[0] != 0 || cost_abs[1] != 0) { - int vf = (int)roundf(cost_abs[0]); - int vg = (int)roundf(cost_abs[1]); - str += "Cost f: " + std::to_string(vf); - str += ", g: " + std::to_string(vg) + "\n"; - } - if (prod[0] != 0 || prod[1] != 0) { - int vf = (int)roundf(prod[0]*100); - int vg = (int)roundf(prod[1]*100); - str += "Production f: " + std::to_string(vf); - str += "%, g: " + std::to_string(vg) + "%\n"; - } - if (trade != 0) { str += "Improves Trade Rate\n"; } - if (improved_heal != 0) { str += "Improves Heal Ability\n"; } - if (improved_convert != 0) { str += "Improves Convert Ability\n"; } - if (aff_id.size() > 0) { - str += "of entitiy "; - for (int id : aff_id) str += std::to_string(id) + " "; - str += "\n"; - } - if (aff_class.size() > 0) { - str += "of class "; - for (int c : aff_class) str += std::to_string(c) + " "; - str += "\n"; - } - if (aff_level != -1) { - str += "of level " + std::to_string(aff_level) + "\n"; - } - return str; - } -}; - -class TechLookup { - public: - TechLookup() {} - - TechBonus id (int i) { return map_id[i]; } - - std::unordered_map<int, TechBonus> map_id; -}; - -class Tech { - public: - Tech() {} - - std::string name; - int id; - int level; - int req_id; - std::vector<float> cost { 0, 0 }; - - TechBonus bonus; - - vec2 spritebounds { 0, 0 }; -}; - +#ifndef TECH_H
+#define TECH_H
+
+#include <vector>
+#include <unordered_map>
+#include <string>
+
+#include <math.h>
+
+#include <iostream>
+
+#include "../umath/vec2.h"
+
+class TechBonus {
+ public:
+ float attack { 0 };
+ float defence { 0 };
+ int sight { 0 };
+ int range { 0 };
+ int move { 0 };
+ std::vector<float> cost { 0, 0 };
+ std::vector<float> cost_abs { 0, 0 };
+ std::vector<float> prod { 0, 0 };
+ int trade { 0 } ;
+ int improved_heal { 0 };
+ int improved_convert { 0 };
+ int req_range { 999 };
+
+ std::vector<int> aff_id;
+ std::vector<int> aff_class;
+ int aff_level { -1 };
+ int aff_all { 0 };
+
+ TechBonus operator+(const TechBonus &rhs) {
+ TechBonus b;
+ b.attack = attack + rhs.attack;
+ b.defence = defence + rhs.defence;
+ b.sight = sight + rhs.sight;
+ b.move = move + rhs.move;
+ for (int i=0; i<cost.size(); i++) {
+ b.cost[i] = cost[i] + rhs.cost[i];
+ b.cost_abs[i] = cost_abs[i] + rhs.cost_abs[i];
+ b.prod[i] = prod[i] + rhs.prod[i];
+ }
+ b.trade = trade + rhs.trade;
+ b.improved_heal = improved_heal + rhs.improved_heal;
+ b.improved_convert = improved_convert + rhs.improved_convert;
+ return b;
+ }
+
+ std::string to_string () {
+ std::string str = "";
+ if (attack != 0) {
+ int value = (int)roundf(attack*100);
+ str += "Attack: " + std::to_string(value) + "%\n";
+ }
+ if (defence != 0) {
+ int value = (int)roundf(defence*100);
+ str += "Defence: " + std::to_string(value) + "%\n";
+ }
+ if (sight != 0) {
+ str += "Sight: " + std::to_string(sight) + "\n";
+ }
+ if (range != 0) {
+ str += "Range: " + std::to_string(range) + "\n";
+ }
+ if (move != 0) {
+ str += "Range: " + std::to_string(range) + "\n";
+ }
+ if (cost[0] != 0 || cost[1] != 0) {
+ int vf = (int)roundf(cost[0]*100);
+ int vg = (int)roundf(cost[1]*100);
+ str += "Cost f: " + std::to_string(vf);
+ str += "%, g: " + std::to_string(vg) + "%\n";
+ }
+ if (cost_abs[0] != 0 || cost_abs[1] != 0) {
+ int vf = (int)roundf(cost_abs[0]);
+ int vg = (int)roundf(cost_abs[1]);
+ str += "Cost f: " + std::to_string(vf);
+ str += ", g: " + std::to_string(vg) + "\n";
+ }
+ if (prod[0] != 0 || prod[1] != 0) {
+ int vf = (int)roundf(prod[0]*100);
+ int vg = (int)roundf(prod[1]*100);
+ str += "Production f: " + std::to_string(vf);
+ str += "%, g: " + std::to_string(vg) + "%\n";
+ }
+ if (trade != 0) { str += "Improves Trade Rate\n"; }
+ if (improved_heal != 0) { str += "Improves Heal Ability\n"; }
+ if (improved_convert != 0) { str += "Improves Convert Ability\n"; }
+ if (aff_id.size() > 0) {
+ str += "of entitiy ";
+ for (int id : aff_id) str += std::to_string(id) + " ";
+ str += "\n";
+ }
+ if (aff_class.size() > 0) {
+ str += "of class ";
+ for (int c : aff_class) str += std::to_string(c) + " ";
+ str += "\n";
+ }
+ if (aff_level != -1) {
+ str += "of level " + std::to_string(aff_level) + "\n";
+ }
+ return str;
+ }
+};
+
+class TechLookup {
+ public:
+ TechLookup() {}
+
+ TechBonus id (int i) { return map_id[i]; }
+
+ std::unordered_map<int, TechBonus> map_id;
+};
+
+class Tech {
+ public:
+ Tech() {}
+
+ std::string name;
+ int id;
+ int level;
+ int req_id;
+ std::vector<float> cost { 0, 0 };
+
+ TechBonus bonus;
+
+ vec2 spritebounds { 0, 0 };
+};
+
#endif
\ No newline at end of file diff --git a/game/tile.h b/game/tile.h index 64e9132..c5c46c6 100644 --- a/game/tile.h +++ b/game/tile.h @@ -1,23 +1,23 @@ -#ifndef TILE_H -#define TILE_H - -#include <vector> -#include <string> - -#include "../umath/vec2.h" - -class Tile { - public: - Tile() {} - - std::string name; - int move_cost { 1 }; - int sight_cost { 1 }; - int range_bonus { 0 }; - float attack_bonus { 0 }; - float defence_bonus { 0 }; - - vec2 spritebounds; -}; - +#ifndef TILE_H
+#define TILE_H
+
+#include <vector>
+#include <string>
+
+#include "../umath/vec2.h"
+
+class Tile {
+ public:
+ Tile() {}
+
+ std::string name;
+ int move_cost { 1 };
+ int sight_cost { 1 };
+ int range_bonus { 0 };
+ float attack_bonus { 0 };
+ float defence_bonus { 0 };
+
+ vec2 spritebounds;
+};
+
#endif
\ No newline at end of file diff --git a/game/view.cpp b/game/view.cpp index 190bd53..1542fa5 100644 --- a/game/view.cpp +++ b/game/view.cpp @@ -1,207 +1,207 @@ -#include "view.h" - -void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) { - Ground &gr = gst.inv->ground; - std::vector<Entity> &entities = gst.entities; - - vec2 absmouse { mouse }; - absmouse -= cam; - - cursor_ground = -1; - cursor_entity = -1; - back = -1; - opt = -1; - hover_ground = -1; - - bool hfound = false; - for (int y=0; y<gr.sizey && !hfound; y++) { - for (int x=0; x<gr.sizex && !hfound; x++) { - vec2 pos { (float)x*32, (float)y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - hover_ground = x+y*gr.sizex; - hfound = true; - } - } - } - - if (menu_train.active) { - menu_train.over = menu_train.mouse_option(mouse); - } - if (menu_build.active) { - menu_build.over = menu_build.mouse_option(mouse); - } - if (menu_unit.active) { - menu_unit.over = menu_unit.mouse_option(mouse); - } - if (menu_day.active) { - menu_day.over = menu_day.mouse_option(mouse); - } - if (menu_tech.active) { - menu_tech.over = menu_tech.mouse_option(mouse); - } - if (menu_trade.active) { - menu_trade.over = menu_trade.mouse_option(mouse); - } - if (menu_age_up.active) { - menu_age_up.over = menu_age_up.mouse_option(mouse); - } - - if (mheld[0] == 1) { - bool found = false; - - if (moves.size() > 0 && !found) { - for (int i=0; i<moves.size() && !found; i++) { - int x = moves[i] % gr.sizex; - int y = moves[i] / gr.sizex; - int valid = 1; - for (Entity &e : gst.entities) { - if (e.x == x && e.y == y && e.info->unit == 1) { - valid = 0; - } - } - if (!valid) continue; - vec2 pos { (float)x*32, (float)y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - cursor_ground = moves[i]; - } - } - found = true; - } - - if (attacks.size() > 0 && !found) { - for (int i=0; i<attacks.size() && !found; i++) { - int x = attacks[i] % gr.sizex; - int y = attacks[i] / gr.sizex; - vec2 pos { (float)x*32, (float)y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - cursor_ground = attacks[i]; - } - } - found = true; - } - - if (heals.size() > 0 && !found) { - for (int i=0; i<heals.size() && !found; i++) { - int x = heals[i] % gr.sizex; - int y = heals[i] / gr.sizex; - vec2 pos { (float)x*32, (float)y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - cursor_ground = heals[i]; - } - } - found = true; - } - - if (converts.size() > 0 && !found) { - for (int i=0; i<converts.size() && !found; i++) { - int x = converts[i] % gr.sizex; - int y = converts[i] / gr.sizex; - vec2 pos { (float)x*32, (float)y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - cursor_ground = converts[i]; - } - } - found = true; - } - - if (menu_train.active && !found) { - int selected = menu_train.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - if (menu_build.active && !found) { - int selected = menu_build.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - if (menu_unit.active && !found) { - int selected = menu_unit.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - if (menu_day.active && !found) { - int selected = menu_day.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - if (menu_tech.active && !found) { - int selected = menu_tech.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - if (menu_trade.active && !found) { - int selected = menu_trade.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - if (menu_age_up.active && !found) { - int selected = menu_age_up.mouse_option(mouse); - if (selected != -1) { - opt = selected; found = true; - } else { - back = 1; found = 1; - } - } - - for (int i=0; i<entities.size() && !found; i++) { - if (entities[i].done) continue; - if (entities[i].owner != gst.turn) continue; - vec2 pos { (float)entities[i].x*32, (float)entities[i].y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - cursor_entity = i; - if (entities[i].info->unit == 1) { - found = true; - } - } - } - if (cursor_entity != -1) found = true; - - for (int y=0; y<gr.sizey && !found; y++) { - for (int x=0; x<gr.sizex && !found; x++) { - vec2 pos { (float)x*32, (float)y*32 }; - if (pos.x < absmouse.x && absmouse.x <= pos.x+32 - && pos.y < absmouse.y && absmouse.y <= pos.y+32) - { - cursor_ground = x+y*gr.sizex; - found = true; - } - } - } - } +#include "view.h"
+
+void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) {
+ Ground &gr = gst.inv->ground;
+ std::vector<Entity> &entities = gst.entities;
+
+ vec2 absmouse { mouse };
+ absmouse -= cam;
+
+ cursor_ground = -1;
+ cursor_entity = -1;
+ back = -1;
+ opt = -1;
+ hover_ground = -1;
+
+ bool hfound = false;
+ for (int y=0; y<gr.sizey && !hfound; y++) {
+ for (int x=0; x<gr.sizex && !hfound; x++) {
+ vec2 pos { (float)x*32, (float)y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ hover_ground = x+y*gr.sizex;
+ hfound = true;
+ }
+ }
+ }
+
+ if (menu_train.active) {
+ menu_train.over = menu_train.mouse_option(mouse);
+ }
+ if (menu_build.active) {
+ menu_build.over = menu_build.mouse_option(mouse);
+ }
+ if (menu_unit.active) {
+ menu_unit.over = menu_unit.mouse_option(mouse);
+ }
+ if (menu_day.active) {
+ menu_day.over = menu_day.mouse_option(mouse);
+ }
+ if (menu_tech.active) {
+ menu_tech.over = menu_tech.mouse_option(mouse);
+ }
+ if (menu_trade.active) {
+ menu_trade.over = menu_trade.mouse_option(mouse);
+ }
+ if (menu_age_up.active) {
+ menu_age_up.over = menu_age_up.mouse_option(mouse);
+ }
+
+ if (mheld[0] == 1) {
+ bool found = false;
+
+ if (moves.size() > 0 && !found) {
+ for (int i=0; i<moves.size() && !found; i++) {
+ int x = moves[i] % gr.sizex;
+ int y = moves[i] / gr.sizex;
+ int valid = 1;
+ for (Entity &e : gst.entities) {
+ if (e.x == x && e.y == y && e.info->unit == 1) {
+ valid = 0;
+ }
+ }
+ if (!valid) continue;
+ vec2 pos { (float)x*32, (float)y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ cursor_ground = moves[i];
+ }
+ }
+ found = true;
+ }
+
+ if (attacks.size() > 0 && !found) {
+ for (int i=0; i<attacks.size() && !found; i++) {
+ int x = attacks[i] % gr.sizex;
+ int y = attacks[i] / gr.sizex;
+ vec2 pos { (float)x*32, (float)y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ cursor_ground = attacks[i];
+ }
+ }
+ found = true;
+ }
+
+ if (heals.size() > 0 && !found) {
+ for (int i=0; i<heals.size() && !found; i++) {
+ int x = heals[i] % gr.sizex;
+ int y = heals[i] / gr.sizex;
+ vec2 pos { (float)x*32, (float)y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ cursor_ground = heals[i];
+ }
+ }
+ found = true;
+ }
+
+ if (converts.size() > 0 && !found) {
+ for (int i=0; i<converts.size() && !found; i++) {
+ int x = converts[i] % gr.sizex;
+ int y = converts[i] / gr.sizex;
+ vec2 pos { (float)x*32, (float)y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ cursor_ground = converts[i];
+ }
+ }
+ found = true;
+ }
+
+ if (menu_train.active && !found) {
+ int selected = menu_train.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ if (menu_build.active && !found) {
+ int selected = menu_build.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ if (menu_unit.active && !found) {
+ int selected = menu_unit.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ if (menu_day.active && !found) {
+ int selected = menu_day.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ if (menu_tech.active && !found) {
+ int selected = menu_tech.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ if (menu_trade.active && !found) {
+ int selected = menu_trade.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ if (menu_age_up.active && !found) {
+ int selected = menu_age_up.mouse_option(mouse);
+ if (selected != -1) {
+ opt = selected; found = true;
+ } else {
+ back = 1; found = 1;
+ }
+ }
+
+ for (int i=0; i<entities.size() && !found; i++) {
+ if (entities[i].done) continue;
+ if (entities[i].owner != gst.turn) continue;
+ vec2 pos { (float)entities[i].x*32, (float)entities[i].y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ cursor_entity = i;
+ if (entities[i].info->unit == 1) {
+ found = true;
+ }
+ }
+ }
+ if (cursor_entity != -1) found = true;
+
+ for (int y=0; y<gr.sizey && !found; y++) {
+ for (int x=0; x<gr.sizex && !found; x++) {
+ vec2 pos { (float)x*32, (float)y*32 };
+ if (pos.x < absmouse.x && absmouse.x <= pos.x+32
+ && pos.y < absmouse.y && absmouse.y <= pos.y+32)
+ {
+ cursor_ground = x+y*gr.sizex;
+ found = true;
+ }
+ }
+ }
+ }
}
\ No newline at end of file diff --git a/game/view.h b/game/view.h index 6a316de..26ef3fc 100644 --- a/game/view.h +++ b/game/view.h @@ -1,40 +1,40 @@ -#ifndef VIEW_H -#define VIEW_H - -#include <vector> -#include <functional> - -#include "gst.h" -#include "menu.h" - -class View { - public: - View (vec2 res) : res(res) {} - - vec2 res; - - int hover_ground {-1}; - int selected_ground {-1}; - int selected_entity {-1}; - int cursor_ground {-1}; - int cursor_entity {-1}; - int back {-1}; - int opt {-1}; - std::vector<int> moves; - std::vector<int> attacks; - std::vector<int> builds; - std::vector<int> heals; - std::vector<int> converts; - - Menu_unit menu_unit; - Menu_day menu_day; - Menu_build menu_build; - Menu_train menu_train; - Menu_tech menu_tech; - Menu_trade menu_trade; - Menu_age_up menu_age_up; - - void process (Gst &gst, vec2 cam, vec2 mouse, int *mheld); -}; - +#ifndef VIEW_H
+#define VIEW_H
+
+#include <vector>
+#include <functional>
+
+#include "gst.h"
+#include "menu.h"
+
+class View {
+ public:
+ View (vec2 res) : res(res) {}
+
+ vec2 res;
+
+ int hover_ground {-1};
+ int selected_ground {-1};
+ int selected_entity {-1};
+ int cursor_ground {-1};
+ int cursor_entity {-1};
+ int back {-1};
+ int opt {-1};
+ std::vector<int> moves;
+ std::vector<int> attacks;
+ std::vector<int> builds;
+ std::vector<int> heals;
+ std::vector<int> converts;
+
+ Menu_unit menu_unit;
+ Menu_day menu_day;
+ Menu_build menu_build;
+ Menu_train menu_train;
+ Menu_tech menu_tech;
+ Menu_trade menu_trade;
+ Menu_age_up menu_age_up;
+
+ void process (Gst &gst, vec2 cam, vec2 mouse, int *mheld);
+};
+
#endif
\ No newline at end of file |