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