LuaAI
Good lua support for Wesnoth's AI would be cool.
The role and responsibilities of ai support engine
AI is constructed from components. AI support engines (src/ai/composite/engine_*.?pp) are stateful components in the context of the ai for the specific side, responsible with taking config snippets and translating them into c++ components.
[stage] # this stage will be parsed by default cpp engine {ANYTHING_HERE_CAN_BE_CPP_ENGINE_SPECIFIC} [/stage]
[stage] engine=cpp # this stage will be parsed by default cpp engine {ANYTHING_HERE_CAN_BE_CPP_ENGINE_SPECIFIC} [/stage]
[stage] engine=fai # this stage will be parsed by formula ai engine {ANYTHING_HERE_CAN_BE_FAI_ENGINE_SPECIFIC} [/stage]
[stage] engine=lua # this stage will be parsed by lua engine {ANYTHING_HERE_CAN_BE_LUA_ENGINE_SPECIFIC} [/stage]
So, I've committed a stub lua engine , src/ai/composite/engine_lua.cpp
This engine is constructed when the ai is not yet fully initialized, so, the constructor is passed two arguments: the config of the engine (if present, i.e. when loading a savegame) and the readonly_context (which provides functions to access the game state but not to modify it)
At this point, ai aspects and ai goals are created. Supporting writing aspects and goals in lua is not first-priority (since they tend to have a simple config like 'target units standing on locations matching this SLF' or 'aggression=0.5' and can be written in plain WML), but, it would be interesting to have in the future (since some aspects handle calculation of interesting things like attack ratings)
When the ai is fully initialized, full ai_context is passed to the engine. Then, ai stages and their parts are parsed. At this point we're interested in parsing stages and candidate actions, so lua engine has to override those methods from engine which deal with parsing stages and candidate actions from config.
stage = stateful object in the context of the ai for the specific side, it's just a 'part of ai turn' with do_play_stage() method. candidate_action = stateful object in the context of the candidate action evaluation loop stage, it's 'evaluator+executor' pair (if THIS, than doing THAT has score SCORE)
Exposing game state
ai context includes functions which provide access to
# current side number # unit map # game map # information about teams, villages # information about turn and time of day # scenario info such as income per turn # current values of ai aspects (aggression, attack_depth, avoid, passive_leader, passive_leader_shares_keep, leader_aggression,caution, grouping, leader_goal, leader_value, number_of_possible_recruits_to_force_recruit, recruitment_ignore_bad_combat, recruitment_ignore_bad_movement, recruitment_pattern, scout_village_targeting, simple_targeting, support_villages, village_value, villages_per_scout,...) # action handlers (more on them below)
Exposing action handlers
- action handlers ('move,attack,recruit,recall,stop' actions from src/ai/actions.cpp must be made available to lua code. there are helper functions for that in ai_context. note that it's possible to check if the action is allowed before actually executing it. the code, when used in candidate_actions is usually similar to this:
---evaluation---
move_ = check_move_action(leader->first,keep,false); if (move_->is_ok()){ return get_score(); }
---later, if selected for execution---
move_->execute();
Note: (1) action (or the list of actions) is usually cached between evaluation and execution (2) it is possible to check if the move is 'ok' without executing it.
P.S. it is, probably, also needed to somehow prohibit modification of game state via lua handlers (i.e. prohibit calling stuff such as wesnoth.fire() from AIs). also it's important to prevent changes of state of ai for side A by ai of side B. For start,it's probably enough to prevent only accidential changes, but, if it's possible to achieve a proper separation between lua code for different AIs, it'll be a good thing.