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