ai/lua/core.cpp

Go to the documentation of this file.
00001 /* $Id: core.cpp 53940 2012-04-15 16:33:36Z nephro $ */
00002 /*
00003    Copyright (C) 2010 - 2012 by Yurii Chernyi <terraninfo@terraninfo.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  * @file
00018  * Provides core classes for the Lua AI.
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" // (Nephro)
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     // Create the ai elements table.
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;//-1 means 'select what is best'
00221     double aggression = context.get_aggression();//use the aggression from the context
00222 
00223     if (!lua_isnoneornil(L, index + 1) &&  attacker_weapon != -1) {
00224         attacker_weapon = lua_tointeger(L, index + 1) - 1; // Done for consistency of the Lua style
00225     }
00226     
00227     //TODO: Right now, aggression is used by the attack execution functions to determine the weapon to be used.
00228     // If a decision is made to expand the function that determines the weapon, this block must be refactored
00229     // to parse aggression if a single int is on the stack, or create a table of parameters, if a table is on the
00230     // stack.
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     //TODO fendrin: talk to Crab about the from argument.
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     //TODO fendrin: talk to Crab about the from argument.
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 // Goals and targets
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         //to factor out
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 // Aspect section
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); // create a table that we'll use as an array
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); // Index for the map location
00415 
00416         push_map_location(L, *it);
00417 
00418         // Deprecated
00419         //lua_createtable(L, 2, 0); // Table for a single map location
00420 
00421         //lua_pushstring(L, "x");
00422         //lua_pushinteger(L, it->x + 1);
00423         //lua_settable(L, -3);
00424 
00425         //lua_pushstring(L, "y");
00426         //lua_pushinteger(L, it->y + 1);
00427         //lua_settable(L, -3);
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(); // @note: abbreviation
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); // create an exmpty table with predefined size
00510     for (int i = 0; i < size; ++i)
00511     {
00512         lua_pushinteger(L, i + 1); // Indexing in Lua starts from 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 // End of aspect section
00554 
00555 static int cfun_attack_rating(lua_State *L) 
00556 {
00557     int top = lua_gettop(L);
00558     // the attack_analysis table should be on top of the stack
00559     lua_getfield(L, -1, "att_ptr"); // [-2: attack_analysis; -1: pointer to attack_analysis object in c++]
00560     // now the pointer to our attack_analysis C++ object is on top
00561     attack_analysis* aa_ptr = static_cast< attack_analysis * >(lua_touserdata(L, -1)); 
00562     
00563     //[-2: attack_analysis; -1: pointer to attack_analysis object in c++]
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); // Creating a table for a pair of map_location's
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); // setting  the pair as an element of the movements table
00596     }   
00597     
00598     
00599 }
00600 
00601 static void push_attack_analysis(lua_State *L, attack_analysis& aa)
00602 {
00603     lua_newtable(L);
00604     
00605     // Pushing a pointer to the current object 
00606     lua_pushstring(L, "att_ptr");
00607     lua_pushlightuserdata(L, &aa);
00608     lua_rawset(L, -3);
00609     
00610     // Registering callback function for the rating method
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); // the main table
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         //push_map_location(L, key); // deprecated
00714         
00715         // This should be factored out. The same function is defined in data/lua/location_set.lua
00716         // At this point, it is not clear, where this(hashing) function can be placed
00717         // Implemented it this way, to test the new version of the data structure
00718         // as requested from the users of LuaAI <Nephro>
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);//stack size is now 1 [ -1: ai_context]
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);//return with stack size 0 []
00822         return NULL;
00823     }
00824     //push data table here
00825     lua_newtable(L);// stack size is 2 [ -1: new table, -2: ai as string ]
00826     lua_pushinteger(L, engine->get_readonly_context().get_side());
00827 
00828     lua_setfield(L, -2, "side");//stack size is 2 [- 1: new table; -2 ai as string]
00829 
00830     static luaL_Reg const callbacks[] = {
00831         { "attack",             &cfun_ai_execute_attack         },
00832         // Move maps
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         // End of move maps
00840         // Goals and targets
00841         { "get_targets",        &cfun_ai_get_targets            },
00842         // End of G & T
00843         // Aspects
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         // End of aspects
00865         // Validation/cache functions
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         // End of validation functions
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     //compile the ai as a closure
00896     if (!luaW_pcall(L, 1, 1, true)) {
00897         return NULL;//return with stack size 0 []
00898     }
00899 
00900     // Retrieve the ai elements table from the registry.
00901     lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00902     lua_rawget(L, LUA_REGISTRYINDEX);   //stack size is now 2  [-1: ais_table -2: f]
00903     // Push the function in the table so that it is not collected.
00904     size_t length_ai = lua_rawlen(L, -1);//length of ais_table
00905     lua_pushvalue(L, -2); //stack size is now 3: [-1: ai_context  -2: ais_table  -3: ai_context]
00906     lua_rawseti(L, -2, length_ai + 1);// ais_table[length+1]=ai_context.  stack size is now 2 [-1: ais_table  -2: ai_context]
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);//stack size is now 1 [ -1: f]
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);//return with stack size 0 []
00919         return NULL;
00920     }
00921 
00922 
00923     // Retrieve the ai elements table from the registry.
00924     lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
00925     lua_rawget(L, LUA_REGISTRYINDEX);   //stack size is now 2  [-1: ais_table -2: f]
00926     // Push the function in the table so that it is not collected.
00927     size_t length = lua_rawlen(L, -1);//length of ais_table
00928     lua_pushvalue(L, -2); //stack size is now 3: [-1: f  -2: ais_table  -3: f]
00929     lua_rawseti(L, -2, length + 1);// ais_table[length+1]=f.  stack size is now 2 [-1: ais_table  -2: f]
00930     lua_remove(L, -1);//stack size is now 1 [-1: f]
00931     lua_remove(L, -1);//stack size is now 0 []
00932     // Create the proxy C++ action handler.
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)));//stack size is now 1 [-1: ais_table key]
00940     lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table]
00941     lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_context -2: ais_table]
00942     lua_remove(L,-2);
00943 }
00944 
00945 lua_ai_context::~lua_ai_context()
00946 {
00947     // Remove the ai context from the registry, so that it can be collected.
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);//get the old stack size
00958 
00959     // Load the user function from the registry.
00960     lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));//stack size is now 1 [-1: ais_table key]
00961     lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table]
00962     lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_action  -2: ais_table]
00963     lua_remove(L, -2);//stack size is 1 [-1: ai_action]
00964     //load the lua ai context as a parameter
00965     context_.load();//stack size is 2 [-1: ai_context -2: ai_action]
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)) // @note for Crab: how much nrets should we actually have here
00973     {                   // there were 2 initially, but aspects like recruitment pattern
00974         l_obj->store(L, initial_top + 1); // return a lot of results
00975     }
00976 
00977     lua_settop(L, initial_top);//empty stack
00978 }
00979 
00980 lua_ai_action_handler::~lua_ai_action_handler()
00981 {
00982     // Remove the function from the registry, so that it can be collected.
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 } // of namespace ai
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:30 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs