Symphony Of Empires
world.cpp
Go to the documentation of this file.
1 // Symphony of Empires
2 // Copyright (C) 2021, Symphony of Empires contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // world.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <filesystem>
26 #include <cstdio>
27 #include <cstdlib>
28 #include <cstring>
29 #include <cassert>
30 #include <set>
31 #ifndef _MSC_VER
32 # include <sys/cdefs.h>
33 #endif
34 #include <tbb/blocked_range.h>
35 #include <tbb/concurrent_vector.h>
36 #include <tbb/parallel_for.h>
37 #include <tbb/combinable.h>
38 
39 #include "eng3d/binary_image.hpp"
40 #include "eng3d/log.hpp"
41 #include "eng3d/serializer.hpp"
42 #include "eng3d/state.hpp"
43 #include "eng3d/utils.hpp"
44 #include "eng3d/string.hpp"
45 
46 #include "server/emigration.hpp"
47 #include "province.hpp"
48 #include "world.hpp"
49 #include "diplomacy.hpp"
50 #include "indpobj.hpp"
51 #include "server/lua_api.hpp"
53 #include "action.hpp"
54 #include "server/economy.hpp"
55 
56 #undef min
57 #undef max
58 
60 
61 namespace AI {
62  void init(World& world);
63  void do_tick(World& world);
64 }
65 
66 template<typename T>
67 static const T& find_or_throw(const std::string_view ref_name) {
68  const auto& list = World::get_instance().get_list((T*)nullptr);
69  const auto result = std::find_if(list.begin(), list.end(), [ref_name](const auto& o) {
70  return !strcmp(o.ref_name.c_str(), ref_name.data());
71  });
72 
73  if(result == list.end())
74  CXX_THROW(Eng3D::LuaException, translate_format("Object<%s> not found", typeid(T).name()).c_str());
75  return *result;
76 }
77 
78 // Creates a new world
80  // Register our API functions
81  lua_register(lua.state, "add_terrain_type", LuaAPI::add_terrain_type);
82  lua_register(lua.state, "get_terrain_type", LuaAPI::get_terrain_type);
83  lua_register(lua.state, "get_terrain_type_by_id", LuaAPI::get_terrain_type_by_id);
84 
85  lua_register(lua.state, "add_technology", LuaAPI::add_technology);
86  lua_register(lua.state, "get_technology", LuaAPI::get_technology);
87  lua_register(lua.state, "add_req_tech_to_tech", LuaAPI::add_req_tech_to_tech);
88 
89  lua_register(lua.state, "add_building_type", LuaAPI::add_building_type);
90  lua_register(lua.state, "get_building_type", LuaAPI::get_building_type);
91 
92  lua_register(lua.state, "add_good", LuaAPI::add_good);
93  lua_register(lua.state, "get_good", LuaAPI::get_good);
94 
95  lua_register(lua.state, "add_input_to_industry_type", LuaAPI::add_input_to_industry_type);
96  lua_register(lua.state, "add_output_to_industry_type", LuaAPI::add_output_to_industry_type);
97  lua_register(lua.state, "add_req_good_to_industry_type", LuaAPI::add_req_good_to_industry_type);
98  lua_register(lua.state, "add_req_technology_to_industry_type", LuaAPI::add_req_technology_to_industry_type);
99 
100  lua_register(lua.state, "add_nation", LuaAPI::add_nation);
101  lua_register(lua.state, "get_nation", LuaAPI::get_nation);
102  lua_register(lua.state, "get_nation_by_id", LuaAPI::get_nation_by_id);
103  lua_register(lua.state, "get_all_nations", LuaAPI::get_all_nations);
104  lua_register(lua.state, "switch_nation_soul", LuaAPI::switch_nation_soul);
105  lua_register(lua.state, "nation_declare_war_no_cb", LuaAPI::nation_declare_war_no_cb);
106 
107  lua_register(lua.state, "get_provinces_owned_by_nation", LuaAPI::get_provinces_owned_by_nation);
108  lua_register(lua.state, "get_provinces_with_nucleus_by_nation", LuaAPI::get_provinces_with_nucleus_by_nation);
109  lua_register(lua.state, "set_nation_primary_language", LuaAPI::set_nation_primary_language);
110  lua_register(lua.state, "set_nation_capital", LuaAPI::set_nation_capital);
111  lua_register(lua.state, "add_nation_accepted_language", LuaAPI::add_accepted_language);
112  lua_register(lua.state, "add_nation_accepted_religion", LuaAPI::add_accepted_religion);
113  lua_register(lua.state, "add_nation_client_hint", LuaAPI::add_nation_client_hint);
114  lua_register(lua.state, "set_nation_ideology", [](lua_State* L) {
115  auto& nation = g_world.nations.at(lua_tonumber(L, 1));
116  const auto& ideology = g_world.ideologies.at(lua_tonumber(L, 2));
117  nation.ideology_id = ideology.get_id();
118  nation.subideology_id = SubideologyId(0);
119  const std::string subideology_ref_name = luaL_checkstring(L, 3);
120  for(const auto& subideology : ideology.subideologies) {
121  if(subideology.ref_name.get_string() == subideology_ref_name) {
122  nation.subideology_id = subideology.get_id();
123  nation.current_policy.economic = subideology.economic;
124  nation.current_policy.political = subideology.political;
125  break;
126  }
127  }
128  return 0;
129  });
130  lua_register(lua.state, "get_nation_relation", LuaAPI::get_nation_relation);
131  lua_register(lua.state, "set_nation_relation", LuaAPI::set_nation_relation);
132  lua_register(lua.state, "nation_declare_unjustified_war", LuaAPI::nation_declare_unjustified_war);
133  lua_register(lua.state, "nation_make_puppet", [](lua_State* L) {
134  const auto& nation = g_world.nations.at(lua_tonumber(L, 1));
135  auto& other_nation = g_world.nations.at(lua_tonumber(L, 2));
136  other_nation.make_puppet(nation);
137  auto& relation = g_world.get_relation(nation, other_nation);
138  relation.alliance = 0.45f; // Just below to not make a customs union
139  relation.relation = 0.f;
140  return 0;
141  });
142  lua_register(lua.state, "nation_make_customs_union", [](lua_State* L) {
143  auto& nation = g_world.nations.at(lua_tonumber(L, 1));
144  auto& other_nation = g_world.nations.at(lua_tonumber(L, 2));
145  auto& relation = g_world.get_relation(nation, other_nation);
146  relation.alliance = 1.f;
147  relation.relation = 0.f;
148  return 0;
149  });
150  lua_register(lua.state, "set_nation_flag", [](lua_State* L) {
151  auto& nation = g_world.nations.at(lua_tonumber(L, 1));
152  nation.flags[luaL_checkstring(L, 2)] = lua_tonumber(L, 3);
153  return 0;
154  });
155  lua_register(lua.state, "get_nation_flag", [](lua_State* L) {
156  auto& nation = g_world.nations.at(lua_tonumber(L, 1));
157  lua_pushnumber(L, nation.flags[luaL_checkstring(L, 2)]);
158  return 1;
159  });
160 
161  lua_register(lua.state, "add_province", LuaAPI::add_province);
162  lua_register(lua.state, "update_province", LuaAPI::update_province);
163  lua_register(lua.state, "get_province", LuaAPI::get_province);
164  lua_register(lua.state, "get_province_by_id", LuaAPI::get_province_by_id);
165  lua_register(lua.state, "province_add_unit", LuaAPI::province_add_unit);
166  lua_register(lua.state, "update_province_building", LuaAPI::update_province_building);
167  lua_register(lua.state, "add_province_pop", LuaAPI::add_province_pop);
168  lua_register(lua.state, "set_province_language", LuaAPI::set_province_language);
169  lua_register(lua.state, "set_province_religion", LuaAPI::set_province_religion);
170  lua_register(lua.state, "give_province_to", LuaAPI::give_province_to);
171  lua_register(lua.state, "give_hard_province_to", LuaAPI::give_hard_province_to);
172  lua_register(lua.state, "get_province_owner", LuaAPI::get_province_owner);
173  lua_register(lua.state, "get_province_controller", LuaAPI::get_province_controller);
174  lua_register(lua.state, "get_province_neighbours", LuaAPI::get_province_neighbours);
175  lua_register(lua.state, "get_province_nuclei", LuaAPI::get_province_nuclei);
176  lua_register(lua.state, "get_province_pops_size", [](lua_State* L) {
177  const auto& province = g_world.provinces.at(lua_tonumber(L, 1));
178  lua_pushnumber(L, province.pops.size());
179  return 1;
180  });
181  lua_register(lua.state, "get_province_pop", [](lua_State* L) {
182  const auto& province = g_world.provinces.at(lua_tonumber(L, 1));
183  const auto& pop = province.pops.at(lua_tonumber(L, 2));
184  lua_pushnumber(L, pop.size);
185  lua_pushnumber(L, pop.budget);
186  lua_pushnumber(L, pop.literacy);
187  lua_pushnumber(L, pop.life_needs_met);
188  lua_pushnumber(L, 1.f);
189  lua_pushnumber(L, 1.f);
190  lua_pushnumber(L, (size_t)pop.type_id);
191  lua_pushnumber(L, IdeologyId(0));
192  lua_pushnumber(L, pop.militancy);
193  return 9;
194  });
195  lua_register(lua.state, "set_province_pop", [](lua_State* L) {
196  auto& province = g_world.provinces.at(lua_tonumber(L, 1));
197  auto& pop = province.pops.at(lua_tonumber(L, 2));
198  pop.size = lua_tonumber(L, 3);
199  pop.budget = lua_tonumber(L, 4);
200  pop.literacy = lua_tonumber(L, 5);
201  pop.life_needs_met = lua_tonumber(L, 6);
202  //lua_tonumber(L, 7);
203  //lua_tonumber(L, 8);
204  pop.type_id = PopTypeId(lua_tonumber(L, 9));
205  pop.militancy = lua_tonumber(L, 10);
206  return 0;
207  });
208 
209  lua_register(lua.state, "get_province_buildings_size", [](lua_State* L) {
210  const auto& province = g_world.provinces.at(lua_tonumber(L, 1));
211  lua_pushnumber(L, province.buildings.size());
212  return 1;
213  });
214  lua_register(lua.state, "get_province_building", [](lua_State* L) {
215  const auto& province = g_world.provinces.at(lua_tonumber(L, 1));
216  const auto& building = province.buildings.at(lua_tonumber(L, 2));
217  lua_pushnumber(L, building.level);
218  lua_pushnumber(L, building.production_scale);
219  lua_pushnumber(L, building.workers);
220  return 3;
221  });
222  lua_register(lua.state, "set_province_building", [](lua_State* L) {
223  auto& province = g_world.provinces.at(lua_tonumber(L, 1));
224  auto& building = province.buildings.at(lua_tonumber(L, 2));
225  building.level = lua_tonumber(L, 3);
226  building.production_scale = lua_tonumber(L, 4);
227  building.workers = lua_tonumber(L, 5);
228  return 0;
229  });
230 
231  lua_register(lua.state, "rename_province", LuaAPI::rename_province);
232  lua_register(lua.state, "add_province_nucleus", LuaAPI::add_province_nucleus);
233  lua_register(lua.state, "add_province_owner", LuaAPI::add_province_owner);
234 
235  lua_register(lua.state, "add_event", LuaAPI::add_event);
236  lua_register(lua.state, "get_event", LuaAPI::get_event);
237  lua_register(lua.state, "update_event", LuaAPI::update_event);
238  lua_register(lua.state, "add_event_receivers", LuaAPI::add_event_receivers);
239 
240  lua_register(lua.state, "add_decision", LuaAPI::add_decision);
241 
242  lua_register(lua.state, "add_pop_type", LuaAPI::add_pop_type);
243  lua_register(lua.state, "get_pop_type", LuaAPI::get_pop_type);
244  lua_register(lua.state, "get_pop_type_by_id", LuaAPI::get_pop_type_by_id);
245 
246  lua_register(lua.state, "add_language", LuaAPI::add_language);
247  lua_register(lua.state, "get_language", LuaAPI::get_language);
248  lua_register(lua.state, "get_language_by_id", LuaAPI::get_language_by_id);
249 
250  lua_register(lua.state, "add_religion", LuaAPI::add_religion);
251  lua_register(lua.state, "get_religion", LuaAPI::get_religion);
252  lua_register(lua.state, "get_religion_by_id", LuaAPI::get_religion_by_id);
253 
254  lua_register(lua.state, "add_unit_type", LuaAPI::add_unit_type);
255  lua_register(lua.state, "get_unit_type", LuaAPI::get_unit_type);
256  lua_register(lua.state, "add_req_good_unit_type", LuaAPI::add_req_good_unit_type);
257 
258  lua_register(lua.state, "add_ideology", [](lua_State* L) {
259  if(g_world.needs_to_sync)
260  luaL_error(L, "MP-Sync in this function is not supported");
261 
262  Ideology ideology{};
263  ideology.ref_name = luaL_checkstring(L, 1);
264  ideology.name = luaL_checkstring(L, 2);
265  ideology.color = (std::byteswap<std::uint32_t>(static_cast<int>(lua_tonumber(L, 3))) >> 8) | 0xff000000;
266  g_world.insert(ideology);
267  lua_pushnumber(L, g_world.ideologies.size() - 1);
268  return 1;
269  });
270  lua_register(lua.state, "add_ideology_subideology", [](lua_State* L) {
271  if(g_world.needs_to_sync)
272  luaL_error(L, "MP-Sync in this function is not supported");
273 
274  auto& ideology = g_world.ideologies.at(lua_tonumber(L, 1));
275  Ideology::Subideology subideology{};
276  subideology.ref_name = luaL_checkstring(L, 2);
277  subideology.name = luaL_checkstring(L, 3);
278  subideology.economic.distributism = lua_tonumber(L, 4);
279  subideology.economic.mercantilist = lua_tonumber(L, 5);
280  subideology.economic.capitalism = lua_tonumber(L, 6);
281  subideology.political.individualism = lua_tonumber(L, 7);
282  subideology.political.state_power = lua_tonumber(L, 8);
283  subideology.political.equalitarianism = lua_tonumber(L, 9);
284  subideology.political.secular = lua_tonumber(L, 10);
285  subideology.political.pluralism = lua_tonumber(L, 11);
286 
287  subideology.cached_id = SubideologyId(ideology.subideologies.size());
288  ideology.subideologies.push_back(subideology);
289  return 0;
290  });
291  lua_register(lua.state, "get_ideology", [](lua_State* L) {
292  const auto& ideology = find_or_throw<Ideology>(luaL_checkstring(L, 1));
293  lua_pushnumber(L, (size_t)g_world.get_id(ideology));
294  lua_pushstring(L, ideology.name.c_str());
295  lua_pushnumber(L, std::byteswap<std::uint32_t>((ideology.color & 0x00ffffff) << 8));
296  return 3;
297  });
298  lua_register(lua.state, "get_ideology_by_id", [](lua_State* L) {
299  const auto& ideology = g_world.ideologies.at(lua_tonumber(L, 1));
300  lua_pushstring(L, ideology.ref_name.c_str());
301  lua_pushstring(L, ideology.name.c_str());
302  lua_pushnumber(L, std::byteswap<std::uint32_t>((ideology.color & 0x00ffffff) << 8));
303  return 3;
304  });
305 
306  lua_register(lua.state, "get_day", [](lua_State* L) {
307  lua_pushnumber(L, g_world.get_day());
308  return 1;
309  });
310  lua_register(lua.state, "get_month", [](lua_State* L) {
311  lua_pushnumber(L, g_world.get_month());
312  return 1;
313  });
314  lua_register(lua.state, "get_year", [](lua_State* L) {
315  lua_pushnumber(L, g_world.get_year());
316  return 1;
317  });
318  lua_register(lua.state, "set_date", [](lua_State* L) {
319  const int year = lua_tonumber(L, 1) * 12 * 30;
320  const int month = lua_tonumber(L, 2) * 30;
321  const int day = lua_tonumber(L, 3);
322  g_world.time = year + month + day;
323  return 1;
324  });
325 
326  /*LuaAPI::register_new_table(lua.state, "Ideology", {}, {
327  { "test", [](lua_State* L) {
328  Eng3D::Log::debug("lua_test", "hello world");
329  return 0;
330  }}
331  });*/
332 
333  // Constants for ease of readability
334  lua_pushboolean(lua.state, true);
335  lua_setglobal(lua.state, "EVENT_CONDITIONS_MET");
336  lua_pushboolean(lua.state, false);
337  lua_setglobal(lua.state, "EVENT_CONDITIONS_UNMET");
338 
339  lua_pushboolean(lua.state, true);
340  lua_setglobal(lua.state, "EVENT_DO_MANY_TIMES");
341  lua_pushboolean(lua.state, false);
342  lua_setglobal(lua.state, "EVENT_DO_ONE_TIME");
343 
344  // Technology types
345  lua_pushnumber(lua.state, TechnologyType::STRATEGIC);
346  lua_setglobal(lua.state, "TECH_STRATEGIC");
347  lua_pushnumber(lua.state, TechnologyType::MILITARY);
348  lua_setglobal(lua.state, "TECH_MILITARY");
349  lua_pushnumber(lua.state, TechnologyType::NAVY);
350  lua_setglobal(lua.state, "TECH_NAVY");
351  lua_pushnumber(lua.state, TechnologyType::SOCIAL);
352  lua_setglobal(lua.state, "TECH_SOCIAL");
353  lua_pushnumber(lua.state, TechnologyType::ECONOMIC);
354  lua_setglobal(lua.state, "TECH_ECONOMIC");
355  lua_pushnumber(lua.state, TechnologyType::POLITICS);
356  lua_setglobal(lua.state, "TECH_POLITICS");
357 
358  // Policies control
359 #define POLICY_CAPITALIST 1
360  lua_pushnumber(lua.state, POLICY_CAPITALIST);
361  lua_setglobal(lua.state, "POLICY_CAPITALIST");
362  lua_register(lua.state, "relative_nation_policy_stance", [](lua_State* L) {
363  auto& nation = g_world.nations.at(lua_tonumber(L, 1));
364  float val = lua_tonumber(L, 3);
365  float ret_val = 0.f;
366  auto& policy = nation.current_policy;
367  switch((int)lua_tonumber(L, 2)) {
368  case POLICY_CAPITALIST:
369  ret_val = policy.economic.capitalism = glm::clamp(policy.economic.capitalism + val, -1.f, 1.f);
370  break;
371  default:
372  break;
373  }
374  lua_pushnumber(L, ret_val);
375  return 1;
376  });
377 
378  lua_register(lua.state, "UI_CallBuiltin", LuaAPI::ui_call_builtin);
379 
380  // Set path for `require` statements in lua.state, this will allow us to require
381  // without using data/scripts
382  lua_getglobal(lua.state, "package");
383  lua_getfield(lua.state, -1, "path");
384  std::string curr_path = lua_tostring(lua.state, -1);
385 
386  // Add all scripts onto the path (with glob operator '?')
387  const auto paths = Eng3D::State::get_instance().package_man.get_paths();
388  for(const auto& path : paths) {
389  Eng3D::Log::debug("lua", "Added path " + path);
390  curr_path.append(";" + path + "/lua/?.lua");
391  }
392  lua_pop(lua.state, 1);
393  lua_pushstring(lua.state, curr_path.c_str());
394  lua_setfield(lua.state, -2, "path");
395  lua_pop(lua.state, 1);
396 }
397 
398 static void lua_exec_all_of(World& world, const std::vector<std::string> files, const std::string& dir = "lua") {
399  std::string files_buf = "require(\"classes/base\")\n\n";
400  for(const auto& file : files) {
401  auto paths = Eng3D::State::get_instance().package_man.get_multiple(dir + "/" + file + ".lua");
402  for(const auto& path : paths) {
403 #ifdef E3D_TARGET_WINDOWS
404  std::string m_path;
405  for(auto& c : path->get_abs_path())
406  if(c == '\\') m_path += "\\\\";
407  else m_path += c;
408 #else
409  std::string m_path = path->get_abs_path();
410 #endif
411  files_buf += "print(\"" + m_path + "\")\nassert(loadfile(\"" + m_path + "\"))()\n";
412  }
413  }
414  Eng3D::Log::debug("lua", "Buffer " + files_buf);
415  if(luaL_loadstring(world.lua.state, files_buf.c_str()) != LUA_OK || lua_pcall(world.lua.state, 0, 0, 0) != LUA_OK)
416  CXX_THROW(Eng3D::LuaException, lua_tostring(world.lua.state, -1));
417 }
418 
421  ar.from_file("world.cch");
423  Eng3D::Deser::deserialize(ar, *this);
424 } catch(const std::exception& e) {
425  Eng3D::Log::error("cache", e.what());
426 
427  // Execute all lua files
428  lua_exec_all_of(*this, std::vector<std::string> {
429  "terrain_types", "good_types", "ideologies", "languages",
430  "building_types", "technology", "religions", "pop_types",
431  "industry_types", "unit_types", "boat_types",
432  "nations", "provinces", "init"
433  }, "lua/entities");
434 
435  auto div = std::make_unique<Eng3D::BinaryImage>(Eng3D::State::get_instance().package_man.get_unique("map/provinces.png")->get_abs_path());
436  width = div->width;
437  height = div->height;
438  tiles = std::make_unique<ProvinceId[]>(width * height);
439 
440  Eng3D::Log::debug("world", translate("Associate tiles with provinces"));
441 
442  // Build a lookup table for super fast speed on finding provinces
443  // 16777216 * 4 = c.a 64 MB, that quite a lot but we delete the table after anyways
444  Eng3D::Log::debug("world", translate("Building the province lookup table"));
445  std::vector<ProvinceId> province_color_table(0xffffff + 1, ProvinceId(0));
446  for(const auto& province : provinces)
447  province_color_table[province.color & 0xffffff] = this->get_id(province);
448 
449  const auto* raw_buffer = div->buffer.get();
450  tbb::parallel_for(static_cast<size_t>(0), height, [this, &province_color_table, raw_buffer](const auto j) {
451  const auto off = j * width;
452  for(size_t i = 0; i < width; i++)
453  tiles[off + i] = province_color_table[raw_buffer[off + i] & 0xffffff];
454  });
455 
456 //#if 0
457  std::set<uint32_t> colors_found;
458  std::set<uint32_t> colors_used;
459  for(size_t i = 0; i < width * height; i++) {
460  const auto province_id = province_color_table[raw_buffer[i] & 0xffffff];
461  if(province_id == (ProvinceId)0)
462  colors_found.insert(raw_buffer[i]);
463  colors_used.insert(raw_buffer[i] & 0xffffff);
464  }
465  if(!colors_found.empty()) {
466  std::unique_ptr<FILE, int(*)(FILE*)> province_fp(fopen("uprovinces.lua", "w+t"), fclose);
467  if(province_fp != nullptr) {
468  for(const auto& color_raw : colors_found) {
469  uint32_t color = color_raw << 8;
470  fprintf(province_fp.get(), "province=Province:new{ref_name=\"province_%06x\",name=translate(\"Unknown\"),color=0x%06x,terrain=tt_sea,rgo_size={}}\n", static_cast<unsigned int>(std::byteswap<std::uint32_t>(color)), static_cast<unsigned int>(std::byteswap<std::uint32_t>(color)));
471  fprintf(province_fp.get(), "province:register()\n");
472  }
473  }
474 
475  std::unique_ptr<FILE, int(*)(FILE*)> color_fp(fopen("ucolors.txt", "w+t"), fclose);
476  if(color_fp != nullptr) {
477  for(size_t i = 0; i < province_color_table.size(); i++) {
478  if((i % 128 == 0) && (province_color_table[i] == ProvinceId(0))) {
479  const uint32_t color = i << 8;
480  fprintf(color_fp.get(), "%06lx\n", static_cast<unsigned long int>(std::byteswap<std::uint32_t>(color)));
481  }
482  }
483  }
484 
485  // Flush files before throwing
486  province_fp.reset();
487  color_fp.reset();
488 
489  // Exit
490  Eng3D::Log::error("world", "There are unregistered provinces, please register them!");
491  }
492 
493  std::string provinces_ref_names = "";
494  for(auto& province : provinces)
495  if(!colors_used.contains(province.color & 0xffffff))
496  provinces_ref_names += "'" + std::string{province.ref_name.get_string()} + "'";
497 
498  if(!provinces_ref_names.empty()) {
499  std::string error = "Province " + provinces_ref_names + " is registered but missing on province.png, please add it!";
500  Eng3D::Log::error("world", error);
501  CXX_THROW(std::runtime_error, error.c_str());
502  }
503 //#endif
504  div.reset();
505 
506  // Calculate the edges of the province (min and max x and y coordinates)
507  Eng3D::Log::debug("world", translate("Calculate the edges of the province (min and max x and y coordinates)"));
508 
509  // Init the province bounds
510  for(auto& province : provinces) {
511  province.box_area.right = province.box_area.bottom = 0.f;
512  province.box_area.left = width;
513  province.box_area.top = height;
514  }
515 
516  for(size_t i = 0; i < width; i++) {
517  for(size_t j = 0; j < height; j++) {
518  auto& province = provinces[this->tiles[i + j * width]];
519  province.box_area.left = glm::min(province.box_area.left, static_cast<float>(i));
520  province.box_area.right = glm::max(province.box_area.right, static_cast<float>(i));
521  province.box_area.bottom = glm::max(province.box_area.bottom, static_cast<float>(j));
522  province.box_area.top = glm::min(province.box_area.top, static_cast<float>(j));
523  }
524  }
525 
526  // Correct stuff from provinces
527  Eng3D::Log::debug("world", translate("Correcting values for provinces"));
528  for(auto& province : provinces) {
529  province.box_area.right = glm::min(width, static_cast<size_t>(province.box_area.right));
530  province.box_area.bottom = glm::min(height, static_cast<size_t>(province.box_area.bottom));
531  }
532 
533  // Neighbours
534  Eng3D::Log::debug("world", translate("Calculating neighbours for provinces"));
535  for(size_t i = 0; i < width * height; i++) {
536  auto& province = this->provinces[this->tiles[i]];
537  if(i > this->width) { // Up
538  auto other_tile = this->tiles[i - this->width];
539  province.neighbour_ids.push_back(other_tile);
540  }
541  if(i < (this->width * this->height) - this->width) { // Down
542  auto other_tile = this->tiles[i + this->width];
543  province.neighbour_ids.push_back(other_tile);
544  }
545  if(i > 1) { // Left
546  auto other_tile = this->tiles[i - 1];
547  province.neighbour_ids.push_back(other_tile);
548  }
549  if(i < (this->width * this->height) - 1) { // Right
550  auto other_tile = this->tiles[i + 1];
551  province.neighbour_ids.push_back(other_tile);
552  }
553  }
554 
555  // Remove neighbouring duplicates first
556  for(auto& province : this->provinces) {
557  auto last = std::unique(province.neighbour_ids.begin(), province.neighbour_ids.end());
558  province.neighbour_ids.erase(last, province.neighbour_ids.end());
559  std::erase(province.neighbour_ids, province); // Erase self
560  }
561 
562  // Then sort and remove any remaining duplicates
563  for(auto& province : this->provinces) {
564  std::sort(province.neighbour_ids.begin(), province.neighbour_ids.end());
565  auto last = std::unique(province.neighbour_ids.begin(), province.neighbour_ids.end());
566  province.neighbour_ids.erase(last, province.neighbour_ids.end());
567  }
568  unit_manager.init(*this);
569 
570  // Create diplomatic relations between nations
571  Eng3D::Log::debug("world", translate("Creating diplomatic relations"));
572  // Relations between nations start at 0 (and latter modified by lua scripts)
573  // since we use cantor's pairing function we only have to make an n*2 array so yeah let's do that!
574  this->relations.resize(this->nations.size() * this->nations.size());
575 
576  // Auto-relocate capitals for countries which do not have one
577  for(auto& nation : this->nations) {
578  if(!nation.exists()) continue;
579  //Eng3D::Log::debug("world", translate("Relocating capital of [" + nation.ref_name + "]"));
580  nation.auto_relocate_capital();
581  }
582 
583  // Write the entire world to the cache file
586  Eng3D::Deser::serialize(ar, *this);
587  ar.to_file("world.cch");
588 }
589 
591  const std::vector<std::string> mod_files = {
592  "mod", "postinit"
593  };
594  lua_exec_all_of(*this, mod_files, "lua/init");
595 
596  // Server needs now to sync changes to clients (changing state is not enough)
597  this->needs_to_sync = true;
598  Eng3D::Log::debug("game", translate("World fully intiialized"));
599  AI::init(*this); // Initialize the AI
600 }
601 
602 static inline void unit_do_tick(World& world, Unit& unit) {
603  // Do not evaluate if we have an ongoing battle
604  if(unit.on_battle) {
605  unit.stop_movement();
606  return;
607  }
608 
609  auto& province = world.provinces[unit.province_id()];
610  // Replenish units
611  if(unit.size < unit.base)
612  unit.size = glm::min<float>(unit.base, unit.size + unit.experience * 10.f);
613 
614  if(unit.has_target_province()) {
615  assert(unit.get_target_province_id() != unit.province_id());
616  auto& unit_target = world.provinces[unit.get_target_province_id()];
617  bool can_move = true, can_take = false;
618  if(unit_target.controller_id != unit.owner_id) {
619  const auto& relation = world.get_relation(unit_target.controller_id, unit.owner_id);
620  can_move = relation.has_landpass();
621  can_take = relation.has_war;
622  }
623 
624  if(can_move) {
625  bool unit_moved = unit.update_movement(world.unit_manager);
626  if(unit_moved && can_take) {
627  // Moving to a province not owned by us!
628  if(unit.owner_id != unit_target.owner_id) {
629  // Relation between original owner and the conqueree
630  const auto& relation = world.get_relation(unit_target.owner_id, unit.owner_id);
631  if(relation.is_allied()) // Allies will liberate countries implicitly and give back to the original owner
632  world.nations[unit_target.owner_id].control_province(unit_target);
633  else // Non allied means provinces aren't returned implicitly
634  world.nations[unit.owner_id].control_province(unit_target);
635  } else { // Liberating our own provinces
636  world.nations[unit.owner_id].control_province(unit_target);
637  }
638  }
639  }
640  }
641 }
642 
643 static inline void unit_do_battle_tick(World& world, Unit& unit) {
644  if(unit.on_battle)
645  return;
646 
647  auto& province = world.provinces[unit.province_id()];
648  if(province.battle.active) {
649  // TODO: let neutral people pass thru? or something more realistic
650  // Can we join the attackers side?
651  bool will_attack = false;
652  for(const auto attacker_id : province.battle.attacker_nations_ids) {
653  if(unit.owner_id == attacker_id) {
654  will_attack = true;
655  break;
656  }
657  const auto& relation = world.get_relation(unit.owner_id, attacker_id);
658  if(relation.is_allied()) {
659  will_attack = true;
660  break;
661  }
662  }
663 
664  if(will_attack) {
665  auto& nation_ids = province.battle.attacker_nations_ids;
666  if(std::find(nation_ids.begin(), nation_ids.end(), unit.owner_id) == nation_ids.end())
667  nation_ids.push_back(unit.owner_id);
668  } else {
669  auto& nation_ids = province.battle.defender_nations_ids;
670  if(std::find(nation_ids.begin(), nation_ids.end(), unit.owner_id) == nation_ids.end())
671  nation_ids.push_back(unit.owner_id);
672  }
673  province.battle.unit_ids.push_back(unit.get_id());
674  unit.on_battle = true;
675  unit.stop_movement();
676  } else {
677  // No battle on the current province, create a new one so check if we can start a new battle
678  const auto& unit_ids = world.unit_manager.get_province_units(province);
679  std::vector<UnitId> enemy_unit_ids;
680  for(const auto other_unit_id : unit_ids) {
681  auto& other_unit = world.unit_manager.units[other_unit_id];
682  // Make sure the other unit isn't the same nation or already in battle, remember that if it's already
683  // in battle then we can't probably join
684  if(unit.owner_id == other_unit.owner_id)
685  continue;
686  // Check relations, if we're at war we will attack this unit
687  const auto& relation = world.get_relation(unit.owner_id, other_unit.owner_id);
688  if(!relation.has_war)
689  continue;
690  enemy_unit_ids.push_back(other_unit_id);
691  }
692 
693  // If we found an unit we can attack, start a battle
694  if(!enemy_unit_ids.empty()) {
695  province.battle = Province::Battle();
696  province.battle.active = true;
697 
698  // We attack, they defend from us
699  unit.on_battle = true;
700  unit.stop_movement();
701  province.battle.unit_ids.push_back(unit);
702  province.battle.attacker_nations_ids.push_back(unit.owner_id);
703 
704  std::vector<NationId> v;
705  for(const auto enemy_unit_id : enemy_unit_ids) {
706  auto& enemy_unit = world.unit_manager.units[enemy_unit_id];
707  enemy_unit.on_battle = true;
708  enemy_unit.stop_movement();
709  province.battle.unit_ids.push_back(enemy_unit);
710  v.push_back(enemy_unit.owner_id);
711  }
712  std::sort(v.begin(), v.end());
713  v.erase(std::unique(v.begin(), v.end()), v.end());
714  province.battle.defender_nations_ids = v;
715 
716  Eng3D::Log::debug("game", string_format("New battle on province %s", province.name.c_str()));
717  }
718  }
719 
720  // Assert no duplicate units in battles
721  std::vector<UnitId> unit_ids;
722  for(auto& province : world.provinces)
723  if(province.battle.active)
724  for(const auto unit_id : province.battle.unit_ids)
725  unit_ids.push_back(unit_id);
726  std::sort(unit_ids.begin(), unit_ids.end());
727  assert(std::adjacent_find(unit_ids.begin(), unit_ids.end()) == unit_ids.end());
728 }
729 
730 void World::fire_special_event(const std::string_view event_ref_name, const std::string_view nation_ref_name, const std::string_view other_nation_ref_name) {
731  auto event_it = std::find_if(this->events.begin(), this->events.end(), [&](const auto& e) {
732  return e.ref_name.get_string() == event_ref_name;
733  });
734  if(event_it == this->events.end())
735  CXX_THROW(std::runtime_error, translate_format("Can't find special event %s", event_ref_name.data()));
736 
737  auto nation_it = std::find_if(this->nations.begin(), this->nations.end(), [&](const auto& e) {
738  return e.ref_name.get_string() == nation_ref_name;
739  });
740  if(nation_it == this->nations.end())
741  CXX_THROW(std::runtime_error, translate_format("Can't find the first nation %s for firing special event %s", nation_ref_name.data(), event_ref_name.data()));
742 
743  auto other_nation_it = std::find_if(this->nations.begin(), this->nations.end(), [&](const auto& e) {
744  return e.ref_name.get_string() == other_nation_ref_name;
745  });
746  if(other_nation_it == this->nations.end())
747  CXX_THROW(std::runtime_error, translate_format("Can't find the second nation %s for firing special event %s", nation_ref_name.data(), event_ref_name.data()));
748 
749  bool discard = false;
750  LuaAPI::fire_event(this->lua.state, *nation_it, *event_it, discard, other_nation_ref_name);
751 }
752 
755 
756  profiler.start("AI");
757  AI::do_tick(*this);
758  profiler.stop("AI");
759 
760  profiler.start("Economy");
761  // Every ticks_per_month ticks do an economical tick
763  profiler.stop("Economy");
764 
765  profiler.start("E-packages");
766  if(g_server != nullptr) {
769  }
770  profiler.stop("E-packages");
771 
772  profiler.start("Research");
773  for(auto& nation : nations)
774  nation.research[nation.focus_tech_id] += nation.get_research_points();
775  profiler.stop("Research");
776 
777  profiler.start("Treaties");
778  // Do the treaties clauses
779  for(const auto& treaty : treaties) {
780  if(!treaty.in_effect()) continue;
781 
782  // Treaties clauses now will be enforced
783  Eng3D::Log::debug("game", string_format("Enforcing treaty %s", treaty.name));
784  for(auto& clause : treaty.clauses) {
785  assert(clause != nullptr);
786  if(clause->type == TreatyClauseType::PAYMENT) {
787  auto dyn_clause = static_cast<TreatyClause::Payment*>(clause);
788  if(!dyn_clause->in_effect()) continue;
789  dyn_clause->enforce();
790  } else if(clause->type == TreatyClauseType::ANNEX_PROVINCES) {
791  auto dyn_clause = static_cast<TreatyClause::AnnexProvince*>(clause);
792  if(!dyn_clause->in_effect()) continue;
793  dyn_clause->enforce();
794  } else if(clause->type == TreatyClauseType::LIBERATE_NATION) {
795  auto dyn_clause = static_cast<TreatyClause::LiberateNation*>(clause);
796  if(!dyn_clause->in_effect()) continue;
797  dyn_clause->enforce();
798  } else if(clause->type == TreatyClauseType::HUMILIATE) {
799  auto dyn_clause = static_cast<TreatyClause::Humiliate*>(clause);
800  if(!dyn_clause->in_effect()) continue;
801  dyn_clause->enforce();
802  } else if(clause->type == TreatyClauseType::IMPOSE_POLICIES) {
803  auto dyn_clause = static_cast<TreatyClause::ImposePolicies*>(clause);
804  if(!dyn_clause->in_effect()) continue;
805  dyn_clause->enforce();
806  } else if(clause->type == TreatyClauseType::PUPPET) {
807  auto dyn_clause = static_cast<TreatyClause::Puppet*>(clause);
808  if(!dyn_clause->in_effect()) continue;
809  dyn_clause->enforce();
810  }
811  }
812 
813  auto& relation = this->get_relation(treaty.sender_id, treaty.receiver_id);
814  if(relation.has_war) {
815  // Once treaty is signed, puppets of the sender will stop
816  // war with the puppets of the receiver, and also stop war
817  // with each other depending on the clauses
818  relation.has_war = false;
819  }
820  }
821  profiler.stop("Treaties");
822 
823  profiler.start("Units");
824  // Evaluate units
825  this->unit_manager.units.for_each([this](Unit& unit) {
826  unit_do_tick(*this, unit);
827  });
828  this->unit_manager.units.for_each([this](Unit& unit) {
829  unit_do_battle_tick(*this, unit);
830  });
831  profiler.stop("Units");
832 
833  // Perform all battles of the active wars
834  profiler.start("Battles");
835  std::vector<UnitId> clear_units;
836  for(auto& province : provinces) {
837  if(province.battle.active) {
838  auto& units = this->unit_manager.units;
839  const auto attacker_unit_ids = province.battle.get_attacker_unit_ids();
840  const auto defender_unit_ids = province.battle.get_defender_unit_ids();
841 
842  // Assert that there are NO units on both teams
843  std::vector<UnitId> v;
844  std::set_intersection(attacker_unit_ids.begin(), attacker_unit_ids.end(), defender_unit_ids.begin(), defender_unit_ids.end(), std::back_inserter(v));
845  assert(v.empty());
846 
847  // Once one side has fallen; this battle has ended
848  if(defender_unit_ids.empty() || attacker_unit_ids.empty()) {
849  if(!attacker_unit_ids.empty() && defender_unit_ids.empty()) {
850  // Attackers win
851  this->nations[units[attacker_unit_ids[0]].owner_id].control_province(province);
852  } else if(attacker_unit_ids.empty() && !defender_unit_ids.empty()) {
853  // Defenders win
854  this->nations[units[defender_unit_ids[0]].owner_id].control_province(province);
855  }
856 
857  for(const auto unit_id : attacker_unit_ids) {
858  auto& unit = units[unit_id];
859  this->nations[unit.owner_id].prestige += unit.base / 10000.f; // Prestige reward
860  unit.on_battle = false;
861  }
862 
863  for(const auto unit_id : defender_unit_ids) {
864  auto& unit = units[unit_id];
865  this->nations[unit.owner_id].prestige += unit.base / 10000.f; // Prestige reward
866  unit.on_battle = false;
867  }
868  province.battle.active = false;
869  continue;
870  }
871 
872  for(auto attacker_id : attacker_unit_ids) {
873  auto& attacker = units[attacker_id];
874  for(auto defender_id : defender_unit_ids) {
875  auto& defender = units[defender_id];
876  province.battle.defender_casualties += attacker.attack(defender);
877  if(defender.size > 1.f)
878  province.battle.attacker_casualties += defender.attack(attacker);
879  }
880  }
881 
882  // Clear dead units
883  for(size_t i = 0; i < province.battle.unit_ids.size(); ) {
884  const auto unit_id = province.battle.unit_ids[i];
885  auto& unit = units[unit_id];
886  assert(unit_id == unit.get_id());
887  if(unit.size < 1.f) {
888  Eng3D::Log::debug("game", string_format("Removing unit id=%zu from province %s", (size_t)unit_id, province.name.c_str()));
889  assert(std::find(clear_units.begin(), clear_units.end(), unit_id) == clear_units.end());
890  clear_units.push_back(unit_id);
891  province.battle.unit_ids.erase(province.battle.unit_ids.begin() + i);
892  continue;
893  }
894  i++;
895  }
896  }
897  }
898  profiler.stop("Battles");
899 
900  profiler.start("Cleaning");
901  for(const auto unit_id : clear_units) {
902  const auto& unit = this->unit_manager.units[unit_id];
903  this->nations[unit.owner_id].prestige -= unit.base / 1000.f; // Prestige penalty for losing unit
904  this->unit_manager.remove_unit(unit_id);
905  }
906  profiler.stop("Cleaning");
907 
908  profiler.start("Revolts");
909  for(auto& province : provinces) {
910  if(Nation::is_invalid(province.owner_id)) continue;
911  auto& owner_nation = nations[province.owner_id];
912  const auto militancy = province.average_militancy();
913  if (0 && militancy > 0.5f) {
914  bool has_found_revolt_nation = false;
915  for(const auto nuclei_id : province.nuclei) {
916  auto& revolt_nation = nations[nuclei_id];
917  if(revolt_nation == owner_nation) continue;
918  if(revolt_nation.owned_provinces.empty()) {
919  revolt_nation.declare_war(owner_nation);
920  revolt_nation.control_province(province);
921  const auto& unit_ids = unit_manager.get_province_units(province);
922  for(const auto unit_id : unit_ids) {
923  auto& unit = unit_manager.units[unit_id];
924  if(unit.owner_id == province.controller_id)
925  unit.set_owner(revolt_nation);
926  }
927  has_found_revolt_nation = true;
928  break;
929  }
930  }
931 
932  if (!has_found_revolt_nation) {
933  for(auto& revolt_nation : nations) {
934  if(revolt_nation == owner_nation) continue;
935  if(revolt_nation.owned_provinces.empty()) {
936  revolt_nation.declare_war(owner_nation);
937  revolt_nation.control_province(province);
938  const auto& unit_ids = unit_manager.get_province_units(province);
939  for(const auto unit_id : unit_ids) {
940  auto& unit = unit_manager.units[unit_id];
941  if(unit.owner_id == province.controller_id)
942  unit.set_owner(revolt_nation);
943  }
944  has_found_revolt_nation = true;
945  break;
946  }
947  }
948  }
949  }
950  }
951  profiler.stop("Revolts");
952 
953  profiler.start("Emigration");
954  do_emigration(*this);
955  profiler.stop("Emigration");
956 
957  profiler.start("Events");
959  profiler.stop("Events");
960 
961  profiler.start("Send packets");
962  if(g_server != nullptr)
964  profiler.stop("Send packets");
965 
966  if(!(time % ticks_per_month))
967  Eng3D::Log::debug("game", Eng3D::translate_format("%i/%i/%i", time / 12 / ticks_per_month, (time / ticks_per_month % 12) + 1, (time % ticks_per_month) + 1));
968  Eng3D::Log::debug("game", Eng3D::translate_format("Tick %i done", time));
969  time++;
970 
971  if(g_server != nullptr) {
972  // Tell clients that this tick has been done
973  Eng3D::Networking::Packet packet{};
975  Eng3D::Deser::serialize<ActionType>(ar, ActionType::WORLD_TICK);
977  packet.data(ar.get_buffer(), ar.size());
978  g_server->broadcast(packet);
979  }
980 }
@ WORLD_TICK
Definition: action.hpp:34
std::vector< std::shared_ptr< Eng3D::IO::Asset::Base > > get_multiple(const Eng3D::IO::Path &path)
Obtains multiple assets iff they share a common path (useful for concating files that might clash,...
Definition: io.cpp:157
std::vector< std::string > get_paths(void) const
Obtain all the paths that are currently under the management of a package, that is return the absolut...
Definition: io.cpp:181
void broadcast(const Eng3D::Networking::Packet &packet)
This will broadcast the given packet to all clients currently on the server.
Definition: network.cpp:292
static State & get_instance()
Definition: state.cpp:514
Eng3D::IO::PackageManager package_man
Definition: state.hpp:122
static StringManager & get_instance()
Definition: string.cpp:53
Roughly a batallion, consisting of approximately 500 soldiers each.
Definition: unit.hpp:80
bool on_battle
Definition: unit.hpp:135
float size
Definition: unit.hpp:132
void set_owner(const Nation &nation)
Definition: unit.cpp:184
NationId owner_id
Definition: unit.hpp:128
void stop_movement()
Definition: unit.hpp:95
float base
Definition: unit.hpp:133
ProvinceId get_target_province_id() const
Definition: unit.hpp:121
float experience
Definition: unit.hpp:134
ProvinceId province_id() const
Definition: unit.cpp:83
bool has_target_province() const
Definition: unit.hpp:117
bool update_movement(UnitManager &unit_manager)
Definition: unit.cpp:99
Eng3D::Freelist< Unit > units
Definition: unit.hpp:173
void remove_unit(UnitId unit)
Definition: unit.cpp:138
std::vector< UnitId > get_province_units(ProvinceId province_id) const
Definition: unit.hpp:165
Definition: world.hpp:114
UnitManager unit_manager
Definition: world.hpp:145
void load_mod()
Definition: world.cpp:590
bool needs_to_sync
Used to signal the lua scripts of invalid operations (eg. adding a country midgame)
Definition: world.hpp:224
Nation::Relation & get_relation(NationId a, NationId b)
Definition: world.hpp:192
void load_initial()
Definition: world.cpp:419
Economy::EconomyState economy_state
Definition: world.hpp:147
void fire_special_event(const std::string_view event_ref_name, const std::string_view nation_ref_name, const std::string_view other_nation_ref_name)
Definition: world.cpp:730
void do_tick()
Definition: world.cpp:753
void init_lua()
Definition: world.cpp:79
void insert(T &ptr)
Definition: world.hpp:150
Eng3D::Profiler profiler
Definition: world.hpp:130
ProvinceManager province_manager
Definition: world.hpp:146
static World & get_instance()
Definition: world.hpp:121
int time
Definition: world.hpp:221
constexpr static unsigned int ticks_per_month
Definition: world.hpp:116
Eng3D::LuaVM lua
Definition: world.hpp:216
void do_emigration(World &world)
Definition: emigration.cpp:45
@ NAVY
Definition: indpobj.hpp:300
@ MILITARY
Definition: indpobj.hpp:299
@ STRATEGIC
Definition: indpobj.hpp:298
@ ECONOMIC
Definition: indpobj.hpp:302
@ SOCIAL
Definition: indpobj.hpp:301
@ POLITICS
Definition: indpobj.hpp:303
Definition: ai.cpp:49
void init(World &world)
Definition: ai.cpp:57
void do_tick(World &world)
Definition: ai.cpp:67
void do_tick(World &world, EconomyState &economy_state)
Definition: economy.cpp:290
void deserialize(Eng3D::Deser::Archive &ar, T &obj)
Definition: serializer.hpp:154
void serialize(Eng3D::Deser::Archive &ar, const T &obj)
Definition: serializer.hpp:144
std::string translate(const std::string_view str)
Definition: string.cpp:76
void error(const std::string_view category, const std::string_view msg)
Definition: log.cpp:68
void debug(const std::string_view category, const std::string_view msg)
Definition: log.cpp:58
std::string string_format(const std::string_view format, Args &&... args)
String formatter.
Definition: string.hpp:100
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
int province_add_unit(lua_State *L)
Definition: lua_api.cpp:544
int add_event(lua_State *L)
Definition: lua_api.cpp:682
int add_decision(lua_State *L)
Definition: lua_api.cpp:733
int get_religion_by_id(lua_State *L)
Definition: lua_api.cpp:915
int get_terrain_type(lua_State *L)
Definition: lua_api.cpp:141
int set_nation_relation(lua_State *L)
Definition: lua_api.cpp:405
int ui_call_builtin(lua_State *L)
Definition: lua_api.cpp:1072
int get_pop_type_by_id(lua_State *L)
Definition: lua_api.cpp:825
int add_province_pop(lua_State *L)
Definition: lua_api.cpp:635
int get_province_nuclei(lua_State *L)
Definition: lua_api.cpp:623
int add_province_owner(lua_State *L)
Definition: lua_api.cpp:675
int get_religion(lua_State *L)
Definition: lua_api.cpp:907
int get_terrain_type_by_id(lua_State *L)
Definition: lua_api.cpp:130
int update_province(lua_State *L)
Definition: lua_api.cpp:487
int add_req_technology_to_industry_type(lua_State *L)
Definition: lua_api.cpp:252
int get_good(lua_State *L)
Definition: lua_api.cpp:222
int add_event_receivers(lua_State *L)
Definition: lua_api.cpp:725
int add_good(lua_State *L)
Definition: lua_api.cpp:210
int get_province_by_id(lua_State *L)
Definition: lua_api.cpp:524
int get_technology(lua_State *L)
Definition: lua_api.cpp:166
int add_technology(lua_State *L)
Definition: lua_api.cpp:151
int add_req_good_unit_type(lua_State *L)
Definition: lua_api.cpp:955
int add_accepted_religion(lua_State *L)
Definition: lua_api.cpp:378
int set_nation_primary_language(lua_State *L)
Definition: lua_api.cpp:362
int add_pop_type(lua_State *L)
Definition: lua_api.cpp:745
int get_province_owner(lua_State *L)
Definition: lua_api.cpp:597
int get_province_neighbours(lua_State *L)
Definition: lua_api.cpp:611
int set_province_religion(lua_State *L)
Definition: lua_api.cpp:669
int add_input_to_industry_type(lua_State *L)
Definition: lua_api.cpp:229
int add_terrain_type(lua_State *L)
Definition: lua_api.cpp:114
int get_nation_relation(lua_State *L)
Definition: lua_api.cpp:395
int nation_declare_war_no_cb(lua_State *L)
Definition: lua_api.cpp:318
int add_nation_client_hint(lua_State *L)
Definition: lua_api.cpp:384
int add_req_tech_to_tech(lua_State *L)
Definition: lua_api.cpp:176
int add_output_to_industry_type(lua_State *L)
Definition: lua_api.cpp:237
int add_province_nucleus(lua_State *L)
Definition: lua_api.cpp:654
int add_unit_type(lua_State *L)
Definition: lua_api.cpp:923
int get_all_nations(lua_State *L)
Definition: lua_api.cpp:297
int switch_nation_soul(lua_State *L)
Definition: lua_api.cpp:309
int get_nation(lua_State *L)
Definition: lua_api.cpp:283
int add_accepted_language(lua_State *L)
Definition: lua_api.cpp:372
int update_province_building(lua_State *L)
Definition: lua_api.cpp:559
int get_provinces_with_nucleus_by_nation(lua_State *L)
Definition: lua_api.cpp:340
int get_event(lua_State *L)
Definition: lua_api.cpp:713
int get_province_controller(lua_State *L)
Definition: lua_api.cpp:604
int get_provinces_owned_by_nation(lua_State *L)
Definition: lua_api.cpp:327
int set_province_language(lua_State *L)
Definition: lua_api.cpp:663
int nation_declare_unjustified_war(lua_State *L)
Definition: lua_api.cpp:415
int add_building_type(lua_State *L)
Definition: lua_api.cpp:182
void fire_event(lua_State *L, Nation &nation, Event &event, bool &is_multi, const std::string_view extra)
Definition: lua_api.cpp:972
int get_pop_type(lua_State *L)
Definition: lua_api.cpp:793
int get_province(lua_State *L)
Definition: lua_api.cpp:504
int get_language(lua_State *L)
Definition: lua_api.cpp:871
int add_language(lua_State *L)
Definition: lua_api.cpp:855
int give_hard_province_to(lua_State *L)
Definition: lua_api.cpp:575
int get_building_type(lua_State *L)
Definition: lua_api.cpp:197
int get_language_by_id(lua_State *L)
Definition: lua_api.cpp:883
int add_nation(lua_State *L)
Definition: lua_api.cpp:259
int add_province(lua_State *L)
Definition: lua_api.cpp:423
int add_req_good_to_industry_type(lua_State *L)
Definition: lua_api.cpp:245
int get_unit_type(lua_State *L)
Definition: lua_api.cpp:941
int rename_province(lua_State *L)
Definition: lua_api.cpp:648
int give_province_to(lua_State *L)
Definition: lua_api.cpp:569
int update_event(lua_State *L)
Definition: lua_api.cpp:700
int get_nation_by_id(lua_State *L)
Definition: lua_api.cpp:290
int set_nation_capital(lua_State *L)
Definition: lua_api.cpp:366
void check_events(lua_State *L)
Definition: lua_api.cpp:1021
int add_religion(lua_State *L)
Definition: lua_api.cpp:894
void parallel_for(T range, F &&func)
Server * g_server
#define L
Definition: stb_vorbis.c:5131
static Eng3D::Networking::Packet form_packet(const std::vector< Nation > &list)
Definition: action.cpp:64
static Eng3D::Networking::Packet form_packet(const std::vector< Province > &list)
Definition: action.cpp:55
static Eng3D::Networking::Packet form_packet(const Eng3D::Freelist< Unit > &units)
Definition: action.cpp:117
Base class that serves as archiver, stores (in memory) the data required for serialization/deserializ...
Definition: serializer.hpp:64
void from_file(const ::std::string &path)
Definition: serializer.cpp:61
void for_each(const F &lambda) const
Definition: freelist.hpp:75
lua_State * state
Definition: luavm.hpp:49
void stop(const std::string &name)
Definition: profiler.cpp:95
void start(const std::string &name)
Definition: profiler.cpp:84
constexpr bool is_invalid() const
Checks if the current id is invalid.
Definition: entity.hpp:133
constexpr Id get_id() const
Definition: entity.hpp:152
bool has_landpass() const
Definition: nation.hpp:71
#define CXX_THROW(class,...)
Definition: utils.hpp:98
#define POLICY_CAPITALIST
World g_world
Definition: world.cpp:59