The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
core.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2010 - 2025
3 by Yurii Chernyi <terraninfo@terraninfo.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16/**
17 * @file
18 * Provides core classes for the Lua AI.
19 *
20 */
21
22#include <cstring>
23
24#include "ai/lua/core.hpp"
27#include "scripting/lua_common.hpp" // for new(L)
30#include "ai/lua/lua_object.hpp" // (Nephro)
31
32#include "log.hpp"
33#include "pathfind/pathfind.hpp"
34#include "play_controller.hpp"
35#include "resources.hpp"
36#include "terrain/filter.hpp"
37#include "units/unit.hpp"
38#include "ai/actions.hpp"
39#include "ai/lua/engine_lua.hpp"
42
43
44static lg::log_domain log_ai_engine_lua("ai/engine/lua");
45#define LOG_LUA LOG_STREAM(info, log_ai_engine_lua)
46#define WRN_LUA LOG_STREAM(warn, log_ai_engine_lua)
47#define ERR_LUA LOG_STREAM(err, log_ai_engine_lua)
48
49static char const aisKey[] = "ai contexts";
50static char const atkKey[] = "attack analysis";
51
52template<> struct lua_object_traits<ai::attack_analysis> {
53 inline static auto metatable = atkKey;
54 inline static ai::attack_analysis get(lua_State* L, int n) {
55 auto atk = static_cast<ai::attack_analysis*>(luaL_checkudata(L, n, atkKey));
56 return *atk;
57 }
58};
59
60namespace ai {
61
62static void push_attack_analysis(lua_State *L, const attack_analysis&);
63
64void lua_ai_context::init(lua_State *L)
65{
66 // Create the ai elements table.
67 lua_newtable(L);
68 lua_setfield(L, LUA_REGISTRYINDEX, aisKey);
69}
70
72{
73 int top = lua_gettop(L);
74
75 lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
76 lua_rawgeti(L, -1, num_);
77
78 lua_getfield(L, -1, "params");
79 luaW_toconfig(L, -1, cfg);
80
81 lua_settop(L, top);
82}
83
85{
86 int top = lua_gettop(L);
87
88 lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
89 lua_rawgeti(L, -1, num_);
90
92 lua_setfield(L, -2, "params");
93
94 lua_settop(L, top);
95}
96
98{
99 int top = lua_gettop(L);
100
101 lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
102 lua_rawgeti(L, -1, num_);
103
104 lua_getfield(L, -1, "data");
105 luaW_toconfig(L, -1, cfg);
106
107 lua_settop(L, top);
108}
109
111{
112 int top = lua_gettop(L);
113
114 lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
115 lua_rawgeti(L, -1, num_);
116
118 lua_setfield(L, -2, "data");
119
120 lua_settop(L, top);
121}
122
123static ai::engine_lua &get_engine(lua_State *L, int n)
124{
125 if(!lua_islightuserdata(L, n)) {
126 lua_pushstring(L, "AI engine pointer was invalid");
127 lua_error(L);
128 // lua_error never returns, so the below return will not execute.
129 }
130 return *(static_cast<ai::engine_lua*>(lua_touserdata(L, n)));
131}
132
133static ai::engine_lua &get_engine(lua_State *L)
134{
135 return get_engine(L, lua_upvalueindex(1));
136}
137
139{
141}
142
144{
145 lua_ai_load ctx(*this, false);
146}
147
149{
150 lua_newtable(L);
151 lua_pushboolean(L,action_result->is_ok());
152 lua_setfield(L, -2, "ok");
153 lua_pushboolean(L,action_result->is_gamestate_changed());
154 lua_setfield(L, -2, "gamestate_changed");
155 lua_pushinteger(L,action_result->get_status());
156 lua_setfield(L, -2, "status");
157 lua_pushstring(L, actions::get_error_name(action_result->get_status()).c_str());
158 lua_setfield(L, -2, "result");
159 return 1;
160}
161
162static int cfun_ai_get_suitable_keep(lua_State *L)
163{
164 int index = 1;
165
167 unit* leader = nullptr;
168 if (lua_isuserdata(L, index))
169 {
170 leader = luaW_tounit(L, index);
171 if (!leader) return luaL_argerror(L, 1, "unknown unit");
172 }
173 else return luaW_type_error(L, 1, "unit");
174 const map_location loc = leader->get_location();
175 const pathfind::paths leader_paths(*leader, false, true, context.current_team());
176 const map_location &res = context.suitable_keep(loc,leader_paths);
177 if (!res.valid()) {
178 return 0;
179 }
180 else {
181 lua_pushinteger(L, res.wml_x());
182 lua_pushinteger(L, res.wml_y());
183 return 2;
184 }
185}
186
187static int ai_move(lua_State *L, bool exec, bool remove_movement)
188{
189 int side = get_readonly_context(L).get_side();
190 map_location from = luaW_checklocation(L, 1);
192 bool unreach_is_ok = false;
193 if (lua_isboolean(L, 3)) {
194 unreach_is_ok = luaW_toboolean(L, 3);
195 }
196 ai::move_result_ptr move_result = ai::actions::execute_move_action(side,exec,from,to,remove_movement, unreach_is_ok);
198}
199
200static int cfun_ai_execute_move_full(lua_State *L)
201{
202 return ai_move(L, true, true);
203}
204
205static int cfun_ai_execute_move_partial(lua_State *L)
206{
207 return ai_move(L, true, false);
208}
209
210static int cfun_ai_check_move(lua_State *L)
211{
212 return ai_move(L, false, false);
213}
214
215static int ai_attack(lua_State *L, bool exec)
216{
218
219 int side = context.get_side();
220 map_location attacker = luaW_checklocation(L, 1);
221 map_location defender = luaW_checklocation(L, 2);
222
223 int attacker_weapon = -1;//-1 means 'select what is best'
224 double aggression = context.get_aggression();//use the aggression from the context
225
226 if (!lua_isnoneornil(L, 3)) {
227 attacker_weapon = lua_tointeger(L, 3);
228 if (attacker_weapon != -1) {
229 attacker_weapon--; // Done for consistency of the Lua style
230 }
231 }
232
233 // Note: Right now, aggression is used by the attack execution functions to determine the weapon to be used.
234 // If a decision is made to expand the function that determines the weapon, this block must be refactored
235 // to parse aggression if a single int is on the stack, or create a table of parameters, if a table is on the
236 // stack.
237 if (!lua_isnoneornil(L, 4) && lua_isnumber(L,4)) {
238 aggression = lua_tonumber(L, 4);
239 }
240
241 ai::attack_result_ptr attack_result = ai::actions::execute_attack_action(side,exec,attacker,defender,attacker_weapon,aggression);
243}
244
245static int cfun_ai_execute_attack(lua_State *L)
246{
247 return ai_attack(L, true);
248}
249
250static int cfun_ai_check_attack(lua_State *L)
251{
252 return ai_attack(L, false);
253}
254
255static int ai_stopunit_select(lua_State *L, bool exec, bool remove_movement, bool remove_attacks)
256{
257 int side = get_readonly_context(L).get_side();
259
260 ai::stopunit_result_ptr stopunit_result = ai::actions::execute_stopunit_action(side,exec,loc,remove_movement,remove_attacks);
262}
263
264static int cfun_ai_execute_stopunit_moves(lua_State *L)
265{
266 return ai_stopunit_select(L, true, true, false);
267}
268
269static int cfun_ai_execute_stopunit_attacks(lua_State *L)
270{
271 return ai_stopunit_select(L, true, false, true);
272}
273
274static int cfun_ai_execute_stopunit_all(lua_State *L)
275{
276 return ai_stopunit_select(L, true, true, true);
277}
278
279static int cfun_ai_check_stopunit(lua_State *L)
280{
281 return ai_stopunit_select(L, false, true, true);
282}
283
284static int ai_recruit(lua_State *L, bool exec)
285{
286 const char *unit_name = luaL_checkstring(L, 1);
287 int side = get_readonly_context(L).get_side();
288 map_location where;
289 luaW_tolocation(L, 2, where);
293}
294
295static int cfun_ai_execute_recruit(lua_State *L)
296{
297 return ai_recruit(L, true);
298}
299
300static int cfun_ai_check_recruit(lua_State *L)
301{
302 return ai_recruit(L, false);
303}
304
305static int ai_recall(lua_State *L, bool exec)
306{
307 const char *unit_id = luaL_checkstring(L, 1);
308 int side = get_readonly_context(L).get_side();
309 map_location where;
310 luaW_tolocation(L, 2, where);
312 ai::recall_result_ptr recall_result = ai::actions::execute_recall_action(side,exec,std::string(unit_id),where,from);
314}
315
316static int cfun_ai_execute_recall(lua_State *L)
317{
318 return ai_recall(L, true);
319}
320
321static int cfun_ai_check_recall(lua_State *L)
322{
323 return ai_recall(L, false);
324}
325
326static int cfun_ai_fallback_human(lua_State*)
327{
329}
330
331// Goals and targets
332
333static int cfun_ai_get_targets(lua_State *L)
334{
336 std::vector<target> targets = get_engine(L).get_ai_context()->find_targets(enemy_dst_src);
337 int i = 1;
338
339 lua_createtable(L, 0, 0);
340 for (std::vector<target>::iterator it = targets.begin(); it != targets.end(); ++it)
341 {
342 lua_pushinteger(L, i);
343
344 //to factor out
345 lua_createtable(L, 3, 0);
346
347 lua_pushstring(L, "type");
348 lua_pushstring(L, ai_target::get_string(it->type).c_str());
349 lua_rawset(L, -3);
350
351 lua_pushstring(L, "loc");
352 luaW_pushlocation(L, it->loc);
353 lua_rawset(L, -3);
354
355 lua_pushstring(L, "value");
356 lua_pushnumber(L, it->value);
357 lua_rawset(L, -3);
358
359 lua_rawset(L, -3);
360 ++i;
361 }
362 return 1;
363}
364
365// Aspect section
366static int cfun_ai_get_aggression(lua_State *L)
367{
368 double aggression = get_readonly_context(L).get_aggression();
369 lua_pushnumber(L, aggression);
370 return 1;
371}
372
373static int cfun_ai_get_attacks(lua_State *L)
374{
375 // Unlike the other aspect fetchers, this one is not deprecated!
376 // This is because ai.aspects.attacks returns the viable units but this returns a full attack analysis
378 lua_createtable(L, attacks.size(), 0);
379 int table_index = lua_gettop(L);
380
381 ai::attacks_vector::const_iterator it = attacks.begin();
382 for (int i = 1; it != attacks.end(); ++it, ++i)
383 {
384 push_attack_analysis(L, *it);
385
386 lua_rawseti(L, table_index, i);
387 }
388 return 1;
389}
390
391static int cfun_ai_get_avoid(lua_State *L)
392{
393 std::set<map_location> locs;
394 terrain_filter avoid = get_readonly_context(L).get_avoid();
395 avoid.get_locations(locs);
396 luaW_push_locationset(L, locs);
397
398 return 1;
399}
400
401static int cfun_ai_get_caution(lua_State *L)
402{
403 double caution = get_readonly_context(L).get_caution();
404 lua_pushnumber(L, caution);
405 return 1;
406}
407
408static int cfun_ai_get_grouping(lua_State *L)
409{
410 std::string grouping = get_readonly_context(L).get_grouping();
411 lua_pushstring(L, grouping.c_str());
412 return 1;
413}
414
415static int cfun_ai_get_leader_aggression(lua_State *L)
416{
417 double leader_aggression = get_readonly_context(L).get_leader_aggression();
418 lua_pushnumber(L, leader_aggression);
419 return 1;
420}
421
422static int cfun_ai_get_leader_goal(lua_State *L)
423{
426 return 1;
427}
428
429namespace
430{
431// TODO: name this something better
432void visit_helper(lua_State* L, const utils::variant<bool, std::vector<std::string>>& input)
433{
434 utils::visit(
435 [L](const auto& v) {
436 if constexpr(utils::decayed_is_same<bool, decltype(v)>) {
437 lua_pushboolean(L, v);
438 } else {
439 lua_createtable(L, v.size(), 0);
440 for(const std::string& str : v) {
441 lua_pushlstring(L, str.c_str(), str.size());
442 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
443 }
444 }
445 },
446 input);
447}
448} // namespace
449
450static int cfun_ai_get_leader_ignores_keep(lua_State *L)
451{
452 visit_helper(L, get_readonly_context(L).get_leader_ignores_keep());
453 return 1;
454}
455
456static int cfun_ai_get_leader_value(lua_State *L)
457{
458 double leader_value = get_readonly_context(L).get_leader_value();
459 lua_pushnumber(L, leader_value);
460 return 1;
461}
462
463static int cfun_ai_get_passive_leader(lua_State *L)
464{
465 visit_helper(L, get_readonly_context(L).get_passive_leader());
466 return 1;
467}
468
470{
471 visit_helper(L, get_readonly_context(L).get_passive_leader_shares_keep());
472 return 1;
473}
474
475static int cfun_ai_get_recruitment_pattern(lua_State *L)
476{
477 std::vector<std::string> recruiting = get_readonly_context(L).get_recruitment_pattern();
478 int size = recruiting.size();
479 lua_createtable(L, size, 0); // create an empty table with predefined size
480 for (int i = 0; i < size; ++i)
481 {
482 lua_pushinteger(L, i + 1); // Indexing in Lua starts from 1
483 lua_pushstring(L, recruiting[i].c_str());
484 lua_settable(L, -3);
485 }
486 return 1;
487}
488
490{
491 double scout_village_targeting = get_readonly_context(L).get_scout_village_targeting();
492 lua_pushnumber(L, scout_village_targeting);
493 return 1;
494}
495
496static int cfun_ai_get_simple_targeting(lua_State *L)
497{
498 bool simple_targeting = get_readonly_context(L).get_simple_targeting();
499 lua_pushboolean(L, simple_targeting);
500 return 1;
501}
502
503static int cfun_ai_get_support_villages(lua_State *L)
504{
505 bool support_villages = get_readonly_context(L).get_support_villages();
506 lua_pushboolean(L, support_villages);
507 return 1;
508}
509
510static int cfun_ai_get_village_value(lua_State *L)
511{
512 double village_value = get_readonly_context(L).get_village_value();
513 lua_pushnumber(L, village_value);
514 return 1;
515}
516
517static int cfun_ai_get_villages_per_scout(lua_State *L)
518{
519 int villages_per_scout = get_readonly_context(L).get_villages_per_scout();
520 lua_pushnumber(L, villages_per_scout);
521 return 1;
522}
523// End of aspect section
524
525static int impl_attack_rating(lua_State *L)
526{
527 // the attack_analysis userdata should be on top of the stack
528 const attack_analysis* aa_ptr = static_cast< attack_analysis * >(luaL_checkudata(L, -1, atkKey));
529 // the engine pointer is stored as the first uservalue
530 lua_getiuservalue(L, -1, 1);
531 auto& roc = get_engine(L, -1).get_readonly_context();
532
533 double aggression = roc.get_aggression();
534 double rating = aa_ptr->rating(aggression, roc);
535
536 lua_pushnumber(L, rating);
537 return 1;
538}
539
540static void push_movements(lua_State *L, const std::vector< std::pair < map_location, map_location > > & moves)
541{
542 lua_createtable(L, moves.size(), 0);
543
544 int table_index = lua_gettop(L);
545
546 std::vector< std::pair < map_location, map_location > >::const_iterator move = moves.begin();
547
548 for (int i = 1; move != moves.end(); ++move, ++i)
549 {
550 lua_createtable(L, 2, 0); // Creating a table for a pair of map_location's
551
552 lua_pushstring(L, "src");
553 luaW_pushlocation(L, move->first);
554 lua_rawset(L, -3);
555
556 lua_pushstring(L, "dst");
557 luaW_pushlocation(L, move->second);
558 lua_rawset(L, -3);
559
560 lua_rawseti(L, table_index, i); // setting the pair as an element of the movements table
561 }
562
563}
564
565static int impl_atkstat_destroy(lua_State* L)
566{
567 auto atk = static_cast<attack_analysis*>(luaL_checkudata(L, -1, atkKey));
568 atk->~attack_analysis();
569 return 0;
570}
571
572static int impl_atkstat_tostring(lua_State* L)
573{
574 // The attack analysis userdata should be at the top of the stack.
575 auto atk = static_cast<attack_analysis*>(luaL_checkudata(L, -1, atkKey));
576 luaW_getglobal(L, "string", "format");
577 lua_pushstring(L, "attack analysis @ (%d,%d)");
578 lua_pushinteger(L, atk->target.wml_x());
579 lua_pushinteger(L, atk->target.wml_y());
580 lua_call(L, 3, 1);
581 return 1;
582}
583
584#define ATTACK_GETTER(name, type) LATTR_GETTER(name, type, attack_analysis, atk)
585static luaW_Registry atkAnalysisReg{"attack analysis"};
586
587static int impl_atkstat_get(lua_State* L)
588{
589 return atkAnalysisReg.get(L);
590}
591
592static int impl_atkstat_dir(lua_State* L)
593{
594 return atkAnalysisReg.dir(L);
595}
596
597static void push_attack_analysis(lua_State *L, const attack_analysis& aa)
598{
599 new(L, 1) attack_analysis(aa);
600 if(luaL_newmetatable(L, atkKey)) {
601 static luaL_Reg const callbacks[] {
602 { "__gc", &impl_atkstat_destroy},
603 { "__tostring", &impl_atkstat_tostring},
604 { "__index", &impl_atkstat_get},
605 { "__dir", &impl_atkstat_dir},
606 { nullptr, nullptr }
607 };
608 luaL_setfuncs(L, callbacks, 0);
609 lua_pushstring(L, atkKey);
610 lua_setfield(L, -2, "__metatable");
611 }
612 lua_setmetatable(L, -2);
613 // Record the engine pointer for this attack analysis
614 lua_pushlightuserdata(L, &get_engine(L));
615 lua_setiuservalue(L, -2, 1);
616}
617
619 (void)atk;
620 lua_pushcfunction(L, &impl_attack_rating);
621 return lua_index_raw(L);
622}
623
625 (void)atk;
626 push_movements(L, atk.movements);
627 return lua_index_raw(L);
628}
629
631 return atk.target;
632}
633
634ATTACK_GETTER("target_value", double) {
635 return atk.target_value;
636}
637
638ATTACK_GETTER("avg_losses", double) {
639 return atk.avg_losses;
640}
641
642ATTACK_GETTER("chance_to_kill", double) {
643 return atk.chance_to_kill;
644}
645
646ATTACK_GETTER("avg_damage_inflicted", double) {
647 return atk.avg_damage_inflicted;
648}
649
650ATTACK_GETTER("target_starting_damage", int) {
651 return atk.target_starting_damage;
652}
653
654ATTACK_GETTER("avg_damage_taken", double) {
655 return atk.avg_damage_taken;
656}
657
658ATTACK_GETTER("resources_used", double) {
659 return atk.resources_used;
660}
661
662ATTACK_GETTER("terrain_quality", double) {
663 return atk.terrain_quality;
664}
665
666ATTACK_GETTER("alternative_terrain_quality", double) {
667 return atk.alternative_terrain_quality;
668}
669
670ATTACK_GETTER("vulnerability", double) {
671 return atk.vulnerability;
672}
673
674ATTACK_GETTER("support", double) {
675 return atk.support;
676}
677
678ATTACK_GETTER("leader_threat", bool) {
679 return atk.leader_threat;
680}
681
682ATTACK_GETTER("uses_leader", bool) {
683 return atk.uses_leader;
684}
685
686ATTACK_GETTER("is_surrounded", bool) {
687 return atk.is_surrounded;
688}
689
690static void push_move_map(lua_State *L, const move_map& m)
691{
692 lua_createtable(L, 0, 0); // the main table
693
694 if (m.empty())
695 {
696 return;
697 }
698
699 move_map::const_iterator it = m.begin();
700
701 int index = 1;
702
703 std::hash<map_location> lhash;
704
705 do
706 {
707 map_location key = it->first;
708 lua_pushinteger(L, lhash(key));
709
710 lua_createtable(L, 0, 0);
711
712 while (key == it->first) {
713
714 luaW_pushlocation(L, it->second);
715 lua_rawseti(L, -2, index);
716
717 ++index;
718 ++it;
719
720 }
721
722 lua_settable(L, -3);
723
724 index = 1;
725
726 } while (it != m.end());
727}
728
729static int cfun_ai_get_dstsrc(lua_State *L)
730{
733 push_move_map(L, dst_src);
734 return 1;
735}
736
737static int cfun_ai_get_srcdst(lua_State *L)
738{
741 push_move_map(L, src_dst);
742 return 1;
743}
744
745static int cfun_ai_get_enemy_dstsrc(lua_State *L)
746{
749 push_move_map(L, enemy_dst_src);
750 return 1;
751}
752
753static int cfun_ai_get_enemy_srcdst(lua_State *L)
754{
757 push_move_map(L, enemy_src_dst);
758 return 1;
759}
760
761static int cfun_ai_is_dst_src_valid(lua_State *L)
762{
764 lua_pushboolean(L, valid);
765 return 1;
766}
767
768static int cfun_ai_is_dst_src_enemy_valid(lua_State *L)
769{
771 lua_pushboolean(L, valid);
772 return 1;
773}
774
775static int cfun_ai_is_src_dst_valid(lua_State *L)
776{
778 lua_pushboolean(L, valid);
779 return 1;
780}
781
782static int cfun_ai_is_src_dst_enemy_valid(lua_State *L)
783{
785 lua_pushboolean(L, valid);
786 return 1;
787}
788
789static int cfun_ai_recalculate_move_maps(lua_State *L)
790{
792 return 0;
793}
794
796{
798 return 0;
799}
800
801template<typename T>
803{
804 return std::dynamic_pointer_cast<typesafe_aspect<T> >(p).get();
805}
806
807static int impl_ai_aspect_get(lua_State* L)
808{
810 aspect_map::const_iterator iter = aspects.find(luaL_checkstring(L, 2));
811 if(iter == aspects.end()) {
812 return 0;
813 }
814
815 // A few aspects require special delicate handling...
816 if(typesafe_aspect<attacks_vector>* aspect_as_attacks_vector = try_aspect_as<attacks_vector>(iter->second)) {
818 aspect_attacks_base* real_aspect = dynamic_cast<aspect_attacks_base*>(aspect_as_attacks_vector);
819 while(real_aspect == nullptr) {
820 // It's probably a composite aspect, so find the active facet
821 composite_aspect<attacks_vector>& composite = dynamic_cast<composite_aspect<attacks_vector>&>(*aspect_as_attacks_vector);
822 aspect_as_attacks_vector = &dynamic_cast<typesafe_aspect<attacks_vector>&>(composite.find_active());
823 real_aspect = dynamic_cast<aspect_attacks_base*>(aspect_as_attacks_vector);
824 }
825 int my_side = get_engine(L).get_readonly_context().get_side();
826 std::vector<unit_const_ptr> attackers, enemies;
827 for(unit_map::const_iterator u = resources::gameboard->units().begin(); u != resources::gameboard->units().end(); ++u) {
828 if(!u.valid()) {
829 continue;
830 }
831 if(u->side() == my_side && real_aspect->is_allowed_attacker(*u)) {
832 attackers.push_back(u.get_shared_ptr());
833 } else if(u->side() != my_side && real_aspect->is_allowed_enemy(*u)) {
834 enemies.push_back(u.get_shared_ptr());
835 }
836 }
837 lua_createtable(L, 0, 2);
838 lua_createtable(L, attackers.size(), 0);
839 for(std::size_t i = 0; i < attackers.size(); i++) {
840 luaW_pushunit(L, attackers[i]->underlying_id());
841 lua_rawseti(L, -2, i + 1);
842 }
843 lua_setfield(L, -2, "own");
844 lua_createtable(L, enemies.size(), 0);
845 for(std::size_t i = 0; i < enemies.size(); i++) {
846 luaW_pushunit(L, enemies[i]->underlying_id());
847 lua_rawseti(L, -2, i + 1);
848 }
849 lua_setfield(L, -2, "enemy");
850 } else if(typesafe_aspect<unit_advancements_aspect>* aspect_as_unit_advancements_aspects = try_aspect_as<unit_advancements_aspect>(iter->second)) {
851 const unit_advancements_aspect& val = aspect_as_unit_advancements_aspects->get();
852 int my_side = get_engine(L).get_readonly_context().get_side();
853 lua_newtable(L);
854 std::hash<map_location> lhash;
855 for (unit_map::const_iterator u = resources::gameboard->units().begin(); u != resources::gameboard->units().end(); ++u) {
856 if (!u.valid() || u->side() != my_side) {
857 continue;
858 }
859 lua_pushinteger(L, lhash(u->get_location()));
860 lua_push(L, val.get_advancements(u));
861 lua_settable(L, -3);
862 }
863 } else {
864 iter->second->get_lua(L);
865 }
866 return 1;
867}
868
869static int impl_ai_aspect_list(lua_State* L)
870{
872 std::vector<std::string> aspect_names;
873 std::transform(aspects.begin(), aspects.end(), std::back_inserter(aspect_names), std::mem_fn(&aspect_map::value_type::first));
874 lua_push(L, aspect_names);
875 return 1;
876}
877
878static int impl_ai_aspect_set(lua_State* L)
879{
880 lua_pushstring(L, "attempted to write to the ai.aspects table, which is read-only");
881 return lua_error(L);
882}
883
884static luaL_Reg const mutating_callbacks[] = {
885 { "attack", &cfun_ai_execute_attack },
886 { "move", &cfun_ai_execute_move_partial },
887 { "move_full", &cfun_ai_execute_move_full },
888 { "recall", &cfun_ai_execute_recall },
889 { "recruit", &cfun_ai_execute_recruit },
890 { "stopunit_all", &cfun_ai_execute_stopunit_all },
891 { "stopunit_attacks", &cfun_ai_execute_stopunit_attacks },
892 { "stopunit_moves", &cfun_ai_execute_stopunit_moves },
893 { "fallback_human", &cfun_ai_fallback_human},
894 { nullptr, nullptr }
895};
896
897static int impl_ai_get(lua_State* L)
898{
899 if(!lua_isstring(L,2)) {
900 return 0;
901 }
903 std::string m = lua_tostring(L,2);
904 if(m == "side") {
905 lua_pushinteger(L, engine.get_readonly_context().get_side());
906 return 1;
907 }
908 if(m == "aspects") {
909 lua_newtable(L); // [-1: Aspects table]
910 lua_newtable(L); // [-1: Aspects metatable -2: Aspects table]
911 lua_pushlightuserdata(L, &engine); // [-1: Engine -2: Aspects mt -3: Aspects table]
912 lua_pushcclosure(L, &impl_ai_aspect_get, 1); // [-1: Metafunction -2: Aspects mt -3: Aspects table]
913 lua_setfield(L, -2, "__index"); // [-1: Aspects metatable -2: Aspects table]
914 lua_pushcfunction(L, &impl_ai_aspect_set); // [-1: Metafunction -2: Aspects mt -3: Aspects table]
915 lua_setfield(L, -2, "__newindex"); // [-1: Aspects metatable -2: Aspects table]
916 lua_pushlightuserdata(L, &engine); // [-1: Engine -2: Aspects mt -3: Aspects table]
917 lua_pushcclosure(L, &impl_ai_aspect_list, 1); // [-1: Metafunction -2: Aspects mt -3: Aspects table]
918 lua_setfield(L, -2, "__dir"); // [-1: Aspects metatable -2: Aspects table]
919 lua_setmetatable(L, -2); // [-1: Aspects table]
920 return 1;
921 }
922 lua_pushstring(L, "read_only");
923 lua_rawget(L, 1);
924 bool read_only = luaW_toboolean(L, -1);
925 lua_pop(L, 1);
926 if(read_only) {
927 return 0;
928 }
929 for (const luaL_Reg* p = mutating_callbacks; p->name; ++p) {
930 if(m == p->name) {
931 lua_pushlightuserdata(L, &engine);
932 lua_pushcclosure(L, p->func, 1);
933 return 1;
934 }
935 }
936 return 0;
937}
938
939static int impl_ai_list(lua_State* L)
940{
941 auto callbacks = lua_check<std::vector<std::string>>(L, 2);
942 callbacks.push_back("side");
943 callbacks.push_back("aspects");
944 if(!luaW_table_get_def(L, 1, "read_only", false)) {
945 for(const luaL_Reg* c = mutating_callbacks; c->name; ++c) {
946 callbacks.push_back(c->name);
947 }
948 }
949 lua_push(L, callbacks);
950 return 1;
951}
952
954 //push data table here
955 lua_newtable(L); // [-1: ai table]
956 static luaL_Reg const callbacks[] = {
957 // Move maps
958 { "get_new_dst_src", &cfun_ai_get_dstsrc },
959 { "get_new_src_dst", &cfun_ai_get_srcdst },
960 { "get_new_enemy_dst_src", &cfun_ai_get_enemy_dstsrc },
961 { "get_new_enemy_src_dst", &cfun_ai_get_enemy_srcdst },
962 { "recalculate_move_maps", &cfun_ai_recalculate_move_maps },
963 { "recalculate_enemy_move_maps", &cfun_ai_recalculate_move_maps_enemy },
964 // Validation/cache functions
965 { "is_dst_src_valid", &cfun_ai_is_dst_src_valid },
966 { "is_enemy_dst_src_valid", &cfun_ai_is_dst_src_enemy_valid },
967 { "is_src_dst_valid", &cfun_ai_is_src_dst_valid },
968 { "is_enemy_src_dst_valid", &cfun_ai_is_src_dst_enemy_valid },
969 // End of move maps
970 // Goals and targets
971 { "get_targets", &cfun_ai_get_targets },
972 // Attack analysis
973 { "get_attacks", &cfun_ai_get_attacks },
974 // Deprecated aspects (don't add anything new here!)
975 { "get_aggression", &cfun_ai_get_aggression },
976 { "get_avoid", &cfun_ai_get_avoid },
977 { "get_caution", &cfun_ai_get_caution },
978 { "get_grouping", &cfun_ai_get_grouping },
979 { "get_leader_aggression", &cfun_ai_get_leader_aggression },
980 { "get_leader_goal", &cfun_ai_get_leader_goal },
981 { "get_leader_ignores_keep", &cfun_ai_get_leader_ignores_keep },
982 { "get_leader_value", &cfun_ai_get_leader_value },
983 { "get_passive_leader", &cfun_ai_get_passive_leader },
984 { "get_passive_leader_shares_keep", &cfun_ai_get_passive_leader_shares_keep },
985 { "get_recruitment_pattern", &cfun_ai_get_recruitment_pattern },
986 { "get_scout_village_targeting", &cfun_ai_get_scout_village_targeting },
987 { "get_simple_targeting", &cfun_ai_get_simple_targeting },
988 { "get_support_villages", &cfun_ai_get_support_villages },
989 { "get_village_value", &cfun_ai_get_village_value },
990 { "get_villages_per_scout", &cfun_ai_get_villages_per_scout },
991 // End of aspects
992 { "suitable_keep", &cfun_ai_get_suitable_keep },
993 { "check_recall", &cfun_ai_check_recall },
994 { "check_move", &cfun_ai_check_move },
995 { "check_stopunit", &cfun_ai_check_stopunit },
996 { "check_attack", &cfun_ai_check_attack },
997 { "check_recruit", &cfun_ai_check_recruit },
998 { nullptr, nullptr }
999 };
1000 for (const luaL_Reg* p = callbacks; p->name; ++p) {
1001 lua_pushlightuserdata(L, engine); // [-1: engine -2: ai table]
1002 lua_pushcclosure(L, p->func, 1); // [-1: function -2: ai table]
1003 lua_pushstring(L, p->name); // [-1: name -2: function -3: ai table]
1004 lua_pushvalue(L, -2); // [-1: function -2: name -3: function -4: ai table]
1005 lua_rawset(L, -4); // [-1: function -2: ai table]
1006 lua_pop(L, 1); // [-1: ai table]
1007 }
1008 lua_newtable(L); // [-1: metatable -2: ai table]
1009 lua_pushlightuserdata(L, engine); // [-1: engine -2: metatable -3: ai table]
1010 lua_pushcclosure(L, &impl_ai_get, 1); // [-1: metafunc -2: metatable -3: ai table]
1011 lua_setfield(L, -2, "__index"); // [-1: metatable -2: ai table]
1012 lua_pushcfunction(L, &impl_ai_list); // [-1: metafunc -2: metatable -3: ai table]
1013 lua_setfield(L, -2, "__dir"); // [-1: metatable -2: ai table]
1014 lua_setmetatable(L, -2); // [-1: ai table]
1015}
1016
1017static std::size_t generate_and_push_ai_state(lua_State* L, ai::engine_lua* engine)
1018{
1019 // Retrieve the ai elements table from the registry.
1020 lua_getfield(L, LUA_REGISTRYINDEX, aisKey); // [-1: AIs registry table]
1021 std::size_t length_ai = lua_rawlen(L, -1); // length of table
1022 lua_newtable(L); // [-1: AI state table -2: AIs registry table]
1023 generate_and_push_ai_table(L, engine); // [-1: AI routines -2: AI state -3: AIs registry]
1024 lua_setfield(L, -2, "ai"); // [-1: AI state -2: AIs registry]
1025 lua_pushvalue(L, -1); // [-1: AI state -2: AI state -3: AIs registry]
1026 lua_rawseti(L, -3, length_ai + 1); // [-1: AI state -2: AIs registry]
1027 lua_remove(L, -2); // [-1: AI state table]
1028 return length_ai + 1;
1029}
1030
1032{
1033 luaW_getglobal(L, "wesnoth", "wml_actions", "micro_ai");
1035 luaW_pcall(L, 1, 0);
1036}
1037
1039{
1040 int res_ai = luaL_loadbufferx(L, code, strlen(code), /*name*/ code, "t"); // [-1: AI code]
1041 if (res_ai != 0)
1042 {
1043
1044 char const *m = lua_tostring(L, -1);
1045 ERR_LUA << "error while initializing ai: " <<m;
1046 lua_pop(L, 2);//return with stack size 0 []
1047 return nullptr;
1048 }
1049 //push data table here
1050 std::size_t idx = generate_and_push_ai_state(L, engine); // [-1: AI state -2: AI code]
1051 lua_pushvalue(L, -2); // [-1: AI code -2: AI state -3: AI code]
1052 lua_setfield(L, -2, "update_self"); // [-1: AI state -2: AI code]
1053 lua_pushlightuserdata(L, engine);
1054 lua_setfield(L, -2, "engine"); // [-1: AI state -2: AI code]
1055 lua_pop(L, 2);
1056 return new lua_ai_context(L, idx, engine->get_readonly_context().get_side());
1057}
1058
1060{
1061 lua_ai_load ctx(*this, true); // [-1: AI state table]
1062
1063 // Load the AI code and arguments
1064 lua_getfield(L, -1, "update_self"); // [-1: AI code -2: AI state]
1065 lua_getfield(L, -2, "params"); // [-1: Arguments -2: AI code -3: AI state]
1066 lua_getfield(L, -3, "data"); // [-1: Persistent data -2: Arguments -3: AI code -4: AI state]
1067
1068 // Call the function
1069 if (!luaW_pcall(L, 2, 1, true)) { // [-1: Result -2: AI state]
1070 return; // return with stack size 0 []
1071 }
1072
1073 // Store the state for use by components
1074 lua_setfield(L, -2, "self"); // [-1: AI state]
1075
1076 // And return with empty stack.
1077 lua_pop(L, 1);
1078}
1079
1081{
1082 int res = luaL_loadbufferx(L, code, strlen(code), /*name*/ code, "t");//stack size is now 1 [ -1: f]
1083 if (res)
1084 {
1085 char const *m = lua_tostring(L, -1);
1086 ERR_LUA << "error while creating ai function: " <<m;
1087 lua_pop(L, 2);//return with stack size 0 []
1088 return nullptr;
1089 }
1090
1091 // Retrieve the ai elements table from the registry.
1092 lua_getfield(L, LUA_REGISTRYINDEX, aisKey); //stack size is now 2 [-1: ais_table -2: f]
1093 // Push the function in the table so that it is not collected.
1094 std::size_t length = lua_rawlen(L, -1);//length of ais_table
1095 lua_pushvalue(L, -2); //stack size is now 3: [-1: f -2: ais_table -3: f]
1096 lua_rawseti(L, -2, length + 1);// ais_table[length+1]=f. stack size is now 2 [-1: ais_table -2: f]
1097 lua_remove(L, -1);//stack size is now 1 [-1: f]
1098 lua_remove(L, -1);//stack size is now 0 []
1099 // Create the proxy C++ action handler.
1100 return new lua_ai_action_handler(L, context, length + 1);
1101}
1102
1103int lua_ai_load::refcount = 0;
1104
1105lua_ai_load::lua_ai_load(lua_ai_context& ctx, bool read_only) : L(ctx.L), was_readonly(false)
1106{
1107 refcount++;
1108 lua_getfield(L, LUA_REGISTRYINDEX, aisKey); // [-1: AI registry]
1109 lua_rawgeti(L, -1, ctx.num_); // [-1: AI state -2: AI registry]
1110 lua_remove(L,-2); // [-1: AI state]
1111
1112 // Check if the AI table is already loaded. If so, we have less work to do.
1113 lua_getglobal(L, "ai");
1114 if(!lua_isnoneornil(L, -1)) {
1115 // Save the previous read-only state
1116 lua_getfield(L, -1, "read_only");
1118 lua_pop(L, 1);
1119 // Update the read-only state
1120 lua_pushstring(L, "read_only");
1121 lua_pushboolean(L, read_only);
1122 lua_rawset(L, -3);
1123 lua_pop(L, 1); // Pop the ai table off the stack
1124 } else {
1125 lua_pop(L, 1); // Pop the nil value off the stack
1126 // Load the AI functions table into global scope
1127 lua_getfield(L, -1, "ai"); // [-1: AI functions -2: AI state]
1128 lua_pushstring(L, "read_only"); // [-1: key -2: AI functions -3: AI state]
1129 lua_pushboolean(L, read_only); // [-1: value -2: key -3: AI functions -4: AI state]
1130 lua_rawset(L, -3); // [-1: AI functions -2: AI state]
1131 lua_setglobal(L, "ai"); // [-1: AI state]
1132 }
1133}
1134
1136{
1137 refcount--;
1138 if (refcount == 0) {
1139 // Remove the AI functions from the global scope
1140 lua_pushnil(L);
1141 lua_setglobal(L, "ai");
1142 } else {
1143 // Restore the read-only state
1144 lua_getglobal(L, "ai");
1145 lua_pushstring(L, "read_only");
1146 lua_pushboolean(L, was_readonly);
1147 lua_rawset(L, -3);
1148 lua_pop(L, 1);
1149 }
1150}
1151
1153{
1154 // Remove the ai context from the registry, so that it can be collected.
1155 lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
1156 lua_pushnil(L);
1157 lua_rawseti(L, -2, num_);
1158 lua_pop(L, 1);
1159}
1160
1161void lua_ai_action_handler::handle(const config &cfg, const config &filter_own, bool read_only, const lua_object_ptr& l_obj)
1162{
1163 int initial_top = lua_gettop(L);//get the old stack size
1164
1165 // Load the context
1166 lua_ai_load ctx(context_, read_only); // [-1: AI state table]
1167
1168 // Load the user function from the registry.
1169 lua_getfield(L, LUA_REGISTRYINDEX, aisKey); // [-1: AI registry -2: AI state]
1170 lua_rawgeti(L, -1, num_); // [-1: AI action -2: AI registry -3: AI state]
1171 lua_remove(L, -2); // [-1: AI action -2: AI state]
1172
1173 // Load the arguments
1174 int iState = lua_absindex(L, -2);
1175 lua_getfield(L, iState, "self");
1177 lua_getfield(L, iState, "data");
1178
1179 int num = 3;
1180 if (!filter_own.empty()) {
1181 luaW_pushconfig(L, filter_own);
1182 num=4;
1183 }
1184
1185 // Call the function
1186 luaW_pcall(L, num, l_obj ? 1 : 0, true);
1187 if (l_obj) {
1188 l_obj->store(L, -1);
1189 }
1190
1191 lua_settop(L, initial_top);//empty stack
1192}
1193
1195{
1196 // Remove the function from the registry, so that it can be collected.
1197 lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
1198 lua_pushnil(L);
1199 lua_rawseti(L, -2, num_);
1200 lua_pop(L, 1);
1201}
1202
1203} // of namespace ai
map_location loc
Definition move.cpp:172
Managing the AI-Game interaction - AI actions and their results.
#define ERR_LUA
Aspect: attacks.
int get_status() const
Definition actions.cpp:148
bool is_gamestate_changed() const
Definition actions.cpp:119
static recall_result_ptr execute_recall_action(side_number side, bool execute, const std::string &unit_id, const map_location &where, const map_location &from)
Ask the game to recall a unit for us on specified location.
Definition actions.cpp:1054
static const std::string & get_error_name(int error_code)
get human-readable name of the error by code.
Definition actions.cpp:1097
static attack_result_ptr execute_attack_action(side_number side, bool execute, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon, double aggression)
Ask the game to attack an enemy defender using our unit attacker from attackers current location,...
Definition actions.cpp:1030
static move_result_ptr execute_move_action(side_number side, bool execute, const map_location &from, const map_location &to, bool remove_movement, bool unreach_is_ok=false)
Ask the game to move our unit from location 'from' to location 'to', optionally - doing a partial mov...
Definition actions.cpp:1042
static recruit_result_ptr execute_recruit_action(side_number side, bool execute, const std::string &unit_name, const map_location &where, const map_location &from)
Ask the game to recruit a unit for us on specified location.
Definition actions.cpp:1065
static stopunit_result_ptr execute_stopunit_action(side_number side, bool execute, const map_location &unit_location, bool remove_movement, bool remove_attacks)
Ask the game to remove unit movements and/or attack.
Definition actions.cpp:1076
double rating(double aggression, const readonly_context &ai_obj) const
Definition attack.cpp:268
aspect & find_active()
Definition aspect.hpp:303
virtual std::vector< target > find_targets(const move_map &enemy_dstsrc)=0
virtual ai_context_ptr get_ai_context()
Definition engine.cpp:124
readonly_context & get_readonly_context()
Definition engine.cpp:137
Proxy class for calling AI action handlers defined in Lua.
Definition core.hpp:71
lua_ai_context & context_
Definition core.hpp:74
static lua_ai_action_handler * create(lua_State *L, char const *code, lua_ai_context &context)
Definition core.cpp:1080
void handle(const config &cfg, const config &filter_own, bool read_only, const lua_object_ptr &l_obj)
Definition core.cpp:1161
Proxy table for the AI context.
Definition core.hpp:34
void set_persistent_data(const config &)
Definition core.cpp:110
void update_state()
Definition core.cpp:1059
void get_persistent_data(config &) const
Definition core.cpp:97
void push_ai_table()
Definition core.cpp:143
static void init(lua_State *L)
Definition core.cpp:64
static lua_ai_context * create(lua_State *L, char const *code, engine_lua *engine)
Definition core.cpp:1038
void set_arguments(const config &)
Definition core.cpp:84
void get_arguments(config &) const
Definition core.cpp:71
lua_State * L
Definition core.hpp:36
void apply_micro_ai(const config &cfg)
Definition core.cpp:1031
lua_ai_load(lua_ai_context &ctx, bool read_only)
Definition core.cpp:1105
bool was_readonly
Definition core.hpp:62
static int refcount
Definition core.hpp:60
lua_State * L
Definition core.hpp:59
virtual const team & current_team() const =0
virtual int get_villages_per_scout() const =0
virtual std::string get_grouping() const =0
virtual bool get_simple_targeting() const =0
virtual void recalculate_move_maps() const =0
virtual void set_dst_src_valid_lua()=0
virtual bool is_src_dst_enemy_valid_lua() const =0
virtual config get_leader_goal() const =0
virtual double get_aggression() const =0
virtual bool is_src_dst_valid_lua() const =0
virtual bool is_dst_src_enemy_valid_lua() const =0
virtual void set_src_dst_enemy_valid_lua()=0
virtual const aspect_map & get_aspects() const =0
virtual const std::vector< std::string > get_recruitment_pattern() const =0
virtual const attacks_vector & get_attacks() const =0
virtual void set_dst_src_enemy_valid_lua()=0
virtual const map_location & suitable_keep(const map_location &leader_location, const pathfind::paths &leader_paths) const =0
get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return near...
virtual double get_caution() const =0
virtual void recalculate_move_maps_enemy() const =0
virtual const move_map & get_enemy_srcdst() const =0
virtual bool is_dst_src_valid_lua() const =0
virtual const move_map & get_dstsrc() const =0
virtual double get_scout_village_targeting() const =0
virtual double get_leader_aggression() const =0
virtual bool get_support_villages() const =0
virtual const move_map & get_enemy_dstsrc() const =0
virtual void set_src_dst_valid_lua()=0
virtual const move_map & get_srcdst() const =0
virtual const terrain_filter & get_avoid() const =0
virtual double get_village_value() const =0
virtual double get_leader_value() const =0
virtual side_number get_side() const =0
Get the side number.
const std::vector< std::string > get_advancements(const unit_map::const_iterator &unit) const
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
bool empty() const
Definition config.cpp:823
virtual const unit_map & units() const override
This class represents a single unit of a specific type.
Definition unit.hpp:39
Composite AI contexts.
static lg::log_domain log_ai_engine_lua("ai/engine/lua")
static char const atkKey[]
Definition core.cpp:50
#define ATTACK_GETTER(name, type)
Definition core.cpp:584
static char const aisKey[]
Definition core.cpp:49
LUA AI Support engine - creating specific ai components from config.
const config * cfg
const map_location & get_location() const
The current map location this unit is at.
Definition unit.hpp:1327
Standard logging facilities (interface).
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
void luaW_pushlocation(lua_State *L, const map_location &ml)
Converts a map location object to a Lua table pushed at the top of the stack.
bool luaW_toboolean(lua_State *L, int n)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
int luaW_push_locationset(lua_State *L, const std::set< map_location > &locs)
Converts a set of map locations to a Lua table pushed at the top of the stack.
bool luaW_tolocation(lua_State *L, int index, map_location &loc)
Converts an optional table or pair of integers to a map location object.
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
bool luaW_getglobal(lua_State *L, const std::vector< std::string > &path)
Pushes the value found by following the variadic names (char *), if the value is not nil.
Lua object(value) wrapper implementation.
unit * luaW_tounit(lua_State *L, int index, bool only_on_map)
Converts a Lua value to a unit pointer.
Definition lua_unit.cpp:142
lua_unit * luaW_pushunit(lua_State *L, Args... args)
Definition lua_unit.hpp:116
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition actions.cpp:59
static int cfun_ai_is_src_dst_valid(lua_State *L)
Definition core.cpp:775
static int cfun_ai_get_leader_value(lua_State *L)
Definition core.cpp:456
static ai::readonly_context & get_readonly_context(lua_State *L)
Definition core.cpp:138
static int cfun_ai_get_simple_targeting(lua_State *L)
Definition core.cpp:496
static int cfun_ai_execute_stopunit_all(lua_State *L)
Definition core.cpp:274
std::vector< attack_analysis > attacks_vector
Definition game_info.hpp:52
std::shared_ptr< recruit_result > recruit_result_ptr
Definition game_info.hpp:84
static int ai_recruit(lua_State *L, bool exec)
Definition core.cpp:284
static int impl_ai_aspect_set(lua_State *L)
Definition core.cpp:878
static int cfun_ai_get_recruitment_pattern(lua_State *L)
Definition core.cpp:475
static int cfun_ai_get_villages_per_scout(lua_State *L)
Definition core.cpp:517
static int cfun_ai_execute_stopunit_moves(lua_State *L)
Definition core.cpp:264
static int impl_ai_list(lua_State *L)
Definition core.cpp:939
static int impl_attack_rating(lua_State *L)
Definition core.cpp:525
static int cfun_ai_get_targets(lua_State *L)
Definition core.cpp:333
static int ai_move(lua_State *L, bool exec, bool remove_movement)
Definition core.cpp:187
static void generate_and_push_ai_table(lua_State *L, ai::engine_lua *engine)
Definition core.cpp:953
static int cfun_ai_fallback_human(lua_State *)
Definition core.cpp:326
static int cfun_ai_recalculate_move_maps_enemy(lua_State *L)
Definition core.cpp:795
static int cfun_ai_get_enemy_srcdst(lua_State *L)
Definition core.cpp:753
static luaW_Registry atkAnalysisReg
Definition core.cpp:585
static int impl_atkstat_get(lua_State *L)
Definition core.cpp:587
static int cfun_ai_check_attack(lua_State *L)
Definition core.cpp:250
static int cfun_ai_is_dst_src_enemy_valid(lua_State *L)
Definition core.cpp:768
static int cfun_ai_is_dst_src_valid(lua_State *L)
Definition core.cpp:761
static ai::engine_lua & get_engine(lua_State *L, int n)
Definition core.cpp:123
std::shared_ptr< lua_object_base > lua_object_ptr
Definition core.hpp:28
std::shared_ptr< aspect > aspect_ptr
Definition game_info.hpp:97
static int cfun_ai_get_avoid(lua_State *L)
Definition core.cpp:391
std::shared_ptr< attack_result > attack_result_ptr
Definition game_info.hpp:82
static int cfun_ai_get_scout_village_targeting(lua_State *L)
Definition core.cpp:489
static int cfun_ai_check_stopunit(lua_State *L)
Definition core.cpp:279
static int cfun_ai_execute_attack(lua_State *L)
Definition core.cpp:245
static int cfun_ai_get_leader_goal(lua_State *L)
Definition core.cpp:422
static std::size_t generate_and_push_ai_state(lua_State *L, ai::engine_lua *engine)
Definition core.cpp:1017
static int impl_atkstat_tostring(lua_State *L)
Definition core.cpp:572
static void push_attack_analysis(lua_State *L, const attack_analysis &)
Definition core.cpp:597
std::shared_ptr< stopunit_result > stopunit_result_ptr
Definition game_info.hpp:87
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
Definition game_info.hpp:43
static int cfun_ai_execute_recall(lua_State *L)
Definition core.cpp:316
static int cfun_ai_check_move(lua_State *L)
Definition core.cpp:210
static int cfun_ai_execute_stopunit_attacks(lua_State *L)
Definition core.cpp:269
static int cfun_ai_get_caution(lua_State *L)
Definition core.cpp:401
static int cfun_ai_execute_recruit(lua_State *L)
Definition core.cpp:295
static int cfun_ai_execute_move_partial(lua_State *L)
Definition core.cpp:205
static int ai_recall(lua_State *L, bool exec)
Definition core.cpp:305
static int cfun_ai_get_enemy_dstsrc(lua_State *L)
Definition core.cpp:745
static int impl_atkstat_destroy(lua_State *L)
Definition core.cpp:565
static void push_move_map(lua_State *L, const move_map &m)
Definition core.cpp:690
static int impl_ai_aspect_list(lua_State *L)
Definition core.cpp:869
static int impl_ai_aspect_get(lua_State *L)
Definition core.cpp:807
static int cfun_ai_check_recruit(lua_State *L)
Definition core.cpp:300
static int transform_ai_action(lua_State *L, const ai::action_result_ptr &action_result)
Definition core.cpp:148
static int ai_attack(lua_State *L, bool exec)
Definition core.cpp:215
static int cfun_ai_get_leader_ignores_keep(lua_State *L)
Definition core.cpp:450
static int cfun_ai_get_leader_aggression(lua_State *L)
Definition core.cpp:415
static int cfun_ai_get_passive_leader_shares_keep(lua_State *L)
Definition core.cpp:469
static int cfun_ai_is_src_dst_enemy_valid(lua_State *L)
Definition core.cpp:782
static int cfun_ai_recalculate_move_maps(lua_State *L)
Definition core.cpp:789
static int impl_ai_get(lua_State *L)
Definition core.cpp:897
static int cfun_ai_get_passive_leader(lua_State *L)
Definition core.cpp:463
static int cfun_ai_get_dstsrc(lua_State *L)
Definition core.cpp:729
static int cfun_ai_get_suitable_keep(lua_State *L)
Definition core.cpp:162
static int cfun_ai_get_aggression(lua_State *L)
Definition core.cpp:366
static int cfun_ai_execute_move_full(lua_State *L)
Definition core.cpp:200
std::shared_ptr< move_result > move_result_ptr
Definition game_info.hpp:85
static int ai_stopunit_select(lua_State *L, bool exec, bool remove_movement, bool remove_attacks)
Definition core.cpp:255
static void push_movements(lua_State *L, const std::vector< std::pair< map_location, map_location > > &moves)
Definition core.cpp:540
static int cfun_ai_get_attacks(lua_State *L)
Definition core.cpp:373
std::shared_ptr< action_result > action_result_ptr
Definition game_info.hpp:81
static int impl_atkstat_dir(lua_State *L)
Definition core.cpp:592
static int cfun_ai_check_recall(lua_State *L)
Definition core.cpp:321
static int cfun_ai_get_srcdst(lua_State *L)
Definition core.cpp:737
std::shared_ptr< recall_result > recall_result_ptr
Definition game_info.hpp:83
static int cfun_ai_get_grouping(lua_State *L)
Definition core.cpp:408
std::map< std::string, aspect_ptr > aspect_map
typesafe_aspect< T > * try_aspect_as(const aspect_ptr &p)
Definition core.cpp:802
static int cfun_ai_get_support_villages(lua_State *L)
Definition core.cpp:503
static int cfun_ai_get_village_value(lua_State *L)
Definition core.cpp:510
static luaL_Reg const mutating_callbacks[]
Definition core.cpp:884
game_board * gameboard
Definition resources.cpp:20
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
Definition general.hpp:32
This module contains various pathfinding functions and utilities.
std::decay_t< T > luaW_table_get_def(lua_State *L, int index, std::string_view k, const T &def)
returns t[k] where k is the table at index index and k is k or def if it is not convertible to the co...
void lua_push(lua_State *L, const T &val)
static config unit_name(const unit *u)
Definition reports.cpp:163
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
int get(lua_State *L)
Implement __index metamethod.
static ai::attack_analysis get(lua_State *L, int n)
Definition core.cpp:54
Encapsulates the map of the game.
Definition location.hpp:46
bool valid() const
Definition location.hpp:111
int wml_y() const
Definition location.hpp:187
int wml_x() const
Definition location.hpp:186
static const map_location & null_location()
Definition location.hpp:103
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition pathfind.hpp:73
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition enum_base.hpp:46
mock_party p
static map_location::direction n
#define i
#define c