The Battle for Wesnoth  1.19.27+dev
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"
25 #include "ai/composite/aspect.hpp"
27 #include "scripting/lua_common.hpp" // for new(L)
28 #include "scripting/lua_unit.hpp"
29 #include "scripting/push_check.hpp"
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 
44 static 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 
49 static char const aisKey[] = "ai contexts";
50 static char const atkKey[] = "attack analysis";
51 
52 template<> 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 
60 namespace ai {
61 
62 static void push_attack_analysis(lua_State *L, const attack_analysis&);
63 
64 void 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 
123 static 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 
133 static ai::engine_lua &get_engine(lua_State *L)
134 {
135  return get_engine(L, lua_upvalueindex(1));
136 }
137 
139 {
140  return get_engine(L).get_readonly_context();
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 
162 static 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 
187 static 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);
191  map_location to = luaW_checklocation(L, 2);
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 
200 static int cfun_ai_execute_move_full(lua_State *L)
201 {
202  return ai_move(L, true, true);
203 }
204 
205 static int cfun_ai_execute_move_partial(lua_State *L)
206 {
207  return ai_move(L, true, false);
208 }
209 
210 static int cfun_ai_check_move(lua_State *L)
211 {
212  return ai_move(L, false, false);
213 }
214 
215 static 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 
245 static int cfun_ai_execute_attack(lua_State *L)
246 {
247  return ai_attack(L, true);
248 }
249 
250 static int cfun_ai_check_attack(lua_State *L)
251 {
252  return ai_attack(L, false);
253 }
254 
255 static 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 
264 static int cfun_ai_execute_stopunit_moves(lua_State *L)
265 {
266  return ai_stopunit_select(L, true, true, false);
267 }
268 
269 static int cfun_ai_execute_stopunit_attacks(lua_State *L)
270 {
271  return ai_stopunit_select(L, true, false, true);
272 }
273 
274 static int cfun_ai_execute_stopunit_all(lua_State *L)
275 {
276  return ai_stopunit_select(L, true, true, true);
277 }
278 
279 static int cfun_ai_check_stopunit(lua_State *L)
280 {
281  return ai_stopunit_select(L, false, true, true);
282 }
283 
284 static 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 
295 static int cfun_ai_execute_recruit(lua_State *L)
296 {
297  return ai_recruit(L, true);
298 }
299 
300 static int cfun_ai_check_recruit(lua_State *L)
301 {
302  return ai_recruit(L, false);
303 }
304 
305 static 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 
316 static int cfun_ai_execute_recall(lua_State *L)
317 {
318  return ai_recall(L, true);
319 }
320 
321 static int cfun_ai_check_recall(lua_State *L)
322 {
323  return ai_recall(L, false);
324 }
325 
326 static int cfun_ai_fallback_human(lua_State*)
327 {
329 }
330 
331 // Goals and targets
332 
333 static int cfun_ai_get_targets(lua_State *L)
334 {
335  move_map enemy_dst_src = get_readonly_context(L).get_enemy_dstsrc();
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
366 static 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 
373 static 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 
391 static 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 
401 static 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 
408 static 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 
415 static 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 
422 static int cfun_ai_get_leader_goal(lua_State *L)
423 {
425  luaW_pushconfig(L, goal);
426  return 1;
427 }
428 
429 namespace
430 {
431 // TODO: name this something better
432 void 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 
450 static 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 
456 static 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 
463 static 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 
475 static 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 
489 static int cfun_ai_get_scout_village_targeting(lua_State *L)
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 
496 static 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 
503 static 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 
510 static 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 
517 static 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 
525 static 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 
540 static 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 
565 static 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 
572 static 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)
585 static luaW_Registry atkAnalysisReg{"attack analysis"};
586 
587 static int impl_atkstat_get(lua_State* L)
588 {
589  return atkAnalysisReg.get(L);
590 }
591 
592 static int impl_atkstat_dir(lua_State* L)
593 {
594  return atkAnalysisReg.dir(L);
595 }
596 
597 static 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 
634 ATTACK_GETTER("target_value", double) {
635  return atk.target_value;
636 }
637 
638 ATTACK_GETTER("avg_losses", double) {
639  return atk.avg_losses;
640 }
641 
642 ATTACK_GETTER("chance_to_kill", double) {
643  return atk.chance_to_kill;
644 }
645 
646 ATTACK_GETTER("avg_damage_inflicted", double) {
647  return atk.avg_damage_inflicted;
648 }
649 
650 ATTACK_GETTER("target_starting_damage", int) {
651  return atk.target_starting_damage;
652 }
653 
654 ATTACK_GETTER("avg_damage_taken", double) {
655  return atk.avg_damage_taken;
656 }
657 
658 ATTACK_GETTER("resources_used", double) {
659  return atk.resources_used;
660 }
661 
662 ATTACK_GETTER("terrain_quality", double) {
663  return atk.terrain_quality;
664 }
665 
666 ATTACK_GETTER("alternative_terrain_quality", double) {
667  return atk.alternative_terrain_quality;
668 }
669 
670 ATTACK_GETTER("vulnerability", double) {
671  return atk.vulnerability;
672 }
673 
674 ATTACK_GETTER("support", double) {
675  return atk.support;
676 }
677 
678 ATTACK_GETTER("leader_threat", bool) {
679  return atk.leader_threat;
680 }
681 
682 ATTACK_GETTER("uses_leader", bool) {
683  return atk.uses_leader;
684 }
685 
686 ATTACK_GETTER("is_surrounded", bool) {
687  return atk.is_surrounded;
688 }
689 
690 static 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 
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 
729 static int cfun_ai_get_dstsrc(lua_State *L)
730 {
733  push_move_map(L, dst_src);
734  return 1;
735 }
736 
737 static int cfun_ai_get_srcdst(lua_State *L)
738 {
741  push_move_map(L, src_dst);
742  return 1;
743 }
744 
745 static int cfun_ai_get_enemy_dstsrc(lua_State *L)
746 {
747  move_map enemy_dst_src = get_readonly_context(L).get_enemy_dstsrc();
749  push_move_map(L, enemy_dst_src);
750  return 1;
751 }
752 
753 static int cfun_ai_get_enemy_srcdst(lua_State *L)
754 {
755  move_map enemy_src_dst = get_readonly_context(L).get_enemy_srcdst();
757  push_move_map(L, enemy_src_dst);
758  return 1;
759 }
760 
761 static int cfun_ai_is_dst_src_valid(lua_State *L)
762 {
763  bool valid = get_readonly_context(L).is_dst_src_valid_lua();
764  lua_pushboolean(L, valid);
765  return 1;
766 }
767 
768 static int cfun_ai_is_dst_src_enemy_valid(lua_State *L)
769 {
771  lua_pushboolean(L, valid);
772  return 1;
773 }
774 
775 static int cfun_ai_is_src_dst_valid(lua_State *L)
776 {
777  bool valid = get_readonly_context(L).is_src_dst_valid_lua();
778  lua_pushboolean(L, valid);
779  return 1;
780 }
781 
782 static int cfun_ai_is_src_dst_enemy_valid(lua_State *L)
783 {
785  lua_pushboolean(L, valid);
786  return 1;
787 }
788 
789 static int cfun_ai_recalculate_move_maps(lua_State *L)
790 {
792  return 0;
793 }
794 
795 static int cfun_ai_recalculate_move_maps_enemy(lua_State *L)
796 {
798  return 0;
799 }
800 
801 template<typename T>
803 {
804  return std::dynamic_pointer_cast<typesafe_aspect<T> >(p).get();
805 }
806 
807 static int impl_ai_aspect_get(lua_State* L)
808 {
809  const aspect_map& aspects = get_engine(L).get_readonly_context().get_aspects();
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);
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 
869 static int impl_ai_aspect_list(lua_State* L)
870 {
871  const aspect_map& aspects = get_engine(L).get_readonly_context().get_aspects();
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 
878 static 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 
884 static 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 
897 static 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 
939 static 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 
953 static void generate_and_push_ai_table(lua_State* L, ai::engine_lua* engine) {
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 
1017 static 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");
1034  luaW_pushconfig(L, cfg);
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 
1080 lua_ai_action_handler* lua_ai_action_handler::create(lua_State *L, char const *code, lua_ai_context &context)
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 
1103 int lua_ai_load::refcount = 0;
1104 
1105 lua_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");
1117  was_readonly = luaW_toboolean(L, -1);
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 
1161 void 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");
1176  luaW_pushconfig(L, cfg);
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.
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
lua_ai_action_handler(lua_State *l, lua_ai_context &context, int num)
Definition: core.hpp:76
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
lua_ai_context(lua_State *l, int num, int side)
Definition: core.hpp:39
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 int get_villages_per_scout() const =0
virtual std::string get_grouping() const =0
virtual const terrain_filter & get_avoid() const =0
virtual bool get_simple_targeting() const =0
virtual void recalculate_move_maps() const =0
virtual const aspect_map & get_aspects() const =0
virtual const attacks_vector & get_attacks() const =0
virtual void set_dst_src_valid_lua()=0
virtual const move_map & get_enemy_srcdst() const =0
virtual const move_map & get_enemy_dstsrc() const =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 const team & current_team() const =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 void set_src_dst_enemy_valid_lua()=0
virtual const move_map & get_srcdst() const =0
virtual void set_dst_src_enemy_valid_lua()=0
virtual double get_caution() const =0
virtual void recalculate_move_maps_enemy() const =0
virtual bool is_dst_src_valid_lua() const =0
virtual const std::vector< std::string > get_recruitment_pattern() 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_dstsrc() const =0
virtual void set_src_dst_valid_lua()=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
Definition: game_board.hpp:106
This class represents a single unit of a specific type.
Definition: unit.hpp:39
Composite AI contexts.
#define ERR_LUA
Definition: core.cpp:47
static lg::log_domain log_ai_engine_lua("ai/engine/lua")
static char const atkKey[]
Definition: core.cpp:50
static char const aisKey[]
Definition: core.cpp:49
LUA AI Support engine - creating specific ai components from config.
const config * cfg
std::size_t i
Definition: function.cpp:1031
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.
Definition: lua_common.cpp:883
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.
Definition: lua_common.cpp:785
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.
Definition: lua_common.cpp:912
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.
Definition: lua_common.cpp:855
bool luaW_tolocation(lua_State *L, int index, map_location &loc)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:798
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:847
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 int cfun_ai_get_simple_targeting(lua_State *L)
Definition: core.cpp:496
typesafe_aspect< T > * try_aspect_as(const aspect_ptr &p)
Definition: core.cpp:802
static int cfun_ai_execute_stopunit_all(lua_State *L)
Definition: core.cpp:274
std::vector< attack_analysis > attacks_vector
Definition: game_info.hpp:51
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 ai::engine_lua & get_engine(lua_State *L, int n)
Definition: core.cpp:123
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
std::shared_ptr< lua_object_base > lua_object_ptr
Definition: core.hpp:27
std::shared_ptr< aspect > aspect_ptr
Definition: game_info.hpp:95
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:79
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
ATTACK_GETTER("rating", lua_index_raw)
Definition: core.cpp:618
std::map< std::string, aspect_ptr > aspect_map
Definition: game_info.hpp:104
static int cfun_ai_get_support_villages(lua_State *L)
Definition: core.cpp:503
static ai::readonly_context & get_readonly_context(lua_State *L)
Definition: core.cpp:138
static int cfun_ai_get_village_value(lua_State *L)
Definition: core.cpp:510
static luaL_Reg const mutating_callbacks[]
Definition: core.cpp:884
CURSOR_TYPE get()
Definition: cursor.cpp:205
game_board * gameboard
Definition: resources.cpp:20
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:81
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
constexpr auto transform
Definition: ranges.hpp:45
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
Definition: general.hpp:31
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
This module contains various pathfinding functions and utilities.
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
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...
Definition: push_check.hpp:435
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
static const map_location & null_location()
Definition: location.hpp:103
int wml_x() const
Definition: location.hpp:186
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_char c
mock_party p
static map_location::direction n