29 #include <tbb/blocked_range.h>
30 #include <tbb/concurrent_vector.h>
31 #include <tbb/parallel_for.h>
32 #include <tbb/combinable.h>
34 #include "eng3d/binary_image.hpp"
35 #include "eng3d/serializer.hpp"
36 #include "eng3d/log.hpp"
37 #include "eng3d/rand.hpp"
59 for(
const auto& province : world.provinces)
60 if(world.terrain_types[province.terrain_type_id].is_water_body)
62 ai_man.resize(world.nations.size());
69 std::vector<float> nation_strengths(world.nations.size(), 0.f);
70 for(
const auto& province : world.provinces) {
72 for(
const auto unit_id : units) {
74 nation_strengths[unit.owner_id] += unit.get_strength();
77 for(
const auto& nation : world.nations)
78 ai_man[nation].military_strength = nation_strengths[nation];
96 struct BuildingInvestment {
104 for(auto& nation : nations_range) {
105 auto& ai = ai_man[nation];
106 if(!nation.exists()) {
107 if(!(world.time % world.ticks_per_month) && nation.ai_controlled)
108 for(auto& treaty : world.treaties)
109 for(auto& [other_nation, approval] : treaty.approval_status)
110 if(other_nation == nation)
111 approval = TreatyApproval::ACCEPTED;
116 if(nation.ai_controlled) {
118 auto our_strength = ai.military_strength;
119 auto enemy_strength = 0.f;
120 std::vector<NationId> enemy_ids, ally_ids;
121 for(const auto& other : world.nations) {
122 if(other.get_id() != nation.get_id()) {
123 const auto& relation = world.get_relation(nation, other);
124 if(relation.has_war) {
125 enemy_strength += ai_man[other].military_strength;
126 enemy_ids.push_back(other);
127 } else if(relation.is_allied()) {
128 our_strength += ai_man[other].military_strength;
129 ally_ids.push_back(other);
133 auto advantage = glm::max(our_strength, 1.f) / glm::max(enemy_strength, glm::epsilon<float>());
134 if(advantage < ai.strength_threshold) {
136 for(const auto& other : world.nations) {
137 if(other.get_id() != nation.get_id()) {
138 const auto& relation = world.get_relation(nation, other);
139 if(!relation.has_war) {
141 for(const auto enemy_id : enemy_ids) {
142 const auto& enemy_rel = world.get_relation(other, enemy_id);
143 if(enemy_rel.has_war)
144 alliance_proposals.local().emplace_back(nation, other);
153 if(nation.ai_do_cmd_troops) {
154 ai.calc_weights(nation);
155 ai.collect_eval_provinces(world, nation);
156 ai.calc_nation_risk(world, nation);
157 ai.calc_province_risk(world, nation);
160 for(const auto province_id : ai.eval_provinces) {
161 const auto& province = world.provinces[province_id];
162 const auto& unit_ids = world.unit_manager.get_province_units(province_id);
163 for(const auto unit_id : unit_ids) {
164 auto& unit = world.unit_manager.units[unit_id];
165 if(unit.owner_id != nation || !unit.can_move()) continue;
167 bool can_set_target = true;
168 if(unit.has_target_province())
169 can_set_target = ai.get_rand() > ai.override_threshold;
172 const auto& highest_risk = ai.get_highest_priority_province(world, province, unit);
175 if(highest_risk.get_id() != province.get_id()) {
177 cmd.nation_id = nation.get_id();
178 cmd.unit_id = unit.get_id();
179 cmd.target_province_id = highest_risk.get_id();
180 unit_movements.local().push_back(cmd);
188 for(const auto province_id : nation.controlled_provinces) {
189 auto& province = world.provinces[province_id];
190 for(const auto& building_type : world.building_types) {
191 if(!building_type.can_build_military()) continue;
192 auto& building = province.buildings[static_cast<size_t>(building_type.get_id())];
193 if(!building.can_do_output(province, building_type.input_ids))
196 auto& unit_type = world.unit_types[rand() % world.unit_types.size()];
199 cmd.nation_id = nation.get_id();
200 cmd.province_id = province_id;
201 cmd.building_id = BuildingId(building_type.get_id());
202 cmd.unit_type_id = unit_type.get_id();
203 build_units.local().push_back(cmd);
210 if(nation.ai_controlled && nation.can_directly_control_factories()) {
211 for(const auto province_id : nation.controlled_provinces) {
212 auto& province = world.provinces[province_id];
216 decltype(province.products.begin()) product;
219 std::vector<ProductInfo> v;
220 for(auto it = province.products.begin(); it != province.products.end(); it++)
221 v.push_back(ProductInfo{ it, std::distance(province.products.begin(), it) });
223 std::sort(v.begin(), v.end(), [&](const auto& a, const auto& b) {
224 return a.product->ds_ratio() > b.product->ds_ratio();
227 for (const auto& product_info : v) {
230 const auto it = std::find_if(world.building_types.begin(), world.building_types.end(), [&](const auto& e) {
231 return e.output_id == product_info.id;
234 if(it != world.building_types.end()) {
236 const auto investment = nation.budget / 15.f;
237 BuildingInvestment cmd{};
238 cmd.nation_id = nation.get_id();
239 cmd.province_id = province_id;
240 cmd.building_id = BuildingId(it->get_id());
241 cmd.amount = investment;
242 building_investments.local().push_back(cmd);
251 unit_movements.combine_each([&](
const auto& list) {
252 for(
const auto& e : list) {
253 const auto& target_province = world.provinces[e.target_province_id];
254 auto& unit = world.unit_manager.units[e.unit_id];
255 unit.set_target(target_province);
259 build_units.combine_each([&](
const auto& list) {
260 for(
const auto& e : list) {
261 auto& province = world.provinces[e.province_id];
262 const auto& unit_type = world.unit_types[e.unit_type_id];
263 province.buildings[e.building_id].work_on_unit(unit_type);
267 building_investments.combine_each([&](
const auto& list) {
268 for(
const auto& e : list) {
269 auto& nation = world.nations[e.nation_id];
270 nation.budget -= e.amount;
271 auto& province = world.provinces[e.province_id];
272 province.buildings[e.building_id].estate_state.invest(e.amount);
278 alliance_proposals.combine_each([&](
const auto& alliance_proposals_range) {
279 for(
const auto& [nation_id, other_id] : alliance_proposals_range) {
280 const auto& nation = world.nations[nation_id];
281 const auto& other_nation = world.nations[other_id];
282 world.fire_special_event(
"special_alliance", nation.ref_name.c_str(), other_nation.ref_name.c_str());
std::vector< AIManager > ai_man
std::vector< ProvinceId > g_water_provinces
Eng3D::Freelist< Unit > units
std::vector< UnitId > get_province_units(ProvinceId province_id) const
void do_tick(World &world)
void parallel_for(T range, F &&func)