From bb16c32bde58cba70e4877aa2d3ebd04332eb575 Mon Sep 17 00:00:00 2001 From: jacopograndi Date: Tue, 4 Jan 2022 13:35:02 +0100 Subject: linux compile and imgs --- game/gst.cpp | 1208 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 604 insertions(+), 604 deletions(-) (limited to 'game/gst.cpp') 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 -#include - - -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 Gst::get_cost (EntityInfo *info, Player &player) { - std::vector 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; icost.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 Gst::get_bonuses (Entity &atk, Entity &def) { - auto &tiles = inv->tiles; - auto &ground = inv->ground; - std::vector 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 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 Gst::get_possible_trains (Entity &ent) { - Player &player = get_player(ent.owner); - auto &cls = ent.info->train_class; - std::vector trains; - if (ent.info->id == 107) { // market special case - std::vector 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 Gst::get_possible_builds (Entity &ent) { - std::vector 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 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; iprod[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 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 +#include + + +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 Gst::get_cost (EntityInfo *info, Player &player) { + std::vector 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; icost.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 Gst::get_bonuses (Entity &atk, Entity &def) { + auto &tiles = inv->tiles; + auto &ground = inv->ground; + std::vector 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 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 Gst::get_possible_trains (Entity &ent) { + Player &player = get_player(ent.owner); + auto &cls = ent.info->train_class; + std::vector trains; + if (ent.info->id == 107) { // market special case + std::vector 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 Gst::get_possible_builds (Entity &ent) { + std::vector 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 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; iprod[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 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 -- cgit v1.2.3-54-g00ecf