Difference between revisions of "LuaAI"

From The Battle for Wesnoth Wiki
(Behavior(sticky) candidate actions)
Line 149: Line 149:
 
Here the behavior CA is added to the configuration of the AI when the event triggers. Obviously this will happen when side 2 gets its first turn, but the event can be whatever needed. The definition is very similar to a simple candidate action, but here we also filter out a unit and state that we want the behavior to be sticky. If we don't, the action will not try to remove itself, when the unit gets killed, and this could cause errors.<br />
 
Here the behavior CA is added to the configuration of the AI when the event triggers. Obviously this will happen when side 2 gets its first turn, but the event can be whatever needed. The definition is very similar to a simple candidate action, but here we also filter out a unit and state that we want the behavior to be sticky. If we don't, the action will not try to remove itself, when the unit gets killed, and this could cause errors.<br />
 
Such CA`s can also be added from inside other CA or stage code using wesnoth.wml_actions.add_ai_behavior(cfg) function.
 
Such CA`s can also be added from inside other CA or stage code using wesnoth.wml_actions.add_ai_behavior(cfg) function.
 +
 +
== Behavior function library ==
 +
Behaviors are defined using generators. A behavior generator receives arguments(unit info, configuration, etc) and returns a pair of functions: evaluator and executor. These functions are to be passed to the add_ai_behavior tag, or directly to the function.
 +
=== Patrolling ===
 +
The only behavior defined at the moment is the patrol behavior. It's also defined incorrectly and is to be fixed soon. The error is that it returns only the executor and we have to write the evaluation function manually.<br />
 +
Inclusion of the patrolling code:
 +
wesnoth.require("ai/lua/patrol.lua")
 +
Usage:
 +
patrol_rark = patrol_gen("Rark", {{x=14, y=7}, {x=15, y=7}, {x=15, y=8}, {x=14, y=8}})
 +
Note: this is only the executor, when it get's fixed, patrol_rark will be the pair of both functions.
 +
As you can see, the first argument is the name of the unit, the second is a table of coordinates of arbitrary length.

Revision as of 11:46, 11 July 2011

A page containing information on configuring the AI using Lua. NB: previous contents of the page moved to http://wiki.wesnoth.org/LuaAI(old)

Aspects

Patch r49721 enabled users to write aspects using Lua. This simplifies the definition of aspects that are meant to change depending on the game state. A good example could be aggression, which changes depending on the time of the day(since ToD affects the actual battle performance of your forces).
Static aggression:

[aspect]
	id="aggression"
	engine="lua"
	value="0.3"
[/aspect]

Dynamic aggression:

[aspect]
	id=aggression
	engine=lua
	     
	code=<<
		wesnoth.fire("store_time_of_day")
		local value = 0
		tod = tostring(wesnoth.get_variable('time_of_day').name) 
		if (tod == 'Morning') then
			value = 0.2
		else
			value = 1
		end
	
		wesnoth.fire("clear_variable", {name = "time_of_day"})
		return value
	>>      
[/aspect]

Note: the way of getting the ToD is hacky here, but I will create a more elegant method soon(Nephro).
Also note the difference between 'code' and 'value' attributes, this is important.

At the moment, it is possible to create the following aspects using Lua(the list will be constantly updated):

aggression                                   // double
attack_depth                                 // int
avoid                                        // exposed as map_location[], where map_location is a table of form {x, y}
caution                                      // double
grouping                                     // string
leader_aggression                            // double
leader_goal                                  // exposed as a config
leader_value                                 // double
number_of_possible_recruits_to_force_recruit // double
passive_leader                               // bool
passive_leader_shares_keep                   // bool
recruitment_ignore_bad_combat                // bool
recruitment_ignore_bad_movement              // bool
recruitment_pattern                          // string[]
scout_village_targeting                      // double
simple_targeting                             // bool
support_villages                             // bool
village_value                                // double
villages_per_scout                           // int



Note: simple numeric, bool and string aspect creation can be enabled just by adding a specific factory to registry.cpp, this will also soon be done.

Preload event

It is a good idea to have such a preload event in your scenario if you are intending to use Lua for AI programming or customizing. The code of this event will most probably be moved out to a macro(except for the line that requires patrol.lua, since it is not necessary).

