33 #include "eng3d/utils.hpp"
34 #include "eng3d/log.hpp"
43 int LuaAPI::register_new_table(lua_State*
L,
const std::string& name,
const std::vector<luaL_Reg> meta,
const std::vector<luaL_Reg> methods) {
44 if(luaL_newmetatable(
L, name.c_str())) {
48 for(
const auto& reg : methods)
49 lua_register(
L, reg.name, reg.func);
50 lua_setfield(
L, -2,
"__index");
53 for(
const auto& reg : meta)
54 lua_register(
L, reg.name, reg.func);
56 lua_pushstring(
L, name.c_str());
57 lua_setfield(
L, -2,
"__metatable");
59 lua_setglobal(
L, name.c_str());
69 static const T& find_or_throw(
const std::string_view ref_name) {
71 const auto result = std::find_if(list.begin(), list.end(), [ref_name](
const auto& o) {
72 return !strcmp(o.ref_name.c_str(), ref_name.data());
75 if(result == list.end())
81 lua_pushnumber(
L, (*index)++);
82 lua_pushnumber(
L, number);
91 lua_pushnumber(
L, (*index)++);
92 lua_pushstring(
L, text.c_str());
100 static float pop_number(lua_State*
L) {
101 const float amount = lua_tonumber(
L, -1);
106 static std::string pop_string(lua_State*
L) {
107 const std::string& text = luaL_checkstring(
L, -1);
109 luaL_error(
L,
"Expected a text but got empty string");
116 luaL_error(
L,
"MP-Sync in this function is not supported");
119 terrain_type.
ref_name = luaL_checkstring(
L, 1);
120 terrain_type.name = luaL_checkstring(
L, 2);
121 terrain_type.color = std::byteswap<std::uint32_t>(
static_cast<int>(lua_tonumber(
L, 3))) >> 8;
122 terrain_type.color |= 0xff000000;
123 terrain_type.penalty = lua_tonumber(
L, 4);
124 terrain_type.is_water_body = lua_toboolean(
L, 5);
126 lua_pushnumber(
L,
g_world.terrain_types.size() - 1);
131 const auto& terrain_type =
g_world.terrain_types.at(lua_tonumber(
L, 1));
133 lua_pushstring(
L, terrain_type.ref_name.c_str());
134 lua_pushstring(
L, terrain_type.name.c_str());
135 lua_pushnumber(
L, std::byteswap<std::uint32_t>((terrain_type.color & 0x00ffffff) << 8));
136 lua_pushnumber(
L, terrain_type.penalty);
137 lua_pushboolean(
L, terrain_type.is_water_body);
142 const auto& terrain_type = find_or_throw<TerrainType>(luaL_checkstring(
L, 1));
144 lua_pushstring(
L, terrain_type.name.c_str());
145 lua_pushnumber(
L, std::byteswap<std::uint32_t>((terrain_type.color & 0x00ffffff) << 8));
146 lua_pushnumber(
L, terrain_type.penalty);
147 lua_pushboolean(
L, terrain_type.is_water_body);
153 luaL_error(
L,
"MP-Sync in this function is not supported");
156 technology.
ref_name = luaL_checkstring(
L, 1);
157 technology.name = luaL_checkstring(
L, 2);
158 technology.description = lua_tostring(
L, 3);
159 technology.cost = (lua_tonumber(
L, 4));
162 lua_pushnumber(
L,
g_world.technologies.size() - 1);
167 const auto& technology = find_or_throw<Technology>(luaL_checkstring(
L, 1));
169 lua_pushstring(
L, technology.name.c_str());
170 lua_pushstring(
L, technology.description.c_str());
171 lua_pushnumber(
L, technology.cost);
172 lua_pushnumber(
L, technology.type);
184 luaL_error(
L,
"MP-Sync in this function is not supported");
187 building_type.
ref_name = luaL_checkstring(
L, 1);
188 building_type.name = luaL_checkstring(
L, 2);
189 building_type.can_plot_on_sea(lua_toboolean(
L, 3));
190 building_type.can_build_land_units(lua_toboolean(
L, 4));
191 building_type.can_build_naval_units(lua_toboolean(
L, 5));
193 lua_pushnumber(
L,
g_world.building_types.size() - 1);
198 const auto& building_type = find_or_throw<BuildingType>(luaL_checkstring(
L, 1));
200 lua_pushnumber(
L, (
size_t)building_type.get_id());
201 lua_pushstring(
L, building_type.ref_name.c_str());
202 lua_pushstring(
L, building_type.name.c_str());
203 lua_pushboolean(
L, building_type.can_plot_on_sea());
204 lua_pushboolean(
L, building_type.can_build_land_units());
205 lua_pushboolean(
L, building_type.can_build_naval_units());
206 lua_pushnumber(
L, 0.f);
212 luaL_error(
L,
"MP-Sync in this function is not supported");
215 commodity.
ref_name = luaL_checkstring(
L, 1);
216 commodity.name = luaL_checkstring(
L, 2);
218 lua_pushnumber(
L,
g_world.commodities.size() - 1);
223 const auto& commodity = find_or_throw<Commodity>(luaL_checkstring(
L, 1));
225 lua_pushstring(
L, commodity.name.c_str());
230 auto& industry_type =
g_world.building_types.at(lua_tonumber(
L, 1));
231 auto& commodity =
g_world.commodities.at(lua_tonumber(
L, 2));
232 industry_type.input_ids.push_back(commodity);
233 industry_type.num_req_workers += 100;
238 auto& industry_type =
g_world.building_types.at(lua_tonumber(
L, 1));
239 auto& commodity =
g_world.commodities.at(lua_tonumber(
L, 2));
240 industry_type.output_id = commodity;
241 industry_type.num_req_workers += 100;
246 auto& industry_type =
g_world.building_types.at(lua_tonumber(
L, 1));
247 auto& commodity =
g_world.commodities.at(lua_tonumber(
L, 2));
248 industry_type.req_goods.emplace_back(commodity, lua_tonumber(
L, 3));
253 auto& industry_type =
g_world.building_types.at(lua_tonumber(
L, 1));
254 auto& technology =
g_world.technologies.at(lua_tonumber(
L, 2));
255 industry_type.req_technologies.push_back(technology);
261 luaL_error(
L,
"MP-Sync in this function is not supported");
264 nation.
ref_name = luaL_checkstring(
L, 1);
265 nation.name = luaL_checkstring(
L, 2);
267 nation.commodity_production.resize(
g_world.commodities.size(), 1.f);
268 nation.religion_discrim.resize(
g_world.religions.size(), 0.f);
269 nation.language_acceptance.resize(
g_world.languages.size(), 0.f);
270 nation.client_hints.resize(
g_world.ideologies.size());
271 nation.research.resize(
g_world.technologies.size());
274 for(
const auto& other_nation :
g_world.nations) {
275 if(nation.ref_name == other_nation.ref_name)
276 luaL_error(
L,
string_format(
"Duplicate ref_name %s", nation.ref_name.c_str()).c_str());
279 lua_pushnumber(
L,
g_world.nations.size() - 1);
284 const auto& nation = find_or_throw<Nation>(luaL_checkstring(
L, 1));
286 lua_pushstring(
L, nation.name.c_str());
291 const auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
292 lua_pushstring(
L, nation.name.c_str());
293 lua_pushstring(
L, nation.ref_name.c_str());
301 for(
const auto& nation :
g_world.nations) {
302 lua_pushnumber(
L, nation);
303 lua_rawseti(
L, -2, i + 1);
310 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
311 auto& target =
g_world.nations.at(lua_tonumber(
L, 2));
312 if(&nation == &target)
313 luaL_error(
L,
string_format(
"%s can't switch to itself", nation.ref_name.c_str()).c_str());
319 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
320 auto& other_nation =
g_world.nations.at(lua_tonumber(
L, 2));
321 if(&nation == &other_nation)
322 luaL_error(
L,
string_format(
"%s can't declare war on itself", nation.ref_name.c_str()).c_str());
323 nation.declare_war(other_nation);
328 const auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
332 for(
const auto province_id : nation.owned_provinces) {
333 lua_pushnumber(
L, (
size_t)province_id);
334 lua_rawseti(
L, -2, i + 1);
341 const auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
345 for(
const auto& province :
g_world.provinces) {
346 bool is_nuclei =
false;
347 for(
const auto& nucleus_id : province.nuclei) {
348 auto& nucleus =
g_world.nations[nucleus_id];
349 if(&nucleus == &nation) {
354 if(!is_nuclei)
continue;
356 lua_rawseti(
L, -2, i + 1);
367 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
368 nation.capital_id =
ProvinceId(lua_tonumber(
L, 2));
373 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
374 nation.language_acceptance.at(lua_tonumber(
L, 2)) = 1.f;
379 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
380 nation.religion_discrim.at(lua_tonumber(
L, 2)) = 1.f;
385 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
388 hint.name = luaL_checkstring(
L, 3);
389 hint.color = std::byteswap<std::uint32_t>(
static_cast<int>(lua_tonumber(
L, 4))) >> 8;
390 hint.color |= 0xff000000;
391 nation.client_hints[hint.ideology_id] = hint;
396 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
397 auto& other_nation =
g_world.nations.at(lua_tonumber(
L, 2));
399 lua_pushnumber(
L, relation.alliance);
400 lua_pushnumber(
L, relation.relation);
401 lua_pushboolean(
L, relation.has_war);
406 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
407 auto& other_nation =
g_world.nations.at(lua_tonumber(
L, 2));
410 relation.relation = lua_tonumber(
L, 4);
411 relation.has_war = lua_toboolean(
L, 5);
416 auto& nation =
g_world.nations.at(lua_tonumber(
L, 1));
417 auto& other_nation =
g_world.nations.at(lua_tonumber(
L, 2));
419 nation.declare_war(other_nation);
425 luaL_error(
L,
"MP-Sync in this function is not supported");
428 province.
ref_name = luaL_checkstring(
L, 1);
429 province.color = (std::byteswap<std::uint32_t>(
static_cast<int>(lua_tonumber(
L, 2))) >> 8) | 0xff000000;
430 province.name = luaL_checkstring(
L, 3);
434 province.rgo_size.resize(
g_world.commodities.size(), 0);
435 luaL_checktype(
L, 5, LUA_TTABLE);
436 size_t n_rgo_size = lua_rawlen(
L, 5);
437 for(
size_t i = 1; i <= n_rgo_size; i++) {
438 lua_rawgeti(
L, 5, i);
439 if(!lua_istable(
L, -1))
440 luaL_error(
L,
"RGO size is a multidimensional table, \'rgo_size={\"wheat\",1}\' is not valid, do \'rgo_size={{\"wheat\",1}}\' instead");
443 lua_rawgeti(
L, -1, 1);
444 const Commodity& commodity = find_or_throw<Commodity>(luaL_checkstring(
L, -1));
447 lua_rawgeti(
L, -1, 2);
448 const uint32_t amount = (uint32_t)lua_tonumber(
L, -1);
451 province.rgo_size[commodity] = amount;
457 for(
size_t i = 0; i <
g_world.provinces.size(); i++) {
458 if(province.color ==
g_world.provinces[i].color) {
459 luaL_error(
L,
string_format(
"%s province has same color as %s", province.ref_name.c_str(),
g_world.provinces[i].ref_name.c_str()).c_str());
460 }
else if(province.ref_name ==
g_world.provinces[i].ref_name) {
461 luaL_error(
L,
string_format(
"Duplicate ref_name %s", province.ref_name.c_str()).c_str());
466 province.languages.resize(
g_world.languages.size(), 0.f);
467 province.religions.resize(
g_world.religions.size(), 0.f);
468 province.buildings.resize(
g_world.building_types.size());
469 for(
auto& building : province.buildings)
470 building.estate_foreign.resize(
g_world.nations.size());
474 for(
auto& pop : province.pops) {
481 province.box_area =
Eng3D::Rect(0, 0, std::numeric_limits<uint32_t>::max(), std::numeric_limits<uint32_t>::max());
483 lua_pushnumber(
L,
g_world.provinces.size() - 1);
488 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
489 province.ref_name = luaL_checkstring(
L, 2);
490 province.color = (std::byteswap<std::uint32_t>(
static_cast<int>(lua_tonumber(
L, 3))) >> 8) | 0xff000000;
491 province.name = luaL_checkstring(
L, 4);
494 for(
size_t i = 0; i <
g_world.provinces.size(); i++) {
495 if(province.color ==
g_world.provinces[i].color) {
496 luaL_error(
L,
string_format(
"%s province has same color as %s", province.ref_name.c_str(),
g_world.provinces[i].ref_name.c_str()).c_str());
497 }
else if(province.ref_name ==
g_world.provinces[i].ref_name) {
498 luaL_error(
L,
string_format(
"Duplicate ref_name %s", province.ref_name.c_str()).c_str());
505 const Province& province = find_or_throw<Province>(luaL_checkstring(
L, 1));
508 lua_pushnumber(
L, std::byteswap<std::uint32_t>((province.
color & 0x00ffffff) << 8));
512 for(
size_t i = 0; i < province.
rgo_size.size(); i++) {
514 lua_pushnumber(
L, index++);
525 const auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
526 lua_pushstring(
L, province.ref_name.c_str());
527 lua_pushstring(
L, province.name.c_str());
528 lua_pushnumber(
L, std::byteswap<std::uint32_t>((province.color & 0x00ffffff) << 8));
529 lua_pushnumber(
L, (
size_t)province.terrain_type_id);
532 for(
size_t i = 0; i < province.rgo_size.size(); i++) {
533 if(province.rgo_size[i] != 0) {
534 lua_pushnumber(
L, index++);
545 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
546 auto& unit_type =
g_world.unit_types.at(lua_tonumber(
L, 2));
547 const size_t size = lua_tonumber(
L, 3);
551 unit.type_id = unit_type;
552 unit.experience = 1.f;
554 unit.base = unit_type.max_health;
561 luaL_error(
L,
"MP-Sync in this function is not supported");
562 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
563 const auto& building_type =
g_world.building_types.at(lua_tonumber(
L, 2));
564 province.buildings[building_type].level = lua_tonumber(
L, 3);
565 province.buildings[building_type].budget += 1000.f;
570 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
571 g_world.nations.at(lua_tonumber(
L, 2)).give_province(province);
576 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
577 auto& nation =
g_world.nations.at(lua_tonumber(
L, 2));
579 for(
const auto unit_id : unit_ids) {
581 if(unit.owner_id == province.controller_id)
582 unit.set_owner(nation);
584 nation.control_province(province);
585 nation.give_province(province);
588 if(!
g_world.nations[province.controller_id].exists())
590 if(unit.owner_id == province.controller_id)
591 unit.set_owner(nation);
598 const auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
599 lua_pushstring(
L,
g_world.nations[province.controller_id].ref_name.c_str());
605 const auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
606 lua_pushnumber(
L, (
size_t)province.controller_id);
612 const auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
615 for(
const auto neighbour_id : province.neighbour_ids) {
616 lua_pushnumber(
L, (
size_t)neighbour_id);
617 lua_rawseti(
L, -2, i + 1);
624 const auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
627 for(
const auto& nucleus_id : province.nuclei) {
628 lua_pushnumber(
L, (
size_t)nucleus_id);
629 lua_rawseti(
L, -2, i + 1);
636 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
637 auto& pop = province.pops.at(lua_tonumber(
L, 2));
638 pop.size = lua_tonumber(
L, 3);
640 luaL_error(
L,
"Can't create pops with 0 size");
643 pop.literacy = lua_tonumber(
L, 4);
644 pop.budget = pop.size;
649 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
650 province.name = luaL_checkstring(
L, 2);
655 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
656 province.nuclei.emplace_back(
static_cast<size_t>(lua_tonumber(
L, 2)));
657 std::sort(province.nuclei.begin(), province.nuclei.end());
658 auto last = std::unique(province.nuclei.begin(), province.nuclei.end());
659 province.nuclei.erase(last, province.nuclei.end());
664 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
665 province.languages.at(lua_tonumber(
L, 2)) = lua_tonumber(
L, 3);
670 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
671 province.religions.at(lua_tonumber(
L, 2)) = lua_tonumber(
L, 3);
676 auto& province =
g_world.provinces.at(lua_tonumber(
L, 1));
677 auto& nation =
g_world.nations.at(lua_tonumber(
L, 2));
678 nation.give_province(province);
684 luaL_error(
L,
"MP-Sync in this function is not supported");
689 event.conditions_function = luaL_ref(
L, LUA_REGISTRYINDEX);
691 event.do_event_function = luaL_ref(
L, LUA_REGISTRYINDEX);
692 event.title = luaL_checkstring(
L, 4);
693 event.text = luaL_checkstring(
L, 5);
694 event.checked = lua_toboolean(
L, 6);
701 auto&
event =
g_world.events[lua_tonumber(
L, 1)];
702 event.ref_name = luaL_checkstring(
L, 2);
704 event.conditions_function = luaL_ref(
L, LUA_REGISTRYINDEX);
706 event.do_event_function = luaL_ref(
L, LUA_REGISTRYINDEX);
707 event.title = luaL_checkstring(
L, 5);
708 event.text = luaL_checkstring(
L, 6);
709 event.checked = lua_toboolean(
L, 7);
714 const auto&
event = find_or_throw<Event>(luaL_checkstring(
L, 1));
717 lua_pushinteger(
L, event.conditions_function);
718 lua_pushinteger(
L, event.do_event_function);
719 lua_pushstring(
L, event.title.c_str());
720 lua_pushstring(
L, event.text.c_str());
721 lua_pushboolean(
L, event.checked);
727 auto&
event =
g_world.events.at(lua_tonumber(
L, 1));
728 for(
size_t i = 0; i < lua_tonumber(
L, 2); i++)
729 event.receiver_ids.push_back((
size_t)lua_tonumber(
L, 3 + i));
736 decision.
ref_name = luaL_checkstring(
L, 2);
737 decision.
name = luaL_checkstring(
L, 3);
740 decision.
effects = luaL_checkstring(
L, 5);
741 event.decisions.push_back(decision);
747 luaL_error(
L,
"MP-Sync in this function is not supported");
750 pop_type.
ref_name = luaL_checkstring(
L, 1);
751 pop_type.name = luaL_checkstring(
L, 2);
752 pop_type.social_value = lua_tonumber(
L, 3);
754 pop_type.basic_needs_amount.resize(
g_world.commodities.size(), 0.f);
755 pop_type.luxury_needs_satisfaction.resize(
g_world.commodities.size(), 0.f);
756 pop_type.luxury_needs_deminishing_factor.resize(
g_world.commodities.size(), 0.f);
761 while(lua_next(
L, -2)) {
764 const auto& commodity = find_or_throw<Commodity>(pop_string(
L));
766 const float amount = pop_number(
L);
768 pop_type.basic_needs_amount[commodity] = amount;
774 while(lua_next(
L, -2)) {
777 const auto& commodity = find_or_throw<Commodity>(pop_string(
L));
779 const float satisfaction = pop_number(
L);
781 const float deminishing = pop_number(
L);
783 pop_type.luxury_needs_satisfaction[commodity] = satisfaction;
784 pop_type.luxury_needs_deminishing_factor[commodity] = deminishing;
789 lua_pushnumber(
L,
g_world.pop_types.size() - 1);
794 const auto& pop_type = find_or_throw<PopType>(luaL_checkstring(
L, 1));
796 lua_pushnumber(
L, (
size_t)pop_type.get_id());
797 lua_pushstring(
L, pop_type.name.c_str());
798 lua_pushnumber(
L, pop_type.social_value);
801 for(
size_t i = 0; i < pop_type.basic_needs_amount.size(); i++) {
802 if(pop_type.basic_needs_amount[i] != 0) {
803 lua_pushnumber(
L, index++);
812 for(
size_t i = 0; i < pop_type.luxury_needs_satisfaction.size(); i++) {
813 if(pop_type.luxury_needs_satisfaction[i] != 0) {
814 lua_pushnumber(
L, index++);
834 lua_pushnumber(
L, index++);
844 lua_pushnumber(
L, index++);
857 luaL_error(
L,
"MP-Sync in this function is not supported");
860 language.
ref_name = luaL_checkstring(
L, 1);
861 language.name = luaL_checkstring(
L, 2);
862 language.color = (std::byteswap<std::uint32_t>(
static_cast<int>(lua_tonumber(
L, 3))) >> 8) | 0xff000000;
863 language.adjective = luaL_checkstring(
L, 4);
864 language.noun = luaL_checkstring(
L, 5);
865 language.combo_form = luaL_checkstring(
L, 6);
867 lua_pushnumber(
L,
g_world.languages.size() - 1);
872 const auto& language = find_or_throw<Language>(luaL_checkstring(
L, 1));
875 lua_pushstring(
L, language.name.c_str());
876 lua_pushnumber(
L, std::byteswap<std::uint32_t>((language.color & 0x00ffffff) << 8));
877 lua_pushstring(
L, language.adjective.c_str());
878 lua_pushstring(
L, language.noun.c_str());
879 lua_pushstring(
L, language.combo_form.c_str());
884 const auto& language =
g_world.languages.at(lua_tonumber(
L, 1));
885 lua_pushstring(
L, language.ref_name.c_str());
886 lua_pushstring(
L, language.name.c_str());
887 lua_pushnumber(
L, std::byteswap<std::uint32_t>((language.color & 0x00ffffff) << 8));
888 lua_pushstring(
L, language.adjective.c_str());
889 lua_pushstring(
L, language.noun.c_str());
890 lua_pushstring(
L, language.combo_form.c_str());
896 luaL_error(
L,
"MP-Sync in this function is not supported");
899 religion.
ref_name = luaL_checkstring(
L, 1);
900 religion.name = luaL_checkstring(
L, 2);
901 religion.color = (std::byteswap<std::uint32_t>(
static_cast<int>(lua_tonumber(
L, 3))) >> 8) | 0xff000000;
903 lua_pushnumber(
L,
g_world.religions.size() - 1);
908 const auto& religion = find_or_throw<Religion>(luaL_checkstring(
L, 1));
910 lua_pushstring(
L, religion.name.c_str());
911 lua_pushnumber(
L, std::byteswap<std::uint32_t>((religion.color & 0x00ffffff) << 8));
916 const auto& religion =
g_world.religions.at(lua_tonumber(
L, 1));
917 lua_pushstring(
L, religion.ref_name.c_str());
918 lua_pushstring(
L, religion.name.c_str());
919 lua_pushnumber(
L, std::byteswap<std::uint32_t>((religion.color & 0x00ffffff) << 8));
925 luaL_error(
L,
"MP-Sync in this function is not supported");
928 unit_type.
ref_name = luaL_checkstring(
L, 1);
929 unit_type.name = luaL_checkstring(
L, 2);
930 unit_type.attack = (lua_tonumber(
L, 3));
931 unit_type.defense = (lua_tonumber(
L, 4));
932 unit_type.max_health = (lua_tonumber(
L, 5));
933 unit_type.is_ground = lua_toboolean(
L, 6);
934 unit_type.is_naval = lua_toboolean(
L, 7);
935 unit_type.speed = (lua_tonumber(
L, 8));
937 lua_pushnumber(
L,
g_world.unit_types.size() - 1);
942 const auto unit_type = find_or_throw<UnitType>(luaL_checkstring(
L, 1));
945 lua_pushstring(
L, unit_type.name.c_str());
946 lua_pushnumber(
L, unit_type.attack);
947 lua_pushnumber(
L, unit_type.defense);
948 lua_pushnumber(
L, unit_type.max_health);
949 lua_pushboolean(
L, unit_type.is_ground);
950 lua_pushboolean(
L, unit_type.is_naval);
951 lua_pushnumber(
L, unit_type.speed);
956 auto& unit_type =
g_world.unit_types.at(lua_tonumber(
L, 1));
957 auto& commodity =
g_world.commodities.at(lua_tonumber(
L, 2));
958 size_t amount = lua_tonumber(
L, 3);
959 unit_type.req_goods.emplace_back(commodity, amount);
963 static int traceback(lua_State*
L) {
964 lua_getglobal(
L,
"debug");
965 lua_getfield(
L, -1,
"traceback");
967 lua_pushinteger(
L, 1);
976 auto orig_event = event;
984 lua_pushstring(
L, extra.data());
990 goto restore_original;
992 is_multi = lua_toboolean(
L, -1);
997 auto local_event = event;
999 local_event.extra_data = std::string(extra);
1001 if(local_event.decisions.empty()) {
1005 for(
auto& descision : local_event.decisions) {
1006 descision.extra_data = local_event.extra_data;
1007 if(descision.do_decision_function == 0) {
1008 Eng3D::Log::error(
"event",
translate_format(
"(Lua event %s on descision %s has no function callback", orig_event.ref_name.c_str(), descision.ref_name.c_str()));
1009 goto restore_original;
1012 nation.
inbox.push_back(local_event);
1023 for(
auto& event :
g_world.events) {
1024 if(event.checked)
continue;
1025 bool is_multi =
true, has_fired =
false;
1026 for(
const auto nation_id : event.receiver_ids) {
1027 auto& nation =
g_world.nations[nation_id];
1028 if(nation.exists()) {
1029 lua_rawgeti(
L, LUA_REGISTRYINDEX, event.conditions_function);
1030 lua_pushstring(
L, nation.ref_name.c_str());
1031 lua_pcall(
L, 1, 1, 0);
1032 bool r = lua_toboolean(
L, -1);
1041 if(has_fired && !is_multi)
1042 event.checked =
true;
1048 const auto& nation =
g_world.nations[nation_id];
1050 lua_rawgeti(
L, LUA_REGISTRYINDEX, dec.do_decision_function);
1052 lua_pushstring(
L, nation.ref_name.c_str());
1053 if(!dec.extra_data.get_string().empty()) {
1054 lua_pushstring(
L, dec.extra_data.c_str());
1058 const std::string_view err_msg = lua_tostring(
L, -1);
1073 const std::string builtin_fn = luaL_checkstring(
L, 1);
1076 if(builtin_fn ==
"gs.ai_control.form_packet") {
1079 }
else if(builtin_fn ==
"gs.ai_do_cmd_troops.get") {
1080 if(gs.curr_nation ==
nullptr)
1082 lua_pushboolean(
L, gs.curr_nation->ai_do_cmd_troops);
1084 }
else if(builtin_fn ==
"gs.ai_do_cmd_troops.set") {
1085 if(gs.curr_nation ==
nullptr)
1087 gs.curr_nation->ai_do_cmd_troops = lua_toboolean(
L, 2);
1089 }
else if(builtin_fn ==
"gs.map.reload_shaders") {
1090 gs.map->reload_shaders();
1092 }
else if(builtin_fn ==
"gs.shader_opt.set") {
1093 auto options = gs.map->map_render->options.get_options();
1094 const std::string optname = luaL_checkstring(
L, 2);
1095 for(
const auto& option : options) {
1096 if(option.get_option() == optname) {
1097 bool is_used = lua_toboolean(
L, 3);
1098 Eng3D::Log::debug(
"lua_bind",
"Setting map_shader option " + optname +
" to " + (is_used ?
"TRUE" :
"FALSE"));
1099 if(optname ==
"NOISE") {
1100 gs.map->map_render->options.noise.used = is_used;
1101 }
else if(optname ==
"SDF") {
1102 gs.map->map_render->options.sdf.used = is_used;
1103 }
else if(optname ==
"LIGHTING") {
1104 gs.map->map_render->options.lighting.used = is_used;
1105 }
else if(optname ==
"CITY_LIGHTS") {
1106 gs.map->map_render->options.city_lights.used = is_used;
1107 }
else if(optname ==
"PARALLAX") {
1108 gs.map->map_render->options.parallax.used = is_used;
1109 }
else if(optname ==
"RIVERS") {
1110 gs.map->map_render->options.rivers.used = is_used;
1111 }
else if(optname ==
"WATER") {
1112 gs.map->map_render->options.water.used = is_used;
1113 }
else if(optname ==
"GRID") {
1114 gs.map->map_render->options.grid.used = is_used;
1115 }
else if(optname ==
"UNITS") {
1116 gs.map->map_render->options.units.used = is_used;
1117 }
else if(optname ==
"BUILDINGS") {
1118 gs.map->map_render->options.buildings.used = is_used;
1119 }
else if(optname ==
"TREES") {
1120 gs.map->map_render->options.trees.used = is_used;
1122 gs.map->reload_shaders();
1127 }
else if(builtin_fn ==
"gs.shader_opt.get") {
1128 auto options = gs.map->map_render->options.get_options();
1129 const std::string optname = luaL_checkstring(
L, 2);
1130 for(
const auto& option : options) {
1131 if(option.get_option() == optname) {
1132 bool is_used =
false;
1133 if(optname ==
"NOISE") {
1134 is_used = gs.map->map_render->options.noise.used;
1135 }
else if(optname ==
"SDF") {
1136 is_used = gs.map->map_render->options.sdf.used;
1137 }
else if(optname ==
"LIGHTING") {
1138 is_used = gs.map->map_render->options.lighting.used;
1139 }
else if(optname ==
"CITY_LIGHTS") {
1140 is_used = gs.map->map_render->options.city_lights.used;
1141 }
else if(optname ==
"PARALLAX") {
1142 is_used = gs.map->map_render->options.parallax.used;
1143 }
else if(optname ==
"RIVERS") {
1144 is_used = gs.map->map_render->options.rivers.used;
1145 }
else if(optname ==
"WATER") {
1146 is_used = gs.map->map_render->options.water.used;
1147 }
else if(optname ==
"GRID") {
1148 is_used = gs.map->map_render->options.grid.used;
1149 }
else if(optname ==
"UNITS") {
1150 is_used = gs.map->map_render->options.units.used;
1151 }
else if(optname ==
"BUILDINGS") {
1152 is_used = gs.map->map_render->options.buildings.used;
1153 }
else if(optname ==
"TREES") {
1154 is_used = gs.map->map_render->options.trees.used;
1156 Eng3D::Log::debug(
"lua_bind",
"Getting map_shader option " + optname +
" is " + (is_used ?
"TRUE" :
"FALSE"));
1157 lua_pushboolean(
L, is_used);
1162 }
else if(builtin_fn ==
"gs.motion_blur.set") {
1163 gs.motion_blur = lua_toboolean(
L, 2);
1165 }
else if(builtin_fn ==
"gs.motion_blur.get") {
1166 lua_pushboolean(
L, gs.motion_blur);
1168 }
else if(builtin_fn ==
"gs.music_volume.set") {
1169 gs.audio_man.music_volume = luaL_checknumber(
L, 2);
1171 }
else if(builtin_fn ==
"gs.sound_volume.set") {
1172 gs.audio_man.sound_volume = luaL_checknumber(
L, 2);
1174 }
else if(builtin_fn ==
"gs.music_volume.get") {
1175 lua_pushnumber(
L, gs.audio_man.music_volume);
1177 }
else if(builtin_fn ==
"gs.sound_volume.get") {
1178 lua_pushnumber(
L, gs.audio_man.sound_volume);
static State & get_instance()
std::deque< Event > inbox
A single province, which is used to simulate economy in a "bulk-tiles" way instead of doing economica...
std::vector< uint32_t > rgo_size
TerrainTypeId terrain_type_id
Roughly a batallion, consisting of approximately 500 soldiers each.
void set_owner(const Nation &nation)
void add_unit(Unit unit, ProvinceId unit_current_province)
Eng3D::Freelist< Unit > units
std::vector< UnitId > get_province_units(ProvinceId province_id) const
bool needs_to_sync
Used to signal the lua scripts of invalid operations (eg. adding a country midgame)
std::vector< std::pair< Decision, NationId > > taken_decisions
Nation::Relation & get_relation(NationId a, NationId b)
T::Id get_id(const T &obj) const
Get the id of an object, this is a template for all types except for tiles and locally-stored types (...
static World & get_instance()
void append_to_table(lua_State *L, int *index, float number)
void error(const std::string_view category, const std::string_view msg)
void debug(const std::string_view category, const std::string_view msg)
std::string string_format(const std::string_view format, Args &&... args)
String formatter.
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
int province_add_unit(lua_State *L)
int add_event(lua_State *L)
int add_decision(lua_State *L)
int get_religion_by_id(lua_State *L)
int get_terrain_type(lua_State *L)
int set_nation_relation(lua_State *L)
int ui_call_builtin(lua_State *L)
int get_pop_type_by_id(lua_State *L)
int add_province_pop(lua_State *L)
int get_province_nuclei(lua_State *L)
int add_province_owner(lua_State *L)
int get_religion(lua_State *L)
int get_terrain_type_by_id(lua_State *L)
int update_province(lua_State *L)
int add_req_technology_to_industry_type(lua_State *L)
int get_good(lua_State *L)
int add_event_receivers(lua_State *L)
int add_good(lua_State *L)
int get_province_by_id(lua_State *L)
int get_technology(lua_State *L)
int add_technology(lua_State *L)
int add_req_good_unit_type(lua_State *L)
int add_accepted_religion(lua_State *L)
int set_nation_primary_language(lua_State *L)
int add_pop_type(lua_State *L)
int get_province_owner(lua_State *L)
int get_province_neighbours(lua_State *L)
int set_province_religion(lua_State *L)
int add_input_to_industry_type(lua_State *L)
int add_terrain_type(lua_State *L)
int get_nation_relation(lua_State *L)
int nation_declare_war_no_cb(lua_State *L)
int add_nation_client_hint(lua_State *L)
int add_req_tech_to_tech(lua_State *L)
int add_output_to_industry_type(lua_State *L)
int add_province_nucleus(lua_State *L)
int add_unit_type(lua_State *L)
int get_all_nations(lua_State *L)
int switch_nation_soul(lua_State *L)
int get_nation(lua_State *L)
int add_accepted_language(lua_State *L)
int update_province_building(lua_State *L)
int get_provinces_with_nucleus_by_nation(lua_State *L)
int register_new_table(lua_State *L, const std::string &name, const std::vector< luaL_Reg > meta, const std::vector< luaL_Reg > methods)
int get_event(lua_State *L)
int get_province_controller(lua_State *L)
int get_provinces_owned_by_nation(lua_State *L)
int set_province_language(lua_State *L)
int nation_declare_unjustified_war(lua_State *L)
int add_building_type(lua_State *L)
void fire_event(lua_State *L, Nation &nation, Event &event, bool &is_multi, const std::string_view extra)
int get_pop_type(lua_State *L)
int get_province(lua_State *L)
int get_language(lua_State *L)
int add_language(lua_State *L)
int give_hard_province_to(lua_State *L)
int get_building_type(lua_State *L)
int get_language_by_id(lua_State *L)
int add_nation(lua_State *L)
int add_province(lua_State *L)
int add_req_good_to_industry_type(lua_State *L)
int get_unit_type(lua_State *L)
int rename_province(lua_State *L)
int give_province_to(lua_State *L)
int update_event(lua_State *L)
int get_nation_by_id(lua_State *L)
int set_nation_capital(lua_State *L)
void check_events(lua_State *L)
int add_religion(lua_State *L)
Type for military outposts.
A commodity, mostly serves as a "product type".
void for_each(const F &lambda) const
static int call_func(lua_State *L, int nargs, int nret)
const char * c_str() const
Id cached_id
Id used to speed up Id lookups on any context.
constexpr static Id invalid()
Returns an invalid id.
Hints for the client on how to display the nation.
std::vector< float > luxury_needs_satisfaction
std::vector< float > luxury_needs_deminishing_factor
std::vector< float > basic_needs_amount
A product (based off a Commodity) which can be bought by POPs, converted by factories and transported...
Eng3D::StringRef ref_name
std::vector< TechnologyId > req_technologies
Defines a type of unit, it can be a tank, garrison, infantry, etc this is moddable via a lua script a...
#define CXX_THROW(class,...)