diff options
Diffstat (limited to 'game')
-rw-r--r-- | game/entity.h | 2 | ||||
-rw-r--r-- | game/ground.cpp | 4 | ||||
-rw-r--r-- | game/gst.cpp | 142 | ||||
-rw-r--r-- | game/gst.h | 18 | ||||
-rw-r--r-- | game/load.cpp | 16 | ||||
-rw-r--r-- | game/menu.cpp | 48 | ||||
-rw-r--r-- | game/menu.h | 25 | ||||
-rw-r--r-- | game/player.h | 2 | ||||
-rw-r--r-- | game/playercontrol.cpp | 47 | ||||
-rw-r--r-- | game/playercontrol.h | 1 | ||||
-rw-r--r-- | game/tech.h | 3 | ||||
-rw-r--r-- | game/view.cpp | 55 | ||||
-rw-r--r-- | game/view.h | 2 |
13 files changed, 295 insertions, 70 deletions
diff --git a/game/entity.h b/game/entity.h index 36c8198..eeab110 100644 --- a/game/entity.h +++ b/game/entity.h @@ -49,7 +49,7 @@ class Entity { return x == oth.x && y == oth.y && info->unit == oth.info->unit; } - int building = 0; + int building { 0 }; float hp; /**/ int x, y; bool done = false; diff --git a/game/ground.cpp b/game/ground.cpp index 0ea273d..e6055bf 100644 --- a/game/ground.cpp +++ b/game/ground.cpp @@ -88,9 +88,7 @@ std::vector<int> Ground::move_area (Gst &gst, Entity &ent) { std::vector<int> Ground::attack_targets (Gst &gst, Entity &ent) { std::vector<int> attacks; - int range = ent.info->range; - range += gst.tiles[gst.ground.tiles[gst.ground.at(ent.x, ent.y)]] - .range_bonus; + int range = gst.get_range(ent); bool builds = !gst.info_has_ability(ent.info, "Units Only"); bool units = !gst.info_has_ability(ent.info, "Buildings Only"); for (Entity &e : gst.entities) { diff --git a/game/gst.cpp b/game/gst.cpp index f6d5aa1..0a524fc 100644 --- a/game/gst.cpp +++ b/game/gst.cpp @@ -28,25 +28,25 @@ Entity& Gst::get_at (int x, int y) { } float Gst::get_type_bonus (Entity &atk, Entity &def) { - float b = 1; + float b = 0; switch(atk.info->ent_class) { case EntityInfo::Class::inf: - if (def.info->ent_class == EntityInfo::Class::bld) b += 1.0/3; - if (def.info->ent_class == EntityInfo::Class::sie) b += 1.0/3; + 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.0/3; - if (def.info->ent_class == EntityInfo::Class::ran) b += 1.0/3; + 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.5; + 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.5; + if (def.info->ent_class == EntityInfo::Class::bld) b += +0.5f; break; } return b; @@ -54,15 +54,24 @@ float Gst::get_type_bonus (Entity &atk, Entity &def) { std::vector<Bonus> Gst::get_bonuses (Entity &atk, Entity &def) { std::vector<Bonus> bs; - bs.emplace_back( - tiles[ground.tiles[ground.at(atk.x, atk.y)]].attack_bonus, - Bonus::Id::ground, true); - bs.emplace_back( - tiles[ground.tiles[ground.at(def.x, def.y)]].defence_bonus, - Bonus::Id::ground, false); + if (tiles[ground.tiles[ground.at(atk.x, atk.y)]].attack_bonus != 0) { - bs.emplace_back(get_type_bonus(atk, def), Bonus::Id::type, true); - bs.emplace_back(get_type_bonus(def, atk), Bonus::Id::type, false); + 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 (get_type_bonus(atk, def) != 0) { + bs.emplace_back(get_type_bonus(atk, def), Bonus::Id::type, true); + } + if (get_type_bonus(def, atk) != 0) { + bs.emplace_back(get_type_bonus(def, atk), Bonus::Id::type, false); + } if (info_has_ability(atk.info, "Causes Fear")) bs.emplace_back(-1.0f/3, Bonus::Id::ability, false); @@ -95,11 +104,10 @@ std::vector<Bonus> Gst::get_bonuses (Entity &atk, Entity &def) { if (info_has_ability(atk.info, "Frenzy")) bs.emplace_back(1/atk.hp, Bonus::Id::ability, true); - return bs; } -float Gst::get_damage (Entity &atk, Entity &def) { +float Gst::get_damage (Entity &atk, Entity &def, float atk_hp) { float atkmul = 1; float defmul = 1; @@ -109,24 +117,30 @@ float Gst::get_damage (Entity &atk, Entity &def) { else { defmul += bonus.amt; } } - float dam = (atk.info->attack * atk.hp * atkmul) + 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 = info_has_ability(atk.info, "First Strike"); return fs; } -float clamp (float hp) { if (hp > 100) hp = 100; return hp; } +float clamp (float hp) { + if (hp > 100) hp = 100; + if (hp < 0) hp = 0; + return hp; +} -void Gst::battle (Entity &atk, Entity &def) { - std::cout << "! attack " << atk.info->name << "(hp:" << atk.hp << "), " - << def.info->name << "(hp:" << def.hp << ") \n"; - +BattleResult Gst::battle_res (Entity &atk, Entity &def) { + BattleResult result { atk.hp, def.hp }; bool first_strike_atk = info_has_ability(atk.info, "First Strike"); bool first_strike_def = info_has_ability(def.info, "First Strike"); bool skirmish_atk = info_has_ability(atk.info, "Skirmish"); @@ -142,30 +156,54 @@ void Gst::battle (Entity &atk, Entity &def) { 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) { - atk.hp = clamp(atk.hp - get_damage(def, atk)); + if (def_inrange) { + result.atk_hp = clamp( + result.atk_hp - get_damage(def, atk, result.def_hp)); + } if (!info_has_ability(atk.info, "No Counter")) - if (atk.hp > 0) def.hp -= get_damage(atk, def); + if (result.atk_hp > 0) + result.def_hp = clamp( + result.def_hp - get_damage(atk, def, result.atk_hp)); } else { - def.hp = clamp(def.hp - get_damage(atk, def)); - if (!info_has_ability(def.info, "No Counter")) - if (def.hp > 0) atk.hp -= get_damage(def, atk); + result.def_hp = clamp( + result.def_hp - get_damage(atk, def, result.atk_hp)); + if (!info_has_ability(def.info, "No Counter") && def_inrange) + if (result.def_hp > 0) + result.atk_hp = clamp( + result.atk_hp - get_damage(def, atk, result.def_hp)); } if (info_has_ability(atk.info, "Rapid Fire")) - if (def.hp > 0) - def.hp = clamp(def.hp - get_damage(atk, def)); + if (result.def_hp > 0) + result.def_hp = clamp( + result.def_hp - get_damage(atk, def, result.def_hp)); + + if (info_has_ability(def.info, "Rapid Fire") && def_inrange) + if (result.atk_hp > 0) + result.atk_hp = clamp( + result.atk_hp - get_damage(def, atk, result.def_hp)); - if (info_has_ability(def.info, "Rapid Fire")) - if (atk.hp > 0) - atk.hp = clamp(atk.hp - get_damage(def, atk)); + if (result.atk_hp > 0 && info_has_ability(atk.info, "Zeal")) + result.atk_hp = clamp(result.atk_hp + 20); + if (result.def_hp > 0 && info_has_ability(def.info, "Zeal")) + result.def_hp = clamp(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"; - if (atk.hp > 0 && info_has_ability(atk.info, "Zeal")) - atk.hp = clamp(atk.hp + 20); - if (def.hp > 0 && info_has_ability(def.info, "Zeal")) - def.hp = clamp(def.hp + 20); + auto result = battle_res(atk, def); + atk.hp = result.atk_hp; + def.hp = result.def_hp; std::cout << "! result " << atk.info->name << "(hp:" << atk.hp << "), " << def.info->name << "(hp:" << def.hp << ") \n"; @@ -182,6 +220,15 @@ void Gst::clear_dead() { } } +int Gst::get_range (Entity &ent) { + int range = ent.info->range; + if (range > 1) { + range += tiles[ground.tiles[ground.at(ent.x, ent.y)]].range_bonus; + } + if (range < 1) range = 1; + return range; +} + std::vector<int> Gst::get_possible_builds (Entity &ent) { std::vector<int> builds; for (int id : ent.info->build) { @@ -196,7 +243,7 @@ bool Gst::check_req_build(Entity &ent, EntityInfo *info) { for (int id : info->adjacent) { bool adj = false; for (Entity &e : entities) { - if (e.info->id == id) { + 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; @@ -213,7 +260,7 @@ bool Gst::check_req_build(Entity &ent, EntityInfo *info) { } int mindist = 9999; for (Entity &e : entities) { - if (e.info->id == 100) { + 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; @@ -260,4 +307,21 @@ void Gst::end_day () { turn = 0; day++; } + for (Entity &e : entities) { + e.done = false; + e.moved = 0; + if (e.owner == turn) { + Player &player = players[e.owner]; + for (int i=0; i<player.res.size(); i++) { + player.res[i] += e.info->prod[i]; + } + // todo heal when on top of building + if (e.building < 0) { + e.building++; + if (e.building == 0) { + e.hp += 50; if (e.hp > 100) e.hp = 100; + } + } + } + } }
\ No newline at end of file @@ -24,6 +24,21 @@ class Bonus { 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 }; + std::string id_string () { + switch (id) { + case ground: return "Ground"; + case type: return "Class"; + case ability: return "Ability"; + case tech: return "Tech"; + } + } +}; + +class BattleResult { + public: + BattleResult(float atk_hp, float def_hp) + : atk_hp(atk_hp), def_hp(def_hp) {} + float atk_hp, def_hp; }; class Gst { @@ -47,9 +62,12 @@ class Gst { 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 battle (Entity &atk, Entity &def); void clear_dead(); + int get_range(Entity &ent); std::vector<int> get_possible_builds (Entity &ent); diff --git a/game/load.cpp b/game/load.cpp index d1a1722..5baae6c 100644 --- a/game/load.cpp +++ b/game/load.cpp @@ -41,6 +41,8 @@ void load_json (Gst &gst) { 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] }; gst.tiles.push_back(tile); } @@ -88,4 +90,18 @@ void load_json (Gst &gst) { ent.spritebounds = vec2 { it["spritebounds"][0], it["spritebounds"][1] }; gst.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]; + } + gst.techs.push_back(tech); + } }
\ No newline at end of file diff --git a/game/menu.cpp b/game/menu.cpp index a9ec886..b5a91b9 100644 --- a/game/menu.cpp +++ b/game/menu.cpp @@ -1,3 +1,5 @@ +#include <iostream> + #include "menu.h" void Menu::close () { @@ -5,6 +7,7 @@ void Menu::close () { } void Menu::open (vec2 res) { + over = -1; active = true; pos = vec2 { (float)res.x, (float)res.y }; float height = options.size() * 20; @@ -26,4 +29,49 @@ int Menu::mouse_option (vec2 mouse) { 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 bf181b5..462d893 100644 --- a/game/menu.h +++ b/game/menu.h @@ -5,6 +5,7 @@ #include <string> #include "../umath/vec2.h" +#include "tech.h" class Option { public: @@ -22,10 +23,11 @@ class Menu { bool active { false }; std::vector<Option> options; vec2 pos, size; + int over; - void open (vec2 res); void close (); - int mouse_option (vec2 mouse); + virtual void open (vec2 res); + virtual int mouse_option (vec2 mouse); }; class Menu_unit : public Menu { @@ -55,4 +57,23 @@ class Menu_train : public Menu { Menu_train () {} }; + +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 ec4657e..01d8ee9 100644 --- a/game/player.h +++ b/game/player.h @@ -11,6 +11,8 @@ class Player { std::vector<int> res { 0, 0 }; std::vector<int> techs; + int level { 0 }; + int r, g, b; }; diff --git a/game/playercontrol.cpp b/game/playercontrol.cpp index 647f487..90e063e 100644 --- a/game/playercontrol.cpp +++ b/game/playercontrol.cpp @@ -63,23 +63,6 @@ Player_control::Player_control () { view.menu_day.close(); view.selected_ground = -1; gst.end_day(); - for (Entity &e : gst.entities) { - e.done = false; - e.moved = 0; - if (e.owner == gst.turn) { - Player &player = gst.players[e.owner]; - for (int i=0; i<player.res.size(); i++) { - player.res[i] += e.info->prod[i]; - } - // todo heal when on top of building - if (e.building < 0) { - e.building++; - if (e.building == 0) { - e.hp += 50; if (e.hp > 100) e.hp = 100; - } - } - } - } std::cout << "end day " << p << "\n"; return select; } @@ -93,6 +76,36 @@ Player_control::Player_control () { } ); 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.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) { + 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; diff --git a/game/playercontrol.h b/game/playercontrol.h index 62de46d..3096ada 100644 --- a/game/playercontrol.h +++ b/game/playercontrol.h @@ -31,6 +31,7 @@ enum pc_state { target_power, menu_unit, menu_day, + menu_tech, end }; diff --git a/game/tech.h b/game/tech.h index a8de9c1..84ef05c 100644 --- a/game/tech.h +++ b/game/tech.h @@ -11,6 +11,9 @@ class Tech { Tech() {} std::string name; + int id; + int level; + int req_id; std::vector<int> cost { 0, 0 }; vec2 spritebounds { 0, 0 }; diff --git a/game/view.cpp b/game/view.cpp index d00fd2a..095a99a 100644 --- a/game/view.cpp +++ b/game/view.cpp @@ -11,6 +11,36 @@ void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) { 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 (mheld[0] == 1) { bool found = false; @@ -27,8 +57,8 @@ void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) { } 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) + if (pos.x < absmouse.x && absmouse.x <= pos.x+32 + && pos.y < absmouse.y && absmouse.y <= pos.y+32) { cursor_ground = moves[i]; } @@ -41,8 +71,8 @@ void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) { 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) + if (pos.x < absmouse.x && absmouse.x <= pos.x+32 + && pos.y < absmouse.y && absmouse.y <= pos.y+32) { cursor_ground = attacks[i]; } @@ -85,13 +115,22 @@ void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) { 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; + } + } 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) + 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) { @@ -104,8 +143,8 @@ void View::process (Gst &gst, vec2 cam, vec2 mouse, int *mheld) { 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) + 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; diff --git a/game/view.h b/game/view.h index a9d196b..5aab193 100644 --- a/game/view.h +++ b/game/view.h @@ -13,6 +13,7 @@ class View { vec2 res; + int hover_ground {-1}; int selected_ground {-1}; int selected_entity {-1}; int cursor_ground {-1}; @@ -27,6 +28,7 @@ class View { Menu_day menu_day; Menu_build menu_build; Menu_train menu_train; + Menu_tech menu_tech; void process (Gst &gst, vec2 cam, vec2 mouse, int *mheld); }; |