[event]
    name=preload
    first_time_only=no
    [lua]
        code = <<
            H = wesnoth.require "lua/helper.lua"
            W = H.set_wml_action_metatable {}
            _ = wesnoth.textdomain "my-campaign" 
	    ai = {}
	    ca_counter = 0
		
            H.set_wml_var_metatable(_G)

	    wesnoth.require("ai/lua/patrol.lua")

	    >>
	[/lua]
[/event]

The code attribute can be further expanded by any Lua code needed. For example, we can set up some global variables there or include additional code libraries("wesnoth.require("ai/lua/patrol.lua")" - includes code that handles patrolling of units).

Engine code

In the engine tag you should define functions that will handle evaluation and execution of your custom candidate actions and stages. You can also run some code that is intended to be run once in the beginning.
The definition of the [engine] tag should be place inside the [ai] tag.

[engine]
    name="lua"
    code= <<
        -- your engine code here
    >>
[/engine]

Stages

Once the engine has been set up, we can start adding stages to the configuration of our AI.
To add a stage we just use the [stage] tag.

[stage]
    engine=lua
    code=<<
        -- Code for stage execution here
        -- It is better to call predefined functions for the [engine] code, 
        -- than to define the functions here, to keep the structure of the stages clear
    >>
[/stage]

Candidate actions

This is an example from the current version of the lua_ai arena. The stage with an id "ca_loop" is the RCA AI loop stage, as we can see from its name. Currently it has two candidate actions, both Lua backed.

            [stage]
                name=testing_ai_default::candidate_action_evaluation_loop
		id=ca_loop
                [candidate_action]
                    engine=lua
                    name=first
		    id=firstca
                    evaluation="return (...):candidate_action_evaluation_hello()"
                    execution="local ai, cfg = ...; ai:candidate_action_execution_hello(cfg)"
                [/candidate_action]
                [candidate_action]
                    engine=lua
                    name=second
                    evaluation="return (...):candidate_action_evaluation_hello2()"
                    execution="(...):candidate_action_execution_hello2()"
                [/candidate_action]
            [/stage]

Basically, we need to have an engine attribute, an evaluation and execution functions. The syntax (...):foo() means "call eng.foo(eng) where eng is whatever the engine code returns". We can also add, remove, modify candidate actions on the fly, using wesnoth.wml_actions.modify_ai() functionality. Behavior(sticky) candidate actions use this approach.


Behavior(sticky) candidate actions

Sometimes we need a specific unit to do a specific action in our scenario, e.g. we want a scout unit to patrol between 3 places on the map, to provide us with visibility needed. In this case we can create a sticky candidate action that will tie itself to the unit, and remove itself when the unit has died. The syntax for defining a sticky candidate action is the following:

[event]
	name=side 2 turn 1
	first_time_only=yes	
        [add_ai_behavior]
           side=2
           [filter]
                name="Rark"
           [/filter]
	   sticky=yes
	   loop_id=ca_loop
           evaluation="return patrol_eval_rark()"
           execution="patrol_rark()"
        [/add_ai_behavior]
[/event]

Here the behavior CA is added to the configuration of the AI when the event triggers. Obviously this will happen when side 2 gets its first turn, but the event can be whatever needed. The definition is very similar to a simple candidate action, but here we also filter out a unit and state that we want the behavior to be sticky. If we don't, the action will not try to remove itself, when the unit gets killed, and this could cause errors.
Such CA`s can also be added from inside other CA or stage code using wesnoth.wml_actions.add_ai_behavior(cfg) function.

Behavior function library

Behaviors are defined using generators. A behavior generator receives arguments(unit info, configuration, etc) and returns a pair of functions: evaluator and executor. These functions are to be passed to the add_ai_behavior tag, or directly to the function.

Patrolling

The only behavior defined at the moment is the patrol behavior. It's also defined incorrectly and is to be fixed soon. The error is that it returns only the executor and we have to write the evaluation function manually.
Inclusion of the patrolling code:

wesnoth.require("ai/lua/patrol.lua")

Usage:

patrol_rark = patrol_gen("Rark", {{x=14, y=7}, {x=15, y=7}, {x=15, y=8}, {x=14, y=8}})

Note: this is only the executor, when it get's fixed, patrol_rark will be the pair of both functions. As you can see, the first argument is the name of the unit, the second is a table of coordinates of arbitrary length.