aboutsummaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
Diffstat (limited to 'game')
-rw-r--r--game/ai/action.cpp150
-rw-r--r--game/ai/action.h102
-rw-r--r--game/ai/engine.h130
-rw-r--r--game/ai/evaluator.h58
-rw-r--r--game/ai/generator.h202
-rw-r--r--game/ai/performer.h96
-rw-r--r--game/ai/tactic.h62
-rw-r--r--game/constants.h32
-rw-r--r--game/entity.cpp20
-rw-r--r--game/entity.h162
-rw-r--r--game/ground.cpp262
-rw-r--r--game/ground.h72
-rw-r--r--game/gst.cpp1208
-rw-r--r--game/gst.h248
-rw-r--r--game/load.cpp298
-rw-r--r--game/load.h14
-rw-r--r--game/menu.cpp152
-rw-r--r--game/menu.h178
-rw-r--r--game/player.h90
-rw-r--r--game/playercontrol.cpp896
-rw-r--r--game/playercontrol.h182
-rw-r--r--game/tech.cpp2
-rw-r--r--game/tech.h262
-rw-r--r--game/tile.h44
-rw-r--r--game/view.cpp412
-rw-r--r--game/view.h78
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
diff --git a/game/gst.h b/game/gst.h
index 376026e..8ade237 100644
--- a/game/gst.h
+++ b/game/gst.h
@@ -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