00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "lua/lualib.h"
00023 #include "lua/lauxlib.h"
00024 #include "lua/llimits.h"
00025
00026 #include <cassert>
00027 #include <cstring>
00028
00029 #include "core.hpp"
00030 #include "../../scripting/lua.hpp"
00031 #include "../../scripting/lua_api.hpp"
00032 #include "lua_object.hpp"
00033
00034
00035 #include "../../actions.hpp"
00036 #include "../../attack_prediction.hpp"
00037 #include "../../filesystem.hpp"
00038 #include "../../foreach.hpp"
00039 #include "../../game_display.hpp"
00040 #include "../../gamestatus.hpp"
00041 #include "../../log.hpp"
00042 #include "../../map.hpp"
00043 #include "../../pathfind/pathfind.hpp"
00044 #include "../../play_controller.hpp"
00045 #include "../../resources.hpp"
00046 #include "../../terrain_translation.hpp"
00047 #include "../../terrain_filter.hpp"
00048 #include "../../unit.hpp"
00049 #include "../actions.hpp"
00050 #include "../composite/engine_lua.hpp"
00051 #include "../composite/contexts.hpp"
00052
00053 static lg::log_domain log_ai_engine_lua("ai/engine/lua");
00054 #define LOG_LUA LOG_STREAM(info, log_ai_engine_lua)
00055 #define ERR_LUA LOG_STREAM(err, log_ai_engine_lua)
00056
00057 static char const aisKey = 0;
00058
00059 namespace ai {
00060
00061 static void push_map_location(lua_State *L, const map_location& ml);
00062 static void push_attack_analysis(lua_State *L, attack_analysis&);
00063
00064 void lua_ai_context::init(lua_State *L)
00065 {
00066
00067 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00068 lua_newtable(L);
00069 lua_rawset(L, LUA_REGISTRYINDEX);
00070 }
00071
00072 void lua_ai_context::get_persistent_data(config &cfg) const
00073 {
00074 int top = lua_gettop(L);
00075
00076 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00077 lua_rawget(L, LUA_REGISTRYINDEX);
00078 lua_rawgeti(L, -1, num_);
00079
00080 lua_getfield(L, -1, "data");
00081 luaW_toconfig(L, -1, cfg);
00082
00083 lua_settop(L, top);
00084 }
00085
00086 void lua_ai_context::set_persistent_data(const config &cfg)
00087 {
00088 int top = lua_gettop(L);
00089
00090 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00091 lua_rawget(L, LUA_REGISTRYINDEX);
00092 lua_rawgeti(L, -1, num_);
00093
00094 luaW_pushconfig(L, cfg);
00095 lua_setfield(L, -2, "data");
00096
00097 lua_settop(L, top);
00098 }
00099 static ai::engine_lua &get_engine(lua_State *L)
00100 {
00101 return *(static_cast<ai::engine_lua*>(
00102 lua_touserdata(L, lua_upvalueindex(1))));
00103 }
00104
00105 static ai::readonly_context &get_readonly_context(lua_State *L)
00106 {
00107 return get_engine(L).get_readonly_context();
00108 }
00109
00110 static int transform_ai_action(lua_State *L, ai::action_result_ptr action_result)
00111 {
00112 lua_newtable(L);
00113 lua_pushboolean(L,action_result->is_ok());
00114 lua_setfield(L, -2, "ok");
00115 lua_pushboolean(L,action_result->is_gamestate_changed());
00116 lua_setfield(L, -2, "gamestate_changed");
00117 lua_pushinteger(L,action_result->get_status());
00118 lua_setfield(L, -2, "status");
00119 return 1;
00120 }
00121
00122 static bool to_map_location(lua_State *L, int &index, map_location &res)
00123 {
00124 if (lua_isuserdata(L, index))
00125 {
00126 unit const *u = luaW_tounit(L, index);
00127 if (!u) return false;
00128 res = u->get_location();
00129 ++index;
00130 }
00131 else
00132 {
00133 if (!lua_isnumber(L, index)) return false;
00134 res.x = lua_tointeger(L, index) - 1;
00135 ++index;
00136 if (!lua_isnumber(L, index)) return false;
00137 res.y = lua_tointeger(L, index) - 1;
00138 ++index;
00139 }
00140
00141 return true;
00142 }
00143
00144 static int cfun_ai_get_suitable_keep(lua_State *L)
00145 {
00146 int index = 1;
00147
00148 ai::readonly_context &context = get_readonly_context(L);
00149 unit const *leader;
00150 if (lua_isuserdata(L, index))
00151 {
00152 leader = luaW_tounit(L, index);
00153 if (!leader) return luaL_argerror(L, 1, "unknown unit");
00154 }
00155 else return luaL_typerror(L, 1, "unit");
00156 const map_location loc = leader->get_location();
00157 const pathfind::paths leader_paths(*resources::game_map, *resources::units, *leader,
00158 *resources::teams, false, true, context.current_team());
00159 const map_location &res = context.suitable_keep(loc,leader_paths);
00160 if (!res.valid()) {
00161 return 0;
00162 }
00163 else {
00164 lua_pushnumber(L, res.x+1);
00165 lua_pushnumber(L, res.y+1);
00166 return 2;
00167 }
00168 }
00169
00170 static int ai_move(lua_State *L, bool exec, bool remove_movement)
00171 {
00172 int index = 1;
00173 if (false) {
00174 error_call_destructors:
00175 return luaL_typerror(L, index, "location (unit/integers)");
00176 }
00177
00178 int side = get_readonly_context(L).get_side();
00179 map_location from, to;
00180 if (!to_map_location(L, index, from)) goto error_call_destructors;
00181 if (!to_map_location(L, index, to)) goto error_call_destructors;
00182 bool unreach_is_ok = false;
00183 if (lua_isboolean(L, index)) {
00184 unreach_is_ok = lua_toboolean(L, index);
00185 }
00186 ai::move_result_ptr move_result = ai::actions::execute_move_action(side,exec,from,to,remove_movement, unreach_is_ok);
00187 return transform_ai_action(L,move_result);
00188 }
00189
00190 static int cfun_ai_execute_move_full(lua_State *L)
00191 {
00192 return ai_move(L, true, true);
00193 }
00194
00195 static int cfun_ai_execute_move_partial(lua_State *L)
00196 {
00197 return ai_move(L, true, false);
00198 }
00199
00200 static int cfun_ai_check_move(lua_State *L)
00201 {
00202 return ai_move(L, false, false);
00203 }
00204
00205 static int ai_attack(lua_State *L, bool exec)
00206 {
00207 int index = 1;
00208 if (false) {
00209 error_call_destructors:
00210 return luaL_typerror(L, index, "location (unit/integers)");
00211 }
00212
00213 ai::readonly_context &context = get_readonly_context(L);
00214
00215 int side = context.get_side();
00216 map_location attacker, defender;
00217 if (!to_map_location(L, index, attacker)) goto error_call_destructors;
00218 if (!to_map_location(L, index, defender)) goto error_call_destructors;
00219
00220 int attacker_weapon = -1;
00221 double aggression = context.get_aggression();
00222
00223 if (!lua_isnoneornil(L, index + 1) && attacker_weapon != -1) {
00224 attacker_weapon = lua_tointeger(L, index + 1) - 1;
00225 }
00226
00227
00228
00229
00230
00231 if (!lua_isnoneornil(L, index) && lua_isnumber(L,index)) {
00232 aggression = lua_tonumber(L, index);
00233 }
00234
00235 ai::attack_result_ptr attack_result = ai::actions::execute_attack_action(side,exec,attacker,defender,attacker_weapon,aggression);
00236 return transform_ai_action(L,attack_result);
00237 }
00238
00239 static int cfun_ai_execute_attack(lua_State *L)
00240 {
00241 return ai_attack(L, true);
00242 }
00243
00244 static int cfun_ai_check_attack(lua_State *L)
00245 {
00246 return ai_attack(L, false);
00247 }
00248
00249 static int ai_stopunit_select(lua_State *L, bool exec, bool remove_movement, bool remove_attacks)
00250 {
00251 int index = 1;
00252 if (false) {
00253 error_call_destructors:
00254 return luaL_typerror(L, index, "location (unit/integers)");
00255 }
00256
00257 int side = get_readonly_context(L).get_side();
00258 map_location loc;
00259 if (!to_map_location(L, index, loc)) goto error_call_destructors;
00260
00261 ai::stopunit_result_ptr stopunit_result = ai::actions::execute_stopunit_action(side,exec,loc,remove_movement,remove_attacks);
00262 return transform_ai_action(L,stopunit_result);
00263 }
00264
00265 static int cfun_ai_execute_stopunit_moves(lua_State *L)
00266 {
00267 return ai_stopunit_select(L, true, true, false);
00268 }
00269
00270 static int cfun_ai_execute_stopunit_attacks(lua_State *L)
00271 {
00272 return ai_stopunit_select(L, true, false, true);
00273 }
00274
00275 static int cfun_ai_execute_stopunit_all(lua_State *L)
00276 {
00277 return ai_stopunit_select(L, true, true, true);
00278 }
00279
00280 static int cfun_ai_check_stopunit(lua_State *L)
00281 {
00282 return ai_stopunit_select(L, false, true, true);
00283 }
00284
00285 static int ai_recruit(lua_State *L, bool exec)
00286 {
00287 const char *unit_name = luaL_checkstring(L, 1);
00288 int side = get_readonly_context(L).get_side();
00289 map_location where;
00290 if (!lua_isnoneornil(L, 2)) {
00291 where.x = lua_tonumber(L, 2) - 1;
00292 where.y = lua_tonumber(L, 3) - 1;
00293 }
00294
00295 map_location from = map_location::null_location;
00296 ai::recruit_result_ptr recruit_result = ai::actions::execute_recruit_action(side,exec,std::string(unit_name),where,from);
00297 return transform_ai_action(L,recruit_result);
00298 }
00299
00300 static int cfun_ai_execute_recruit(lua_State *L)
00301 {
00302 return ai_recruit(L, true);
00303 }
00304
00305 static int cfun_ai_check_recruit(lua_State *L)
00306 {
00307 return ai_recruit(L, false);
00308 }
00309
00310 static int ai_recall(lua_State *L, bool exec)
00311 {
00312 const char *unit_id = luaL_checkstring(L, 1);
00313 int side = get_readonly_context(L).get_side();
00314 map_location where;
00315 if (!lua_isnoneornil(L, 2)) {
00316 where.x = lua_tonumber(L, 2) - 1;
00317 where.y = lua_tonumber(L, 3) - 1;
00318 }
00319
00320 map_location from = map_location::null_location;
00321 ai::recall_result_ptr recall_result = ai::actions::execute_recall_action(side,exec,std::string(unit_id),where,from);
00322 return transform_ai_action(L,recall_result);
00323 }
00324
00325 static int cfun_ai_execute_recall(lua_State *L)
00326 {
00327 return ai_recall(L, true);
00328 }
00329
00330 static int cfun_ai_check_recall(lua_State *L)
00331 {
00332 return ai_recall(L, false);
00333 }
00334
00335
00336
00337
00338 static int cfun_ai_get_targets(lua_State *L)
00339 {
00340 move_map enemy_dst_src = get_readonly_context(L).get_enemy_dstsrc();
00341 std::vector<target> targets = get_engine(L).get_ai_context()->find_targets(enemy_dst_src);
00342 int i = 1;
00343
00344 lua_createtable(L, 0, 0);
00345 for (std::vector<target>::iterator it = targets.begin(); it != targets.end(); it++)
00346 {
00347 lua_pushinteger(L, i);
00348
00349
00350 lua_createtable(L, 3, 0);
00351
00352
00353 lua_pushstring(L, "type");
00354 lua_pushnumber(L, it->type);
00355 lua_rawset(L, -3);
00356
00357 lua_pushstring(L, "loc");
00358 push_map_location(L, it->loc);
00359 lua_rawset(L, -3);
00360
00361 lua_pushstring(L, "value");
00362 lua_pushnumber(L, it->value);
00363 lua_rawset(L, -3);
00364
00365 lua_rawset(L, -3);
00366 ++i;
00367 }
00368 return 1;
00369 }
00370
00371
00372 static int cfun_ai_get_aggression(lua_State *L)
00373 {
00374 double aggression = get_readonly_context(L).get_aggression();
00375 lua_pushnumber(L, aggression);
00376 return 1;
00377 }
00378
00379 static int cfun_ai_get_attack_depth(lua_State *L)
00380 {
00381 int attack_depth = get_readonly_context(L).get_attack_depth();
00382 lua_pushnumber(L, attack_depth);
00383 return 1;
00384 }
00385
00386 static int cfun_ai_get_attacks(lua_State *L)
00387 {
00388 ai::attacks_vector attacks = get_readonly_context(L).get_attacks();
00389 lua_createtable(L, attacks.size(), 0);
00390 int table_index = lua_gettop(L);
00391
00392 ai::attacks_vector::iterator it = attacks.begin();
00393 for (int i = 1; it != attacks.end(); it++, i++)
00394 {
00395 push_attack_analysis(L, *it);
00396
00397 lua_rawseti(L, table_index, i);
00398 }
00399 return 1;
00400 }
00401
00402 static int cfun_ai_get_avoid(lua_State *L)
00403 {
00404 std::set<map_location> locs;
00405 terrain_filter avoid = get_readonly_context(L).get_avoid();
00406 avoid.get_locations(locs);
00407
00408 int sz = locs.size();
00409 lua_createtable(L, sz, 0);
00410
00411 std::set<map_location>::iterator it = locs.begin();
00412 for (int i = 0; it != locs.end(); ++it, ++i)
00413 {
00414 lua_pushinteger(L, i + 1);
00415
00416 push_map_location(L, *it);
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 lua_settable(L, -3);
00430 }
00431
00432 return 1;
00433 }
00434
00435 static int cfun_ai_get_caution(lua_State *L)
00436 {
00437 double caution = get_readonly_context(L).get_caution();
00438 lua_pushnumber(L, caution);
00439 return 1;
00440 }
00441
00442 static int cfun_ai_get_grouping(lua_State *L)
00443 {
00444 std::string grouping = get_readonly_context(L).get_grouping();
00445 lua_pushstring(L, grouping.c_str());
00446 return 1;
00447 }
00448
00449 static int cfun_ai_get_leader_aggression(lua_State *L)
00450 {
00451 double leader_aggression = get_readonly_context(L).get_leader_aggression();
00452 lua_pushnumber(L, leader_aggression);
00453 return 1;
00454 }
00455
00456 static int cfun_ai_get_leader_goal(lua_State *L)
00457 {
00458 config goal = get_readonly_context(L).get_leader_goal();
00459 luaW_pushconfig(L, goal);
00460 return 1;
00461 }
00462
00463 static int cfun_ai_get_leader_value(lua_State *L)
00464 {
00465 double leader_value = get_readonly_context(L).get_leader_value();
00466 lua_pushnumber(L, leader_value);
00467 return 1;
00468 }
00469
00470 static int cfun_ai_get_passive_leader(lua_State *L)
00471 {
00472 bool passive_leader = get_readonly_context(L).get_passive_leader();
00473 lua_pushboolean(L, passive_leader);
00474 return 1;
00475 }
00476
00477 static int cfun_ai_get_passive_leader_shares_keep(lua_State *L)
00478 {
00479 bool passive_leader_shares_keep = get_readonly_context(L).get_passive_leader_shares_keep();
00480 lua_pushboolean(L, passive_leader_shares_keep);
00481 return 1;
00482 }
00483
00484 static int cfun_ai_get_number_of_possible_recruits_to_force_recruit(lua_State *L)
00485 {
00486 double noprtfr = get_readonly_context(L).get_number_of_possible_recruits_to_force_recruit();
00487 lua_pushnumber(L, noprtfr);
00488 return 1;
00489 }
00490
00491 static int cfun_ai_get_recruitment_ignore_bad_combat(lua_State *L)
00492 {
00493 bool recruitment_ignore_bad_combat = get_readonly_context(L).get_recruitment_ignore_bad_combat();
00494 lua_pushboolean(L, recruitment_ignore_bad_combat);
00495 return 1;
00496 }
00497
00498 static int cfun_ai_get_recruitment_ignore_bad_movement(lua_State *L)
00499 {
00500 bool recruitment_ignore_bad_movement = get_readonly_context(L).get_recruitment_ignore_bad_movement();
00501 lua_pushboolean(L, recruitment_ignore_bad_movement);
00502 return 1;
00503 }
00504
00505 static int cfun_ai_get_recruitment_pattern(lua_State *L)
00506 {
00507 std::vector<std::string> recruiting = get_readonly_context(L).get_recruitment_pattern();
00508 int size = recruiting.size();
00509 lua_createtable(L, size, 0);
00510 for (int i = 0; i < size; ++i)
00511 {
00512 lua_pushinteger(L, i + 1);
00513 lua_pushstring(L, recruiting[i].c_str());
00514 lua_settable(L, -3);
00515 }
00516 return 1;
00517 }
00518
00519 static int cfun_ai_get_scout_village_targeting(lua_State *L)
00520 {
00521 double scout_village_targeting = get_readonly_context(L).get_scout_village_targeting();
00522 lua_pushnumber(L, scout_village_targeting);
00523 return 1;
00524 }
00525
00526 static int cfun_ai_get_simple_targeting(lua_State *L)
00527 {
00528 bool simple_targeting = get_readonly_context(L).get_simple_targeting();
00529 lua_pushboolean(L, simple_targeting);
00530 return 1;
00531 }
00532
00533 static int cfun_ai_get_support_villages(lua_State *L)
00534 {
00535 bool support_villages = get_readonly_context(L).get_support_villages();
00536 lua_pushboolean(L, support_villages);
00537 return 1;
00538 }
00539
00540 static int cfun_ai_get_village_value(lua_State *L)
00541 {
00542 double village_value = get_readonly_context(L).get_village_value();
00543 lua_pushnumber(L, village_value);
00544 return 1;
00545 }
00546
00547 static int cfun_ai_get_villages_per_scout(lua_State *L)
00548 {
00549 int villages_per_scout = get_readonly_context(L).get_villages_per_scout();
00550 lua_pushnumber(L, villages_per_scout);
00551 return 1;
00552 }
00553
00554
00555 static int cfun_attack_rating(lua_State *L)
00556 {
00557 int top = lua_gettop(L);
00558
00559 lua_getfield(L, -1, "att_ptr");
00560
00561 attack_analysis* aa_ptr = static_cast< attack_analysis * >(lua_touserdata(L, -1));
00562
00563
00564
00565 double aggression = get_readonly_context(L).get_aggression();
00566
00567 double rating = aa_ptr->rating(aggression, get_readonly_context(L));
00568
00569 lua_settop(L, top);
00570
00571 lua_pushnumber(L, rating);
00572 return 1;
00573 }
00574
00575 static void push_movements(lua_State *L, const std::vector< std::pair < map_location, map_location > > & moves)
00576 {
00577 lua_createtable(L, moves.size(), 0);
00578
00579 int table_index = lua_gettop(L);
00580
00581 std::vector< std::pair < map_location, map_location > >::const_iterator move = moves.begin();
00582
00583 for (int i = 1; move != moves.end(); move++, i++)
00584 {
00585 lua_createtable(L, 2, 0);
00586
00587 lua_pushstring(L, "src");
00588 push_map_location(L, move->first);
00589 lua_rawset(L, -3);
00590
00591 lua_pushstring(L, "dst");
00592 push_map_location(L, move->second);
00593 lua_rawset(L, -3);
00594
00595 lua_rawseti(L, table_index, i);
00596 }
00597
00598
00599 }
00600
00601 static void push_attack_analysis(lua_State *L, attack_analysis& aa)
00602 {
00603 lua_newtable(L);
00604
00605
00606 lua_pushstring(L, "att_ptr");
00607 lua_pushlightuserdata(L, &aa);
00608 lua_rawset(L, -3);
00609
00610
00611 lua_pushstring(L, "rating");
00612 lua_pushlightuserdata(L, &get_engine(L));
00613 lua_pushcclosure(L, &cfun_attack_rating, 1);
00614 lua_rawset(L, -3);
00615
00616 lua_pushstring(L, "movements");
00617 push_movements(L, aa.movements);
00618 lua_rawset(L, -3);
00619
00620 lua_pushstring(L, "target");
00621 push_map_location(L, aa.target);
00622 lua_rawset(L, -3);
00623
00624 lua_pushstring(L, "target_value");
00625 lua_pushnumber(L, aa.target_value);
00626 lua_rawset(L, -3);
00627
00628 lua_pushstring(L, "avg_losses");
00629 lua_pushnumber(L, aa.avg_losses);
00630 lua_rawset(L, -3);
00631
00632 lua_pushstring(L, "chance_to_kill");
00633 lua_pushnumber(L, aa.chance_to_kill);
00634 lua_rawset(L, -3);
00635
00636 lua_pushstring(L, "avg_damage_inflicted");
00637 lua_pushnumber(L, aa.avg_damage_inflicted);
00638 lua_rawset(L, -3);
00639
00640 lua_pushstring(L, "target_starting_damage");
00641 lua_pushinteger(L, aa.target_starting_damage);
00642 lua_rawset(L, -3);
00643
00644 lua_pushstring(L, "avg_damage_taken");
00645 lua_pushnumber(L, aa.avg_damage_taken);
00646 lua_rawset(L, -3);
00647
00648 lua_pushstring(L, "resources_used");
00649 lua_pushnumber(L, aa.resources_used);
00650 lua_rawset(L, -3);
00651
00652 lua_pushstring(L, "terrain_quality");
00653 lua_pushnumber(L, aa.alternative_terrain_quality);
00654 lua_rawset(L, -3);
00655
00656 lua_pushstring(L, "alternative_terrain_quality");
00657 lua_pushnumber(L, aa.alternative_terrain_quality);
00658 lua_rawset(L, -3);
00659
00660 lua_pushstring(L, "vulnerability");
00661 lua_pushnumber(L, aa.vulnerability);
00662 lua_rawset(L, -3);
00663
00664 lua_pushstring(L, "support");
00665 lua_pushnumber(L, aa.support);
00666 lua_rawset(L, -3);
00667
00668 lua_pushstring(L, "leader_threat");
00669 lua_pushboolean(L, aa.leader_threat);
00670 lua_rawset(L, -3);
00671
00672 lua_pushstring(L, "uses_leader");
00673 lua_pushboolean(L, aa.uses_leader);
00674 lua_rawset(L, -3);
00675
00676 lua_pushstring(L, "is_surrounded");
00677 lua_pushboolean(L, aa.is_surrounded);
00678 lua_rawset(L, -3);
00679 }
00680
00681 static void push_map_location(lua_State *L, const map_location& ml)
00682 {
00683 lua_createtable(L, 2, 0);
00684
00685 lua_pushstring(L, "x");
00686 lua_pushinteger(L, ml.x + 1);
00687 lua_rawset(L, -3);
00688
00689 lua_pushstring(L, "y");
00690 lua_pushinteger(L, ml.y + 1);
00691 lua_rawset(L, -3);
00692 }
00693
00694 static void push_move_map(lua_State *L, const move_map& m)
00695 {
00696 lua_createtable(L, 0, 0);
00697
00698 if (m.empty())
00699 {
00700 return;
00701 }
00702
00703 move_map::const_iterator it = m.begin();
00704
00705 int index = 1;
00706
00707
00708
00709 do
00710 {
00711 map_location key = it->first;
00712
00713
00714
00715
00716
00717
00718
00719 int hashed_index = (key.x + 1) * 16384 + (key.y + 1) + 2000;
00720 lua_pushinteger(L, hashed_index);
00721
00722 lua_createtable(L, 0, 0);
00723
00724 while (key == it->first) {
00725
00726 push_map_location(L, it->second);
00727 lua_rawseti(L, -2, index);
00728
00729 ++index;
00730 ++it;
00731
00732 }
00733
00734 lua_settable(L, -3);
00735
00736 index = 1;
00737
00738 } while (it != m.end());
00739 }
00740
00741 static int cfun_ai_get_dstsrc(lua_State *L)
00742 {
00743 move_map dst_src = get_readonly_context(L).get_dstsrc();
00744 get_readonly_context(L).set_dst_src_valid_lua();
00745 push_move_map(L, dst_src);
00746 return 1;
00747 }
00748
00749 static int cfun_ai_get_srcdst(lua_State *L)
00750 {
00751 move_map src_dst = get_readonly_context(L).get_srcdst();
00752 get_readonly_context(L).set_src_dst_valid_lua();
00753 push_move_map(L, src_dst);
00754 return 1;
00755 }
00756
00757 static int cfun_ai_get_enemy_dstsrc(lua_State *L)
00758 {
00759 move_map enemy_dst_src = get_readonly_context(L).get_enemy_dstsrc();
00760 get_readonly_context(L).set_dst_src_enemy_valid_lua();
00761 push_move_map(L, enemy_dst_src);
00762 return 1;
00763 }
00764
00765 static int cfun_ai_get_enemy_srcdst(lua_State *L)
00766 {
00767 move_map enemy_src_dst = get_readonly_context(L).get_enemy_srcdst();
00768 get_readonly_context(L).set_src_dst_enemy_valid_lua();
00769 push_move_map(L, enemy_src_dst);
00770 return 1;
00771 }
00772
00773 static int cfun_ai_is_dst_src_valid(lua_State *L)
00774 {
00775 bool valid = get_readonly_context(L).is_dst_src_valid_lua();
00776 lua_pushboolean(L, valid);
00777 return 1;
00778 }
00779
00780 static int cfun_ai_is_dst_src_enemy_valid(lua_State *L)
00781 {
00782 bool valid = get_readonly_context(L).is_dst_src_enemy_valid_lua();
00783 lua_pushboolean(L, valid);
00784 return 1;
00785 }
00786
00787 static int cfun_ai_is_src_dst_valid(lua_State *L)
00788 {
00789 bool valid = get_readonly_context(L).is_src_dst_valid_lua();
00790 lua_pushboolean(L, valid);
00791 return 1;
00792 }
00793
00794 static int cfun_ai_is_src_dst_enemy_valid(lua_State *L)
00795 {
00796 bool valid = get_readonly_context(L).is_src_dst_enemy_valid_lua();
00797 lua_pushboolean(L, valid);
00798 return 1;
00799 }
00800
00801 static int cfun_ai_recalculate_move_maps(lua_State *L)
00802 {
00803 get_readonly_context(L).recalculate_move_maps();
00804 return 1;
00805 }
00806
00807 static int cfun_ai_recalculate_move_maps_enemy(lua_State *L)
00808 {
00809 get_readonly_context(L).recalculate_move_maps_enemy();
00810 return 1;
00811 }
00812
00813 lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engine_lua *engine)
00814 {
00815 int res_ai = luaL_loadstring(L, code);
00816 if (res_ai)
00817 {
00818
00819 char const *m = lua_tostring(L, -1);
00820 ERR_LUA << "error while initializing ai: " <<m << '\n';
00821 lua_pop(L, 2);
00822 return NULL;
00823 }
00824
00825 lua_newtable(L);
00826 lua_pushinteger(L, engine->get_readonly_context().get_side());
00827
00828 lua_setfield(L, -2, "side");
00829
00830 static luaL_Reg const callbacks[] = {
00831 { "attack", &cfun_ai_execute_attack },
00832
00833 { "get_new_dst_src", &cfun_ai_get_dstsrc },
00834 { "get_new_src_dst", &cfun_ai_get_srcdst },
00835 { "get_new_enemy_dst_src", &cfun_ai_get_enemy_dstsrc },
00836 { "get_new_enemy_src_dst", &cfun_ai_get_enemy_srcdst },
00837 { "recalculate_move_maps", &cfun_ai_recalculate_move_maps },
00838 { "recalculate_enemy_move_maps",&cfun_ai_recalculate_move_maps_enemy },
00839
00840
00841 { "get_targets", &cfun_ai_get_targets },
00842
00843
00844 { "get_aggression", &cfun_ai_get_aggression },
00845 { "get_avoid", &cfun_ai_get_avoid },
00846 { "get_attack_depth", &cfun_ai_get_attack_depth },
00847 { "get_attacks", &cfun_ai_get_attacks },
00848 { "get_caution", &cfun_ai_get_caution },
00849 { "get_grouping", &cfun_ai_get_grouping },
00850 { "get_leader_aggression", &cfun_ai_get_leader_aggression },
00851 { "get_leader_goal", &cfun_ai_get_leader_goal },
00852 { "get_leader_value", &cfun_ai_get_leader_value },
00853 { "get_number_of_possible_recruits_to_force_recruit", &cfun_ai_get_number_of_possible_recruits_to_force_recruit},
00854 { "get_passive_leader", &cfun_ai_get_passive_leader },
00855 { "get_passive_leader_shares_keep", &cfun_ai_get_passive_leader_shares_keep},
00856 { "get_recruitment_ignore_bad_combat", &cfun_ai_get_recruitment_ignore_bad_combat},
00857 { "get_recruitment_ignore_bad_movement", &cfun_ai_get_recruitment_ignore_bad_movement},
00858 { "get_recruitment_pattern", &cfun_ai_get_recruitment_pattern },
00859 { "get_scout_village_targeting", &cfun_ai_get_scout_village_targeting },
00860 { "get_simple_targeting", &cfun_ai_get_simple_targeting },
00861 { "get_support_villages", &cfun_ai_get_support_villages },
00862 { "get_village_value", &cfun_ai_get_village_value },
00863 { "get_villages_per_scout", &cfun_ai_get_villages_per_scout },
00864
00865
00866 { "is_dst_src_valid", &cfun_ai_is_dst_src_valid },
00867 { "is_enemy_dst_src_valid", &cfun_ai_is_dst_src_enemy_valid },
00868 { "is_src_dst_valid", &cfun_ai_is_src_dst_valid },
00869 { "is_enemy_src_dst_valid", &cfun_ai_is_src_dst_enemy_valid },
00870
00871 { "move", &cfun_ai_execute_move_partial },
00872 { "move_full", &cfun_ai_execute_move_full },
00873 { "recall", &cfun_ai_execute_recall },
00874 { "recruit", &cfun_ai_execute_recruit },
00875 { "stopunit_all", &cfun_ai_execute_stopunit_all },
00876 { "stopunit_attacks", &cfun_ai_execute_stopunit_attacks },
00877 { "stopunit_moves", &cfun_ai_execute_stopunit_moves },
00878 { "suitable_keep", &cfun_ai_get_suitable_keep },
00879 { "check_recall", &cfun_ai_check_recall },
00880 { "check_move", &cfun_ai_check_move },
00881 { "check_stopunit", &cfun_ai_check_stopunit },
00882 { "check_attack", &cfun_ai_check_attack },
00883 { "check_recruit", &cfun_ai_check_recruit },
00884
00885
00886 { NULL, NULL }
00887 };
00888
00889 for (const luaL_Reg *p = callbacks; p->name; ++p) {
00890 lua_pushlightuserdata(L, engine);
00891 lua_pushcclosure(L, p->func, 1);
00892 lua_setfield(L, -2, p->name);
00893 }
00894
00895
00896 if (!luaW_pcall(L, 1, 1, true)) {
00897 return NULL;
00898 }
00899
00900
00901 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00902 lua_rawget(L, LUA_REGISTRYINDEX);
00903
00904 size_t length_ai = lua_rawlen(L, -1);
00905 lua_pushvalue(L, -2);
00906 lua_rawseti(L, -2, length_ai + 1);
00907 lua_pop(L, 2);
00908 return new lua_ai_context(L, length_ai + 1, engine->get_readonly_context().get_side());
00909 }
00910
00911 lua_ai_action_handler* lua_ai_action_handler::create(lua_State *L, char const *code, lua_ai_context &context)
00912 {
00913 int res = luaL_loadstring(L, code);
00914 if (res)
00915 {
00916 char const *m = lua_tostring(L, -1);
00917 ERR_LUA << "error while creating ai function: " <<m << '\n';
00918 lua_pop(L, 2);
00919 return NULL;
00920 }
00921
00922
00923
00924 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00925 lua_rawget(L, LUA_REGISTRYINDEX);
00926
00927 size_t length = lua_rawlen(L, -1);
00928 lua_pushvalue(L, -2);
00929 lua_rawseti(L, -2, length + 1);
00930 lua_remove(L, -1);
00931 lua_remove(L, -1);
00932
00933 return new lua_ai_action_handler(L, context, length + 1);
00934 }
00935
00936
00937 void lua_ai_context::load()
00938 {
00939 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00940 lua_rawget(L, LUA_REGISTRYINDEX);
00941 lua_rawgeti(L, -1, num_);
00942 lua_remove(L,-2);
00943 }
00944
00945 lua_ai_context::~lua_ai_context()
00946 {
00947
00948 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00949 lua_rawget(L, LUA_REGISTRYINDEX);
00950 lua_pushnil(L);
00951 lua_rawseti(L, -2, num_);
00952 lua_pop(L, 1);
00953 }
00954
00955 void lua_ai_action_handler::handle(config &cfg, bool configOut, lua_object_ptr l_obj)
00956 {
00957 int initial_top = lua_gettop(L);
00958
00959
00960 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00961 lua_rawget(L, LUA_REGISTRYINDEX);
00962 lua_rawgeti(L, -1, num_);
00963 lua_remove(L, -2);
00964
00965 context_.load();
00966
00967 if (!configOut)
00968 {
00969 luaW_pushconfig(L, cfg);
00970 luaW_pcall(L, 2, 0, true);
00971 }
00972 else if (luaW_pcall(L, 1, 5, true))
00973 {
00974 l_obj->store(L, initial_top + 1);
00975 }
00976
00977 lua_settop(L, initial_top);
00978 }
00979
00980 lua_ai_action_handler::~lua_ai_action_handler()
00981 {
00982
00983 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00984 lua_rawget(L, LUA_REGISTRYINDEX);
00985 lua_pushnil(L);
00986 lua_rawseti(L, -2, num_);
00987 lua_pop(L, 1);
00988 }
00989
00990 }