aboutsummaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
Diffstat (limited to 'game')
-rw-r--r--game/entity.cpp3
-rw-r--r--game/entity.h43
-rw-r--r--game/ground.cpp82
-rw-r--r--game/ground.h22
-rw-r--r--game/gst.cpp1
-rw-r--r--game/gst.h34
-rw-r--r--game/menu.cpp29
-rw-r--r--game/menu.h47
-rw-r--r--game/player.h12
-rw-r--r--game/playercontrol.cpp116
-rw-r--r--game/playercontrol.h87
-rw-r--r--game/tile.cpp1
-rw-r--r--game/tile.h23
-rw-r--r--game/view.cpp77
-rw-r--r--game/view.h32
15 files changed, 609 insertions, 0 deletions
diff --git a/game/entity.cpp b/game/entity.cpp
new file mode 100644
index 0000000..8362c40
--- /dev/null
+++ b/game/entity.cpp
@@ -0,0 +1,3 @@
+#include "entity.h"
+#include <iostream>
+; \ No newline at end of file
diff --git a/game/entity.h b/game/entity.h
new file mode 100644
index 0000000..1fcf026
--- /dev/null
+++ b/game/entity.h
@@ -0,0 +1,43 @@
+#ifndef ENTITIES_H
+#define ENTITIES_H
+
+#include <vector>
+#include <string>
+
+#include "../umath/vec2.h"
+
+class Ability {
+ public:
+ Ability();
+};
+
+class EntityInfo {
+ public:
+ EntityInfo() { spritebounds = vec2 { 16*6, 16 }; }
+
+ std::string name;
+
+ float hp;
+ float attack;
+ float defence;
+ int range;
+ float sight;
+ int move;
+ std::vector<Ability> abilities;
+
+ vec2 spritebounds;
+};
+
+class Entity {
+ public:
+ Entity(int x, int y, EntityInfo &info, int owner)
+ : x(x), y(y), info(info), owner(owner) {}
+
+ int x, y;
+ bool done = false;
+ EntityInfo &info;
+
+ int owner;
+};
+
+#endif \ No newline at end of file
diff --git a/game/ground.cpp b/game/ground.cpp
new file mode 100644
index 0000000..c0ba2ca
--- /dev/null
+++ b/game/ground.cpp
@@ -0,0 +1,82 @@
+#include "ground.h"
+#include "gst.h"
+
+#include <iostream>
+#include <algorithm>
+
+Ground::Ground (int sx, int sy) {
+ sizex = sx; sizey = sy;
+ tiles = new int[sx*sy];
+ for (int i=0; i<sx*sy; i++) tiles[i] = 0;
+}
+
+Ground::~Ground () {
+
+}
+
+int Ground::at(int x, int y) {
+ return x+y*sizex;
+}
+
+
+// move area
+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) {
+ std::vector<int> moves;
+ std::vector<int> visited { at(ent.x, ent.y) };
+ std::vector<step> frontier { step { at(ent.x, ent.y), ent.info.move } };
+
+ 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 walkedm = maxf.m - gst.tiles[gst.ground.tiles[t]].move_cost;
+ bool obstructed = false;
+ for (Entity &e : gst.entities) {
+ if (e.owner != ent.owner && at(e.x, e.y) == t) {
+ obstructed = true;
+ break;
+ }
+ }
+ if (walkedm >= 0 && !obstructed) {
+ frontier.emplace_back(t, walkedm);
+ moves.push_back(t);
+ }
+ }
+ }
+ visited.push_back(maxf.pos);
+ }
+
+ std::cout << "iters: " << iter;
+
+ return moves;
+} \ No newline at end of file
diff --git a/game/ground.h b/game/ground.h
new file mode 100644
index 0000000..545deb9
--- /dev/null
+++ b/game/ground.h
@@ -0,0 +1,22 @@
+#ifndef GROUND_H
+#define GROUND_H
+
+#include "entity.h"
+
+class Gst;
+
+class Ground {
+ public:
+ Ground (int sx, int sy);
+ ~Ground ();
+
+ int *tiles;
+
+ 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);
+};
+
+#endif \ No newline at end of file
diff --git a/game/gst.cpp b/game/gst.cpp
new file mode 100644
index 0000000..5c195c8
--- /dev/null
+++ b/game/gst.cpp
@@ -0,0 +1 @@
+#include "gst.h" \ No newline at end of file
diff --git a/game/gst.h b/game/gst.h
new file mode 100644
index 0000000..340d596
--- /dev/null
+++ b/game/gst.h
@@ -0,0 +1,34 @@
+#ifndef GST_H
+#define GST_H
+
+#include <vector>
+
+#include "ground.h"
+#include "entity.h"
+#include "tile.h"
+#include "player.h"
+
+class Gst {
+ public:
+ Gst(int sx, int sy) : ground(sx, sy) {}
+
+ std::vector<EntityInfo> infos;
+ std::vector<Tile> tiles;
+ std::vector<Entity> entities;
+ Ground ground;
+
+ std::vector<Player> players;
+
+ int turn { 0 };
+ int day { 0 };
+
+ void end_day () {
+ day++;
+ if (day >= players.size()) {
+ day = 0;
+ turn++;
+ }
+ }
+};
+
+#endif \ No newline at end of file
diff --git a/game/menu.cpp b/game/menu.cpp
new file mode 100644
index 0000000..76913b5
--- /dev/null
+++ b/game/menu.cpp
@@ -0,0 +1,29 @@
+#include "menu.h"
+
+void Menu::close () {
+ active = false;
+}
+
+void Menu::open (vec2 res) {
+ active = true;
+ pos = vec2 { (float)res.x, (float)res.y };
+ float height = options.size() * 20;
+ size = vec2 { 120, height+10 };
+ pos *= 0.5f;
+ pos -= size/2;
+}
+
+int Menu::mouse_option (vec2 mouse) {
+ int i=0;
+ for (Option opt : options) {
+ vec2 off { 10, 10.0f + i*20 };
+ vec2 sizeopt { 100, 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;
+} \ No newline at end of file
diff --git a/game/menu.h b/game/menu.h
new file mode 100644
index 0000000..95be683
--- /dev/null
+++ b/game/menu.h
@@ -0,0 +1,47 @@
+#ifndef MENU_H
+#define MENU_H
+
+#include <vector>
+#include <string>
+
+#include "../umath/vec2.h"
+
+class Option {
+ public:
+ Option(std::string name, int id) : name(name), id(id) {}
+
+ std::string name;
+ int id;
+};
+
+
+class Menu {
+ public:
+ bool active { false };
+ std::vector<Option> options;
+ vec2 pos, size;
+
+ void open (vec2 res);
+ void close ();
+ int mouse_option (vec2 mouse);
+};
+
+class Menu_unit : public Menu {
+ public:
+ Menu_unit () {}
+
+ enum Opts {
+ move, attack, done
+ };
+};
+
+class Menu_day : public Menu {
+ public:
+ Menu_day () {}
+
+ enum Opts {
+ end_day, tech, empire_review, scoring
+ };
+};
+
+#endif \ No newline at end of file
diff --git a/game/player.h b/game/player.h
new file mode 100644
index 0000000..2cee05f
--- /dev/null
+++ b/game/player.h
@@ -0,0 +1,12 @@
+#ifndef PLAYER_H
+#define PLAYER_H
+
+
+class Player {
+ public:
+ Player (int r, int g, int b) : r(r), g(g), b(b) {}
+
+ int r, g, b;
+};
+
+#endif \ No newline at end of file
diff --git a/game/playercontrol.cpp b/game/playercontrol.cpp
new file mode 100644
index 0000000..15b1b86
--- /dev/null
+++ b/game/playercontrol.cpp
@@ -0,0 +1,116 @@
+#include <iostream>
+#include <string>
+
+#include "playercontrol.h"
+#include "entity.h"
+
+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;
+ // end turn calcs
+ for (Entity &e : gst.entities) {
+ e.done = false;
+ }
+ 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(
+ select, sel_unit, -1,
+ [](Gst &gst, View &view, Fsm &fsm, int p) {
+ view.selected_entity = p;
+ view.menu_unit.options.clear();
+ view.menu_unit.options.emplace_back("Move", Menu_unit::Opts::move);
+ view.menu_unit.options.emplace_back("Attack", Menu_unit::Opts::attack);
+ view.menu_unit.options.emplace_back("Done", Menu_unit::Opts::done);
+ view.menu_unit.open(view.res);
+ 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::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.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.ground.sizex;
+ ent.y = p / gst.ground.sizex;
+ // remove move points
+ view.menu_unit.options.clear();
+ view.menu_unit.options.emplace_back("Attack", Menu_unit::Opts::attack);
+ view.menu_unit.options.emplace_back("Done", Menu_unit::Opts::done);
+ view.menu_unit.open(view.res);
+ return menu_unit;
+ }
+ );
+ 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
new file mode 100644
index 0000000..4e66e07
--- /dev/null
+++ b/game/playercontrol.h
@@ -0,0 +1,87 @@
+#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,
+ menu_power,
+ target_power,
+ menu_unit,
+ menu_day,
+ 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/tile.cpp b/game/tile.cpp
new file mode 100644
index 0000000..a765b2e
--- /dev/null
+++ b/game/tile.cpp
@@ -0,0 +1 @@
+#include "tile.h" \ No newline at end of file
diff --git a/game/tile.h b/game/tile.h
new file mode 100644
index 0000000..3b83531
--- /dev/null
+++ b/game/tile.h
@@ -0,0 +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;
+ int sight_cost;
+ int range_bonus;
+ float attack_bonus;
+ float defence_bonus;
+
+ vec2 spritebounds;
+};
+
+#endif \ No newline at end of file
diff --git a/game/view.cpp b/game/view.cpp
new file mode 100644
index 0000000..6599a0e
--- /dev/null
+++ b/game/view.cpp
@@ -0,0 +1,77 @@
+#include "view.h"
+
+void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) {
+ Ground &gr = gst.ground;
+ std::vector<Entity> &entities = gst.entities;
+
+ vec2 absmouse { mouse };
+ absmouse -= cam;
+
+ cursor_ground = -1;
+ cursor_entity = -1;
+ back = -1;
+ opt = -1;
+
+ 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;
+ 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 (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;
+ }
+ }
+
+ for (int i=0; i<entities.size() && !found; i++) {
+ if (entities[i].done) continue;
+ if (entities[i].owner != gst.day) 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;
+ 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
new file mode 100644
index 0000000..6aa3486
--- /dev/null
+++ b/game/view.h
@@ -0,0 +1,32 @@
+#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 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;
+
+ Menu_unit menu_unit;
+ Menu_day menu_day;
+
+ void process (Gst &gst, vec2 cam, vec2 mouse, int *mheld);
+};
+
+#endif \ No newline at end of file