https://wiki.wesnoth.org/api.php?action=feedcontributions&user=Gfgtdf&feedformat=atomThe Battle for Wesnoth Wiki - User contributions [en]2024-03-29T13:35:42ZUser contributionsMediaWiki 1.31.16https://wiki.wesnoth.org/index.php?title=SideWML&diff=71717SideWML2023-10-24T21:31:14Z<p>Gfgtdf: remove outdated information about controller=null</p>
<hr />
<div>{{WML Tags}}<br />
<br />
The term "side" refers to a single player in the Wesnoth turn order, which can be controlled by either a human or an AI. Every [[ScenarioWML|scenario]] must have at least one side. There is no hard limit on the number of sides a single scenario can have.<br />
<br />
Usually the number of sides in a scenario is fixed. However, the Lua function [[LuaAPI/wesnoth/sides#wesnoth.sides.create|wesnoth.sides.create]] can be used to dynamically add new sides if required.<br />
<br />
Sides in a scenario are described by the '''[side]''' tag, which recognizes the following keys and tags.<br />
<br />
== Common Keys ==<br />
<br />
These keys are always permitted in a '''[side]''' tag.<br />
<br />
* '''side''': a number. The leader of this side is placed on the tile represented by this number (see [[BuildingMaps]]). When defining sides, they must be defined in order since the side number is checked against the number of sides seen so far. Currently, the Multiplayer server rejects entering a scenario with more than 9 sides, even if those extra sides are AI sides. {{DevFeature1.13|2}} The server doesn't limit the number of sides anymore.<br />
<br />
* '''controller''' (required): how moves for this side should be inputted.<br />
** '''ai''': the Wesnoth AI makes this side's moves.<br />
** '''human''': a player controls this side's moves.<br />
** '''null''': the side doesn't get a turn to move. Events that would usually occur on the side's turn will not take place. This includes healing (ability, villages and rest) and ''side turn'' events.<br />
** '''a number''': gives this side's control to a side with '''side''' matching the number (multiplayer only). {{DevFeature1.13|2}} using a number is deprecated, use previous_save_id= instead.<br />
** Note: in multiplayer, when reading the side's data with ''[store_side]'', the value may differ between clients and using it for conditional actions may cause OOS. Discussion in https://r.wesnoth.org/p643343<br />
<br />
* '''type''': if present, the keys describing a unit (including '''type''') which will begin on the side's keep will be the remainder of the '''[side]''' tag, See [[SingleUnitWML]]. Note that if the keys '''x''', '''y''' are included, the leader will begin there regardless of keep location. If this side has a recall list from a previous level, then the recall list will be searched for a leader (using ''canrecruit=yes'') and if one is found it will be used instead of the one described in the '''[side]''' tag. Typical keys used for defining the leader unit are ''id'', ''name'' and ''unrenamable=yes'', see [[SingleUnitWML]]. The unit will automatically be set to be able to recruit.<br />
<br />
* '''recruit''': a list of unit types. At the beginning of the scenario, the side gains recruitment of these units. Units in the side recruit list can always be recruited by a leader on this side, in addition to any units in the individual leader's '''extra_recruit''' list. {{DevFeature1.13|?}} in multiplayer, unless you specify ''faction=Custom'', this will be overwritten by the recruit list from the faction.<br />
<br />
* '''gold''': the starting gold for this side. Default: 100. (If gold is carried over from a previous scenario, this value is the minimum starting gold.)<br />
<br />
* '''income''': the base income for this side. Default: 0. This is added to ''base_income'', '''[game_config]''' to determine the side's base income. (see [[GameConfigWML]]).<br />
<br />
* '''hidden''': if 'yes', side is not shown in status table.<br />
<br />
* '''fog''': if 'yes', this side cannot see any tiles it is not within vision of, except at the start. Please note that the AI currently ignores the fog.<br />
<br />
* '''fog_data''': describes the area which this team has de-fogged, using the same format as shroud_data. (This is not particularly useful when defining a side, though, as the game will recalculate fog as turns begin and end.) It is used in saved games.<br />
<br />
* '''[fog_override]''' With keys x= and y=, this records the hexes that have been cleared (multiturn) with {{tag|DirectActionsWML|lift_fog}}.<br />
<br />
* '''shroud''': if 'yes', this side cannot see any tiles it has not moved within sight of. Please note that the AI currently ignores the shroud. NOTE: with shroud=no, this team *ignores* shroud, so it is not possible to modify it using place_shroud and remove_shroud tags. If you want to do so, use "shroud=yes" and place_shroud/remove_shroud tags.<br />
<br />
* '''shroud_data''': describes the area which this team has de-shrouded. An example:<br />
|<br />
|00011111000<br />
:This would leave the first column on the map unaltered and would change the second column for 11 tiles. A '0' means: shrouded, '1' means unshrouded. You can either call an external file using {@filename} (see [[PreprocessorRef]]) or place the data in quotes. For making an external file see [[ShroudDataWML]].<br />
<br />
* '''persistent''': whether the side exists in any other scenarios. If 'yes', then ''save_id'' (see below) is used to identify the side in other scenarios. Defaults to 'yes' for sides with a human controller, and 'no' for ai controlled sides.<br />
<br />
* '''save_id''': defaults to the leader's ''id'' if available, 'Unknown' otherwise. The ID of the side with respect to the previous and next scenarios. Used to carry over the side's recall list (including the side's leader), recruitment list, and starting gold from scenario to scenario. Also used for the side's displayed name in the victory gold-calculation dialog.<br />
<br />
* '''previous_save_id''': {{DevFeature1.13|2}} defaults to ''save_id''. Only used in mp games, specially mp campaigns. This attribute specifies which user should play this side by default. For example if a side has previous_save_id="Konrad" then the side will be assigned to that player who played the side with the save_id="Konrad" in the previous level. If used in the first scenario, multiple sides with the same ''previous_save_id'' will be assigned to the same player.<br />
<br />
* '''team_name''': a non translatable string representing the team's description. Sides with the same team_name are allied. Default ''side''. ''team_name'' is now a comma-separated list of teams that the side is on.<br />
<br />
* '''user_team_name''': a translatable string representing the team's description. This has no effect on alliances. Default ''team_name''.<br />
<br />
* '''current_player''': a translatable string representing the player's or leader's name. Defaults to the leader's id; if the side's leader is a human player in multiplayer, the default is the player's username. {{DevFeature1.13|0}} This field is now always the player name (mp server nick) it impossible to change it with wml/lua. {{DevFeature1.13|5}} You can use ''side_name'' instead to specify the name for the side (which is then used in new turn dialogs, statisitc dialogs etc.)<br />
<br />
* '''side_name''': {{DevFeature1.13|5}} a translatable string representing the name of the side, used for example in the new turn dialog. Defaults to ''name'' if the side was inside a '''[scenario]''' and to the player's name if the side was inside a '''[multiplayer]'''.<br />
<br />
* '''color''': May be either a numeric color index or a color name (e.g. 'blue', 'purple', 'orange', etc.). The numeric form is deprecated. The default list of numbers and corresponding colors can be found in data/core/team_colors.cfg. Can also be an inline color range (the rgb key from [[GameConfigWML#Color_Palettes]]).<br />
<br />
* '''flag''': a custom flag animation to use instead of the default one to mark captured villages. An automatic side-coloring is applied.<br />
** Example animation that has three frames and loops every 750ms: ''flag=misc/myflag-[1~3].png:750''<br />
<br />
* '''flag_icon''': a custom flag icon to indicate the side playing in the statusbar (a size of 24x16 is recommended). An automatic side-coloring is applied.<br />
<br />
* '''village_gold''': the amount of gold given to this side per village it controls per turn. Default specified in ''village_income'', '''[game_config]''' ([[GameConfigWML]]).<br />
<br />
* '''village_support''': the number of unit levels this side is able to support (does not pay upkeep on) per village it controls. Default specified in ''village_support'', '''[game_config]''' ([[GameConfigWML]]).<br />
<br />
* '''recall_cost''': the amount of gold it costs to recall a unit. Default specified in ''recall_cost'', '''[game_config]''' ([[GameConfigWML]]). {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
<br />
* '''share_maps''': whether sides allied with this side see all terrains that this side sees, if they are on shroud. {{DevFeature1.13|1}} This has been deprecated in favor of share_vision (see below).<br />
<br />
* '''share_view''': whether sides allied with this side see the units that this side sees, if they are on FoW (fog). {{DevFeature1.13|1}} This has been deprecated in favor of share_vision (see below).<br />
<br />
* '''share_vision''': {{DevFeature1.13|1}} all/shroud/none. If ''all'', both shroud and fog view will be shared by this side. If ''shroud'', only shroud view will be shared. If ''none'', the view is not shared.<br />
<br />
* '''scroll_to_leader''': optional. If 'no', scroll to the leader is not performed on the start of each turn. (default: yes)<br />
<br />
* '''suppress_end_turn_confirmation''': If "yes", then the player will not be asked to confirm ending their turn even if they have not done anything. This is provided for some (probably few) user-made scenarios in which players often skip their turns. (default: no)<br />
<br />
* '''[ai]''' if '''controller=ai''', gives parameters to the AI. See [[AiWML]].<br />
<br />
* '''[village]''' describes a village the side begins in control of.<br />
** ''x'', ''y'' the location of the village. If the pair of coordinates is not a village or is duplicated in another '''[village]''' tag, behaviour is undefined. Recent game engine or wmllint should warn about these.<br />
<br />
* '''[unit]''' describes a unit which begins on the side. See [[SingleUnitWML]]. If the side has a recall list and the unit is not given a location, it will start on the recall list. Note that the ''side'' attribute under '''[unit]''' will be ignored, as the side will come from the ''side'' attribute of '''[side]'''.<br />
<br />
* '''[leader]''' describes the leader for the side, basically same as '''[unit]''' except that ''canrecruit'' will default to yes and current position to the side starting location if not specified. {{DevFeature1.17|17}} Furthermore, if left out, the '''name''' and '''save_id''' attributes in '''[side]''' will be set to the '''name''' and '''id''' attributes in the first '''[leader]''' tag.<br />
<br />
* '''defeat_condition''' Specifies when a side is considered ''defeated'' this is checked ''for all sides'', after every player action and at the beginning of every turn.<br />
** '''no_leader_left''': (default) The side is considered defeated if it has no units with canrecruit=yes<br />
** '''no_units_left''': The side is defeated as soon as it has no units left.<br />
** '''never''': The side is never considered defeated.<br />
** '''always''': The side is always considered defeated.<br />
<br />
: For the meaning and significance of ''defeated'', see [[ScenarioWML#Scenario_End_Conditions]]<br />
<br />
== Multiplayer Keys ==<br />
<br />
These keys are only permitted in a '''[side]''' tag for a '''[multiplayer]''' scenario.<br />
<br />
* '''allow_player''': if false then this side will not be allowed to be modified and will be hidden during game creation. False also prevents this side from being included in shuffle sides. Defaults to yes.<br />
<br />
* '''disallow_observers''': prevents observers from seeing this side turn. (default: no)<br />
<br />
* '''disallow_shuffle''': {{DevFeature1.13|0}} do not shuffle this side if the "shuffle sides" option is used. (Usually all playable sides are shuffled.) (default: no)<br />
<br />
* '''chose_random''': {{DevFeature1.13|0}} indicates if a side chose a random faction during creation <br />
<br />
* '''controller_lock''': if true then this side's controller ("Player/Type") modification is limited. It is bound to the '''controller''' attribute in [[SideWML]].<br />
<br />
* '''team_lock''': if true then this side's team is not allowed to be modified.<br />
<br />
* '''color_lock''': if true then this side's color is not allowed to be modified.<br />
<br />
* '''gold_lock''': if true then this side's gold is not allowed to be modified. <br />
<br />
* '''income_lock''': if true then this side's income is not allowed to be modified.<br />
<br />
* '''faction_lock''': if true then this side's faction is not allowed to be modified.<br />
<br />
* '''no_leader''': if 'yes', prevents the engine from generating a leader from the multiplayer faction, basically an alias of '''leader_lock'''<br />
<br />
* '''leader_lock''': if true then this side's leader (type or gender) is not allowed to be modified.<br />
<br />
* '''faction''': if a valid faction id is provided then this side's faction will default to it in the game setup screen. {{DevFeature1.13|?}} if this key isn't included in the ''[side]'' then a random faction will be chosen, and the side's recruit list set from the faction. To use a custom ''recruit'' list, you must also specify ''faction=Custom''.<br />
<br />
* '''faction_from_recruit''': if true then this side will be locked to the faction that matches the recruits better.<br />
<br />
N.B. the ''lock'' attributes use [[ScenarioWML]] '''force_lock_settings''' as their default value. I.e. if no value to ''lock'' was set, it will take '''force_lock_settings''' value.<br />
<br />
== See Also ==<br />
* [[EraWML]]<br />
* [[ScenarioWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=SideWML&diff=71060SideWML2023-05-01T17:34:29Z<p>Gfgtdf: /* Common Keys */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
The term "side" refers to a single player in the Wesnoth turn order, which can be controlled by either a human or an AI. Every [[ScenarioWML|scenario]] must have at least one side. There is no hard limit on the number of sides a single scenario can have.<br />
<br />
Usually the number of sides in a scenario is fixed. However, the Lua function [[LuaAPI/wesnoth/sides#wesnoth.sides.create|wesnoth.sides.create]] can be used to dynamically add new sides if required.<br />
<br />
Sides in a scenario are described by the '''[side]''' tag, which recognizes the following keys and tags.<br />
<br />
== Common Keys ==<br />
<br />
These keys are always permitted in a '''[side]''' tag.<br />
<br />
* '''side''': a number. The leader of this side is placed on the tile represented by this number (see [[BuildingMaps]]). When defining sides, they must be defined in order since the side number is checked against the number of sides seen so far. Currently, the Multiplayer server rejects entering a scenario with more than 9 sides, even if those extra sides are AI sides. {{DevFeature1.13|2}} The server doesn't limit the number of sides anymore.<br />
<br />
* '''controller''' (required): how moves for this side should be inputted.<br />
** '''ai''': the Wesnoth AI makes this side's moves.<br />
** '''human''': a player controls this side's moves.<br />
** '''null''': the side doesn't get a turn to move and doesn't have a leader generated from the contents of the [side] tag. (It still can get units from [unit] tags in the [side] tag.) Events that would usually occur on the side's turn will not take place. This includes healing (ability, villages and rest) and ''side turn'' events.<br />
** '''a number''': gives this side's control to a side with '''side''' matching the number (multiplayer only). {{DevFeature1.13|2}} using a number is deprecated, use previous_save_id= instead.<br />
** Note: in multiplayer, when reading the side's data with ''[store_side]'', the value may differ between clients and using it for conditional actions may cause OOS. Discussion in https://r.wesnoth.org/p643343<br />
<br />
* '''type''': if present, the keys describing a unit (including '''type''') which will begin on the side's keep will be the remainder of the '''[side]''' tag, See [[SingleUnitWML]]. Note that if the keys '''x''', '''y''' are included, the leader will begin there regardless of keep location. If this side has a recall list from a previous level, then the recall list will be searched for a leader (using ''canrecruit=yes'') and if one is found it will be used instead of the one described in the '''[side]''' tag. Typical keys used for defining the leader unit are ''id'', ''name'' and ''unrenamable=yes'', see [[SingleUnitWML]]. The unit will automatically be set to be able to recruit.<br />
<br />
* '''recruit''': a list of unit types. At the beginning of the scenario, the side gains recruitment of these units. Units in the side recruit list can always be recruited by a leader on this side, in addition to any units in the individual leader's '''extra_recruit''' list. {{DevFeature1.13|?}} in multiplayer, unless you specify ''faction=Custom'', this will be overwritten by the recruit list from the faction.<br />
<br />
* '''gold''': the starting gold for this side. Default: 100. (If gold is carried over from a previous scenario, this value is the minimum starting gold.)<br />
<br />
* '''income''': the base income for this side. Default: 0. This is added to ''base_income'', '''[game_config]''' to determine the side's base income. (see [[GameConfigWML]]).<br />
<br />
* '''hidden''': if 'yes', side is not shown in status table.<br />
<br />
* '''fog''': if 'yes', this side cannot see any tiles it is not within vision of, except at the start. Please note that the AI currently ignores the fog.<br />
<br />
* '''fog_data''': describes the area which this team has de-fogged, using the same format as shroud_data. (This is not particularly useful when defining a side, though, as the game will recalculate fog as turns begin and end.) It is used in saved games.<br />
<br />
* '''[fog_override]''' With keys x= and y=, this records the hexes that have been cleared (multiturn) with {{tag|DirectActionsWML|lift_fog}}.<br />
<br />
* '''shroud''': if 'yes', this side cannot see any tiles it has not moved within sight of. Please note that the AI currently ignores the shroud. NOTE: with shroud=no, this team *ignores* shroud, so it is not possible to modify it using place_shroud and remove_shroud tags. If you want to do so, use "shroud=yes" and place_shroud/remove_shroud tags.<br />
<br />
* '''shroud_data''': describes the area which this team has de-shrouded. An example:<br />
|<br />
|00011111000<br />
:This would leave the first column on the map unaltered and would change the second column for 11 tiles. A '0' means: shrouded, '1' means unshrouded. You can either call an external file using {@filename} (see [[PreprocessorRef]]) or place the data in quotes. For making an external file see [[ShroudDataWML]].<br />
<br />
* '''persistent''': whether the side exists in any other scenarios. If 'yes', then ''save_id'' (see below) is used to identify the side in other scenarios. Defaults to 'yes' for sides with a human controller, and 'no' for ai controlled sides.<br />
<br />
* '''save_id''': defaults to the leader's ''id'' if available, 'Unknown' otherwise. The ID of the side with respect to the previous and next scenarios. Used to carry over the side's recall list (including the side's leader), recruitment list, and starting gold from scenario to scenario. Also used for the side's displayed name in the victory gold-calculation dialog.<br />
<br />
* '''previous_save_id''': {{DevFeature1.13|2}} defaults to ''save_id''. Only used in mp games, specially mp campaigns. This attribute specifies which user should play this side by default. For example if a side has previous_save_id="Konrad" then the side will be assigned to that player who played the side with the save_id="Konrad" in the previous level. If used in the first scenario, multiple sides with the same ''previous_side_id'' will be assigned to the same player.<br />
<br />
* '''team_name''': a non translatable string representing the team's description. Sides with the same team_name are allied. Default ''side''. ''team_name'' is now a comma-separated list of teams that the side is on.<br />
<br />
* '''user_team_name''': a translatable string representing the team's description. This has no effect on alliances. Default ''team_name''.<br />
<br />
* '''current_player''': a translatable string representing the player's or leader's name. Defaults to the leader's id; if the side's leader is a human player in multiplayer, the default is the player's username. {{DevFeature1.13|0}} This field is now always the player name (mp server nick) it impossible to change it with wml/lua. {{DevFeature1.13|5}} You can use ''side_name'' instead to specify the name for the side (which is then used in new turn dialogs, statisitc dialogs etc.)<br />
<br />
* '''side_name''': {{DevFeature1.13|5}} a translatable string representing the name of the side, used for example in the new turn dialog. Defaults to ''name'' if the side was inside a '''[scenario]''' and to the player's name if the side was inside a '''[multiplayer]'''.<br />
<br />
* '''color''': May be either a numeric color index or a color name (e.g. 'blue', 'purple', 'orange', etc.). The numeric form is deprecated. The default list of numbers and corresponding colors can be found in data/core/team_colors.cfg. Can also be an inline color range (the rgb key from [[GameConfigWML#Color_Palettes]]).<br />
<br />
* '''flag''': a custom flag animation to use instead of the default one to mark captured villages. An automatic side-coloring is applied.<br />
** Example animation that has three frames and loops every 750ms: ''flag=misc/myflag-[1~3].png:750''<br />
<br />
* '''flag_icon''': a custom flag icon to indicate the side playing in the statusbar (a size of 24x16 is recommended). An automatic side-coloring is applied.<br />
<br />
* '''village_gold''': the amount of gold given to this side per village it controls per turn. Default specified in ''village_income'', '''[game_config]''' ([[GameConfigWML]]).<br />
<br />
* '''village_support''': the number of unit levels this side is able to support (does not pay upkeep on) per village it controls. Default specified in ''village_support'', '''[game_config]''' ([[GameConfigWML]]).<br />
<br />
* '''recall_cost''': the amount of gold it costs to recall a unit. Default specified in ''recall_cost'', '''[game_config]''' ([[GameConfigWML]]). {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
<br />
* '''share_maps''': whether sides allied with this side see all terrains that this side sees, if they are on shroud. {{DevFeature1.13|1}} This has been deprecated in favor of share_vision (see below).<br />
<br />
* '''share_view''': whether sides allied with this side see the units that this side sees, if they are on FoW (fog). {{DevFeature1.13|1}} This has been deprecated in favor of share_vision (see below).<br />
<br />
* '''share_vision''': {{DevFeature1.13|1}} all/shroud/none. If ''all'', both shroud and fog view will be shared by this side. If ''shroud'', only shroud view will be shared. If ''none'', the view is not shared.<br />
<br />
* '''scroll_to_leader''': optional. If 'no', scroll to the leader is not performed on the start of each turn. (default: yes)<br />
<br />
* '''suppress_end_turn_confirmation''': If "yes", then the player will not be asked to confirm ending their turn even if they have not done anything. This is provided for some (probably few) user-made scenarios in which players often skip their turns. (default: no)<br />
<br />
* '''[ai]''' if '''controller=ai''', gives parameters to the AI. See [[AiWML]].<br />
<br />
* '''[village]''' describes a village the side begins in control of.<br />
** ''x'', ''y'' the location of the village. If the pair of coordinates is not a village or is duplicated in another '''[village]''' tag, behaviour is undefined. Recent game engine or wmllint should warn about these.<br />
<br />
* '''[unit]''' describes a unit which begins on the side. See [[SingleUnitWML]]. If the side has a recall list and the unit is not given a location, it will start on the recall list. Note that the ''side'' attribute under '''[unit]''' will be ignored, as the side will come from the ''side'' attribute of '''[side]'''.<br />
<br />
* '''[leader]''' describes the leader for the side, basically same as '''[unit]''' except that ''canrecruit'' will default to yes and current position to the side starting location if not specified. {{DevFeature1.17|17}} furthermore if left out the '''name''' and '''save_id''' attributes in '''[side]''' will be set to the '''name''' and '''id''' attributes in '''[leader]'''<br />
<br />
* '''defeat_condition''' Specifies when a side is considered ''defeated'' this is checked ''for all sides'', after every player action and at the beginning of every turn.<br />
** '''no_leader_left''': (default) The side is considered defeated if it has no units with canrecruit=yes<br />
** '''no_units_left''': The side is defeated as soon as it has no units left.<br />
** '''never''': The side is never considered defeated.<br />
** '''always''': The side is always considered defeated.<br />
<br />
: For the meaning and significance of ''defeated'', see [[ScenarioWML#Scenario_End_Conditions]]<br />
<br />
== Multiplayer Keys ==<br />
<br />
These keys are only permitted in a '''[side]''' tag for a '''[multiplayer]''' scenario.<br />
<br />
* '''allow_player''': if false then this side will not be allowed to be modified and will be hidden during game creation. False also prevents this side from being included in shuffle sides. Defaults to yes.<br />
<br />
* '''disallow_observers''': prevents observers from seeing this side turn. (default: no)<br />
<br />
* '''disallow_shuffle''': {{DevFeature1.13|0}} do not shuffle this side if the "shuffle sides" option is used. (Usually all playable sides are shuffled.) (default: no)<br />
<br />
* '''chose_random''': {{DevFeature1.13|0}} indicates if a side chose a random faction during creation <br />
<br />
* '''controller_lock''': if true then this side's controller ("Player/Type") modification is limited. It is bound to the '''controller''' attribute in [[SideWML]].<br />
<br />
* '''team_lock''': if true then this side's team is not allowed to be modified.<br />
<br />
* '''color_lock''': if true then this side's color is not allowed to be modified.<br />
<br />
* '''gold_lock''': if true then this side's gold is not allowed to be modified. <br />
<br />
* '''income_lock''': if true then this side's income is not allowed to be modified.<br />
<br />
* '''faction_lock''': if true then this side's faction is not allowed to be modified.<br />
<br />
* '''no_leader''': if 'yes', prevents the engine from generating a leader from the multiplayer faction, basically an alias of '''leader_lock'''<br />
<br />
* '''leader_lock''': if true then this side's leader (type or gender) is not allowed to be modified.<br />
<br />
* '''faction''': if a valid faction id is provided then this side's faction will default to it in the game setup screen. {{DevFeature1.13|?}} if this key isn't included in the ''[side]'' then a random faction will be chosen, and the side's recruit list set from the faction. To use a custom ''recruit'' list, you must also specify ''faction=Custom''.<br />
<br />
* '''faction_from_recruit''': if true then this side will be locked to the faction that matches the recruits better.<br />
<br />
N.B. the ''lock'' attributes use [[ScenarioWML]] '''force_lock_settings''' as their default value. I.e. if no value to ''lock'' was set, it will take '''force_lock_settings''' value.<br />
<br />
== See Also ==<br />
* [[EraWML]]<br />
* [[ScenarioWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=SideWML&diff=71059SideWML2023-05-01T17:29:55Z<p>Gfgtdf: /* Multiplayer Keys */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
The term "side" refers to a single player in the Wesnoth turn order, which can be controlled by either a human or an AI. Every [[ScenarioWML|scenario]] must have at least one side. There is no hard limit on the number of sides a single scenario can have.<br />
<br />
Usually the number of sides in a scenario is fixed. However, the Lua function [[LuaAPI/wesnoth/sides#wesnoth.sides.create|wesnoth.sides.create]] can be used to dynamically add new sides if required.<br />
<br />
Sides in a scenario are described by the '''[side]''' tag, which recognizes the following keys and tags.<br />
<br />
== Common Keys ==<br />
<br />
These keys are always permitted in a '''[side]''' tag.<br />
<br />
* '''side''': a number. The leader of this side is placed on the tile represented by this number (see [[BuildingMaps]]). When defining sides, they must be defined in order since the side number is checked against the number of sides seen so far. Currently, the Multiplayer server rejects entering a scenario with more than 9 sides, even if those extra sides are AI sides. {{DevFeature1.13|2}} The server doesn't limit the number of sides anymore.<br />
<br />
* '''controller''' (required): how moves for this side should be inputted.<br />
** '''ai''': the Wesnoth AI makes this side's moves.<br />
** '''human''': a player controls this side's moves.<br />
** '''null''': the side doesn't get a turn to move and doesn't have a leader generated from the contents of the [side] tag. (It still can get units from [unit] tags in the [side] tag.) Events that would usually occur on the side's turn will not take place. This includes healing (ability, villages and rest) and ''side turn'' events.<br />
** '''a number''': gives this side's control to a side with '''side''' matching the number (multiplayer only). {{DevFeature1.13|2}} using a number is deprecated, use previous_save_id= instead.<br />
** Note: in multiplayer, when reading the side's data with ''[store_side]'', the value may differ between clients and using it for conditional actions may cause OOS. Discussion in https://r.wesnoth.org/p643343<br />
<br />
* '''no_leader''': if 'no' (default), then keys describing a unit which will begin on the side's keep will be the remainder of the '''[side]''' tag, See [[SingleUnitWML]]. Note that if the keys '''x''', '''y''' are included, the leader will begin there regardless of keep location. If this side has a recall list from a previous level, then the recall list will be searched for a leader (using ''canrecruit=yes'') and if one is found it will be used instead of the one described in the '''[side]''' tag. Typical keys used for defining the leader unit are ''type'' (mandatory), ''id'', ''name'' and ''unrenamable=yes'', see [[SingleUnitWML]]. The unit will automatically be set to be able to recruit.<br />
<br />
* '''recruit''': a list of unit types. At the beginning of the scenario, the side gains recruitment of these units. Units in the side recruit list can always be recruited by a leader on this side, in addition to any units in the individual leader's '''extra_recruit''' list. {{DevFeature1.13|?}} in multiplayer, unless you specify ''faction=Custom'', this will be overwritten by the recruit list from the faction.<br />
<br />
* '''gold''': the starting gold for this side. Default: 100. (If gold is carried over from a previous scenario, this value is the minimum starting gold.)<br />
<br />
* '''income''': the base income for this side. Default: 0. This is added to ''base_income'', '''[game_config]''' to determine the side's base income. (see [[GameConfigWML]]).<br />
<br />
* '''hidden''': if 'yes', side is not shown in status table.<br />
<br />
* '''fog''': if 'yes', this side cannot see any tiles it is not within vision of, except at the start. Please note that the AI currently ignores the fog.<br />
<br />
* '''fog_data''': describes the area which this team has de-fogged, using the same format as shroud_data. (This is not particularly useful when defining a side, though, as the game will recalculate fog as turns begin and end.) It is used in saved games.<br />
<br />
* '''[fog_override]''' With keys x= and y=, this records the hexes that have been cleared (multiturn) with {{tag|DirectActionsWML|lift_fog}}.<br />
<br />
* '''shroud''': if 'yes', this side cannot see any tiles it has not moved within sight of. Please note that the AI currently ignores the shroud. NOTE: with shroud=no, this team *ignores* shroud, so it is not possible to modify it using place_shroud and remove_shroud tags. If you want to do so, use "shroud=yes" and place_shroud/remove_shroud tags.<br />
<br />
* '''shroud_data''': describes the area which this team has de-shrouded. An example:<br />
|<br />
|00011111000<br />
:This would leave the first column on the map unaltered and would change the second column for 11 tiles. A '0' means: shrouded, '1' means unshrouded. You can either call an external file using {@filename} (see [[PreprocessorRef]]) or place the data in quotes. For making an external file see [[ShroudDataWML]].<br />
<br />
* '''persistent''': whether the side exists in any other scenarios. If 'yes', then ''save_id'' (see below) is used to identify the side in other scenarios. Defaults to 'yes' for sides with a human controller, and 'no' for ai controlled sides.<br />
<br />
* '''save_id''': defaults to the leader's ''id'' if available, 'Unknown' otherwise. The ID of the side with respect to the previous and next scenarios. Used to carry over the side's recall list (including the side's leader), recruitment list, and starting gold from scenario to scenario. Also used for the side's displayed name in the victory gold-calculation dialog.<br />
<br />
* '''previous_save_id''': {{DevFeature1.13|2}} defaults to ''save_id''. Only used in mp games, specially mp campaigns. This attribute specifies which user should play this side by default. For example if a side has previous_save_id="Konrad" then the side will be assigned to that player who played the side with the save_id="Konrad" in the previous level. If used in the first scenario, multiple sides with the same ''previous_side_id'' will be assigned to the same player.<br />
<br />
* '''team_name''': a non translatable string representing the team's description. Sides with the same team_name are allied. Default ''side''. ''team_name'' is now a comma-separated list of teams that the side is on.<br />
<br />
* '''user_team_name''': a translatable string representing the team's description. This has no effect on alliances. Default ''team_name''.<br />
<br />
* '''current_player''': a translatable string representing the player's or leader's name. Defaults to the leader's id; if the side's leader is a human player in multiplayer, the default is the player's username. {{DevFeature1.13|0}} This field is now always the player name (mp server nick) it impossible to change it with wml/lua. {{DevFeature1.13|5}} You can use ''side_name'' instead to specify the name for the side (which is then used in new turn dialogs, statisitc dialogs etc.)<br />
<br />
* '''side_name''': {{DevFeature1.13|5}} a translatable string representing the name of the side, used for example in the new turn dialog. Defaults to ''name'' if the side was inside a '''[scenario]''' and to the player's name if the side was inside a '''[multiplayer]'''.<br />
<br />
* '''color''': May be either a numeric color index or a color name (e.g. 'blue', 'purple', 'orange', etc.). The numeric form is deprecated. The default list of numbers and corresponding colors can be found in data/core/team_colors.cfg. Can also be an inline color range (the rgb key from [[GameConfigWML#Color_Palettes]]).<br />
<br />
* '''flag''': a custom flag animation to use instead of the default one to mark captured villages. An automatic side-coloring is applied.<br />
** Example animation that has three frames and loops every 750ms: ''flag=misc/myflag-[1~3].png:750''<br />
<br />
* '''flag_icon''': a custom flag icon to indicate the side playing in the statusbar (a size of 24x16 is recommended). An automatic side-coloring is applied.<br />
<br />
* '''village_gold''': the amount of gold given to this side per village it controls per turn. Default specified in ''village_income'', '''[game_config]''' ([[GameConfigWML]]).<br />
<br />
* '''village_support''': the number of unit levels this side is able to support (does not pay upkeep on) per village it controls. Default specified in ''village_support'', '''[game_config]''' ([[GameConfigWML]]).<br />
<br />
* '''recall_cost''': the amount of gold it costs to recall a unit. Default specified in ''recall_cost'', '''[game_config]''' ([[GameConfigWML]]). {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
<br />
* '''share_maps''': whether sides allied with this side see all terrains that this side sees, if they are on shroud. {{DevFeature1.13|1}} This has been deprecated in favor of share_vision (see below).<br />
<br />
* '''share_view''': whether sides allied with this side see the units that this side sees, if they are on FoW (fog). {{DevFeature1.13|1}} This has been deprecated in favor of share_vision (see below).<br />
<br />
* '''share_vision''': {{DevFeature1.13|1}} all/shroud/none. If ''all'', both shroud and fog view will be shared by this side. If ''shroud'', only shroud view will be shared. If ''none'', the view is not shared.<br />
<br />
* '''scroll_to_leader''': optional. If 'no', scroll to the leader is not performed on the start of each turn. (default: yes)<br />
<br />
* '''suppress_end_turn_confirmation''': If "yes", then the player will not be asked to confirm ending their turn even if they have not done anything. This is provided for some (probably few) user-made scenarios in which players often skip their turns. (default: no)<br />
<br />
* '''[ai]''' if '''controller=ai''', gives parameters to the AI. See [[AiWML]].<br />
<br />
* '''[village]''' describes a village the side begins in control of.<br />
** ''x'', ''y'' the location of the village. If the pair of coordinates is not a village or is duplicated in another '''[village]''' tag, behaviour is undefined. Recent game engine or wmllint should warn about these.<br />
<br />
* '''[unit]''' describes a unit which begins on the side. See [[SingleUnitWML]]. If the side has a recall list and the unit is not given a location, it will start on the recall list. Note that the ''side'' attribute under '''[unit]''' will be ignored, as the side will come from the ''side'' attribute of '''[side]'''.<br />
<br />
* '''[leader]''' same as '''[unit]''' except that ''canrecruit'' will default to yes and current position to the side starting location if not specified.<br />
<br />
* '''defeat_condition''' Specifies when a side is considered ''defeated'' this is checked ''for all sides'', after every player action and at the beginning of every turn.<br />
** '''no_leader_left''': (default) The side is considered defeated if it has no units with canrecruit=yes<br />
** '''no_units_left''': The side is defeated as soon as it has no units left.<br />
** '''never''': The side is never considered defeated.<br />
** '''always''': The side is always considered defeated.<br />
<br />
: For the meaning and significance of ''defeated'', see [[ScenarioWML#Scenario_End_Conditions]]<br />
<br />
== Multiplayer Keys ==<br />
<br />
These keys are only permitted in a '''[side]''' tag for a '''[multiplayer]''' scenario.<br />
<br />
* '''allow_player''': if false then this side will not be allowed to be modified and will be hidden during game creation. False also prevents this side from being included in shuffle sides. Defaults to yes.<br />
<br />
* '''disallow_observers''': prevents observers from seeing this side turn. (default: no)<br />
<br />
* '''disallow_shuffle''': {{DevFeature1.13|0}} do not shuffle this side if the "shuffle sides" option is used. (Usually all playable sides are shuffled.) (default: no)<br />
<br />
* '''chose_random''': {{DevFeature1.13|0}} indicates if a side chose a random faction during creation <br />
<br />
* '''controller_lock''': if true then this side's controller ("Player/Type") modification is limited. It is bound to the '''controller''' attribute in [[SideWML]].<br />
<br />
* '''team_lock''': if true then this side's team is not allowed to be modified.<br />
<br />
* '''color_lock''': if true then this side's color is not allowed to be modified.<br />
<br />
* '''gold_lock''': if true then this side's gold is not allowed to be modified. <br />
<br />
* '''income_lock''': if true then this side's income is not allowed to be modified.<br />
<br />
* '''faction_lock''': if true then this side's faction is not allowed to be modified.<br />
<br />
* '''no_leader''': if 'yes', prevents the engine from generating a leader from the multiplayer faction, basically an alias of '''leader_lock'''<br />
<br />
* '''leader_lock''': if true then this side's leader (type or gender) is not allowed to be modified.<br />
<br />
* '''faction''': if a valid faction id is provided then this side's faction will default to it in the game setup screen. {{DevFeature1.13|?}} if this key isn't included in the ''[side]'' then a random faction will be chosen, and the side's recruit list set from the faction. To use a custom ''recruit'' list, you must also specify ''faction=Custom''.<br />
<br />
* '''faction_from_recruit''': if true then this side will be locked to the faction that matches the recruits better.<br />
<br />
N.B. the ''lock'' attributes use [[ScenarioWML]] '''force_lock_settings''' as their default value. I.e. if no value to ''lock'' was set, it will take '''force_lock_settings''' value.<br />
<br />
== See Also ==<br />
* [[EraWML]]<br />
* [[ScenarioWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=PreprocessorRef&diff=70727PreprocessorRef2023-03-27T18:09:32Z<p>Gfgtdf: /* Built-in macros */</p>
<hr />
<div>{{WML Tags}}<br />
== Overview ==<br />
<br />
Wesnoth loads just one configuration file directly: '''data/_main.cfg'''. However, the '''WML preprocessor''' allows the inclusion of more files. Whenever a WML file is read by Wesnoth, it is passed through the preprocessor.<br />
<br />
The preprocessor can interpret a simple language of string expansions known as ''macros''. A macro should always be defined '''before''' the place where it needs to be used.<br />
<br />
The preprocessor is applied recursively, so included files will be parsed for macros, and after macro expansion will be parsed for macros again, and so on. As a result, you should not write a recursive macro that references itself, because it will cause errors (but, alas, not necessarily error messages).<br />
<br />
== Preprocessor directives ==<br />
<br />
The following directives are used to create and use ''macros'', i.e. shortcuts which reduce repetition of information. See [https://www.wesnoth.org/macro-reference.html the macro reference] for the list of predefined core macros.<br />
<br />
Macros have scoping rules such that addons have separate preprocessing contexts, meaning that they can be overridden however an author of UMC wishes to override them, without worrying about breaking other add-ons.<br />
<br />
The preprocessor has changed several times, so don't expect old Wesnoth versions to behave exactly the same as the current stable and development series.<br />
<br />
'''Note:''' In multiplayer scenarios, these directives will appear to work only for the host and not for other clients. This is because the preprocessor is run only on the host, and the clients receive the resultant WML from the server. It's particularly important to keep this in mind before using preprocessor conditionals.<br />
<br />
=== #define ===<br />
<br />
'''Syntax: #define ''symbol'' [''parameters''] ''<newline>'' ''substitution'' #enddef'''<br />
<br />
All subsequent occurences of '''{''symbol'' [''arguments'']}''' (see below) will be replaced by the contents of the ''substitution'' block, with all occurrences of any parameter {''parameter''} within ''substitution'' replaced by the corresponding value in ''arguments''. For example, the ENEMY_UNIT macro for the [[#Macro inclusions|macro inclusion]] example below could be defined as follows:<br />
<br />
<syntaxhighlight lang="wml"><br />
#define ENEMY_UNIT TYPE X Y<br />
## the ordering above is important, since the preprocessor does not distinguish<br />
## data into different types; only the ordering is used to determine which<br />
## arguments apply to which parameters.<br />
[unit]<br />
type={TYPE} ## the unit will be of type TYPE, so different<br />
## instantiations<br />
## of this macro can create different units.<br />
x={X}<br />
y={Y}<br />
side=2 ## the unit will be an enemy, regardless of the parameter<br />
## values. This reduces "repetition of information",<br />
## since it is no longer necessary to specify<br />
## each created unit as an enemy.<br />
[/unit]<br />
#enddef<br />
</syntaxhighlight><br />
<br />
(See [[SingleUnitWML]] for further information on creating units using WML.)<br />
<br />
'''Note:''' The final line break before #enddef is included in the expansion. This means that if the symbol is used in the middle of a line, you should place the #enddef immediately after the value has ended, without a line break in between. <br />
<br />
'''Important note:''' Although macros may look like they're simplifying the code, they do not help with wml bloating. Macros are very good at ''disguising'' WML bloat, but they do nothing to ''alleviate'' it. So instead of using macros to generate redundant and repetitive instructions, you should be considering how to eliminate redundancy through programming techniques of abstraction. The most popular way to improve your code is using custom [[EventWML|events]] and [[InternalActionsWML#.5Bfire_event.5D|fire_event]] tags. See also: [[Wml_optimisation]].<br />
<br />
=== #arg ===<br />
<br />
{{DevFeature1.13|7}} <br />
<br />
'''Syntax: #arg ''symbol'' ''<newline>'' ''default value'' #endarg'''<br />
<br />
Defines an optional argument for a macro along with its default value. Optional arguments can be used to make a macro more flexible and to allow its user to specify certain parameters only when necessary.<br />
<br />
For example, one could define a shortcut macro for [message] with only one required argument (the text displayed), but several optional ones:<br />
<br />
<syntaxhighlight lang="wml"><br />
#define MESSAGE TEXT<br />
<br />
#arg SPEAKER_ID<br />
narrator<br />
#endarg<br />
<br />
#arg CAPTION<br />
#endarg<br />
<br />
#arg SOUND<br />
#endarg<br />
<br />
#arg IMG<br />
#endarg<br />
<br />
[message]<br />
speaker={SPEAKER_ID}<br />
message={TEXT}<br />
caption={CAPTION}<br />
sound={SOUND}<br />
image={IMG}<br />
[/message]<br />
#enddef<br />
</syntaxhighlight><br />
<br />
The caller of the macro can then decide which, if any, of the default values to override:<br />
<syntaxhighlight lang="wml"><br />
{MESSAGE _"Halt!" SPEAKER_ID="Guard Captain"}<br />
{MESSAGE _"Two days pass..." IMG=wesnoth-icon.png SOUND=ambient/morning.ogg}<br />
{MESSAGE _"..."}<br />
{MESSAGE _"Welcome!" CAPTION=_"Elóndra's shop of wonders" IMG=portraits/elves/shyde.png}<br />
{MESSAGE _"*smash*" SPEAKER_ID="Bridge Troll" SOUND=mace.ogg}<br />
</syntaxhighlight><br />
<br />
'''Note:''' As with #enddef, the final line break before #endarg is included in the default value. This means that if the symbol is used in the middle of a line, you should place the #endarg immediately after the value has ended, without a line break in between.<br />
<br />
=== #undef ===<br />
<br />
'''Syntax:''' '''#undef ''symbol'' '''<br />
<br />
Removes the previous definition of the macro named ''symbol''. Wesnoth expects this to be done when overriding an existing macro, and will warn you if you redefine an existing macro without an explicit #undef before it.<br />
<br />
=== Inclusion directive {} ===<br />
<br />
This directive can be used to include macros, single files or sets of files from a target directory.<br />
<br />
==== File/directory inclusions ====<br />
<br />
'''Syntax: {''path''}'''<br />
<br />
Includes the file with the specified ''path'', which will in turn run the preprocessor on it and perform any required substitutions or inclusions within it. The ''path'' may not contain ''..'' or the inclusion will be skipped.<br />
<br />
The exact location in which the ''path'' will be resolved will depend on its prefix:<br />
<br />
* '''{''path''}''': If ''path'' isn't a known macro (see below), the game will assume it's a relative path to a file in the main game '''data/''' directory and include it.<br />
* '''{~''path''}''': As above, but instead of the game data directory, the path is resolved relative to the user '''data/''' directory, where user made add-ons can normally be found.<br />
* '''{./''path''}''': The path is resolved relative to the location of the current file containing this inclusion.<br />
<br />
Information for locating the user data and game data directories can be found in [[EditingWesnoth]].<br />
<br />
Forward slashes ('''/''') should '''always''' be used as the path delimiter, even if your platform uses a different symbol such as colons (''':''') or backslashes ('''\''')! It is also very important to respect the '''actual letter case''' used to name files and directories for compatibility with case-sensitive filesystems on Unix-based operating systems.<br />
<br />
When ''path'' points to a directory instead of a file, the preprocessor will include all files found within with the '''.cfg''' extension, in alphabetical order; files without this extension (such as '''.map''' or '''.png''' files) are ignored.<br />
<br />
Some directories are handled in a special fashion according to their contents:<br />
<br />
* If there's a file named '''_main.cfg''' in the target directory, only that file will be included and preprocessed. It may include other files from its own directory or subdirectories within it, of course. This is used for managing WML directories as self-contained packages, like user made add-ons.<br />
* If there are files named '''_main.cfg''' in subdirectories of the target and there isn't one in the target itself, they will be all preprocessed. Given the following layout:<br />
dir/<br />
dir/a/_main.cfg<br />
dir/a/other.cfg<br />
dir/b/_main.cfg<br />
dir/b/other.cfg<br />
dir/other.cfg<br />
Using '''{dir}''' will cause dir/a/_main.cfg, dir/b/_main.cfg and dir/other.cfg to be included.<br />
* If there's a file named '''_final.cfg''' but no '''_main.cfg''', the file is guaranteed to be included and processed ''after'' all the other files in the directory.<br />
* If there's a file named '''_initial.cfg''' but no '''_main.cfg''', the file is guaranteed to be included and processed ''before'' all the other files in the directory.<br />
<br />
==== Macro inclusions ====<br />
<br />
'''Syntax: {''symbol'' [''arguments''] [''optional arguments'']}'''<br />
<br />
If the macro named ''symbol'' is defined, the preprocessor will replace this instruction by the expression ''symbol'' was previously defined as, using ''arguments'' as parameters. The number of normal arguments must be exactly the same as in the original definition or an error will occur. Optional arguments can only be placed '''after''' all normal arguments, however they can be specified in any order desired.<br />
<br />
You can create multiple word arguments by using parentheses to delimit the contents. For example, in '''{ENEMY_UNIT Wolf Rider 18 24}''' the four words will be interpreted as separate arguments and cause the preprocessor to fail since the macro was defined above with only three; instead, you should use '''{ENEMY_UNIT (Wolf Rider) 18 24}'''.<br />
<br />
Optional arguments can also be delimited by placing parentheses, however they must be placed around both the argument name '''and''' content:<br />
<br />
<syntaxhighlight lang="wml"><br />
{MESSAGE _"I'll smash you!" (SPEAKER_ID=Bridge Troll) } # Correct<br />
{MESSAGE _"I'll smash you!" SPEAKER_ID=(Bridge Troll) } # Wrong<br />
</syntaxhighlight><br />
<br />
This way even complex arguments can be passed:<br />
<br />
<syntaxhighlight lang="wml"><br />
{MODIFY_UNIT (<br />
[filter_adjacent]<br />
canrecruit=yes<br />
[/filter_adjacent]<br />
) side 2}<br />
</syntaxhighlight><br />
<br />
Using the name of an existing macro as the name of a macro argument is possible, but the argument will always take precedence over the original macro:<br />
<br />
<syntaxhighlight lang="wml"><br />
#define VARIABLE<br />
#enddef<br />
#define MACRO VARIABLE<br />
{VARIABLE} # is calling for the argument, not for the macro above<br />
#enddef<br />
</syntaxhighlight><br />
<br />
=== #ifdef and #ifndef ===<br />
<br />
Unlike the other preprocessor directives, '''#ifdef''' and '''#ifndef''' are not mere conveniences. They are often necessary to distinguish between different gameplay modes or difficulties (see [[#Built-in macros|Built-in macros]] below).<br />
<br />
'''Syntax:''' '''#ifdef ''symbol'' ''substitution-if-defined'' [#else ''substitution-if-not-defined'' ] #endif'''<br />
<br />
If ''symbol'' has been defined with '''#define''' or as a built-in macro, the whole block will be replaced by ''substitution-if-defined''. If not, it will be replaced by ''substitution-if-not-defined'' if it is available.<br />
<br />
'''#ifndef''' is the exact opposite of '''#ifdef''', reversing the logic:<br />
<br />
'''Syntax:''' '''#ifndef ''symbol'' ''substitution-if-not-defined'' [#else ''substitution-if-defined''] #endif'''<br />
<br />
=== #ifhave and #ifnhave ===<br />
<br />
'''Syntax:''' '''#ifhave ''path'' ''substitution-if-path-exists'' [#else ''substitution-if-path-does-not-exist''] #endif'''<br />
<br />
Checks for the existence of a file. Uses the same relative paths as [[#Inclusion_directive_.7B.7D|include directives]].<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang="wml"><br />
#ifhave ~add-ons/My_Addon/_main.cfg<br />
{MY_ADDON_MACROS}<br />
#endif<br />
</syntaxhighlight><br />
<br />
'''#ifnhave''' does the opposite of '''#ifhave''':<br />
<br />
'''Syntax:''' '''#ifnhave ''path'' ''substitution-if-path-does-not-exist'' [#else ''substitution-if-path-exists''] #endif'''<br />
<br />
=== #ifver and #ifnver ===<br />
<br />
'''Syntax:''' '''#ifver ''symbol'' ''operator'' ''version-number'' ''<newline>'' ''substitution-if-condition-met'' [#else ''substitution-if-condition-not-met''] #endif'''<br />
<br />
Compares a version number defined in a macro against an argument for conditional block inclusions, like ''#ifdef'' and ''#ifhave''. ''operator'' is one of ''=='' (equal), ''!='' (not equal), ''<'' (less), ''<='' (less or equal), ''>'' (greater), ''>='' (greater or equal). The specified ''symbol'' should have been previously defined as plain text without more macro inclusions within it, and it must not require any arguments.<br />
<br />
Versions with text suffixes are sorted in binary order and come after all versions with the same number. The most common suffixes begin with "+", but as this represents multiple possible versions, comparing versions against it is not recommended.<br />
<br />
Example:<br />
<syntaxhighlight lang="wml"><br />
#ifver WESNOTH_VERSION >= 1.9.7+<br />
[message]<br />
speaker=narrator<br />
message= _ "I’m on Wesnoth 1.9.7+, 1.9.8 or later!"<br />
[/message]<br />
#else<br />
#ifver WESNOTH_VERSION == 1.9.7<br />
[message]<br />
speaker=narrator<br />
message= _ "I’m on Wesnoth 1.9.7, and I’ll include some workaround code for bug #9001!"<br />
[/message]<br />
#endif<br />
#endif<br />
</syntaxhighlight><br />
<br />
'''#ifnver''' does the opposite of '''#ifver''':<br />
<br />
'''Syntax:''' '''#ifnver ''symbol'' ''operator'' ''version-number'' ''<newline>'' ''substitution-if-condition-not-met'' [#else ''substitution-if-condition-met''] #endif'''<br />
<br />
=== #error ===<br />
<br />
'''Syntax:''' '''#error [''message'']'''<br />
<br />
Causes the WML preprocessor to fail unconditionally upon encountering the line. For add-ons, this will cause the game to display an error and return to the titlescreen if the add-on is required for the user's action (such as playing a campaign or loading a saved game). For core WML, this will cause the game to quit entirely.<br />
<br />
Please note that in spite of the example below, it is '''not''' advisable to use this mechanism in published add-ons for version or feature-checking, since the message is not displayed in a form that permits translation and the additional trace information may confuse players. This directive is only intended as a debugging aid for content creators.<br />
<br />
Example:<br />
<syntaxhighlight lang="wml"><br />
#ifver WESNOTH_VERSION < 1.11.10<br />
#error This add-on does not support Wesnoth 1.11.10!<br />
#endif<br />
</syntaxhighlight><br />
<br />
=== #warning ===<br />
<br />
'''Syntax:''' '''#warning [''message'']'''<br />
<br />
Causes the WML preprocessor to emit a warning upon encountering the line. The message will '''only''' be relayed to stderr, not to the player in the game UI. This directive is only intended as a debugging aid for content creators.<br />
<br />
Example:<br />
<syntaxhighlight lang="wml"><br />
#ifver WESNOTH_VERSION < 1.11.10<br />
#warning On Wesnoth 1.11.9 or earlier, bug workarounds enabled!<br />
#endif<br />
</syntaxhighlight><br />
<br />
=== #deprecated ===<br />
<br />
{{DevFeature1.13|11}}<br />
<br />
'''Syntax:''' '''#deprecated 1 ''message'''''<br />
<br />
'''Syntax:''' '''#deprecated 2 ''version'' ''message'''''<br />
<br />
'''Syntax:''' '''#deprecated 3 ''version'' ''message'''''<br />
<br />
'''Syntax:''' '''#deprecated 4 ''message'''''<br />
<br />
The effect of this directive depends on whether it appears within a macro definition.<br />
<br />
* If it appears at file level, outside any macro definition, then it immediately outputs a warning saying that the file is deprecated, with the provided message. Multiple '''#deprecated''' directives at toplevel in a single file will result in separate messages.<br />
* If it appears inside a macro definition ('''#define ... #enddef'''), then it doesn't output anything. Instead, it marks the macro as deprecated. When that macro is later used, only then will the preprocessor output a warning saying that the macro is deprecated, with the provided message. Multiple '''#deprecated''' directives within a single macro will be merged into one message.<br />
<br />
Note that deprecation messages will only appear if they have been set to. {{DevFeature1.13|12}} This can be done by enabling debug mode, or by going to Advanced Preferences and setting the log-level for the deprecation logdomain. (This can also be done on the command-line.)<br />
<br />
If you provide a deprecation level of 2 or 3, it is required to indicate the earliest version in which the feature could be removed. However, if you provide a deprecation level of 1 or 4, any provided ''version'' will instead be parsed as part of the message, so you will probably not want to provide one at all. Other deprecation levels are not valid. See the documentation for [[InterfaceActionsWML#.5Bdeprecated_message.5D|[deprecated_message]]] for the meaning of the various ''level'' values.<br />
<br />
== Built-in macros ==<br />
<br />
The following macros are automatically defined with empty contents (unless specified otherwise) by the game engine depending on the configuration or gameplay mode.<br />
<br />
Note that except during an actual game, ''MULTIPLAYER'', ''EDITOR'' and previous campaign defines, are not guaranteed to be undefined, especially when coming back to titlescreen, So it is not enough to hide contents inside of an #ifdef to prevent them from being seen by the campaign selection dialog, for example for mp specific [campaign]s or [modification]s type=mp must be used. <br />
<br />
* A campaign define symbol (see ''define'' in [[CampaignWML]]): defined when playing a single-player campaign.<br />
* A campaign difficulty level, usually '''EASY''', '''NORMAL''' or '''HARD''' (see ''difficulties'' in [[CampaignWML]]): defined according to the chosen difficulty when starting a single-player campaign, also stored in saved games.<br />
* '''MULTIPLAYER''': defined when in multiplayer mode.<br />
* '''TUTORIAL''': defined when playing the tutorial campaign.<br />
* '''EDITOR''': defined when running the built-in map editor.<br />
* '''DEBUG_MODE''': defined when the game has been launched in debug mode (i.e. with '''-d''' or '''--debug''' in the command line). Can also be set by typing <code>:</code> to bring up [[CommandMode]], then typing <code>debug</code>, and then restarting the scenario.<br />
* '''APPLE''': defined while processing the main game data when running on Mac OS X.<br />
* '''WESNOTH_VERSION''': defined containing just the game version number when running the WML preprocessor.<br />
* '''CURRENT_FILE''': Expands to the name of the current WML file.<br />
* '''CURRENT_DIRECTORY''': Expands to the preprocessor path of the parent directory for the current WML file (e.g. for <code>&lt;user data dir&gt;/data/add-ons/My_Addon/_main.cfg</code> this evaluates to <code>~add-ons/My_Addon</code>). <br />
* '''LEFT_BRACE''': {{DevFeature1.15|2}} Expands to <code>{</code>.<br />
* '''RIGHT_BRACE''': {{DevFeature1.15|2}} Expands to <code>}</code>.<br />
<br />
A ''very large'' number of additional macros are provided as part of the default game core WML. For a full list of those, check the [https://www.wesnoth.org/macro-reference.html macro reference].<br />
<br />
== Command-line preprocessor ==<br />
<br />
'''Syntax: --preprocess ''&lt;source file/directory>'' ''<target directory>'' '''<br />
<br />
Or the short form:<br />
<br />
'''Syntax: -p ''&lt;source file/directory>'' ''<target directory>'' '''<br />
<br />
You can specify a list of predefined defines with:<br />
<br />
'''Syntax: --preprocess-defines=DEFINE1,DEFINE2,etc'''<br />
<br />
comma separated list of defines to be used by '--preprocess' command. If 'SKIP_CORE' is in the define list the data/core won't be preprocessed.<br />
<br />
The command will preprocess first the common config files in the main game ''data/'' directory, and afterwards the specified ones. You can specify a single file to be preprocessed (if you want to preprocess multiple separate files, you'll need to run a different command line for each one), or an entire directory, which will be preprocessed according to the rules used by the inclusion directive above.<br />
<br />
The resulted preprocessed files will be written in the target directory. There will be two types of files: .cfg files --- the normal ones, and .plain files containing line markers and textdomain changes.<br />
<br />
If by chance, the simple macro define doesn't suffice, you can use:<br />
<br />
'''Syntax: --preprocess-input-macros <file>'''<br />
<br />
To import an existing file that contains macros, and they will be available in the defines database before processing the specified files.<br />
<br />
There is also the possibility to export the preprocessed defines/macro list with:<br />
<br />
'''Syntax: --preprocess-output-macros [<target file>]'''<br />
<br />
This file could be fed to the 'input-macros' argument next time you run it. For example, a scenario would be: parsing just the core first time, and for the intended target files, you would add SKIP_CORE but import the generated macros file - that will be faster than preprocessing the core again. If the target file is not specified, the output file will be _MACROS_.cfg in the target directory of the preprocess's command.<br />
<br />
If ''file/directory'' and ''target directory'' are not absolute paths, they will be considered relative to the game's executable path.<br />
<br />
Some examples:<br />
<br />
* Preprocess the entire tutorial dir, and write the results in the ~/result folder:<br />
-p ~/wesnoth/data/campaigns/tutorial ~/result<br />
* Add the MULTIPLAYER define to the list and preprocess a scenario's config file:<br />
-p ~/.wesnoth/data/add-ons/My_Campaign/scenarios/01_First_Scenario.cfg ~/result --preprocess-defines=MULTIPLAYER<br />
* Add the MY_CAMPAIGN and HARD defines before preprocessing a campaign's files:<br />
-p ~/.wesnoth/data/add-ons/My_Campaign ~/result --preprocess-defines=MY_CAMPAIGN,HARD<br />
<br />
If you want a more detailed (and potentially overwhelming) log, you can simply add the switches '''--log-debug=all''' or '''--log-info=all''' to the command line, so you can see how things are preprocessed in detail.<br />
<br />
== See Also ==<br />
<br />
* [[SyntaxWML]] (explains relationship between comments and preprocessor directives)<br />
* [[ReferenceWML]]<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/wesnoth/sync&diff=70688LuaAPI/wesnoth/sync2023-03-23T04:59:11Z<p>Gfgtdf: </p>
<hr />
<div><br />
The <tt>wesnoth.sync</tt> module contains functions to synchronize data between players. This isn't only for multiplayer - single-player replays will break unless choices are synchronized between the player and the viewer.<br />
<br />
For more information about multiplayer and replay safety see also [[OOS_(Out_of_Sync)]]<br />
<br />
=== wesnoth.sync.evaluate_single ===<br />
<br />
* {{LuaGameOnly}} '''wesnoth.sync.evaluate_single'''([''description''], ''function'', [''ai_function''], [''for_side'']) &rarr; ''result''<br />
<br />
Recovers a WML table that was computed on one client only or was stored in a replay. The actual computation is performed by the function passed as the first function argument, assuming that the client is the side currently playing. For all the other clients, the function will not be called. An optional second function can be passed; if present, it will be used instead of the first one when the client happens to be an AI (hence not enable to interact with a user interface).<br />
<br />
<syntaxhighlight lang=lua><br />
local result = wesnoth.sync.evaluate_single(<br />
function()<br />
-- Called only on the client handling the current side, if it is a human.<br />
local choice = 0<br />
gui.show_dialog(<br />
some_dialog_cfg, nil,<br />
function(window)<br />
choice = window.some_list.value<br />
end)<br />
return { value = choice }<br />
end,<br />
function()<br />
-- Called only on the client handling the current side, if it is an AI.<br />
return { value = math.random(some_list_size) }<br />
end)<br />
wesnoth.interface.add_chat_message(string.format("Selected item: %d", result.value))<br />
</syntaxhighlight><br />
<br />
'''Note:''' The return value must be a valid WML table - the same kind of thing you could store to a WML variable, and not, for instance, a proxy unit, anything else that uses metatables, or a lua table with another table as the value of a string attribute. Unlike other lua functions, '''wesnoth.sync.evaluate_single''' will ''not'' throw an error if the table is invalid, but will silently strip out the contents of any invalid subtag.<br />
<br />
'''Note:''' This function should only be called from a [[EventWML#Multiplayer_safety|synchronized event]]; it may silently fail (or silently fail to synchronize) when called from an unsynced event.<br />
<br />
When wesnoth is running in debug mode (e.g. --debug flag on command line) '''evaluate_single''' will chat a "Lua Warning" if it finds that the table returned was partially invalid.<br />
<br />
The optional first argument ''description'' is a string describing the type of the user input. This is displayed to the other clients while one client executes the passed function. Defaults to "input".<br />
<br />
The final argument specifies on which side the function should be evaluated. Defaults to the currently playing side. If the specified side is empty/null controlled, the engine will choose another side.<br />
<br />
=== wesnoth.sync.evaluate_multiple ===<br />
<br />
* {{LuaGameOnly}} '''wesnoth.sync.evaluate_multiple'''([''description''], ''function'', [''default_function''], [''for_sides'']) &rarr; ''result map''<br />
<br />
Similar to the singular form above, this function takes a function parameter and evaluates it on the specified sides. It takes the following arguments:<br />
* An optional translatable string describing the type of the user input. This is displayed to the other clients while the specified clients execute the passed function. Defaults to "input"<br />
* A function that evaluates the choice, returning a WML table. Unlike above, this function is called for AI and human sides (use if <syntaxhighlight lang=lua inline>controller == "ai"</syntaxhighlight> for checking if it is an AI side)<br />
* An optional function for evaluating the choice in case this side was null controlled. If this function is called, it is called on all clients (unlike the first passed function) defaults to a function returning an empty table.<br />
* An array of integers specifying on which sides this function should be evaluated. The function is evaluated on all passed sides, and each side may only appear once in this array. All specified sides execute the function simultaneously.<br />
<br />
'''Note:''' This function should only be called from a [[EventWML#Multiplayer_safety|synchronized event]]; it will always error-out when called from an unsynced event.<br />
<br />
This function returns a table with integer as keys and WML tables as values. The keys are the sides where that action was evaluated, and the values are the values computed by the passed function on each side.<br />
<syntaxhighlight lang=lua><br />
local _ = wesnoth.textdomain "my-scenario"<br />
local result = wesnoth.sync.evaluate_multiple(<br />
function()<br />
local options = {_"No", _"Yes"}<br />
local result = gui.show_narration({message = _ "Are you sure you want to play this game?"}, options)<br />
return { value = tostring(options[result]) }<br />
end,<br />
{1,2})<br />
wesnoth.message("Player 1 wants to play: " .. result[1].value)<br />
wesnoth.message("Player 2 wants to play: " .. result[2].value)<br />
</syntaxhighlight><br />
<br />
=== wesnoth.sync.run_unsynced ===<br />
<br />
* {{LuaGameOnly}} '''wesnoth.sync.run_unsynced'''(''func'')<br />
<br />
Calls the given function in a unsynced context. In particular, while executing that function, random results will not be synced in mp. The function is called with no arguments, and any return values are ignored.<br />
<br />
=== wesnoth.sync.invoke_command ===<br />
<br />
* {{LuaGameOnly}} '''wesnoth.sync.invoke_command'''(''command_name'', ''cfg'')<br />
<br />
Invoke a custom synced command, which is registered in the [[LuaAPI/wesnoth#wesnoth.custom_synced_commands|wesnoth.custom_synced_commands]] table. You can pass an arbitrary WML table as arguments.<br />
<br />
[[Category:Lua Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/gui/widget&diff=66091LuaAPI/gui/widget2020-09-28T17:22:53Z<p>Gfgtdf: /* close */</p>
<hr />
<div><br />
The '''gui.widget''' module contains functions for managing widgets in custom GUI2 dialogs. Since these functions take a widget userdata as the first parameter, they can only be used in the preshow or postshow of a GUI2 dialog (directly or indirectly). However, the table is available at all times, and additional methods can be installed here for unusual needs.<br />
<br />
=== focus ===<br />
<br />
* '''gui.widget.focus'''(''widget'')<br />
* ''widget'':'''focus'''()<br />
<br />
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
=== set_canvas ===<br />
<br />
* '''gui.widget.set_canvas'''(''widget'', ''layer index'', ''content'')<br />
* ''widget'':'''set_canvas'''(''layer index'', ''content'')<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
<syntaxhighlight lang=lua><br />
-- draw two rectangles in the upper-left corner of the window (assume dialog is the window widget)<br />
dialog.set_canvas(2, {<br />
wml.tag.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
wml.tag.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
</syntaxhighlight><br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
=== add_item ===<br />
<br />
* '''gui.widget.add_item'''(''widget''[, ''position'']) &rarr; ''the new item'', ''position''<br />
* ''widget'':'''add_item'''([''position'']) &rarr; ''the new item'', ''position''<br />
<br />
Add an item to a container widget, for example a listbox. Returns the created item as a widget userdata. You can pass a negative position to count from the end of the container, but the returned position is always positive.<br />
<br />
=== add_item_of_type ===<br />
<br />
* '''gui.widget.add_item_of_type'''(''widget'', ''category''[, ''position'']) &rarr; ''the new item'', ''position''<br />
* ''widget'':'''add_item_of_type'''(''category''[, ''position'']) &rarr; ''the new item'', ''position''<br />
<br />
Add an item to a widget which is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews. You can pass a negative position to count from the end of the container, but the returned position is always positive.<br />
<br />
=== remove_items_at ===<br />
<br />
* '''gui.widget.remove_items_at'''(''widget'', ''position'')<br />
* ''widget'':'''remove_items_at'''(''position'')<br />
<br />
Removes the widget at the given index of a container type widget (like treeviews).<br />
<br />
=== find ===<br />
<br />
* '''gui.widget.find'''(''root widget'', ''path, to, widget'')<br />
* ''widget'':'''find'''(''path, to, widget'')<br />
<br />
Finds a child widget of the widget of the given path. For example, here it searches for the widget with the id 'preview_panel' of the second item of the widget with the id 'unit_list':<br />
<br />
<syntaxhighlight lang=lua><br />
dialog:find(unit_list, 2, preview_panel)<br />
</syntaxhighlight><br />
<br />
=== close ===<br />
<br />
* '''gui.widget.close'''(''dialog'')<br />
* ''widget'':'''close'''()<br />
<br />
Closes the dialog.</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=UnitTypeWML&diff=66090UnitTypeWML2020-09-28T15:56:17Z<p>Gfgtdf: /* After max level advancement (AMLA) */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
__TOC__<br />
<br />
== Unit Type ==<br />
<br />
Each '''[unit_type]''' tag defines one unit type. (for the use of [unit] to create a unit, see [[SingleUnitWML]])<br />
<br />
Unit animation syntax is described in [[AnimationWML]]. In addition to the animation tags described there, the following key/tags are recognized:<br />
* '''[advancefrom]''': Defines the previous unit type on the advancement tree. Allows a campaign-specific unit to be spliced into an already existing advancement tree. It should generally be used only inside a campaign ifdef, to prevent changes to other campaigns. Since all multiplayer content shares MULTIPLAYER define, using advancefrom changes unit type even if the addon is not actively used. For that reason multiplayer advancefrom may only be used with unit types defined in the same addon - then everyone who has the unit has it with same advancements. This tag makes changes to the ''advances_to'' and ''experience'' keys of a base unit to make it advance into this unit. It takes these keys:<br />
** ''unit'': the id of the base unit from which this unit advances. This adds the unit into the list of units which ''unit'' can advance into.<br />
** ''experience'': (optional) If present the experience needed to advance is set to this value. If there are more than one [advancefrom] tags referencing the same base unit within the same preprocessor scope (e.g. a campaign #ifdef) with experience= keys, the lowest value of these is chosen. Note: this will also lower the experience required to advance to other units which the base unit can advance into.<br />
: If the previous unit type makes use of '''[male]''' and/or '''[female]''' tags, then the current (new) unit type is expected to also. That is, the subtypes defined by those tags will only receive this advancement if the new type has a corresponding tag.<br />
* '''advances_to''': When this unit has ''experience'' greater than or equal to ''experience'', it is replaced by a unit of the type that the value of ''advances_to'' refers to. All modifications that have been done to the unit are applied to the unit it is replaced by. The special value 'null' says that the unit does not advance but gets an AMLA instead. Can be a comma-separated list of units that can be chosen from upon advancing.<br />
* '''alignment''': one of lawful/neutral/chaotic/liminal (See [[TimeWML]]). Default is "neutral".<br />
* '''attacks''': the number of times that this unit can attack each turn.<br />
* '''cost''': when a player recruits a unit of this type, the player loses ''cost'' gold. If this would cause gold to drop below 0, the unit cannot be recruited.<br />
* '''recall_cost''': {{DevFeature1.13|0}} the default recall cost of units of this type, overriding the recall cost set in scenario [[SideWML|[side]]] tags or the global [[GameConfigWML|[game_config]]] value. Individual units may override this value in [[SingleUnitWML|[unit]]]. A value of -1 is equivalent to not specifying this attribute. {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
* '''description''': (translatable) the text displayed in the unit descriptor box for this unit. Default 'No description available...'. <br />
* '''do_not_list''': Not used by the game, but by tools for browsing and listing the unit tree. If this is 'yes', the unit will be ignored by these tools. {{DevFeature1.13|?}} When placing units in debug mode this unit isn't listed (but can still be placed using the :create command). This restriction is lifted in version <b>1.14.3</b>.<br />
* '''ellipse''': the ellipse image to display under the unit, which is normally team-colored. Default is "misc/ellipse". "-nozoc" and "-leader" are automatically appended for units without zone of control and with canrecruit=yes respectively. The [http://www.wesnoth.org/macro-reference.xhtml#IS_HERO IS_HERO]/[http://www.wesnoth.org/macro-reference.xhtml#MAKE_HERO MAKE_HERO]/[http://www.wesnoth.org/macro-reference.xhtml#UNMAKE_HERO UNMAKE_HERO] macros change the ellipse to/back from "misc/ellipse-hero". Finally, setting this to "none" will cause the unit to not have any ellipses displayed under it regardless of the user's preferences.<br />
::WARNING: Be aware that setting this to "misc/ellipse-hero" for a unit with canrecruit=yes will result in the ellipse being "misc/ellipse-hero-leader", which is not a supported combination (it doesn't have a graphic, and will cause error logs that the graphic is missing).<br />
* '''experience''': When this unit has experience greater than or equal to ''experience'', it is replaced by a unit with 0 experience of the type that the value of ''advances_to'' refers to. All modifications that have been done to the unit are applied to the unit it is replaced by.<br />
* '''flag_rgb''': usually set by [http://www.wesnoth.org/macro-reference.xhtml#MAGENTA_IS_THE_TEAM_COLOR MAGENTA_IS_THE_TEAM_COLOR]; specifies the colours in the base flag to use for team-colouring the unit, expressed as a colour name (such as magenta) or a comma-separated list of RGB values (in hex format).<br />
* '''gender''': has a value of either ''male'' or ''female'', and determines which of the keys ''male_names'' and ''female_names'' should be read. When a unit of this type is recruited, it will be randomly assigned a name by the random name generator, which will use these names as a base. If '''gender''' is not specified it defaults to ''male''.<br />
* '''halo''': an image to place centered on the unit. It is drawn on top of the unit, and on top of surrounding units if the image is larger than one hex. It works similarly to the halo attribute of {{tag|InterfaceActionsWML|item}}, and it can be animated with a comma-separated list of images.<br />
* '''hide_help''': (yes|no) default=no. Determines if the unit type will appear in the in-game help.<br />
* '''hitpoints''': the maximum HP that the unit has, and the HP it has when it is created.<br />
* '''id''': the value of the ''type'' key for units of this type. This is required and must be unique among all [unit_type] tags. An ''id'' should consist only of alphanumerics and spaces (or underscores). ''type'' keys are found in [[SingleUnitWML]] and [[FilterWML]]. For example, id=Drake Flare<br />
::WARNING : characters "$", "&", "*", "-", "(" and ")" are illegal for use in the unit type id and must be avoided because they might lead to corrupted saved games<br />
*'''ignore_race_traits''': 'yes' or 'no' (default). Determines whether racial traits (see [[UnitsWML]]) are applied. <br />
* '''image''': sets the base image of the unit, which is used on the map.<br />
* '''image_icon''': sets the image used to represent the unit in areas such as the attack dialog and the unit image box in the sidebar. [[ImagePathFunctions#Crop_Function|~CROP]] function can be useful here. You can see Loyalists Paladin as an example.<br />
* '''level''': the amount of upkeep the unit costs. After this unit fights, its opponent gains ''level'' experience. See also kill_experience ([[GameConfigWML]]), and leadership ([[AbilitiesWML]]).<br />
* '''movement''': the number of move points that this unit receives each turn.<br />
* '''movement_type''': See [[UnitsWML#.5Bmovetype.5D|movetype]]. Note that the tags '''[movement_costs]''', '''[vision_costs]''', '''[defense]''', and '''[resistance]''' can be used to modify this movetype.<br />
* '''name''':(translatable) displayed in the Status Table for units of this type.<br />
* '''num_traits''': the number of traits that units of this type should receive when they are recruited, overriding the value set in the [race] tag.<br />
* '''profile''': the portrait image to use for this unit type. You can also set a portrait for an individual unit instead of the whole unit type (see [[SingleUnitWML]]). The engine first looks for the image in the transparent subdirectory and if found that image is used. If not found it will use the image as-is. Depending on the size the engine will or will not scale the image, the cutoff currently is at 300x300. For images which should only be shown on the right side in the dialog append ~RIGHT() to the image.<br />
** If "unit_image" is given instead of a filename, uses the unit's base image as the portrait (in the same manner that unit types without portraits do by default).<br />
* '''small_profile''': the image to use when a smaller portrait is needed than the one used for messages (e.g., in the help system). When this attribute is missing, the value of the '''profile''' attribute is used instead. When present, the heuristic for finding a transparent portrait is disabled for the '''profile''' attribute, so the correct '''profile''' should be set too. If '''profile''' is not present, '''small_profile''' is ignored. Note that image modifiers are allowed; they might be useful for cropping and rescaling a portrait:<br />
small_profile="portraits/elves/transparent/marksman+female.png~CROP(0,20,380,380)~SCALE(205,205)"<br />
profile="portraits/elves/transparent/marksman+female.png"<br />
* '''race''': See {{tag|UnitsWML|race}}. Also used in standard unit filter (see [[FilterWML]]). Mainline Wesnoth features following values: bats, drake, dwarf, elf, falcon, goblin, gryphon, human, khalifate, lizard, mechanical, merman, monster, naga, ogre, orc, troll, undead, wolf, wose. They are defined in /data/core/units.cfg.<br />
* '''undead_variation''': When a unit of this type is killed by a weapon with the plague special, this variation is applied to the new plague unit that is created, whatever its type. For example, if the plague special creates Walking Corpses and undead_variation is set to "troll", you'll get a troll Walking Corpse. Defaults to the undead_variation set in this unit type's race.<br />
* '''usage''': the way that the AI should recruit this unit, as determined by the scenario designer. (See ''recruitment_pattern'', [[AiWML]]). The following are conventions on usage:<br> ** ''scout'': Fast, mobile unit meant for exploration and village grabbing.<br> ** ''fighter'': Melee fighter, melee attack substantially more powerful than ranged.<br> ** ''archer'': Ranged fighter, ranged attack substantially more powerful than melee.<br> ** ''mixed fighter'': Melee and ranged fighter, melee and ranged attacks roughly equal.<br> ** ''healer'': Specialty 'heals' or 'cures'.<br>Note that this field primarily affects recruitment. It also has a small effect on unit movement (the AI tries to keep scouts away from enemies, to some extent). It does not affect the AI's behavior in combat; that is always computed from attack power and hitpoints. Non-standard usages may be used as well.<br />
* '''vision''': the number of vision points to calculate the unit's sight range. Defaults to ''movement'' if not present.<br />
* '''jamming''': the number of jamming points. Defaults to ''0'' if not present. See [[UnitsWML#.5Bmovetype.5D|[jamming_costs]]]<br />
* '''zoc''': if "yes" the unit will have a zone of control regardless of level. If present but set to anything other than "yes," the unit will have no zone of control. If the tag is omitted, zone of control is dictated by unit level (level 0 = no zoc, level 1+ = has zoc).<br />
* '''die_sound''': sets the sound, which is used when the unit dies.<br />
* '''healed_sound''': sets the sound used when the unit is healed in any way (default: heal.wav).<br />
* '''hp_bar_scaling''': Overrides the attribute in ([[GameConfigWML]]).<br />
* '''xp_bar_scaling''': Overrides the attribute in ([[GameConfigWML]]).<br />
* '''bar_offset_x''', '''bar_offset_y''': The offset of the hp and xp bars from the normal bar position of 72x72 unit sprite.<br />
<br />
== After max level advancement (AMLA) ==<br />
* '''[advancement]''': describes what happens to a unit when it reaches the XP required for advancement. It is considered as an advancement in the same way as advancement described by '''advances_to'''; however, if the player chooses this advancement, the unit will have one or more effects applied to it instead of advancing.<br />
** '''id''': unique identifier for this advancement; ''Required'' if there are multiple advancement options, or if ''strict_amla=no''.<br />
** '''always_display''': if set to true displays the AMLA option even if it is the only available one.<br />
** '''description''': a description displayed as the option for this advancement if there is another advancement option that the player must choose from; otherwise, the advancement is chosen automatically and this key is irrelevant.<br />
** '''image''': an image to display next to the description in the advancement menu.<br />
** '''max_times''': default 1. The maximum times the unit can be awarded this advancement. Pass -1 for "unlimited".<br />
** '''strict_amla''': (yes|no) default=no. Disable the AMLA if the unit can advance to another unit.<br />
** '''major_amla''': (yes|no) default=no. Sets whether the unit's XP bar is blue(=yes) or purple(=no). In case of more [advancement] tags, if there is one with major_amla=yes, the XP bar will be blue.<br />
** '''require_amla''': An optional list of AMLA ''id'' keys that act as prerequisites for this advancement to become available. Order is not important, and an AMLA id can be repeated any number of times to indicate that another advancement must be chosen several times before this advancement option will become available.<br />
*** example: <tt>require_amla=tough,tough,incr_damage</tt> assumes there exist other [advancement] options called ''id=tough'' and ''id=incr_damage''. Once ''tough'' is chosen twice and ''incr_damage'' is chosen once, then the current [advancement] will become available.<br />
*** ''require_amla=tough,incr_damage,tough'' is an equivalent way of expressing this.<br />
** '''exclude_amla''': {{DevFeature1.13|2}} An optional list of AMLA ''id'' keys that represent AMLAs that are mutually exclusive to this one. Order is not important, and an AMLA id can be repeated. If the unit already has any of the AMLAs that appear once in this list, then this AMLA will not be made available. If an AMLA id appears multiple times in the list, then this AMLA will be made available only if the other AMLA has been chosen less than the number of times it appears in the list. Of course, for this to really make two AMLAs mutually exclusive, you need to add ''exclude_amla'' to both AMLA defintions.<br />
** '''[effect]''': A modification applied to the unit whenever this advancement is chosen. See [[EffectWML]]<br />
** '''[filter]''': A [[StandardUnitFilter]], the advancement will only be available when the unit passes this filter during the time the advancement dialog is shown.<br />
<br />
== Attacks ==<br />
* '''[attack]''': one of the unit's attacks.<br />
** '''description''': a translatable text for name of the attack, to be displayed to the user.<br />
** '''name''': the name of the attack. Used as a default description, if ''description'' is not present, and to determine the default icon, if ''icon'' is not present (see below). Non-translatable. Used for the ''has_weapon'' key and animation filters; see [[StandardUnitFilter]] and [[AnimationWML]]<br />
** '''type''': the damage type of the attack. Used in determining resistance to this attack (see {{tag|UnitsWML|movetype|resistance}}). {{DevFeature1.15|0}} Damage type icons in the sidebar should be named icons/profiles/''type''.png. See https://github.com/wesnoth/wesnoth/pull/3732<br />
** '''[specials]''': contains the specials of the attack. See [[AbilitiesWML#The_.5Bspecials.5D_tag|AbilitiesWML]].<br />
** '''icon''': the image to use as an icon for the attack in the attack choice menu, as a path relative to the images directory. Defaults to the attack's name in the attacks directory (Ex. if ''name=sword'' then default is ''icon=attacks/sword.png''). <br />
** '''range''': the range of the attack. Used to determine the enemy's retaliation, which will be of the same type. Also displayed on the status table in parentheses; 'melee'(default) displays "melee", while 'ranged' displays "ranged". Range can be anything. Standard values are now "melee" and "ranged". From now on, ''short'' and ''long'' will be treated as totally different ranges. You can create any number of ranges now (with any name), and units can only retaliate against attacks for which they have a corresponding attack of the same range. This value is translatable. {{DevFeature1.15|0}} Range icons in the sidebar should be named icons/profiles/''range''_attack.png. See https://github.com/wesnoth/wesnoth/pull/3732<br />
** '''damage''': the damage of this attack<br />
** '''number''': the number of strikes per attack this weapon has<br />
** '''accuracy''': a number added to the chance to hit whenever using this weapon offensively (i.e. during a strike with this attack, regardless of who initiated the combat); negative values work too<br />
** '''parry''': a number deducted from the enemy chance to hit whenever using this weapon defensively (i.e. during the enemy's strike, regardless of who initiated the combat); negative values work too<br />
** '''movement_used''': determines how many movement points using this attack expends. By default all movement is used up, set this to 0 to make attacking with this attack expend no movement.<br />
** '''attack_weight''': helps the AI to choose which attack to use when attacking, setting it to 0 disables the attack on attack. See the note about weights below.<br />
** '''defense_weight''': used to determine which attack is used for retaliation. This affects gameplay, as the player is not allowed to determine his unit's retaliation weapon. Setting it to 0 disable the attacks on defense. See the note about weights below.<br />
Note: For the weight settings, the engine currently (as of 1.14) recognizes only two situations: >0 (normal) and <= 0 (attack completely disabled), so attack_weight=1 and attack_weight=5 have exactly the same chance of being chosen. https://r.wesnoth.org/t49322<br />
<br />
== Other tags ==<br />
* '''[base_unit]''': Contains one attribute, '''id''', which must be the ID of a unit type. If specified, the UnitTypeWML for that unit is copied into this one, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Additionally, the unit will be marked as variation of the base unit in its own help page, but not in the help page of the base unit.<br />
<br />
* '''[portrait]''': Describes a unit portrait for dialogue. However, generally you should use the profile key instead; [portrait] is mostly for internal use.<br />
** '''size''': The size of the portrait, in pixels.<br />
** '''side''': One of left or right.<br />
** '''mirror''': Whether to flip the image horizontally.<br />
** '''image''': The image path.<br />
<br />
* '''[abilities]''': Defines the abilities of a unit. See [[AbilitiesWML]]<br />
<br />
* '''[event]''': Any [event] written inside the [unit_type] tag will get included into any scenario where a unit of this type appears in. Note that such events get included when a unit of this type first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[EventWML]] and [[WML_Abilities]]<br />
<br />
* '''[variation]''': Defines a variation of a unit. Variations are invoked with an [effect] tag or the variation= attribute in [[SingleUnitWML]]. They are currently used for graphical variations (giving character sprites new weapons) but theoretically you could do anything with it.<br />
** '''variation_id''': The id of this variation. Defaults to ''variation_name''.<br />
** '''variation_name''': Translatable. The name of the variation, which is displayed in the help and in debug mode. Not setting this looks bad unless combined with '''hide_help'''=yes.<br />
** '''inherit''': if ''yes'', inherits all the properties of the base unit, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Defaults to no.<br />
*** The '''id''' key is always inherited, regardless of the value of '''inherit'''.<br />
** All keys and tags of '''[unit_type]''', except ''[advancefrom]'', ''[base_unit]'', ''[female]'', ''[male]'', and ''[variation]''.<br />
<br />
* '''[male]''', '''[female]''': These can specify a variation based on gender for a unit. If these are provided, they will automatically apply based upon the gender of a unit.<br />
** '''inherit''': if ''yes'', inherits all the properties of the base unit, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Defaults to yes.<br />
*** The '''id''' key is always inherited, regardless of the value of '''inherit'''.<br />
** All '''[unit_type]''' tags and keys, excluding ''[advancefrom]'', ''[base_unit]'', ''[female]'', and ''[male]''.<br />
<br />
* {{DevFeature1.15|2}} '''[special_note]''': Adds a special note to the unit's description. This tag will usually be used indirectly via a macro. It contains one key, '''note''', which just specifies the text of the note. Use of this tag results in a bulleted list of special notes, rather than the old format for special notes embedded in the '''description'''.<br />
<br />
== See Also ==<br />
<br />
* [[AnimationWML]]<br />
* [[ReferenceWML]]<br />
* [[TerrainWML]]<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66085LuaAPI/types/widget2020-09-27T23:30:32Z<p>Gfgtdf: /* selected */</p>
<hr />
<div>The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only; the properties depend on the type of the widget.<br />
<br />
An example of accessing a child widget:<br />
<br />
<syntaxhighlight lang=lua><br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
</syntaxhighlight><br />
<br />
== Widget Attributes ==<br />
<br />
=== selected ===<br />
<br />
* ''widget''.'''selected''' &harr; ''boolean''<br />
* Available on: '''[toggle_button]''', '''[toggle_panel]'''<br />
<br />
Whether the item is selected or not. Note that this should only be used for widgets that have only 2 states. There exist in particular 3-State [toggle_button]s (for example in listbox headers): For those selected_index must be used instead..<br />
<br />
=== selected_index ===<br />
<br />
* ''widget''.'''selected_index''' &harr; ''index''<br />
* Available on: '''[listbox]''', '''[multi_page]''', '''[stacked_widget]''', '''[menu_button]''', '''[toggle_button]''', '''[toggle_panel]'''<br />
<br />
The selected index of the item. For '''[toggle_button]''' and '''[toggle_panel]''', this is the same as '''selected''' only encoded as a number (0 or 1) instead of a boolean.<br />
<br />
=== text ===<br />
<br />
* ''widget''.'''text''' &harr; ''text''<br />
* Available on: '''[text_box]'''<br />
<br />
The text of the textbox.<br />
<br />
=== value ===<br />
<br />
* ''widget''.'''value''' &harr; ''position''<br />
* Available on: '''[slider]'''<br />
<br />
The current position of the slider.<br />
<br />
=== percentage ===<br />
<br />
* ''widget''.'''percentage''' &harr; ''position''<br />
* Available on: '''[progress_bar]'''<br />
<br />
The current position of the progress bar, between 0 and 1.<br />
<br />
=== selected_item_path ===<br />
<br />
* ''widget''.'''selected_item_path''' &rarr; ''array of indices''<br />
* Available on: '''[treeview]'''<br />
<br />
A table describing the currently selected node. If for example, in the following treeview, Item 9 is selected, the result will be {2,1,3}.<br />
<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
<br />
=== path ===<br />
<br />
* ''widget''.'''path''' &rarr; ''array of indices''<br />
* Available on: '''[tree_view_node]'''<br />
<br />
A table describing this node in the overall treeview. See [[#selected_item_path|selected_item_path]] for the meaning of the table..<br />
<br />
=== unfolded ===<br />
<br />
* ''widget''.'''unfolded''' &larr; ''boolean''<br />
* Available on: '''[tree_view_node]'''<br />
<br />
Control whether a tree node is currently expanded or not.<br />
<br />
=== unit ===<br />
<br />
* ''widget''.'''unit''' &larr; ''unit or unit type''<br />
* Available on: '''[unit_preview_pane]'''<br />
<br />
Change the displayed unit or unit type in the preview pane.<br />
<br />
=== item_count ===<br />
<br />
* ''widget''.'''item_count''' &rarr; ''number of items''<br />
* Available on: '''[multi_page]''', '''listbox'''<br />
<br />
The number of items in the container widget.<br />
<br />
=== use_markup ===<br />
<br />
* ''widget''.'''use_markup''' &rarr; ''boolean''<br />
* Available on: Most widgets, in particular '''[label]''', '''[button]'''<br />
<br />
Sets whether the widget's label will parse [[Pango formatting]].<br />
<br />
=== label ===<br />
<br />
* ''widget''.'''label''' &larr; ''text''<br />
* Available on: Most widgets, in particular '''[label]''', '''[button]''', '''[image]'''<br />
<br />
The widget's label. Technically this is a special string used in the widget's wml definition. It usually does what one would expect, but also sets the image for '''image''' widgets.<br />
<br />
=== marked_up_text ===<br />
<br />
* ''widget''.'''marked_up_text''' &larr; ''text''<br />
* Available on: Most widgets, in particular '''[label]''', '''[button]'''<br />
<br />
Shortcut for setting label and use_markup=yes.<br />
<br />
=== enabled ===<br />
<br />
* ''widget''.'''enabled''' &larr; ''boolean''<br />
* Available on: All widgets<br />
<br />
=== tooltip ===<br />
<br />
* ''widget''.'''tooltip''' &larr; ''text''<br />
* Available on: All widgets<br />
<br />
=== visible ===<br />
<br />
* ''widget''.'''visible''' &larr; ''visibility string''<br />
* Available on: All widgets<br />
<br />
Determines whether the widget is visible onscreen. The following visibility statuses are recognized:<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
=== type ===<br />
<br />
* ''widget''.'''type''' &rarr; ''string''<br />
* Available on: All widgets<br />
<br />
Returns a string specifying the type of the widget.<br />
<br />
== Widget callbacks ==<br />
<br />
=== on_modified ===<br />
<br />
* ''widget''.'''on_modified''' &larr; ''function''<br />
* Available on: Most widgets, in particular '''[slider]''', '''[toggle_button]''', '''[listbox]''', '''[menu_button]''', '''[text_box]'''<br />
<br />
Triggers when the user changes the value of the widget.<br />
<br />
=== on_left_click ===<br />
<br />
* ''widget''.'''on_left_click''' &larr; ''function''<br />
* Available on: All widgets<br />
<br />
Triggers when the user clicks on the widget.<br />
<br />
=== on_button_click ===<br />
<br />
* ''widget''.'''on_button_click''' &larr; ''function''<br />
* Available on: '''[button]''', '''[repeating_button]'''<br />
<br />
Triggers when the user clicks on the button. This can differ from '''on_left_click''', depending on the type of widget. For example, on a '''[repeating_button]''' it will fire multiple times if the user holds the mouse button down.<br />
<br />
== Widget methods ==<br />
<br />
Any function defined in the [[LuaAPI/gui/widget|gui.widget]] module and taking a widget as its first parameter can be called as a method of a widget. This includes any functions that are added to the module by user code. Note that these methods are available even if the widget itself doesn't support that function, so in some cases it may be necessary to check '''widget.type''' befor calling the method.</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/gui/widget&diff=66081LuaAPI/gui/widget2020-09-27T22:59:03Z<p>Gfgtdf: /* find */</p>
<hr />
<div><br />
The '''gui.widget''' module contains functions for managing widgets in custom GUI2 dialogs. Since these functions take a widget userdata as the first parameter, they can only be used in the preshow or postshow of a GUI2 dialog (directly or indirectly). However, the table is available at all times, and additional methods can be installed here for unusual needs.<br />
<br />
=== focus ===<br />
<br />
* '''gui.widget.focus'''(''widget'')<br />
* ''widget'':'''focus'''()<br />
<br />
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
=== set_canvas ===<br />
<br />
* '''gui.widget.set_canvas'''(''widget'', ''layer index'', ''content'')<br />
* ''widget'':'''set_canvas'''(''layer index'', ''content'')<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
<syntaxhighlight lang=lua><br />
-- draw two rectangles in the upper-left corner of the window (assume dialog is the window widget)<br />
dialog.set_canvas(2, {<br />
wml.tag.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
wml.tag.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
</syntaxhighlight><br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
=== add_item ===<br />
<br />
* '''gui.widget.add_item'''(''widget''[, ''position'']) &rarr; ''the new item'', ''position''<br />
* ''widget'':'''add_item'''([''position'']) &rarr; ''the new item'', ''position''<br />
<br />
Add an item to a container widget, for example a listbox. Returns the created item as a widget userdata. You can pass a negative position to count from the end of the container, but the returned position is always positive.<br />
<br />
=== add_item_of_type ===<br />
<br />
* '''gui.widget.add_item_of_type'''(''widget'', ''category''[, ''position'']) &rarr; ''the new item'', ''position''<br />
* ''widget'':'''add_item_of_type'''(''category''[, ''position'']) &rarr; ''the new item'', ''position''<br />
<br />
Add an item to a widget which is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews. You can pass a negative position to count from the end of the container, but the returned position is always positive.<br />
<br />
=== remove_items_at ===<br />
<br />
* '''gui.widget.remove_items_at'''(''widget'', ''position'')<br />
* ''widget'':'''remove_items_at'''(''position'')<br />
<br />
Removes the widget at the given index of a container type widget (like treeviews).<br />
<br />
=== find ===<br />
<br />
* '''gui.widget.find'''(''root widget'', ''path, to, widget'')<br />
* ''widget'':'''find'''(''path, to, widget'')<br />
<br />
Finds a child widget of the widget of the given path. For example, here it searches for the widget with the id 'preview_panel' of the second item of the widget with the id 'unit_list':<br />
<br />
<syntaxhighlight lang=lua><br />
dialog:find(unit_list, 2, preview_panel)<br />
</syntaxhighlight><br />
<br />
=== close ===<br />
<br />
* '''gui.widget.close'''(''dialog'')<br />
* ''widget'':'''close'''()<br />
* Not Yet Implemented<br />
<br />
Closes the dialog.</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66076LuaAPI/types/widget2020-09-27T22:24:03Z<p>Gfgtdf: </p>
<hr />
<div>The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only; the properties depend on the type of the widget.<br />
<br />
An example of accessing a child widget:<br />
<br />
<syntaxhighlight lang=lua><br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
</syntaxhighlight><br />
<br />
== Widget Attributes ==<br />
<br />
=== selected ===<br />
<br />
* '''w.selected = value'''<br />
* '''boolean'''<br />
* '''get/set'''<br />
* [toggle_button], [toggle_panel]<br />
<br />
Whether the item is selected or not.<br />
<br />
=== selected_index ===<br />
<br />
* '''w.selected_index = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel])<br />
<br />
The selected index of the item.<br />
<br />
=== text ===<br />
<br />
* '''w.text = value'''<br />
* '''string'''<br />
* '''get/set'''<br />
* [text_box]<br />
<br />
The text of the textbox.<br />
<br />
=== value ===<br />
<br />
* '''w.value = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [slider]<br />
<br />
=== percentage ===<br />
<br />
* '''w.percentage = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [progress_bar]<br />
<br />
=== selected_item_path ===<br />
<br />
* '''value = w.selected_item_path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [slider]<br />
<br />
A table describing the currently selected node. If for example, in the following treeview. Item 9 is selected, the result will be {2,1,3}.<br />
<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
<br />
=== path ===<br />
<br />
* '''value = w.path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [tree_view_node]<br />
<br />
See selected_item_path for the syntax.<br />
<br />
=== unfolded ===<br />
<br />
* '''w.unfolded = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* [tree_view_node]<br />
<br />
=== unit ===<br />
<br />
* '''w.unit = value'''<br />
* '''unit''' or '''unit type'''<br />
* '''set'''<br />
* [unit_preview_pane]<br />
<br />
=== item_count ===<br />
<br />
* '''value = w.item_count'''<br />
* '''number'''<br />
* '''get'''<br />
* [multi_page], [listbox]<br />
<br />
=== use_markup ===<br />
<br />
* '''w.use_markup = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
<br />
=== label ===<br />
<br />
* '''w.label = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button], [image]<br />
<br />
The label, technically this is a special string used in the widgets wml definition. It usually does what one would expect, but also sets the image for [image] widgets.<br />
<br />
=== marked_up_text ===<br />
<br />
* '''w.marked_up_text = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
<br />
Shortcut for setting label and use_markup=yes.<br />
<br />
=== enabled ===<br />
<br />
* '''w.enabled = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* all widgets<br />
<br />
=== tooltip ===<br />
<br />
* '''w.tooltip = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
<br />
=== visible ===<br />
<br />
* '''w.visible = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
<br />
The following visibility statuses are recognized:<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
=== type ===<br />
<br />
* '''value = w.type'''<br />
* '''string'''<br />
* '''get'''<br />
* all widgets<br />
<br />
== widget callbacks ==<br />
=== on_modified ===<br />
<br />
* '''function w.on_modified() .... end<br />
* all widgets the allow the user to select a value of any type.<br />
<br />
=== on_left_click ===<br />
<br />
* '''function w.on_left_click() .... end<br />
* all widgets<br />
<br />
=== on_button_click ===<br />
<br />
* '''function w.on_button_click() .... end<br />
* button type widgets<br />
<br />
== widget methods ==<br />
<br />
=== focus ===<br />
<br />
* '''w:focus()'''<br />
<br />
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
=== set_canvas ===<br />
<br />
* '''w:set_canvas(layer index, content)'''<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
<syntaxhighlight lang=lua><br />
-- draw two rectangles in the upper-left corner of the window (assume dialog is the window widget)<br />
dialog:set_canvas(2, {<br />
wml.tag.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
wml.tag.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
</syntaxhighlight><br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
=== add_item ===<br />
<br />
* '''w:add_item()'''<br />
<br />
Add an item to a widget, for example a listbox. Returns the created item as a widget userdata.<br />
<br />
=== add_item_of_type ===<br />
<br />
* '''w:add_item_of_type("category")'''<br />
<br />
Add an item to a widget which is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews.<br />
<br />
=== remove_items_at ===<br />
<br />
* '''w:remove_items_at(2)'''<br />
<br />
Removes the widget at the given index of a container type widget (like treeviews).<br />
<br />
=== find ===<br />
<br />
* '''dialog:find(unit_list, 2, preview_panel)'''<br />
<br />
Finds a child widget of the widget of the given path. For example, here it searches for the widget with the id 'preview_panel' of the second item of the widget with the id 'unit_list'</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66075LuaAPI/types/widget2020-09-27T22:20:26Z<p>Gfgtdf: /* set_canvas */</p>
<hr />
<div>The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only; the properties depend on the type of the widget.<br />
<br />
An example of accessing a child widget:<br />
<br />
<syntaxhighlight lang=lua><br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
</syntaxhighlight><br />
<br />
== Widget Attributes ==<br />
<br />
=== selected ===<br />
<br />
* '''w.selected = value'''<br />
* '''boolean'''<br />
* '''get/set'''<br />
* [toggle_button], [toggle_panel]<br />
<br />
Whether the item is selected or not.<br />
<br />
=== selected_index ===<br />
<br />
* '''w.selected_index = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel])<br />
<br />
The selected index of the item.<br />
<br />
=== text ===<br />
<br />
* '''w.text = value'''<br />
* '''string'''<br />
* '''get/set'''<br />
* [text_box]<br />
<br />
The text of the textbox.<br />
<br />
=== value ===<br />
<br />
* '''w.value = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [slider]<br />
<br />
=== percentage ===<br />
<br />
* '''w.percentage = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [progress_bar]<br />
<br />
=== selected_item_path ===<br />
<br />
* '''value = w.selected_item_path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [slider]<br />
<br />
A table describing the currently selected node. If for example, in the following treeview. Item 9 is selected, the result will be {2,1,3}.<br />
<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
<br />
=== path ===<br />
<br />
* '''value = w.path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [tree_view_node]<br />
<br />
See selected_item_path for the syntax.<br />
<br />
=== unfolded ===<br />
<br />
* '''w.unfolded = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* [tree_view_node]<br />
<br />
=== unit ===<br />
<br />
* '''w.unit = value'''<br />
* '''unit''' or '''unit type'''<br />
* '''set'''<br />
* [unit_preview_pane]<br />
<br />
=== item_count ===<br />
<br />
* '''value = w.item_count'''<br />
* '''number'''<br />
* '''get'''<br />
* [multi_page], [listbox]<br />
<br />
=== use_markup ===<br />
<br />
* '''w.use_markup = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
<br />
=== label ===<br />
<br />
* '''w.label = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button], [image]<br />
<br />
The label, technically this is a special string used in the widgets wml definition. It usually does what one would expect, but also sets the image for [image] widgets.<br />
<br />
=== marked_up_text ===<br />
<br />
* '''w.marked_up_text = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
<br />
Shortcut for setting label and use_markup=yes.<br />
<br />
=== enabled ===<br />
<br />
* '''w.enabled = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* all widgets<br />
<br />
=== tooltip ===<br />
<br />
* '''w.tooltip = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
<br />
=== visible ===<br />
<br />
* '''w.visible = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
<br />
The following visibility statuses are recognized:<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
=== type ===<br />
<br />
* '''value = w.type'''<br />
* '''string'''<br />
* '''get'''<br />
* all widgets<br />
<br />
== widget callbacks ==<br />
=== on_modified ===<br />
<br />
* '''function w.on_modified() .... end<br />
* all widgets the allow the user to select a value of any type.<br />
<br />
=== on_left_click ===<br />
<br />
* '''function w.on_left_click() .... end<br />
* all widgets<br />
<br />
=== on_button_click ===<br />
<br />
* '''function w.on_button_click() .... end<br />
* button type widgets<br />
<br />
== widget methods ==<br />
<br />
=== focus ===<br />
<br />
* '''w.focus()'''<br />
<br />
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
<br />
=== set_canvas ===<br />
<br />
* '''w.set_canvas(layer index, content)'''<br />
<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
<syntaxhighlight lang=lua><br />
-- draw two rectangles in the upper-left corner of the window (assume dialog is the window widget)<br />
dialog:set_canvas(2, {<br />
wml.tag.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
wml.tag.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
</syntaxhighlight><br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
<br />
=== add_item ===<br />
<br />
* '''w.add_item()'''<br />
<br />
Add an item to a widget, for example a listbox. Returns the created item as a widget userdata.<br />
<br />
=== add_item_of_type ===<br />
<br />
* '''w.add_item_of_type("category")'''<br />
<br />
Add an item to a widget which is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews.<br />
<br />
=== remove_items_at ===<br />
<br />
* '''w.remove_items_at(2)'''<br />
<br />
Removes the widget at the given index of a container type widget (like treeviews).<br />
<br />
=== find ===<br />
<br />
* '''dialog.find(unit_list, 2, preview_panel)'''<br />
<br />
Finds a child widget of the widget of the given path. For example, here it searches for the widget with the id 'preview_panel' of the second item of the widget with the id 'unit_list'</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66073LuaAPI/types/widget2020-09-27T21:39:26Z<p>Gfgtdf: </p>
<hr />
<div>the 'widget' userdata offers access to a widget of a gui2 dialog, while there is only one type of widget userdata that covers all widgets including the window itself, The properties of a widget userdataq are different for each widgets. Indexing a widgets userdata can either be used to<br />
<br />
* Access a child widget<br />
Example code<br />
```<br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
``` or to <br />
* Set/Get a property of a widget Some Properties are read-only, the propertied depends on the type of the widget, the following properties exist:<br />
<br />
<br />
=== widget attributes ===<br />
==== selected ====<br />
* '''w.selected = value'''<br />
* '''boolean'''<br />
* '''get/set'''<br />
* [toggle_button], [toggle_panel]<br />
whether the item is selected or not<br />
==== selected_index ====<br />
* '''w.selected_index = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel])<br />
the selected index of the item<br />
==== text ====<br />
* '''w.text = value'''<br />
* '''string'''<br />
* '''get/set'''<br />
* [text_box]<br />
the text of the textbox<br />
==== value ====<br />
* '''w.value = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [slider]<br />
==== percentage ====<br />
* '''w.percentage = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [progress_bar]<br />
==== selected_item_path ====<br />
* '''value = w.selected_item_path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [slider]<br />
a table descibing the currently selected node. If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selected the value will be {2,1,3}<br />
==== path ====<br />
* '''value = w.path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [tree_view_node]<br />
See selected_item_path for the syntax.<br />
==== unfolded ====<br />
* '''w.unfolded = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* [tree_view_node]<br />
==== unit ====<br />
* '''w.unit = value'''<br />
* '''unit''' or '''unit type'''<br />
* '''set'''<br />
* [unit_preview_pane]<br />
==== item_count ====<br />
* '''value = w.item_count'''<br />
* '''number'''<br />
* '''get'''<br />
* [multi_page], [listbox]<br />
==== use_markup ====<br />
* '''w.use_markup = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
==== label ====<br />
* '''w.label = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button], [image]<br />
the label, technically the is a special string used in the widgets wml definition, it usualyl does what one would expect but also sets the image for [image] widgets<br />
==== marked_up_text ====<br />
* '''w.marked_up_text = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
shortcut for setting label and use_markup=yes<br />
==== enabled ====<br />
* '''w.enabled = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* all widgets<br />
==== tooltip ====<br />
* '''w.tooltip = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
==== visible ====<br />
* '''w.visible = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
The following visibility statuses are recognized:<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
==== type ====<br />
* '''value = w.type'''<br />
* '''string'''<br />
* '''get'''<br />
* all widgets<br />
=== widget callbacks ===<br />
==== on_modified ====<br />
* '''function w.on_modified() .... end<br />
* all widgets the allow the user to select a value of any type.<br />
==== on_left_click ====<br />
* '''function w.on_left_click() .... end<br />
* all widgets<br />
==== on_button_click ====<br />
* '''function w.on_button_click() .... end<br />
* button type widgets<br />
<br />
=== widget methods ===<br />
<br />
==== focus ====<br />
* '''w.focus()'''<br />
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
==== set_canvas ====<br />
* '''w.set_canvas(layer index, content)'''<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
-- draw two rectangles in the upper-left corner of the window (empty path = window widget)<br />
wesnoth.set_dialog_canvas(2, {<br />
T.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
T.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
==== add_item ====<br />
* '''w.add_item()'''<br />
add an item to a widget, for example a listbox, returns the created item as a widget userdata.<br />
==== add_item_of_type ====<br />
* '''w.add_item_of_type("category")'''<br />
add an item to a widget which Is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews<br />
==== remove_items_at ====<br />
* '''w.remove_items_at(2)'''<br />
removes the widget at the given index of a container type widget (like treeviews).<br />
==== find ====<br />
* '''dialog.find(unit_list, 2, preview_panel)'''<br />
Finds a child widget of the widget of the given path, for example here is searches for the widget with the id 'preview_panel' of the second item of the widget with the id 'unit_list'</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66072LuaAPI/types/widget2020-09-27T21:36:19Z<p>Gfgtdf: </p>
<hr />
<div>the 'widget' userdata offers access to a widget of a gui2 dialog, while there is only one type of widget userdata that covers all widgets including the window itself, The properties of a widget userdataq are different for each widgets. Indexing a widgets userdata can either be used to<br />
<br />
* Access a child widget<br />
Example code<br />
```<br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
``` or to <br />
* Set/Get a property of a widget Some Properties are read-only, the propertied depends on the type of the widget, the following properties exist:<br />
<br />
<br />
=== widget attributes ===<br />
==== selected ====<br />
* '''w.selected = value'''<br />
* '''boolean'''<br />
* '''get/set'''<br />
* [toggle_button], [toggle_panel]<br />
whether the item is selected or not<br />
==== selected_index ====<br />
* '''w.selected_index = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel])<br />
the selected index of the item<br />
==== text ====<br />
* '''w.text = value'''<br />
* '''string'''<br />
* '''get/set'''<br />
* [text_box]<br />
the text of the textbox<br />
==== value ====<br />
* '''w.value = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [slider]<br />
==== percentage ====<br />
* '''w.percentage = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [progress_bar]<br />
==== selected_item_path ====<br />
* '''value = w.selected_item_path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [slider]<br />
a table descibing the currently selected node. If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selected the value will be {2,1,3}<br />
==== path ====<br />
* '''value = w.path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [tree_view_node]<br />
See selected_item_path for the syntax.<br />
==== unfolded ====<br />
* '''w.unfolded = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* [tree_view_node]<br />
==== unit ====<br />
* '''w.unit = value'''<br />
* '''unit''' or '''unit type'''<br />
* '''set'''<br />
* [unit_preview_pane]<br />
==== item_count ====<br />
* '''value = w.item_count'''<br />
* '''number'''<br />
* '''get'''<br />
* [multi_page], [listbox]<br />
==== use_markup ====<br />
* '''w.use_markup = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
==== label ====<br />
* '''w.label = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button], [image]<br />
the label, technically the is a special string used in the widgets wml definition, it usualyl does what one would expect but also sets the image for [image] widgets<br />
==== marked_up_text ====<br />
* '''w.marked_up_text = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
shortcut for setting label and use_markup=yes<br />
==== enabled ====<br />
* '''w.enabled = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* all widgets<br />
==== tooltip ====<br />
* '''w.tooltip = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
==== visible ====<br />
* '''w.visible = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
The following visibility statuses are recognized:<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
==== type ====<br />
* '''value = w.type'''<br />
* '''string'''<br />
* '''get'''<br />
* all widgets<br />
=== widget callbacks ===<br />
==== on_modified ====<br />
* '''function w.on_modified() .... end<br />
* all widgets the allow the user to select a value of any type.<br />
==== on_left_click ====<br />
* '''function w.on_left_click() .... end<br />
* all widgets<br />
==== on_button_click ====<br />
* '''function w.on_button_click() .... end<br />
* button type widgets<br />
<br />
=== widget methods ===<br />
<br />
==== focus ====<br />
* '''w.focus()'''<br />
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.<br />
==== set_canvas ====<br />
* '''w.set_canvas(layer index, content)'''<br />
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table is described at [[GUICanvasWML]].<br />
<br />
-- draw two rectangles in the upper-left corner of the window (empty path = window widget)<br />
wesnoth.set_dialog_canvas(2, {<br />
T.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= "0,0,255,255" },<br />
T.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = "255,0,0,255" }<br />
})<br />
<br />
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.<br />
==== add_item ====<br />
* '''w.add_item()'''<br />
add an item to a widget, for example a listbox, returns the created item as a widget userdata.<br />
==== add_item_of_type ====<br />
* '''w.add_item_of_type("category")'''<br />
add an item to a widget which Is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66071LuaAPI/types/widget2020-09-27T21:30:44Z<p>Gfgtdf: </p>
<hr />
<div>the 'widget' userdata offers access to a widget of a gui2 dialog, while there is only one type of widget userdata that covers all widgets including the window itself, The properties of a widget userdataq are different for each widgets. Indexing a widgets userdata can either be used to<br />
<br />
* Access a child widget<br />
Example code<br />
```<br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
``` or to <br />
* Set/Get a property of a widget Some Properties are read-only, the propertied depends on the type of the widget, the following properties exist:<br />
<br />
<br />
=== widget attributes ===<br />
==== selected ====<br />
* '''w.selected = value'''<br />
* '''boolean'''<br />
* '''get/set'''<br />
* [toggle_button], [toggle_panel]<br />
whether the item is selected or not<br />
==== selected_index ====<br />
* '''w.selected_index = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel])<br />
the selected index of the item<br />
==== text ====<br />
* '''w.text = value'''<br />
* '''string'''<br />
* '''get/set'''<br />
* [text_box]<br />
the text of the textbox<br />
==== value ====<br />
* '''w.value = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [slider]<br />
==== percentage ====<br />
* '''w.percentage = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [progress_bar]<br />
==== selected_item_path ====<br />
* '''value = w.selected_item_path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [slider]<br />
a table descibing the currently selected node. If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selected the value will be {2,1,3}<br />
==== path ====<br />
* '''value = w.path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [tree_view_node]<br />
See selected_item_path for the syntax.<br />
==== unfolded ====<br />
* '''w.unfolded = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* [tree_view_node]<br />
==== unit ====<br />
* '''w.unit = value'''<br />
* '''unit''' or '''unit type'''<br />
* '''set'''<br />
* [unit_preview_pane]<br />
==== item_count ====<br />
* '''value = w.item_count'''<br />
* '''number'''<br />
* '''get'''<br />
* [multi_page], [listbox]<br />
==== use_markup ====<br />
* '''w.use_markup = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
==== label ====<br />
* '''w.label = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button], [image]<br />
the label, technically the is a special string used in the widgets wml definition, it usualyl does what one would expect but also sets the image for [image] widgets<br />
==== marked_up_text ====<br />
* '''w.marked_up_text = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
shortcut for setting label and use_markup=yes<br />
==== enabled ====<br />
* '''w.enabled = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* all widgets<br />
==== tooltip ====<br />
* '''w.tooltip = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
==== visible ====<br />
* '''w.visible = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
The following visibility statuses are recognized:<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
==== type ====<br />
* '''value = w.type'''<br />
* '''string'''<br />
* '''get'''<br />
* all widgets<br />
=== widget callbacks ===<br />
==== on_modified ====<br />
* '''function w.on_modified() .... end<br />
* all widgets the allow the user to select a value of any type.<br />
==== on_left_click ====<br />
* '''function w.on_left_click() .... end<br />
* all widgets<br />
==== on_button_click ====<br />
* '''function w.on_button_click() .... end<br />
* button type widgets</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66070LuaAPI/types/widget2020-09-27T21:29:05Z<p>Gfgtdf: </p>
<hr />
<div>the 'widget' userdata offers access to a widget of a gui2 dialog, while there is only one type of widget userdata that covers all widgets including the window itself, The properties of a widget userdataq are different for each widgets. Indexing a widgets userdata can either be used to<br />
<br />
* Access a child widget<br />
Example code<br />
```<br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
``` or to <br />
* Set/Get a property of a widget Some Properties are read-only, the propertied depends on the type of the widget, the following properties exist:<br />
<br />
<br />
=== widget attributes ===<br />
<br />
<br />
==== selected ====<br />
<br />
* '''w.selected = value'''<br />
* '''boolean'''<br />
* '''get/set'''<br />
* [toggle_button], [toggle_panel]<br />
<br />
whether the item is selected or not<br />
<br />
<br />
==== selected_index ====<br />
<br />
* '''w.selected_index = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel])<br />
<br />
the selected index of the item<br />
<br />
<br />
==== text ====<br />
<br />
* '''w.text = value'''<br />
* '''string'''<br />
* '''get/set'''<br />
* [text_box]<br />
<br />
the text of the textbox<br />
<br />
==== value ====<br />
<br />
* '''w.value = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [slider]<br />
<br />
<br />
==== percentage ====<br />
<br />
* '''w.percentage = value'''<br />
* '''number'''<br />
* '''get/set'''<br />
* [progress_bar]<br />
<br />
<br />
==== selected_item_path ====<br />
<br />
* '''value = w.selected_item_path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [slider]<br />
<br />
a table descibing the currently selected node. If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selected the value will be {2,1,3}<br />
<br />
==== path ====<br />
<br />
* '''value = w.path'''<br />
* '''array of integers'''<br />
* '''get'''<br />
* [tree_view_node]<br />
<br />
See selected_item_path for the syntax.<br />
<br />
<br />
==== unfolded ====<br />
<br />
* '''w.unfolded = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* [tree_view_node]<br />
<br />
<br />
==== unit ====<br />
<br />
* '''w.unit = value'''<br />
* '''unit''' or '''unit type'''<br />
* '''set'''<br />
* [unit_preview_pane]<br />
<br />
<br />
==== item_count ====<br />
<br />
* '''value = w.item_count'''<br />
* '''number'''<br />
* '''get'''<br />
* [multi_page], [listbox]<br />
<br />
==== use_markup ====<br />
<br />
* '''w.use_markup = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
<br />
==== label ====<br />
<br />
* '''w.label = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button], [image]<br />
<br />
the label, technically the is a special string used in the widgets wml definition, it usualyl does what one would expect but also sets the image for [image] widgets<br />
<br />
==== marked_up_text ====<br />
<br />
* '''w.marked_up_text = value'''<br />
* '''string'''<br />
* '''set'''<br />
* most widgets, in particular [label], [button]<br />
<br />
shortcut for setting label and use_markup=yes<br />
<br />
<br />
==== enabled ====<br />
<br />
* '''w.enabled = value'''<br />
* '''boolean'''<br />
* '''set'''<br />
* all widgets<br />
<br />
==== tooltip ====<br />
<br />
* '''w.tooltip = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
<br />
<br />
==== visible ====<br />
<br />
* '''w.visible = value'''<br />
* '''string'''<br />
* '''set'''<br />
* all widgets<br />
<br />
The following visibility statuses are recognized:<br />
<br />
{| clasS="wikitable"<br />
! String value !! Boolean shorthand !! Meaning<br />
|-<br />
| visible || true || The widget is visible and handles events.<br />
|-<br />
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.<br />
|-<br />
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.<br />
|}<br />
<br />
<br />
==== type ====<br />
<br />
* '''value = w.type'''<br />
* '''string'''<br />
* '''get'''<br />
* all widgets<br />
<br />
<br />
<br />
=== widget callbacks ===<br />
<br />
==== on_modified ====<br />
* '''function w.on_modified() .... end<br />
* all widgets the allow the user to select a value of any type.<br />
<br />
==== on_left_click ====<br />
* '''function w.on_left_click() .... end<br />
* all widgets<br />
<br />
==== on_button_click ====<br />
* '''function w.on_button_click() .... end<br />
* button type widgets</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&diff=66069LuaAPI/types/widget2020-09-27T21:14:45Z<p>Gfgtdf: Created page with "the 'widget' userdata offers access to a widget of a gui2 dialog, whiel there is only one type of widget userdata tha covers all widgets including the window itself, The prope..."</p>
<hr />
<div>the 'widget' userdata offers access to a widget of a gui2 dialog, whiel there is only one type of widget userdata tha covers all widgets including the window itself, The properties of a widget userdataq are different for each widgets. Indexing a widgets userdata cen either be sued to<br />
* Access a child widget<br />
Example code<br />
```<br />
function preshow(dialog)<br />
local okay_button = dialog.okay_button<br />
-- okay_button is now a handle to the the widgets child with the id 'okay_button' <br />
end<br />
```<br />
* Set/Get a property of a widget<br />
Some Properties are read-only, the propertied depends on the type of the widget, the follwing properties exist:<br />
** selected get/set '''boolean''', [toggle_button], [toggle_panel]:whether the item is selected or not<br />
** selected_index, get/set '''integer''', [listbox], [multi_page], [stacked_widget], selectable_item ([menu_button], [toggle_button], [toggle_panel]) :the selected index of the item.<br />
** text, get/set '''string''', [text_box]: the text of the textbox .<br />
** value, get/set, '''integer''' [slider]: the value of the slider<br />
** percentage, get/set, '''integer''' [progress_bar]<br />
** selected_item_path, get '''array of integers''' [tree_view]: a table descibing the currently selected node. If for example in this treeview<br />
+Section1<br />
+Subsection11<br />
*Item1<br />
*Item2<br />
*Item3<br />
+Subsection12<br />
*Item4<br />
*Item5<br />
*Item6<br />
+Section2<br />
+Subsection21<br />
*Item7<br />
*Item8<br />
*Item9<br />
+Subsection22<br />
*Item10<br />
*Item11<br />
*Item12<br />
Item 9 is selected the value will be {2,1,3}<br />
** path, get '''array of integers''' [tree_view_node] table of integers, see selected_item_path<br />
** unfolded, set '''boolean''' [tree_view_node]: whether a node of a treeview is unfolded or not<br />
** unit, set '''unit''' or '''unit type''' userdata [unit_preview_pane]<br />
** item_count, get '''integer''' [multi_page], [listbox]<br />
** use_markup, set, '''boolean''' most widgets, in particular [label], [button]<br />
** marked_up_text, set, '''string''' most widgets, in particular [label], [button]: a shortcut for settigns label with use_markup=true<br />
** enabled, set '''boolean''', all widgets<br />
** tooltip, set '''string''', all widgets<br />
** visible, set '''string''', all widgets<br />
** label, set '''string''', all widgets: the label, technically the is a special string used in the widgets wml definition, it usualyl does what one would expect but also sets the image for [image] widgets<br />
** type, get '''string''', all widgtes<br />
the type of the widget<br />
<br />
<br />
on_modified<br />
"on_left_click<br />
"on_button_click</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=AbilitiesWML&diff=65862AbilitiesWML2020-08-07T11:37:37Z<p>Gfgtdf: /* Available formula variables in Abilities and Weapon Sepcials */</p>
<hr />
<div>{{WML Tags}}<br />
== Abilities and their effects ==<br />
<br />
There are two types of abilities: ones that apply to units (called ''abilities'') and ones that only apply when using a particular attack (called ''specials'' or ''weapon specials''). A unit may have multiple abilities and an attack can have multiple specials, but by convention only one weapon special should be assigned to any given attack.<br />
<br />
== The ''[abilities]'' tag ==<br />
<br />
The following tags are used to describe an ability in WML:<br />
<br />
* '''[heals]''': modifies the hitpoints of a unit at the beginning of the healer's turn<br />
* '''[regenerate]''': modifies the hitpoints of a unit at the beginning of the unit's turn<br />
* '''[resistance]''': modifies the resistance of a unit to damage<br />
* '''[leadership]''': modifies the damage of a unit<br />
* '''[skirmisher]''': negates enemy zones of control<br />
* '''[illuminates]''': modifies the time of day adjacent to the affected units<br />
* '''[teleport]''': allows the unit to teleport<br />
* '''[hides]''': renders the unit invisible to enemies<br />
* {{DevFeature1.15|0}} A tag matching a [[#The_.5Bspecials.5D_tag|weapon special tag]] will confer that weapon special to units based on the given conditions. Most weapon specials are supported; however, '''plagues''', '''heal_on_hit''', and '''swarm''' are not.<br />
Any other name is valid (for example '''[dummy]'''), but will result in an ability that does nothing but report it's there. These tags still use the same common keys and tags as every other ability. '''Note:''' a dummy ability must have an id for the name and description to display.<br />
<br />
=== Available formula variables in Abilities and Weapon Sepcials ===<br />
<br />
{{DevFeature1.15|?}} When using formulas in abilities and weapon specials, the following formula variables are available:<br />
* '''self''': (unit) the unit that has the ability<br />
* '''student''': (unit) for leadership-like abilities this is the unit that is adjacent to the unit that has the ability.<br />
* '''attacker''': (unit) for attack-related abilities and weapon specials, this is the attacking unit during the attack.<br />
* '''defender''': (unit) for attack-related abilities and weapon specials, this is the defending unit during the attack.<br />
* '''other''': (unit) the unit whose stats get modified from the ability. For abilities without 'apply_to=opponent' this is always the same as 'student'.<br />
<br />
=== Common keys and tags for every ability ===<br />
<br />
{{DevFeature1.13|?}} All keys inside any ability that expects a numeric value will also accept formulas using <br />
[[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses.<br />
<br />
* '''name''': the (translatable) name of the ability.<br />
* '''female_name''': the (translatable) name of the ability when possessed by a female unit. Defaults to ''name'' if not specified.<br />
* '''name_inactive''': the (translatable) name of the ability when inactive. Defaults to ''name'' if not specified; if the ability is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).<br />
* '''female_name_inactive''': the (translatable) name of the ability when inactive and possessed by a female unit. Defaults to ''name_inactive'' if not specified.<br />
* '''description''': the (translatable) description of the ability.<br />
* '''description_inactive''': the (translatable) description of the ability when inactive. Defaults to ''description'' if not specified.<br />
* '''affect_self''': if equal to 'yes' (default), the ability will affect the unit that has it.<br />
* '''affect_allies''': if equal to 'yes', the ability will affect units from the same and allied sides in the specified adjacent hexes. If set to 'no' it will not affect own or allied sides. If not set (default) it will affect units on the same side but not from allied sides.<br />
* '''affect_enemies''': if equal to 'yes' (default is 'no'), the ability will affect enemies in the specified adjacent hexes.<br />
* '''cumulative''': if set to 'yes', this ability will be cumulative with the base value for this ability.<br />
* '''id''': this ability will not be cumulative with other abilities using this id. Must be present if cumulative is anything other than 'yes'.<br />
* '''[filter]''': [[StandardUnitFilter]] If the unit owning the ability does not match this filter, the ability will be inactive.<br />
* '''[affect_adjacent]''': an adjacent unit that does not match this filter will not receive its effects. There can be multiple [affect_adjacent] tags in a single ability; a unit needs to match any one of these to receive the effects. The side requirement of matching units is defined by the '''affect_allies''' and '''affect_enemies''' keys. If there are no [affect_adjacent] tags, then no adjacent units will receive the effects.<br />
** '''adjacent''': a comma separated list of any combination of these directions: '''n''','''ne''','''se''','''s''','''sw''','''nw'''. (See [[StandardLocationFilter#Directions|notes]])<br />
** '''[filter]''': a [[StandardUnitFilter]]. {{DevFeature1.13|2}} The variable $other_unit refers to the unit owning the ability.<br />
* '''[filter_self]''': if the owner of the ability does not match this filter, it will not receive the effects of the ability. [filter_self] takes a [[StandardUnitFilter]] as argument.<br />
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the ability will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). In fact, it's really a shorthand for a [filter_adjacent] nested within [filter]. The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate.<br />
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter][filter_location][filter_adjacent_location].<br />
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', etc. If several keys are used all have to match.<br />
<br />
=== Extra keys used by the ''[heals]'' ability ===<br />
<br />
* '''value''': the amount healed.<br />
* '''poison''': can be one of ''slowed'',''cured''. ''slowed'' means poison will not take effect for adjacent units (it's not related to the weapon special "slows").<br />
<br />
=== Extra keys used by the ''[regenerate]'' ability ===<br />
<br />
* '''value''': the amount healed.<br />
* '''poison''': can be one of ''slowed'',''cured''.<br />
<br />
=== Extra keys and tags used by the ''[resistance]'' ability ===<br />
<br />
* '''value''': set resistance to this value.<br />
* '''max_value''': maximum resistance value. This value '''must''' be set in order for [resistance] to function.<br />
* '''add''': adds to resistance.<br />
* '''sub''': subtracts from resistance.<br />
* '''multiply''': multiplies resistance value. <br />
* '''divide''': divides resistance value.<br />
* '''apply_to''': a list of damage types; if left out, the ability applies to all types.<br />
* '''active_on''': one of 'defense' or 'offense'; if left out, the ability is active on both.<br />
These keys affect the actual resistance (e.g. -20%), not the damage modifier normally used in [resistance] (e.g. 120).<br />
* '''[filter_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the owner of the ability uses a matching weapon.<br />
* '''[filter_second_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the opponent uses a matching weapon.<br />
* '''[filter_student]''': {{DevFeature1.15|0}} If present, the ability only takes effect on units matching this filter.<br />
<br />
=== Extra keys used by the ''[leadership]'' ability ===<br />
<br />
* '''value''': the percentage bonus to damage.<br />
* '''[filter_weapon]''': If present, the leadership ability only takes effect when the owner of the ability uses a matching weapon.<br />
* '''[filter_second_weapon]''': If present, the leadership ability only takes effect when the opponent uses a matching weapon.<br />
* '''[filter_student]''': {{DevFeature1.15|0}} If present, the ability only takes effect on units matching this filter.<br />
<br />
=== Extra keys used by the ''[illuminates]'' ability ===<br />
<br />
Because this ability changes the terrain instead of units on it, affect_self, affect_allies, affect_enemies and [filter_adjacent] have no effect.<br />
* '''value''': the percentage bonus to lawful units. Units with '''alignment=lawful''' do +''value'' % damage when under the influence of a unit with this ability. Units with '''alignment=chaotic''' do -''value'' % damage. Units with '''alignment=neutral''' are unaffected by this ability. Units with '''alignment=liminal''' do -(abs(''value'')) % damage. ''value'' can be a negative number; this is useful if you want to give Chaotic units an advantage instead of Lawful ones. <br />
* '''max_value''': the maximum percentage bonus given.<br />
* '''min_value''': the minimum percentage bonus given.<br />
<br />
=== Extra keys used by the ''[hides]'' ability ===<br />
<br />
* '''alert''': the displayed text when the unit is discovered. Default "Ambushed!".<br />
<br />
=== Extra tags used by the ''[teleport]'' ability ===<br />
<br />
* '''[tunnel]''' - a [[DirectActionsWML#.5Btunnel.5D|tunnel tag]] (without the remove key) defining the tunneling source and target hexes, and maybe other conditions. (It automatically applies only to the unit with the ability.) You may use $teleport_unit inside the tunnel tag for filtering purposes.<br />
<br />
=== Extra tags and keys used by weapon special abilities ===<br />
<br />
* '''[filter_weapon]''': If present, the ability only takes effect when the owner of the ability uses a matching weapon.<br />
* '''[filter_second_weapon]''': If present, the ability only takes effect when the opponent uses a matching weapon.<br />
* '''[filter_student]''': If present, the ability only takes effect on units matching this filter.<br />
* Other keys and tags appropriate to the specific weapon special<br />
<br />
=== Macros for common abilities ===<br />
<br />
* ABILITY_AMBUSH<br />
* ABILITY_CURES<br />
* ABILITY_HEALS<br />
* ABILITY_ILLUMINATES<br />
* ABILITY_LEADERSHIP_LEVEL_1 to ABILITY_LEADERSHIP_LEVEL_5<br />
* {{DevFeature1.13|2}} ABILITY_LEADERSHIP (replaces the above leadership macros, which are now deprecated)<br />
* ABILITY_NIGHTSTALK<br />
* ABILITY_REGENERATES<br />
* ABILITY_SKIRMISHER<br />
* ABILITY_STEADFAST<br />
* ABILITY_SUBMERGE<br />
* ABILITY_TELEPORT<br />
<br />
== The ''[specials]'' tag ==<br />
<br />
The '''[specials]''' tag goes inside the '''[attack]''' tag. It can contain the following tags:<br />
<br />
* '''[attacks]''': modifies the number of attacks of a weapon<br />
* '''[berserk]''': pushes the attack for more than one combat round<br />
* '''[chance_to_hit]''': modifies the chance to hit of a weapon<br />
* '''[damage]''': modifies the damage of a weapon<br />
* '''[disable]''': disables the weapon<br />
* '''[drains]''': heals the attacker half of the damage dealt<br />
* '''[firststrike]''': forces the weapon to always strike first<br />
* '''[heal_on_hit]''': heals the attacker when an attack connects<br />
* '''[petrifies]''': turns the target to stone<br />
* '''[plague]''': when used to kill an enemy, a friendly unit takes its place<br />
* '''[poison]''': poisons the target<br />
* '''[slow]''': slows the target<br />
* '''[swarm]''': number of strikes decreases as the unit loses hitpoints<br />
Any other name is valid, but will result in an special that does nothing but report it is there.<br />
<br />
=== Common keys and tags for every weapon special ===<br />
<br />
{{DevFeature1.13|?}} All keys inside any weapon special that expects a numeric value will also accept formulas using [[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses.<br />
<br />
* '''name''': the (translatable) name of the special.<br />
* '''name_inactive''': the (translatable) name of the special when inactive. Defaults to ''name'' if not specified; if the special is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).<br />
* '''description''': the (translatable) description of the special.<br />
* '''description_inactive''': the (translatable) description of the special when inactive. Defaults to ''description'' if not specified.<br />
* '''id''': this ability will not be cumulative with other specials using this id.<br />
* '''active_on''': one of '''defense''' or '''offense'''; if left out, the special is active on both.<br />
* '''apply_to''': one of '''self''','''opponent''','''attacker''','''defender''','''both''' (default: ''self''). Determines who the effects of this special are applied to.<br />
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the special will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]]. In fact, it's really a shorthand for a [filter_adjacent] nested within [filter_self], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate. <br />
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter_self][filter_location][filter_adjacent_location].<br />
* '''[filter_self]''': the special will only be active if the owner matches this [[StandardUnitFilter]] (SUF).<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the opponent.<br />
* '''[filter_opponent]''': the special will only be active if the opponent matches this SUF.<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the unit that owns the weapon.<br />
* '''[filter_attacker]''': the special will only be active if the attacker matches this SUF.<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the defender.<br />
* '''[filter_defender]''' the special will only be active if the defender matches this SUF.<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the attacker.<br />
<br />
=== Common keys and tags for specials with a value ===<br />
<br />
The '''[damage]''', '''[attacks]''', and '''[chance_to_hit]''' specials take values that specify how those specials modify their respective base values. The '''[drains]''' special takes a value specifying the percentage of damage drained (default 50) and '''[heal_on_hit]''' takes the amount to heal (default 0; negative values will harm the attacker, but not kill). <br />
<br />
* '''value''': the value to be used.<br />
* '''add''': the number to add to the base value.<br />
* '''sub''': the number to subtract from the base value.<br />
* '''multiply''': this multiplies the base value.<br />
* '''divide''': this divides the base value.<br />
* '''cumulative''': if set to 'yes', this special will be cumulative with the base value.<br />
* '''backstab''': if set to 'yes', this special will only apply to the attacker, and only when there is an enemy on the target's opposite side (i.e. when the standard backstab special applies). {{DevFeature1.13|2}} This is now deprecated. The same functionality can be achieved with a [filter_adjacent] in [filter_opponent]; see the implementation of the default backstab special for details.<br />
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', '''less_than''', '''greater_than''', '''less_than_equal_to''', '''greater_than_equal_to'''.<br />
<br />
=== Extra keys used by the ''[berserk]'' special ===<br />
<br />
* '''value''': the maximum number of combat rounds (default 1).<br />
* '''cumulative''': if set to 'yes', this special will be cumulative with other active berserk specials (on the current combatant, not with an opponent's berserk).<br />
<br />
=== Extra keys used by the ''[plague]'' special ===<br />
<br />
* '''type''': the unit type to be spawned on kill.<br />
<br />
=== Extra keys used by the ''[swarm]'' special ===<br />
<br />
* '''swarm_attacks_max''': the maximum number of attacks for the swarm. Defaults to the base number of attacks modified by any applicable [attacks] specials. If this is specified, then the base number of attacks is ignored.<br />
* '''swarm_attacks_min''': the minimum number of attacks for the swarm. Defaults to zero. This can be set higher than swarm_attacks_max to cause a unit to gain attacks as health decreases.<br />
The ratio of the unit's current to maximum hit points will be used to scale the number of attacks between these two values.<br />
<br />
Prior to version 1.11, a [swarm] special will cause [attacks] specials to be ignored. In 1.11 and later, [attacks] specials are applied before [swarm].<br />
<br />
=== Macros for common weapon specials ===<br />
<br />
* WEAPON_SPECIAL_BACKSTAB<br />
* WEAPON_SPECIAL_BERSERK<br />
* WEAPON_SPECIAL_CHARGE<br />
* WEAPON_SPECIAL_DRAIN<br />
* WEAPON_SPECIAL_FIRSTSTRIKE<br />
* WEAPON_SPECIAL_MAGICAL<br />
* WEAPON_SPECIAL_MARKSMAN<br />
* WEAPON_SPECIAL_PLAGUE<br />
* WEAPON_SPECIAL_PLAGUE_TYPE TYPE<br />
* WEAPON_SPECIAL_POISON<br />
* WEAPON_SPECIAL_SLOW<br />
* WEAPON_SPECIAL_STONE<br />
* WEAPON_SPECIAL_SWARM<br />
<br />
== See Also ==<br />
<br />
* [[UnitTypeWML]]<br />
* [[SingleUnitWML]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category:WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=AbilitiesWML&diff=65858AbilitiesWML2020-08-05T22:31:42Z<p>Gfgtdf: /* Common keys and tags for every ability */</p>
<hr />
<div>{{WML Tags}}<br />
== Abilities and their effects ==<br />
<br />
There are two types of abilities: ones that apply to units (called ''abilities'') and ones that only apply when using a particular attack (called ''specials'' or ''weapon specials''). A unit may have multiple abilities and an attack can have multiple specials, but by convention only one weapon special should be assigned to any given attack.<br />
<br />
== The ''[abilities]'' tag ==<br />
<br />
The following tags are used to describe an ability in WML:<br />
<br />
* '''[heals]''': modifies the hitpoints of a unit at the beginning of the healer's turn<br />
* '''[regenerate]''': modifies the hitpoints of a unit at the beginning of the unit's turn<br />
* '''[resistance]''': modifies the resistance of a unit to damage<br />
* '''[leadership]''': modifies the damage of a unit<br />
* '''[skirmisher]''': negates enemy zones of control<br />
* '''[illuminates]''': modifies the time of day adjacent to the affected units<br />
* '''[teleport]''': allows the unit to teleport<br />
* '''[hides]''': renders the unit invisible to enemies<br />
* {{DevFeature1.15|0}} A tag matching a [[#The_.5Bspecials.5D_tag|weapon special tag]] will confer that weapon special to units based on the given conditions. Most weapon specials are supported; however, '''plagues''', '''heal_on_hit''', and '''swarm''' are not.<br />
Any other name is valid (for example '''[dummy]'''), but will result in an ability that does nothing but report it's there. These tags still use the same common keys and tags as every other ability. '''Note:''' a dummy ability must have an id for the name and description to display.<br />
<br />
=== Available formula variables in Abilities and Weapon Sepcials ===<br />
<br />
{{DevFeature1.14|?}} When using formulas in abilities and weapon specials, the following formula variables are available:<br />
* '''self''': (unit) the unit that has the ability<br />
* '''student''': (unit) for leadership-like abilities this is the unit that is adjacent to the unit that has the ability.<br />
* '''attacker''': (unit) for attack-related abilities and weapon specials, this is the attacking unit during the attack.<br />
* '''defender''': (unit) for attack-related abilities and weapon specials, this is the defending unit during the attack.<br />
* '''other''': (unit) the unit whose stats get modified from the ability. For abilities without 'apply_to=opponent' this is always the same as 'student'.<br />
<br />
=== Common keys and tags for every ability ===<br />
<br />
{{DevFeature1.13|?}} All keys inside any ability that expects a numeric value will also accept formulas using <br />
[[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses.<br />
<br />
* '''name''': the (translatable) name of the ability.<br />
* '''female_name''': the (translatable) name of the ability when possessed by a female unit. Defaults to ''name'' if not specified.<br />
* '''name_inactive''': the (translatable) name of the ability when inactive. Defaults to ''name'' if not specified; if the ability is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).<br />
* '''female_name_inactive''': the (translatable) name of the ability when inactive and possessed by a female unit. Defaults to ''name_inactive'' if not specified.<br />
* '''description''': the (translatable) description of the ability.<br />
* '''description_inactive''': the (translatable) description of the ability when inactive. Defaults to ''description'' if not specified.<br />
* '''affect_self''': if equal to 'yes' (default), the ability will affect the unit that has it.<br />
* '''affect_allies''': if equal to 'yes', the ability will affect units from the same and allied sides in the specified adjacent hexes. If set to 'no' it will not affect own or allied sides. If not set (default) it will affect units on the same side but not from allied sides.<br />
* '''affect_enemies''': if equal to 'yes' (default is 'no'), the ability will affect enemies in the specified adjacent hexes.<br />
* '''cumulative''': if set to 'yes', this ability will be cumulative with the base value for this ability.<br />
* '''id''': this ability will not be cumulative with other abilities using this id. Must be present if cumulative is anything other than 'yes'.<br />
* '''[filter]''': [[StandardUnitFilter]] If the unit owning the ability does not match this filter, the ability will be inactive.<br />
* '''[affect_adjacent]''': an adjacent unit that does not match this filter will not receive its effects. There can be multiple [affect_adjacent] tags in a single ability; a unit needs to match any one of these to receive the effects. The side requirement of matching units is defined by the '''affect_allies''' and '''affect_enemies''' keys. If there are no [affect_adjacent] tags, then no adjacent units will receive the effects.<br />
** '''adjacent''': a comma separated list of any combination of these directions: '''n''','''ne''','''se''','''s''','''sw''','''nw'''. (See [[StandardLocationFilter#Directions|notes]])<br />
** '''[filter]''': a [[StandardUnitFilter]]. {{DevFeature1.13|2}} The variable $other_unit refers to the unit owning the ability.<br />
* '''[filter_self]''': if the owner of the ability does not match this filter, it will not receive the effects of the ability. [filter_self] takes a [[StandardUnitFilter]] as argument.<br />
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the ability will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). In fact, it's really a shorthand for a [filter_adjacent] nested within [filter]. The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate.<br />
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter][filter_location][filter_adjacent_location].<br />
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', etc. If several keys are used all have to match.<br />
<br />
=== Extra keys used by the ''[heals]'' ability ===<br />
<br />
* '''value''': the amount healed.<br />
* '''poison''': can be one of ''slowed'',''cured''. ''slowed'' means poison will not take effect for adjacent units (it's not related to the weapon special "slows").<br />
<br />
=== Extra keys used by the ''[regenerate]'' ability ===<br />
<br />
* '''value''': the amount healed.<br />
* '''poison''': can be one of ''slowed'',''cured''.<br />
<br />
=== Extra keys and tags used by the ''[resistance]'' ability ===<br />
<br />
* '''value''': set resistance to this value.<br />
* '''max_value''': maximum resistance value. This value '''must''' be set in order for [resistance] to function.<br />
* '''add''': adds to resistance.<br />
* '''sub''': subtracts from resistance.<br />
* '''multiply''': multiplies resistance value. <br />
* '''divide''': divides resistance value.<br />
* '''apply_to''': a list of damage types; if left out, the ability applies to all types.<br />
* '''active_on''': one of 'defense' or 'offense'; if left out, the ability is active on both.<br />
These keys affect the actual resistance (e.g. -20%), not the damage modifier normally used in [resistance] (e.g. 120).<br />
* '''[filter_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the owner of the ability uses a matching weapon.<br />
* '''[filter_second_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the opponent uses a matching weapon.<br />
* '''[filter_student]''': {{DevFeature1.15|0}} If present, the ability only takes effect on units matching this filter.<br />
<br />
=== Extra keys used by the ''[leadership]'' ability ===<br />
<br />
* '''value''': the percentage bonus to damage.<br />
* '''[filter_weapon]''': If present, the leadership ability only takes effect when the owner of the ability uses a matching weapon.<br />
* '''[filter_second_weapon]''': If present, the leadership ability only takes effect when the opponent uses a matching weapon.<br />
* '''[filter_student]''': {{DevFeature1.15|0}} If present, the ability only takes effect on units matching this filter.<br />
<br />
=== Extra keys used by the ''[illuminates]'' ability ===<br />
<br />
Because this ability changes the terrain instead of units on it, affect_self, affect_allies, affect_enemies and [filter_adjacent] have no effect.<br />
* '''value''': the percentage bonus to lawful units. Units with '''alignment=lawful''' do +''value'' % damage when under the influence of a unit with this ability. Units with '''alignment=chaotic''' do -''value'' % damage. Units with '''alignment=neutral''' are unaffected by this ability. Units with '''alignment=liminal''' do -(abs(''value'')) % damage. ''value'' can be a negative number; this is useful if you want to give Chaotic units an advantage instead of Lawful ones. <br />
* '''max_value''': the maximum percentage bonus given.<br />
* '''min_value''': the minimum percentage bonus given.<br />
<br />
=== Extra keys used by the ''[hides]'' ability ===<br />
<br />
* '''alert''': the displayed text when the unit is discovered. Default "Ambushed!".<br />
<br />
=== Extra tags used by the ''[teleport]'' ability ===<br />
<br />
* '''[tunnel]''' - a [[DirectActionsWML#.5Btunnel.5D|tunnel tag]] (without the remove key) defining the tunneling source and target hexes, and maybe other conditions. (It automatically applies only to the unit with the ability.) You may use $teleport_unit inside the tunnel tag for filtering purposes.<br />
<br />
=== Extra tags and keys used by weapon special abilities ===<br />
<br />
* '''[filter_weapon]''': If present, the ability only takes effect when the owner of the ability uses a matching weapon.<br />
* '''[filter_second_weapon]''': If present, the ability only takes effect when the opponent uses a matching weapon.<br />
* '''[filter_student]''': If present, the ability only takes effect on units matching this filter.<br />
* Other keys and tags appropriate to the specific weapon special<br />
<br />
=== Macros for common abilities ===<br />
<br />
* ABILITY_AMBUSH<br />
* ABILITY_CURES<br />
* ABILITY_HEALS<br />
* ABILITY_ILLUMINATES<br />
* ABILITY_LEADERSHIP_LEVEL_1 to ABILITY_LEADERSHIP_LEVEL_5<br />
* {{DevFeature1.13|2}} ABILITY_LEADERSHIP (replaces the above leadership macros, which are now deprecated)<br />
* ABILITY_NIGHTSTALK<br />
* ABILITY_REGENERATES<br />
* ABILITY_SKIRMISHER<br />
* ABILITY_STEADFAST<br />
* ABILITY_SUBMERGE<br />
* ABILITY_TELEPORT<br />
<br />
== The ''[specials]'' tag ==<br />
<br />
The '''[specials]''' tag goes inside the '''[attack]''' tag. It can contain the following tags:<br />
<br />
* '''[attacks]''': modifies the number of attacks of a weapon<br />
* '''[berserk]''': pushes the attack for more than one combat round<br />
* '''[chance_to_hit]''': modifies the chance to hit of a weapon<br />
* '''[damage]''': modifies the damage of a weapon<br />
* '''[disable]''': disables the weapon<br />
* '''[drains]''': heals the attacker half of the damage dealt<br />
* '''[firststrike]''': forces the weapon to always strike first<br />
* '''[heal_on_hit]''': heals the attacker when an attack connects<br />
* '''[petrifies]''': turns the target to stone<br />
* '''[plague]''': when used to kill an enemy, a friendly unit takes its place<br />
* '''[poison]''': poisons the target<br />
* '''[slow]''': slows the target<br />
* '''[swarm]''': number of strikes decreases as the unit loses hitpoints<br />
Any other name is valid, but will result in an special that does nothing but report it is there.<br />
<br />
=== Common keys and tags for every weapon special ===<br />
<br />
{{DevFeature1.13|?}} All keys inside any weapon special that expects a numeric value will also accept formulas using [[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses.<br />
<br />
* '''name''': the (translatable) name of the special.<br />
* '''name_inactive''': the (translatable) name of the special when inactive. Defaults to ''name'' if not specified; if the special is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).<br />
* '''description''': the (translatable) description of the special.<br />
* '''description_inactive''': the (translatable) description of the special when inactive. Defaults to ''description'' if not specified.<br />
* '''id''': this ability will not be cumulative with other specials using this id.<br />
* '''active_on''': one of '''defense''' or '''offense'''; if left out, the special is active on both.<br />
* '''apply_to''': one of '''self''','''opponent''','''attacker''','''defender''','''both''' (default: ''self''). Determines who the effects of this special are applied to.<br />
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the special will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]]. In fact, it's really a shorthand for a [filter_adjacent] nested within [filter_self], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate. <br />
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter_self][filter_location][filter_adjacent_location].<br />
* '''[filter_self]''': the special will only be active if the owner matches this [[StandardUnitFilter]] (SUF).<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the opponent.<br />
* '''[filter_opponent]''': the special will only be active if the opponent matches this SUF.<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the unit that owns the weapon.<br />
* '''[filter_attacker]''': the special will only be active if the attacker matches this SUF.<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the defender.<br />
* '''[filter_defender]''' the special will only be active if the defender matches this SUF.<br />
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.<br />
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the attacker.<br />
<br />
=== Common keys and tags for specials with a value ===<br />
<br />
The '''[damage]''', '''[attacks]''', and '''[chance_to_hit]''' specials take values that specify how those specials modify their respective base values. The '''[drains]''' special takes a value specifying the percentage of damage drained (default 50) and '''[heal_on_hit]''' takes the amount to heal (default 0; negative values will harm the attacker, but not kill). <br />
<br />
* '''value''': the value to be used.<br />
* '''add''': the number to add to the base value.<br />
* '''sub''': the number to subtract from the base value.<br />
* '''multiply''': this multiplies the base value.<br />
* '''divide''': this divides the base value.<br />
* '''cumulative''': if set to 'yes', this special will be cumulative with the base value.<br />
* '''backstab''': if set to 'yes', this special will only apply to the attacker, and only when there is an enemy on the target's opposite side (i.e. when the standard backstab special applies). {{DevFeature1.13|2}} This is now deprecated. The same functionality can be achieved with a [filter_adjacent] in [filter_opponent]; see the implementation of the default backstab special for details.<br />
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', '''less_than''', '''greater_than''', '''less_than_equal_to''', '''greater_than_equal_to'''.<br />
<br />
=== Extra keys used by the ''[berserk]'' special ===<br />
<br />
* '''value''': the maximum number of combat rounds (default 1).<br />
* '''cumulative''': if set to 'yes', this special will be cumulative with other active berserk specials (on the current combatant, not with an opponent's berserk).<br />
<br />
=== Extra keys used by the ''[plague]'' special ===<br />
<br />
* '''type''': the unit type to be spawned on kill.<br />
<br />
=== Extra keys used by the ''[swarm]'' special ===<br />
<br />
* '''swarm_attacks_max''': the maximum number of attacks for the swarm. Defaults to the base number of attacks modified by any applicable [attacks] specials. If this is specified, then the base number of attacks is ignored.<br />
* '''swarm_attacks_min''': the minimum number of attacks for the swarm. Defaults to zero. This can be set higher than swarm_attacks_max to cause a unit to gain attacks as health decreases.<br />
The ratio of the unit's current to maximum hit points will be used to scale the number of attacks between these two values.<br />
<br />
Prior to version 1.11, a [swarm] special will cause [attacks] specials to be ignored. In 1.11 and later, [attacks] specials are applied before [swarm].<br />
<br />
=== Macros for common weapon specials ===<br />
<br />
* WEAPON_SPECIAL_BACKSTAB<br />
* WEAPON_SPECIAL_BERSERK<br />
* WEAPON_SPECIAL_CHARGE<br />
* WEAPON_SPECIAL_DRAIN<br />
* WEAPON_SPECIAL_FIRSTSTRIKE<br />
* WEAPON_SPECIAL_MAGICAL<br />
* WEAPON_SPECIAL_MARKSMAN<br />
* WEAPON_SPECIAL_PLAGUE<br />
* WEAPON_SPECIAL_PLAGUE_TYPE TYPE<br />
* WEAPON_SPECIAL_POISON<br />
* WEAPON_SPECIAL_SLOW<br />
* WEAPON_SPECIAL_STONE<br />
* WEAPON_SPECIAL_SWARM<br />
<br />
== See Also ==<br />
<br />
* [[UnitTypeWML]]<br />
* [[SingleUnitWML]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category:WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=1.15_Roadmap&diff=657841.15 Roadmap2020-07-18T20:52:55Z<p>Gfgtdf: /* 1.15.6 */</p>
<hr />
<div>This page is for consolidating and planning when new features and fixes are intended to land in the 1.15 development branch. The release schedule for Development releases can be found [https://forums.wesnoth.org/viewtopic.php?f=2&t=52785 here]. A thread for discussing this roadmap can also be found [https://forums.wesnoth.org/viewtopic.php?f=2&t=52786 here]. As a reminder, there is also the previous [https://github.com/wesnoth/wesnoth/issues/4750 1.16 Checklist] issue on github, for those who added items to that.<br />
<br />
== Instructions ==<br />
Place the feature or fix you intend to implement within the section of the point release that you intend to have it implemented by. The point release something is planned to be released with is not set in stone, and can be updated as needed depending on the circumstances.<br />
<br />
Additionally, the current set of 1.15 point releases is not final, and can be increased or decreased based on what features and fixes are planned. The only hard deadline, which ''hopefully'' is not an issue, is to have 1.16 released by February 2022. This will allow 1.16 to be in the Ubuntu 22.04 LTS release's repositories, and while I realize we don't plan Wesnoth's releases around any distro's schedule, there are also currently no other criteria to use as a final deadline and February 2022 is easily more than enough time to plan out and implement 1.16, especially given how long 1.14/1.15 have already been going.<br />
<br />
== 1.15.4 ==<br />
<br />
Mainlining World conquest II<br />
<br />
== 1.15.5 ==<br />
<br />
Campaignd support for different min wesnoth versions<br />
<br />
== 1.15.6 ==<br />
<br />
Api to query abilities and traits by id, whcih are then uses by the {TRAIT...}, {ABILITY...} macros<br />
<br />
Re-add the dunefolk faction to WCII<br />
<br />
== 1.15.7 ==<br />
<br />
== 1.15.8 ==<br />
<br />
== 1.15.9 ==<br />
<br />
== 1.15.10 ==<br />
<br />
== 1.15.11 ==<br />
<br />
== 1.15.12 ==<br />
<br />
== 1.15.13 ==<br />
<br />
== 1.15.14 ==<br />
<br />
== 1.15.15 ==<br />
<br />
<br />
[[Category:Roadmaps]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=1.15_Roadmap&diff=657831.15 Roadmap2020-07-18T20:51:52Z<p>Gfgtdf: /* 1.15.5 */</p>
<hr />
<div>This page is for consolidating and planning when new features and fixes are intended to land in the 1.15 development branch. The release schedule for Development releases can be found [https://forums.wesnoth.org/viewtopic.php?f=2&t=52785 here]. A thread for discussing this roadmap can also be found [https://forums.wesnoth.org/viewtopic.php?f=2&t=52786 here]. As a reminder, there is also the previous [https://github.com/wesnoth/wesnoth/issues/4750 1.16 Checklist] issue on github, for those who added items to that.<br />
<br />
== Instructions ==<br />
Place the feature or fix you intend to implement within the section of the point release that you intend to have it implemented by. The point release something is planned to be released with is not set in stone, and can be updated as needed depending on the circumstances.<br />
<br />
Additionally, the current set of 1.15 point releases is not final, and can be increased or decreased based on what features and fixes are planned. The only hard deadline, which ''hopefully'' is not an issue, is to have 1.16 released by February 2022. This will allow 1.16 to be in the Ubuntu 22.04 LTS release's repositories, and while I realize we don't plan Wesnoth's releases around any distro's schedule, there are also currently no other criteria to use as a final deadline and February 2022 is easily more than enough time to plan out and implement 1.16, especially given how long 1.14/1.15 have already been going.<br />
<br />
== 1.15.4 ==<br />
<br />
Mainlining World conquest II<br />
<br />
== 1.15.5 ==<br />
<br />
Campaignd support for different min wesnoth versions<br />
<br />
== 1.15.6 ==<br />
<br />
== 1.15.7 ==<br />
<br />
== 1.15.8 ==<br />
<br />
== 1.15.9 ==<br />
<br />
== 1.15.10 ==<br />
<br />
== 1.15.11 ==<br />
<br />
== 1.15.12 ==<br />
<br />
== 1.15.13 ==<br />
<br />
== 1.15.14 ==<br />
<br />
== 1.15.15 ==<br />
<br />
<br />
[[Category:Roadmaps]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=1.15_Roadmap&diff=657821.15 Roadmap2020-07-18T20:51:14Z<p>Gfgtdf: /* 1.15.4 */</p>
<hr />
<div>This page is for consolidating and planning when new features and fixes are intended to land in the 1.15 development branch. The release schedule for Development releases can be found [https://forums.wesnoth.org/viewtopic.php?f=2&t=52785 here]. A thread for discussing this roadmap can also be found [https://forums.wesnoth.org/viewtopic.php?f=2&t=52786 here]. As a reminder, there is also the previous [https://github.com/wesnoth/wesnoth/issues/4750 1.16 Checklist] issue on github, for those who added items to that.<br />
<br />
== Instructions ==<br />
Place the feature or fix you intend to implement within the section of the point release that you intend to have it implemented by. The point release something is planned to be released with is not set in stone, and can be updated as needed depending on the circumstances.<br />
<br />
Additionally, the current set of 1.15 point releases is not final, and can be increased or decreased based on what features and fixes are planned. The only hard deadline, which ''hopefully'' is not an issue, is to have 1.16 released by February 2022. This will allow 1.16 to be in the Ubuntu 22.04 LTS release's repositories, and while I realize we don't plan Wesnoth's releases around any distro's schedule, there are also currently no other criteria to use as a final deadline and February 2022 is easily more than enough time to plan out and implement 1.16, especially given how long 1.14/1.15 have already been going.<br />
<br />
== 1.15.4 ==<br />
<br />
Mainlining World conquest II<br />
<br />
== 1.15.5 ==<br />
<br />
== 1.15.6 ==<br />
<br />
== 1.15.7 ==<br />
<br />
== 1.15.8 ==<br />
<br />
== 1.15.9 ==<br />
<br />
== 1.15.10 ==<br />
<br />
== 1.15.11 ==<br />
<br />
== 1.15.12 ==<br />
<br />
== 1.15.13 ==<br />
<br />
== 1.15.14 ==<br />
<br />
== 1.15.15 ==<br />
<br />
<br />
[[Category:Roadmaps]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=ScenarioWML&diff=65662ScenarioWML2020-05-20T21:00:59Z<p>Gfgtdf: /* The [scenario] tag */</p>
<hr />
<div>{{WML Tags}}<br />
== the toplevel tags [multiplayer], [test], [tutorial], [scenario] ==<br />
<br />
The top level tags '''[multiplayer]''', '''[test]''', '''[tutorial]''' and '''[scenario]''' are all formatted the same way.<br />
The difference between these tags is the way that the scenarios they describe are accessed.<br />
<br />
The keys '''id''' and '''next_scenario''' affect how scenarios can be accessed.<br />
Whenever a scenario is won, the scenario with id=''next_scenario'' of the same tag type will be played.<br />
Units from the first scenario will be available for recall in the second.<br />
<br />
Some scenarios can be played without playing other scenarios first<br />
(in this case there is nothing on the recall list).<br />
These scenarios are called ''initial scenario''s.<br />
<br />
A list of initial scenarios, and how to access them:<br />
<br />
* All '''[multiplayer]''' scenarios (without ''allow_new_game=no'') are initial scenarios listed in the multiplayer scenario selector screen (accessed by the "multiplayer" button).<br />
* Any '''[test]''' scenario is an initial scenario. A test scenario can be accessed by running the game in test mode. (note: this is NOT the same as debug mode. It can be accessed using -t or --test followed by an optional scenario ID which defaults to 'test'.) {{DevFeature1.13|8}} It can also be accessed by assigning a hotkey to the "Test Scenario" command in hotkey preferences, then pressing that hotkey at the title screen. This will bring up a list of interactive test scenarios to choose from. (Automated test scenarios used for unit testing are excluded from this list but can still be run from the command-line.)<br />
* The '''[tutorial]''' scenario with the attribute '''id=tutorial''' is an initial scenario. The tutorial is accessed by clicking on the "tutorial" button.<br />
** {{DevFeature1.15|3}} the tutorial's scenarios now use '''[scenario]''' instead of tutorial '''[tutorial]'''.<br />
* Any '''[scenario]''' scenario with an id listed in the value of ''first_scenario'' in a campaign tag (see [[CampaignWML]]) is an initial scenario accessed by selecting that campaign after clicking on the "campaign" button.<br />
<br />
== The [scenario] tag ==<br />
<br />
The following keys and tags are recognized in '''[scenario]''' tags:<br />
<br />
* '''id''': A unique identifier for this scenario. All scenarios must have an id. Can't clash with '''id''' used in '''[multiplayer]''' tags.<br />
* '''next_scenario''': The id of the scenario to load when the current one is won. This can be changed dynamically, to build non-linear campaigns.<br />
* '''description''': (translatable) only for multiplayer maps. Will show up as a tooltip when mousing over the minimap in the multiplayer setup screen.<br />
* '''name''': (translatable) is shown in several places in the level, including the intro screen. It is also the default name for saves on the level.<br />
* '''map_data''': inputs valid Wesnoth map data. See [[BuildingMaps]] for a description of the Wesnoth map syntax.<br />
* '''map_file''': {{DevFeature1.14|3}} path to a file containing Wesnoth map data. This is the recommended way. {{DevFeature1.15|3}} the file can be found via [binary_path], as documented for [[DirectActionsWML#.5Breplace_map.5D|[replace_map]]].<br />
* '''turns''': sets an event on turn ''turns'' causing the player to lose. Use ''-1'' to have no turn limit. Default value is ''-1'' on wesnoth-1.13 and ''100'' on wesnoth-1.12. See also [[EventWML]]<br />
* '''turn_at''': the turn to start on (default=1)<br />
*: Note that none of the regular start-of-turn behavior, including poison damage, healing, income and refreshing unit movement and status, will occur before the start of turn 2. All start-of-turn [[EventWML|WML events]] will still be fired, however.<br />
* '''random_start_time''': controls random starting time of day. Possible values are yes and no or list of possible start times; starting from 1 to number of times. for example ''random_start_time=2,3,5,6'' (default depends on version and mp/sp, better include this key)<br />
* '''music''': the music file relative to ''./music/'' to play during the scenario<br />
* '''[music]''': specifies the music tracks to play during this scenario, see [[MusicListWML]].<br />
* '''defeat_music''': specifies a comma-separated list of music tracks which may be chosen to play on defeat. If not provided, the default in [[GameConfigWML]] is used instead. May be overridden by [[DirectActionsWML|endlevel]] clauses.<br />
* '''victory_music''': specifies a comma-separated list of music tracks which may be chosen to play on victory. If not provided, the default in [[GameConfigWML]] is used instead. May be overridden by [[DirectActionsWML|endlevel]] clauses.<br />
* '''theme''': the name of the UI theme that should be used when playing this scenario. Valid ids to use can be found in the files in data/themes. Cutscene and Cutscene_Minimal can be useful for dialog only scenarios.<br />
* '''victory_when_enemies_defeated''': when this is set to '''yes''' (default), the player wins once all non-allied units with '''canrecruit=yes''' (aka leaders) are killed. (Currently this only controls the win condition for when all enemies are defeated; it does not prevent the player from losing if he has no leader.) See Also [[SideWML]]. When this value is true the following keys can be used:<br />
** '''carryover_percentage''': by default 80% of the gold is carried over to the next scenario, with this key the amount can be changed.<br />
** '''carryover_add''': if true the gold will be added to the starting gold the next scenario, if false the next scenario will start with the amount of the current scenario (after taxes) or the minimum in the next scenario. Default is false.<br />
* '''remove_from_carryover_on_defeat''': when this is set to '''yes''' (default), for sides who got defeated (according to the side.defeat_condition), carryover will be removed.<br />
* '''disallow_recall''': when this is set to 'no'(default), the player is allowed to recall units from previous scenarios.<br />
* '''experience_modifier''': the percentage that required XP to level up (for all units in the scenario) is multiplied by. Default 100. Note that when used in a campaign, weird things (like units being above the required XP to level up) can happen if this value is different for different scenarios.<br />
* '''do_healing''': when set to yes, the engine will not skip healing at the first sides turn and will do the healing just like every other turn. <br />
* '''[story]''': describes the intro screen. See [[IntroWML]]<br />
* '''[label]''': sets a label<br />
** '''x''', '''y''': location to set label<br />
** '''text''': the label<br />
* '''[item]''': places an item on map. See [[InterfaceActionsWML#.5Bitem.5D|InterfaceActionsWML]].<br />
* '''[time]''': how a day should progress. See [[TimeWML]]<br />
* '''current_time''': The time of day slot number (starting from zero) active at scenario start.<br />
* '''[time_area]''': how a day should progress in a given area. Everywhere not specified in a [time_area] tag is affected by the [time] tags in the [scenario] tag<br />
** takes x and y coordinates.<br />
** '''[time]''': how a day should progress in those locations. See [[TimeWML]]<br />
** '''current_time''': The time slot number (starting with zero) active at the creation of the area.<br />
** time areas can be used in events, assigned identifiers, and removed at discretion. They also accept complete Standard Location Filters. See [[DirectActionsWML]].<br />
* '''[side]''': describes one player. See [[SideWML]]<br />
* '''[event]''': describes an event that may be triggered at a certain point of the scenario. See [[EventWML]]<br />
* '''map_generation''': another way to generate a map. The map will be generated randomly<br />
** '''default''': the default random map generator<br />
* '''[generator]''' if this is present, the map and scenario will be generated randomly. See [[MapGeneratorWML]]<br />
* [[TerrainGraphicsWML]]: Scenarios can define custom terrain rules for the rendering of the map.<br />
* [[GameConfigWML#Color_Palettes|Color palettes]]<br />
* '''[lua]''': code in Lua. See [[LuaWML]]<br />
<br />
== The [tutorial] tag ==<br />
<br />
The only difference between '''[tutorial]''' and '''[scenario]''' is the name of the tag. They are not interchangeable because the C++ code looks for the specific tag name.<br />
<br />
{{DevFeature1.15|3}} Tutorial scenarios use '''[scenario]''', and that's the tag name the C++ code looks for. There is no '''[tutorial]''' tag any more.<br />
<br />
== The [multiplayer] tag ==<br />
<br />
The following keys and subtags are additionally recognized in '''[multiplayer]''' scenarios:<br />
<br />
* '''force_lock_settings''': provides a default value for [[SideWML]] ''lock'' attributes and forces the "Use map settings" to be checked and disabled. This is useful if author wants to limit game customization in order to keep the scenario/campaign balanced. Individual options can still be enabled if this key is set to '''yes'''. E.g. color selection can be enabled by explicitly setting ''color_lock=yes'' in [[SideWML]].<br />
* '''new_game_title''': if provided will be used instead of '''name''' for campaign entry points.<br />
* '''allow_new_game''': (default=yes) allow/prevent the scenario to be listed in the game configuration screen. This is intended for multiplayer campaigns with multiple entry points.<br />
* '''allow_era''': a list of era ids. Only the eras with matching ids will be allowed to be played with this scenario.<br />
* '''disallow_era''': a list of era ids. Eras with matching ids will not be allowed to be played with this scenario. Cannot be used in parallel with allow_era.<br />
* '''ignore_incompatible_era''': a list of era ids. The eras with matching ids will be considered compatible with this scenario regardless their dependencies.<br />
* '''allow_modification''': same as allow_era, but for modifications.<br />
* '''disallow_modification''': same as disallow_era, but for modifications. Cannot be used in parallel with allow_modification.<br />
* '''ignore_incompatible_modification''': same as ignore_incompatible_era, but for modifications.<br />
* '''force_modification''': a list of modification ids (id key in [modification]). The specified modifications must be enabled to play this scenario.<br />
* '''[options]''': custom options. See [[OptionWML]] for details.<br />
* '''require_scenario''': {{DevFeature1.13|0}} In a multiplayer scenario, this indicates that the scenario file is not enough (you have custom assets like terrain or additional unit art) and other player must download the full add-on not just the scenario WML to join a game. This will also mean that the '''addon_min_version''' attribute will control the minimum version number of your add-on which is compatible with this version.<br />
<br />
== The [test] tag ==<br />
<br />
The following keys and subtags are additionally recognized in '''[test]''' scenarios:<br />
<br />
* '''is_unit_test''': {{DevFeature1.13|8}} If set to 'yes', this scenario will not appear in the list of test scenarios. The list of test scenarios can be reached from the titlescreen via the Start Test Scenario hotkey. This hotkey is not set by default.<br />
<br />
== Scenario End Conditions ==<br />
<br />
In this section we will give a more precise explanation of things that can cause a scenario to end.<br />
<br />
* At the '''end of every turn''', the turn number will be compared with the turn limit. <br />
** If we pass the limit, the ''time over'' event will fire. If turns are not added by WML in response to this event, then the scenario will immediately end in defeat. [[EventWML#The_.27name.27_Key_.28Mandatory.29]]<br />
* At the '''beginning of any turn''', and at '''the end of any user or ai action''', the victory conditions will be checked. This will result either in the scenario ending or continuing. The procedure for this is as follows:<br />
** Every side will have its ''defeat_condition'' evaluated based on the units it currently has on the board. [[SideWML]]<br />
*** At this time, villages of defeated sides will be unflagged, and if ''remove_from_carryover_on_defeat = yes'' then their carryover will be cleared as well.<br />
** If any two not-defeated sides are enemies, the scenario will continue.<br />
*** At this time, the ''enemies defeated'' event will fire.<br />
** Furthermore, if ''victory_when_enemies_defeated=no'' and there exists a human controlled side, then the scenario will continue.<br />
*** The human controlled side may be local or remote, for networked mp play.<br />
** If neither of these conditions is met then the scenario will end. <br />
***In victory or defeat according to whether a local human-controlled side is not defeated.<br />
<br />
== See Also ==<br />
<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=InterfaceActionsWML&diff=65490InterfaceActionsWML2020-03-20T21:31:10Z<p>Gfgtdf: /* [remove_item] */</p>
<hr />
<div>{{WML Tags}}<br />
== Interface actions ==<br />
<br />
Part of [[ActionWML]], interface actions are actions that do not have a direct effect on gameplay;<br />
instead, they show something to the player. The main interface tags<br />
are '''[message]''' and '''[objectives]''', but several other tags affect<br />
the interface also.<br />
<br />
== [inspect] ==<br />
This user interface instantly displays the gamestate inspector dialog at the current scenario state (the same one that can be brought up with [[CommandMode|the ''':inspect''' command]]), which can be used to inspect the values of WML variables, AI configuration, recall lists, and more.<br />
<br />
* '''name''': optional attribute to specify the name of this gamestate inspector dialog. It is just a label to help differentiate between different invocations of gamestate inspector dialog.<br />
<br />
== [message] ==<br />
The most commonly used interface action is [message], which displays a message to the user in a dialog box. It can also be used to take input from the user.<br />
<br />
The following key/tags are accepted for [message]:<br />
* [[StandardUnitFilter]]: The unit whose profile and name are displayed. Do not use a [filter] tag. If no unit matching this filter is found, the message is not displayed (The unit has probably been killed).<br>[message] elements should be constructed so that it is either guaranteed that a certain unit is alive, or so that dialog flows smoothly even if the message isn't displayed.<br />
<br />
* '''speaker''': an alternative to standard unit filter. You may specify as the value of the speaker attribute a unit id or any of the following special values:<br />
** '''narrator''': the dialog box is displayed without a caption for the unit speaking or a unit image<br />
** '''unit''': the primary unit for the event is speaking<br />
** '''second_unit''': {{DevFeature1.13|6}} the secondary unit for the event is speaking<br />
<br />
* '''message''': (translatable) the text to display to the right of the image. ''message'' is sometimes multiple lines; if it is, be sure to use quotes(''' ' ''' or ''' " ''')<br />
* '''male_message''', '''female_message''': {{DevFeature1.13|2}} (translatable) Used instead of ''message'' if the unit's gender matches. Never used if there is no unit (ie ''speaker=narrator''). {{DevFeature1.13|6}} This matches the primary unit, not the secondary unit.<br />
* '''wait_description''': {{DevFeature1.13|2}} the description of this message displayed when other players in a mp game wait for one player doing input in a [message] (with [option]s or [text_input]).<br />
* '''[show_if]''': if present then this message will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
* '''side_for''': (default: all sides) comma-separated list of sides for who message is shown. This will <b>not</b> work with messages that take user input ([option]/[text_input]), which can only ever be shown to the current player. {{DevFeature1.13|0}} side_for= is now also accepted for messages with user input, it specifies on which side the message is shown (defaults to the currently playing side). For messages with input it does not accept a comma seperated list only a single number.<br />
* '''image''': (default: profile image of speaker) the image to display to the left of the message text. Append ~RIGHT() if you want the image to appear on the right side. <br />
** {{DevFeature1.13|0}} <b>none:</b> display no image<br />
* '''mirror''': {{DevFeature1.13|5}}whether to mirror the image specified by the '''image''' attribute.<br />
* '''second_image''': {{DevFeature1.13|6}}same as the '''image''' attribute, but the image is displayed on the right of the message text.<br />
* '''second_mirror''': {{DevFeature1.13|6}}same as '''mirror''', but for the '''second_image''' attribute.<br />
* '''image_pos''': {{DevFeature1.13|5}} whether to show the image on the left or right; supercedes the use of ~RIGHT() described above<br />
* '''caption''': (default: name of speaker) the caption to display beside the image. Name to be displayed. Note: use a translation mark to avoid wmllint errors.<br />
* '''scroll''': Boolean specifying whether the game view should scroll to the speaking unit. Defaults to ''yes''.<br />
* '''highlight''': {{DevFeature1.13|5}} Boolean specifying whether to highlight the speaker. Defaults to ''yes''.<br />
* '''sound''': a sound effect (wav file) to play as the message is displayed. This can be a comma-separated list, from which one will be randomly chosen.<br />
* '''voice''': {{DevFeature1.13|?}} a sound to be played as the message is displayed. This can also be a comma-separated list, from which one will be randomly chosen. This is intended for voiceovers for the message.<br />
* '''[option]''': No '''[option]''' elements have to be used. If '''[option]''' elements are present, then each option will be displayed in a menu for the user to select one option. ''Note: Messages with options will not be shown at all in prestart events''<br />
** '''message''': (translatable) the text displayed for the option. {{DevFeature1.15|1}} This is now a synonym for '''description='''.<br />
** '''image''', '''label''', '''description''', '''default''': See [[DescriptionWML#WML_Format|DescriptionWML]].<br />
** '''value''': {{DevFeature1.13|?}} Gives the option a value to be stored in a variable.<br />
** '''[show_if]''': if present then this option will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
** '''[command]''': an element containing actions which are executed if the option is selected.<br />
* '''variable''': {{DevFeature1.13|?}} If present, either the index or the value of the chosen option will be stored in the specified variable. Option indexing starts from 1. If option has '''[show_if]''' condition evaluated as false, then it is hidden and excluded from the indexing.<br />
* '''[text_input]''': there can be only one [text_input] tag. this adds a text input field to the message. ''Note: Messages with text_input will not be shown at all in prestart events''<br />
** '''variable''': the variable that the user's input will be written to<br />
** '''label''': a text label to the left of the input field<br />
** '''max_length''': the maximum number of characters that may be typed into the field<br />
** '''text''': text that is written into the field in the beginning<br />
* Check [[EventWML#Multiplayer_safety]] to find out in which events you can safely use '''[option]''' and '''[text_input]''' without causing OOS.<br />
<br />
=== Formatting ===<br />
'''[message]''' and other tags such as unit names (user_description), objectives, and floating text can make use of [https://developer.gnome.org/pango/stable/pango-Markup.html Pango markup formatting codes].<br />
<br />
Remember to use single quotes (') instead of double quotes (") within the formatting string, as double quotes cannot be escaped, and the string will appear fragmented and possibly cause errors. Escaping markup is described in https://github.com/wesnoth/wesnoth/blob/master/src/font/pango/escape.hpp#L35-L39.<br />
<br />
For example, if you wanted to write "You are victorious!" in large, italic, gold letters, you might write it this way:<br />
<br />
<nowiki><span color='#BCB088' size='large' font-style='italic'>You are victorious!</span></nowiki><br />
<br />
<br />
These are the codes taken from the Pango markup formatting guide:<br />
<br />
*'''font''', '''font_desc''': A font description string, such as "Sans Italic 12".<br />
*'''font_family''', '''face''': A font family name.<br />
*'''font_size''', '''size''': Font size in 1024ths of a point, or one of the absolute sizes 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', or one of the relative sizes 'smaller' or 'larger'.<br />
*'''font_style''', '''style''': One of 'normal', 'oblique', 'italic'.<br />
*'''font_weight''', '''weight''': One of 'ultralight', 'light', 'normal', 'bold', 'ultrabold', 'heavy', or a numeric weight.<br />
*'''font_variant''', '''variant''': One of 'normal' or 'smallcaps'.<br />
*'''font_stretch''', '''stretch''': One of 'ultracondensed', 'extracondensed', 'condensed', 'semicondensed', 'normal', 'semiexpanded', 'expanded', 'extraexpanded', 'ultraexpanded'.<br />
*'''foreground''', '''fgcolor''', '''color''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''background, bgcolor''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''underline''': One of 'none', 'single', 'double', 'low', 'error'.<br />
*'''underline_color''': The color of underlines; an RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''rise''': Vertical displacement, in 10000ths of an em. Can be negative for subscript, positive for superscript.<br />
*'''strikethrough''': 'true' or 'false' whether to strike through the text.<br />
*'''strikethrough_color''': The color of strikethrough lines; an RGB color specification such as '#00FF00' or a color name such as 'red'<br />
*'''fallback''': 'true' or 'false' whether to enable fallback. If disabled, then characters will only be used from the closest matching font on the system. No fallback will be done to other fonts on the system that might contain the characters in the text. Fallback is enabled by default. Most applications should not disable fallback.<br />
*'''letter_spacing''': Inter-letter spacing in 1024ths of a point.<br />
*'''gravity''': One of 'south', 'east', 'north', 'west', 'auto'.<br />
*'''gravity_hint''': One of 'natural', 'strong', 'line'.<br />
<br />
The following pango attributes are also available directly as attributes of the '''[message]''' tag:<br />
{{DevFeature1.13|4}}<br />
<br />
*'''font'''<br />
*'''font_family'''<br />
*'''font_size'''<br />
*'''font_style'''<br />
*'''font_weight'''<br />
*'''font_variant'''<br />
*'''font_stretch'''<br />
*'''color'''<br />
*'''bgcolor'''<br />
*'''underline'''<br />
*'''underline_color'''<br />
*'''rise'''<br />
*'''strikethrough'''<br />
*'''strikethrough_color'''<br />
*'''fallback'''<br />
*'''letter_spacing'''<br />
*'''gravity'''<br />
*'''gravity_hint'''<br />
<br />
== [objectives] ==<br />
The other tag used for plot development is '''[objectives]'''.<br />
The '''[objectives]''' tag overwrites any previously set objectives,<br />
and displays text which should describe the objectives of the scenario.<br />
Scenario objectives are displayed on the player's first turn after the tag is used,<br />
or as part of the event if it triggers during that player's turn.<br />
Objectives can also be accessed at any time in a scenario using the<br />
"Scenario Objectives" game menu option, making this tag useful for<br />
scenario-specific information that the player may need to refer to during play.<br />
<br />
Attributes of '''[objectives]''':<br />
* '''side''': Default '0'. The side to set the objectives for. A value of 0 sets objectives for all sides. note: There are side-specific objectives and default objectives, which are used in case a side doesn't have specific ones. Specifying 0 sets the default ones.<br />
* '''[[StandardSideFilter]]''' tags and keys: Sets the objectives of all matching sides to these passed specifications (the rest of this [objectives] tag). If no sides (such as when passing side=0) or all sides match, sets the default objectives, and the side specific ones for the matching sides otherwise.<br />
* '''bullet''': Default '• '. Replaces the default bullet, with whatever is passed, for all objectives, gold carryover notes, and notes defined with [note].<br />
* '''summary''': Displayed first in the objectives text, this should describe the basic objective for the overall scenario. Can be omitted.<br />
* '''note''': Displayed last in the objectives text, this is sometimes used for hints or additional information. Can be omitted.<br />
* '''victory_string''': Default ' _ "Victory:"', this text precedes the victory objectives. Can be set to "" too.<br />
* '''defeat_string''': Default ' _ "Defeat:"', this text precedes the defeat objectives. Can be set to "" too.<br />
* '''gold_carryover_string''': Default ' _ "Gold carryover:"', this text precedes the gold carryover information.<br />
* '''notes_string''': Default ' _ "Notes:"', this text precedes the notes.<br />
* '''silent''': Default: not present. If set to "yes", the objectives are silently changed. Else, they will be shown to the user when appropriate.<br />
* '''delayed_variable_substitution''': {{DevFeature1.13|8}} If set to yes, any variables or [insert_tag] are not substituted right away. Instead, they are substituted whenever the objectives are actually viewed.<br />
<br />
Tags of '''[objectives]''':<br />
* '''[objective]''': describes a win or loss condition. Most scenarios have multiple win or loss conditions, so use a separate [objective] subtag for each line; this helps with translations.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet, with whatever is provided, for the objective defined by the [objective] block.<br />
** '''red''': Default '0' for winning objectives, '255' for losing objectives. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255' for winning objectives, '0' for losing objectives. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '0'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''description''': text for the specific win or loss condition.<br />
** '''caption''': a text which will be displayed above the ''description''. This can be used to display a subcategory of objectives below ''victory_string'' or ''defeat_string''.<br />
** '''condition''': The color and placement of the text. Values are 'win'(colored green, placed after ''victory_string'') and 'lose'(colored red, placed after ''defeat_string'').<br />
** '''show_turn_counter''': If set to yes, displays the number of turns remaining in the scenario. Default is no.<br />
** '''[show_if]''': A condition that disables the objective if it doesn't hold. Conditional objectives are refreshed at '''[show_objectives]''' time only, or when manually opening the scenario objectives.<br />
* '''[gold_carryover]''': describes how the gold carryover works in this scenario. This is intended to be a more convenient way of displaying carryover information than using the note= key in [objectives].<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '192'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''bonus''' (boolean): whether an early finish bonus is granted. If omitted, early finish bonus is not mentioned.<br />
** '''carryover_percentage''': the amount of carryover gold. If omitted, the amount is not mentioned.<br />
** '''[show_if]''': {{DevFeature1.13|11}} Gold carryover will not be shown if the specified condition isn't met. Conditional gold carryover is refreshed at '''[show_objectives]''' time only.<br />
* '''[note]''': describes a note, usually used for hints or additional information. This is an easier way of adding several notes than concatenating them together into a single string to use with the ''note='' key.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided for the note defined by the [note] block.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire note, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire note, including the bullet.<br />
** '''blue''': Default '255'. Overrides the default blue coloring of the entire note, including the bullet.<br />
** '''description''': the text of the note.<br />
** '''[show_if]''': The note will not be shown if the specified condition isn't met. Conditional notes are refreshed at '''[show_objectives]''' time only.<br />
<br />
== [set_menu_item] ==<br />
This tag is used to add a custom option in the right-click context menu which can then be used to trigger arbitrary WML commands. The menu items can be set and modified during any event, for example during "start" or "prestart" events. The user can also assign hotkeys to these WML commands unless specified otherwise. When the hotkey is pressed the event will be fired/filtered at the current mouse position.<br />
<br />
'''Note:''' Due to limitations in portable devices where there are no scroll bars for context menus, there is a hard-coded limit of 7 custom WML menu items. If you really need to have more than 7 menu items, try combining some of them in a submenu. {{DevFeature1.13|0}} This limitation is being removed in a [http://forums.wesnoth.org/viewtopic.php?p=572554#p572554 future version] of Wesnoth.<br />
<br />
* '''id''': the unique id for this menu item. If a menu item with this id already exists, it allows you to set specific changes to that item.<br />
* '''description''': the in-game text that will appear for this item in the menu.<br />
* '''image''': the image to display next to this item.<br />
* '''needs_select''': if ''yes'' (default ''no''), then the latest select event (see [[EventWML]]) that triggered before this menu item was chosen will be transmitted over the network before this menu item action will be. This only has any effect in networked multiplayer, and is intended to allow more elaborate menu item behaviour there without causing out of sync errors. If you don't know what this means, just leave it. {{DevFeature1.13|6}} ''needs_select=yes'' is deprecated, consider using manual variable syncing with [sync_variable].<br />
* '''synced''' {{DevFeature1.13|1}}: if ''no'' (default ''yes'') the command handler will only be run on the client that invoked the menu item; this means that changing the gamestate in a command handler of a menu item with ''synced=no'' will cause OOS<br />
* '''use_hotkey''': if ''no'' (default ''yes''), then the user cannot assign hotkeys to this menu item. If ''only'', the menu item is only accessible via hotkeys, not via right-click context; you can use this in combination with [default_hotkey] if you want custom hotkeys in your campaign/mp. <br />
* '''[show_if]''': If present, the menu item will only be available if the conditional statement (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]]) within evaluates to true. When this is evaluated, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked, so it's possible to for example only enable the option on empty hexes or on a particular unit.<br />
* '''[filter_location]''': contains a location filter similar to the one found inside Single Unit Filters (see [[FilterWML]]). The menu item will only be available on matching locations.<br />
* '''[default_hotkey]''': contains a hotkey WML to specify what hotkey to assign to this, '''if the user has no hotkey assigned to this yet'''. (Unlike the rest of a menu item definition, modifying this tag has no effect on the game; it is only effective when initially defining a menu item.) Hotkey WML matches the format in the preferences file and contains the following keys:<br />
** '''key''': a string that contains the key to assign to this.<br />
** '''alt''', '''shift''', '''cmd'''(apple only), '''ctrl''': boolean values.<br />
** '''repeat_on_hold''' {{DevFeature1.13|12}}: if ''yes'' (default ''no''), holding the hotkey will repeat the action continuously, unless it blocks input with something like '''[message]'''. Due to a bug, versions older than 1.13.12 always repeat the action, with no way to disable it.<br />
* '''[command]''': contains the WML actions to be executed when the menu item is selected. Again, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked on.<br />
** '''delayed_variable_substitution ''' (boolean yes|no, default: yes): If no, forces a variable substitution run onto the wml included in this [command] block. Use this, if you want variables which are to substitute to get the values they have at execution time of the event where this set_menu_item appears. Other than that, they get the values they have at invocation time of the menu item.<br />
<br />
== [clear_menu_item] ==<br />
<br />
Removes a menu item from the scenario.<br />
Normally menu items are, including all their defining wml, automatically carried over between scenarios. This tag prevents this. (The behavior is comparable to set_variable/clear_variable).<br />
* '''id''': (string): id of the menu item to clear. Can be a comma-separated list.<br />
<br />
== Other interface tags ==<br />
<br />
The following tags are also action tags:<br />
<br />
=== [change_theme] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Change the current interface theme.<br />
<br />
* '''theme''': The ID of the new theme. Use <code>theme=</code> (empty key) to switch back to the theme that the player has selected in Preferences. On <b>1.14.2</b> and later it is also possible to omit the key entirely to achieve the same effect (on previous versions this will crash the Lua engine).<br />
<br />
=== [item] ===<br />
Makes a graphical item appear on a certain hex. Note this only places the graphics for an item. It does not make the item do anything. Use a moveto event to make moving onto the item do something. <tt>''('''Hint:''' There are a number of predefined items that are used in various campaigns that you can make use of. You can find [http://www.wesnoth.org/macro-reference.xhtml#file:items.cfg a list of them] if you look into the items.cfg file in the wesnoth install directory (under /data/core/macros).)''</tt><br />
* '''x''', '''y''': the location to place the item. (only for [event][item]: full [[StandardLocationFilter|SLF]] support)<br />
* '''image''': the image (in ''images/'' as .png) to place on the hex. This image is aligned with the top-left of the hex (which is 72 pixels wide and 72 pixels tall). It is drawn underneath units. ''('''Hint:''' If using an image smaller than 72x72, then it might be useful to [[ImagePathFunctions#Blit_Function|BLIT]] the image onto <tt>misc/blank-hex.png</tt> (a blank 72x72 image).)''<br />
* '''halo''': an image to place centered on the hex. It is drawn on top of units. Use this instead of ''image'' if the image is bigger than the hex or if you want to animate an image (https://github.com/wesnoth/wesnoth/issues/1219).<br />
* '''name''' an id that can be used to remove the item.<br />
''Example (where the integer after the colon is the duration of each frame or square bracket expansion as per AnimationWML is used): halo=scenery/fire1.png:100,scenery/fire2.png:100,scenery/fire3.png:100,scenery/fire4.png:100,scenery/fire5.png:100,scenery/fire6.png:100,scenery/fire7.png:100,scenery/fire8.png:100''<br />
or equivalently (requires Wesnoth 1.11.2+):<br />
''halo=scenery/fire[1~8].png:100''<br />
* '''team_name''': name of the team for which the item is to be displayed (hidden for others). For multiple teams just put all the names in one string, for example separated by commas. {{DevFeature1.15|0}} In 1.14 the '''[side]team_name''' attribute was expected to be a substring of this '''team_name'''. In 1.15 both are expected to be comma-separated lists of names and the item is visible if the lists intersect. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* '''visible_in_fog''': whether the item should be visible through fog or not. Default yes.<br />
* '''redraw''': (boolean yes|no, default: yes): If no, disables implicit calls to [[InterfaceActionsWML#.5Bredraw.5D|[redraw]]] when placing the items.<br />
* '''[filter_team]''': {{DevFeature1.15|0}} A [[StandardSideFilter]]. Set '''team_name''' to the union of all '''[side]team_name''' attributes of all sides that match the SSF. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* {{DevFeature1.15|0}} If both '''team_name''' and '''[filter_team]''' are set, '''team_name''' is ignored.<br />
<br />
=== [remove_item] ===<br />
Removes any graphical items on a given hex.<br />
* [[StandardLocationFilter]]: the hexes to remove items off<br />
* '''image''': if specified, only removes the given item whose 'item', 'halo' or 'name' atibutes matches exactly this value. (for 'halo' and 'image' this in particular means that the image name must include any [[ImagePathFunctions|image path functions]] appended to the original image name.)<br />
<br />
=== [print] ===<br />
Displays a message across the screen. The message will disappear after a certain time.<br />
* '''text''': (translatable) the text to display.<br />
* '''size''': (default=12) the pointsize of the font to use<br />
* '''duration''': (default=50) the length of time to display the text for. This is measured in the number of 'frames'. A frame in Wesnoth is usually displayed for around 30ms.<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. {{DevFeature1.13|x}} Use of red, green, blue is now deprecated; use color=0,0,0 instead.<br />
<br />
=== [move_unit_fake] ===<br />
Moves an image of a unit along a certain path on the map. The path does not need to be a continuous list of adjacent hexes, so for example only the start and end points can be given, in which case the straightest line between those points will be calculated and used.<br />
* '''type''': the type of the unit whose image to use<br />
* '''x''': a comma-separated list of x locations to move along<br />
* '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
* '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
* '''gender''': the gender of the fake unit. Example: gender=female<br />
* '''variation''': the variation of the fake unit. Example: variation=undead<br />
* '''image_mods''': [[ImagePathFunctions|image path functions]] sequence to be applied on the fake unit.<br />
* '''force_scroll''': Whether to scroll the map or not even when [[#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to ''yes'' starting with version '''1.11.6'''; the attribute did not exist in previous versions and this action behaved as if ''no'' was passed instead.<br />
<br />
=== [move_units_fake] ===<br />
moves multiple images of units along paths on the map. These units are moved in lockstep.<br />
* '''force_scroll''': {{DevFeature1.15|0}} Has the same meaning as in [move_unit_fake] but a different default.<br />
* '''[fake_unit]''': A fake unit to move<br />
** '''type''': the type of unit whose image to use<br />
** '''x''': a comma-separated list of x locations to move along<br />
** '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
** '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
** '''skip_steps''': the number of steps to skip before this unit starts moving<br />
<br />
=== [hide_unit] ===<br />
Temporarily prevents the engine from displaying the given unit. The unit does not become invisible, as it would be with the '''[hides]''' ability; it is still the same plain unit, but without an image. Useful in conjunction with '''[move_unit_fake]''': to move a leader unit into position on-screen. Until 1.8 each '''[hide_unit]''' tag only hides one unit.<br />
* [[StandardUnitFilter]]: All matching units will be hidden<br />
<br />
=== [unhide_unit] ===<br />
Stops the currently hidden units from being hidden.<br />
* [[StandardUnitFilter]]: Only the matching units will be unhidden<br />
<br />
=== [lock_view] ===<br />
Locks gamemap view scrolling for human players, so they cannot scroll the gamemap view until it is unlocked. WML or Lua actions such as '''[scroll_to]''' will continue to work normally, as they ignore this restriction; the locked/unlocked state is preserved when saving the current game.<br />
<br />
This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
{{DevFeature1.13|8}} This now also blocks the player from zooming the gamemap view. WML or Lua zoom will continue to work normally.<br />
<br />
=== [unlock_view] ===<br />
Unlocks gamemap view scrolling for human players.<br />
<br />
=== [scroll] ===<br />
Scroll a certain number of pixels in a given direction. Useful for earthquake/shaking effects.<br />
* '''x''', '''y''': the number of pixels to scroll along the x and y axis<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll] happens for everyone.<br />
<br />
=== [scroll_to] ===<br />
Scroll to a given hex<br />
* [[StandardLocationFilter]], do not use a [filter_location] sub-tag. If more than one location matches the filter, only the first matching location will be used.<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex being scrolled to (defaults to ''no'').<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
<br />
=== [scroll_to_unit] ===<br />
Scroll to a given unit<br />
* [[StandardUnitFilter]]<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex the unit is on (defaults to ''no'').<br />
* '''for_side''': the side or sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
* '''[for_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
<br />
=== [select_unit] ===<br />
Selects a given unit.<br />
* [[StandardUnitFilter]]: The first unit found will be selected.<br />
* '''fire_event''': whether a ''select'' event should be triggered or not (def. ''no''). (Note that select events aren't multiplayer save.)<br />
* '''highlight''': whether the unit's current hex should be highlighted (def. ''yes'').<br />
<br />
=== [sound]===<br />
Plays a sound<br />
* '''name''': the filename of the sound to play (in ''sounds/'' as .wav or .ogg). This can be a comma-separated list, from which one sound will be chosen randomly.<br />
* '''repeat''': repeats the sound for a specified additional number of times (default=0)<br />
<br />
=== [sound_source] ===<br />
Creates a sound source. "Sound sources" is a general name for a mechanism which makes possible for map elements to emit sounds according to some rules, where "map elements" can be specific locations or terrain types. For now, only sound sources tied to locations are supported.<br />
* '''id''': a unique identification key of the sound source<br />
* '''sounds''': a list of comma separated, randomly played sounds associated with the sound source<br />
* '''delay''': a numerical value (in milliseconds) of the minimal delay between two playbacks of the source's sound if the source remains visible on the screen; if one scrolls out and back in, the source will be considered as ready to play<br />
* '''chance''': a percentage (a value from 0 to 100) describing the chance of the source being activated every second after the delay has passed or when the source's location appears on the screen (note that it cannot play more than one file at the same time)<br />
* '''check_fogged''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are fogged<br />
* '''check_shrouded''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are shrouded<br />
* '''x,y''': similar to x,y as found in a [[StandardLocationFilter]], these are the locations associated with the sound source<br />
* '''fade_range''' (default = 3): distance in hexes that determines a "circular" area around the one specified by '''full_range''' where sound volume fades out linearly<br />
* '''full_range''' (default = 14): distance in hexes that determines a "circular" area where source plays with full volume, relative to screen center<br />
* '''loop''': number of times a sound sample should be looped if it stays visible. -1 means infinite (~65000)<br />
<br />
=== [story] ===<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the story screen.<br />
* '''title''': Default title used if a part does not specify one — unlike the intro storyscreen, the scenario name is not used as a default title.<br />
* '''[part]''': As [[IntroWML]].<br />
<br />
=== [remove_sound_source] ===<br />
Removes a previously defined sound source.<br />
* '''id''': the identification key of the sound source to remove<br />
<br />
=== [music]===<br />
Switches to playing different music<br />
* '''name''': the filename of the music to play (in ''music/'' as .ogg)<br />
* see [[MusicListWML]] for the correct syntax<br />
===[volume]===<br />
Changes the game volume to a percent of the preferences volume for the game being played. Values can go from 0 to 100: <br />
* '''music''': Changes the music volume.<br />
* '''sound''': Changes the sound volume.<br />
=== [color_adjust]===<br />
Tints the color of the screen.<br />
* '''red''', '''green''', '''blue''': values from -255 to 255, the amount to tint by for each color<br />
=== [delay] ===<br />
Pauses the game.<br />
* '''time''': the time to pause in milliseconds<br />
* '''accelerate ''' (boolean yes|no, default no): {{DevFeature1.13|0}} whether the delay is affected by acceleration. When [delay] is used to make an animation, this should be set to yes so that your animation matches the ones generated by the game.<br />
<br />
=== [redraw] ===<br />
Redraws the screen (this normally isn't done during events, although some of the other interface actions cause the screen or parts of it to be redrawn).<br />
* '''clear_shroud''' (boolean yes|no, default no): If yes, clears fog and shroud around existing units. Useful if you, for example, spawn friendly units in the middle of an event and want the shroud to update accordingly (otherwise units that spawn inside fog would remain invisible for the duration of the event, since the fog would not automatically get cleared around them).<br />
* '''[[StandardSideFilter]]''': the sides for which to recalculate fog and shroud.<br />
* '''side''': If used (forces clear_shroud=yes), clears fog and shroud for that side.<br />
<br />
=== [unit_overlay] ===<br />
Sets an image that will be drawn over a particular unit, and follow it around<br />
* [[StandardUnitFilter]]: All matching units will get the overlay (do not use [filter])<br />
* '''image''': the image to place on the unit<br />
<br />
=== [remove_unit_overlay] ===<br />
Removes a particular overlayed image from a unit<br />
* [[StandardUnitFilter]]: The overlay will get removed from all matching units (do not use [filter])<br />
* '''image''': the image to remove from the unit<br />
Using remove_object is also possible, see https://github.com/wesnoth/wesnoth/commit/26c2f941f2bcdd89528481e114c0375ad2a46271<br />
<br />
=== [animate_unit] ===<br />
Uses an animation of a unit to animate it on screen (if the unit has the corresponding animation).<br />
* '''flag''': The key to find the custom animation in the unit description (see the '''[extra_anim]''' description in [[AnimationWML]]). Standard animations can be triggered with the following keywords: ''leading recruited standing idling levelout levelin healing healed poisoned movement defend attack death victory pre_teleport post_teleport''<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument, see [[FilterWML]]. By default, the unit at the event location will be animated. You can use this tag to choose any other unit to animate.<br />
* '''[primary_attack]''': If this tag is not present, the filter for animation will be triggered with no attack. If it is here, all attacks from the unit will be filtered, and a matching one will be used to filter the animation. Takes a weapon filter as argument, see [[FilterWML]].<br />
* '''[secondary_attack]''': Similar to '''[primary_attack]'''. May be needed to trigger a defense animation correctly, if there are more than one animations available for the defending unit.<br />
* '''hits''': yes/no/hit/miss/kill: which according variation of a attack/defense animation shall be chosen (required)<br />
* '''text''': a text to hover during the animation <br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''': red value for the text color (0-255)<br />
* '''green''': green value for the text color<br />
* '''blue''': blue value for the text color<br />
* '''with_bars''': yes/no: whether to display the status bars during the animation (e.g. the hitpoint bar)<br />
* '''[animate]''': a sub block with the same syntax as '''[animate_unit]''' except that the '''[filter]''' block is mandatory to find the unit. This block will find and animate another unit simultaneously.<br />
* '''[facing]''': a [[StandardLocationFilter]] specifying what direction the unit should be facing when animated<br />
<br />
=== [label] ===<br />
Places a label on the map.<br />
* '''x''', '''y''': the location of the label. {{DevFeature1.13|1}} (only for [event][label]: full [[StandardLocationFilter|SLF]] support)<br />
* '''text''': what the label should say<br />
* '''team_name''': if specified, the label will only be visible to the given team.<br />
* '''color''': color of the label. The format is r,g,b; r, g and b are numbers between 0 and 255.<br />
* '''visible_in_fog''': whether the label should be visible through fog or not. Default yes.<br />
* '''visible_in_shroud''': whether the label should be visible through shroud or not. Default no.<br />
* '''immutable''': whether this label is protected from being removed or changed by players. Default yes.<br />
* '''category''': the Show/Hide Labels dialog allows showing/hiding all labels of a given category by toggling a checkbox.<br />
* '''tooltip''': A tooltip visible when mouseovering the hex the label is on<br />
* '''side''': the number of the side that placed the label. Can be 0 for labels placed by WML.<br />
<br />
=== [floating_text]===<br />
Floats text (similar to the damage and healing numbers) on the given locations.<br />
* [[StandardLocationFilter]]: the text will be floated on all matching locations simultaneously.<br />
* '''text''': the text to display.<br />
<br />
The default text color is <span style="color: #6b8cff;">'''#6b8cff'''</span>. To change the color, use [[#Formatting|Pango markup]]. For example:<br />
<br />
<pre><br />
# Float some golden yellow text at 20,20.<br />
[floating_text]<br />
x,y=20,20<br />
text="<span color='#cccc33'>" + _ "Your text here" + "</span>"<br />
[/floating_text]<br />
</pre><br />
<br />
=== [deprecated_message] ===<br />
Shows a deprecated message in the message area, this feature is only intended to be used to warn about deprecated macros in mainline. The message is not translatable.<br />
* '''message''': the message to show.<br />
* '''level''': {{DevFeature1.13|10}} The deprecation level, a number from 1 to 3.<br />
* '''what''': {{DevFeature1.13|10}} The name of the thing being deprecated. Use this instead of '''message''' if possible; a stock message will be generated from it. Use '''message''' only if more information is required; it will be appended to the stock message. This should not be translatable<br />
* '''version''': {{DevFeature1.13|10}} For deprecation levels 2 and 3, this indicates the version in which the feature could be removed. It does ''not'' indicate the version in which it became deprecated. <br />
<br />
The meanings of the deprecation levels are as follows:<br />
<br />
# Deprecated, but will only be removed if absolutely necessary. The '''version''' key is ignored.<br />
# It will be removed no earlier than a specified version.<br />
# It will be removed in the next stable version<br />
# It has already been removed, leaving just a stub to inform users of how to update their code.<br />
<br />
Note that as of 1.13.11, deprecation messages show only in the log, not in the chat message area. The '''message''' can be translatable, but does not need to be.<br />
<br />
=== [wml_message] ===<br />
Outputs a message to Wesnoth's console output. Intended for campaign designers to output silent text to the console, without annoying the player; then, that text might contain information useful for later bug-reporting. The log domain for it is '''wml''', and the '''debug/dbg''' log level is available for use with the '''logger''' attribute. Depending on the current log level ('''error''' by default), which may be changed with the in-game :log command, or the --log-<level>=wml command line switch, the messages are echoed to the in-game chat.<br />
* '''message''': the message to show.<br />
* '''logger''': the Wesnoth engine output logger that should catch the text; this might be 'err' (the errors log level), 'warn'/'wrn' (the warnings log level) or anything else (the information log level). Not all information will be displayed depending on the log level chosen when starting Wesnoth.<br />
<br />
Note: As of 1.9.4/1.9.5 (r48805) the following "loggers" should work: If in [wml_message]: err/error, warn/wrn/warning, debug/dbg; using the :log command: Only the long forms error, warning, info and debug (this part gathered by trying rather than source inspecting). The long forms are most likely also the only ones working when starting wesnoth with --log-<level>=wml.<br />
For log level warning or error (as during normal play), only wml_messages with logger error or warning display (for both). With logger info or debug, additionally wml_messages with logger info or debug display (for both).<br />
<br />
=== [test_condition] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Evaluates the contained conditional tags. If they evaluate to the expected value, it prints out a message to the console explaining which part of the condition caused this result in a way similar to [wml_message]. This can be used if your conditional test is failing and you're not sure why.<br />
<br />
* '''result''': Whether you expect the conditions to fail or succeed. If no (the default), a message will be printed if the conditional tags fail. If yes, a message will instead be printed if the conditional tags pass.<br />
* '''logger''': Same as for [wml_message]. Defaults to "warning".<br />
<br />
=== [open_help] ===<br />
Opens the in-game help.<br />
* '''topic''': the id of the topic to open<br />
=== [show_objectives] ===<br />
refreshes the objectives defined by [objectives] and its [show_if] tags, and displays them. (It is also called whenever the user explicitly asks for the objectives; this matters only if the tag was overridden by a [[LuaWML#register_wml_action|Lua]] script.)<br />
* '''side''': the side to show the objectives. If not set, all sides are used.<br />
* '''[[StandardSideFilter]]''' tags and keys: Tag affects the matching sides instead of just all or the one given by the integer value of the side= key.<br />
<br />
=== [chat] ===<br />
Displays a message in the chat area, not visible for observers. Alternative unconditionally visible for everyone: [[LuaWML:Display#wesnoth.message]]. {{DevFeature1.13|9}} can be visible for observers.<br />
* '''speaker''': (default="WML") A string for the name of the sender of the message.<br />
* '''message''': The message that should be displayed.<br />
* '''observable''' (boolean yes|no, default yes): {{DevFeature1.13|9}} Whether the message is displayed for observers.<br />
* '''[[StandardSideFilter]]''' tags and keys as argument; if the same client controls multiple sides that match, then the message will only be displayed once.<br />
<br />
=== [zoom] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Changes the zoom level of the map.<br />
<br />
* '''factor''': The new zoom factor<br />
* '''relative''': If yes, zoom relative to current zoom level. Otherwise, set the absolute zoom level. Default no.<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for interface actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{HIGHLIGHT_UNIT}''' Highlight a unit on the map. Use this to show important units<br />
* '''{HIGHLIGHT_IMAGE}''' Places and highlights an image on the map. Use this to show important items or locations<br />
* '''{SET_IMAGE}''' Places an image on the map which has no other function.<br />
* '''{QUAKE <soundfile>}''' Creates a tremor-like screenshake and plays <soundfile>. For example, '''{QUAKE (rumble.ogg)}'''.<br />
* '''{FLASH_WHITE}''' Flash the screen white momentarily. You can also replace WHITE with RED, BLUE or GREEN for a different colour.<br />
<br />
== See Also ==<br />
* [[DirectActionsWML]]<br />
* [[InternalActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=TerrainMaskWML&diff=65443TerrainMaskWML2020-02-19T04:40:35Z<p>Gfgtdf: </p>
<hr />
<div>{{WML Tags}}<br />
<br />
The [terrain_mask] tag makes map manipulation from within WML much easier.<br />
It uses a Wesnoth map as a "mask" over a given location,<br />
placing it down on top of the scenario map.<br />
Fog ('_f') and Shroud ('_s') are used like alpha in an image; i.e. they cause the previous terrain to be used.<br />
<br />
* '''x,y''': the x,y location in the scenario map to place the top-left corner of the mask onto. Important note: if 'border=yes (default)' and alignment is unset, then (x,y) will not denote the place of the top-left corner but rather of the place of the location (1,1) of the mask data (the top left corner of the 'inner' part of the mask). So the top-left corner of the mask will be placed at (x-1,y-1) or (x-1,1).<br />
* '''mask''': a Wesnoth map; see [[BuildingMaps]].<br />
* '''border''': (default=yes) Overlay on the border as well as the playable map area. The mask used must have a border_size equal to the map's border size (i.e. it must be a normal map), otherwise it will be ignored. {{DevFeature1.15|1}} the '''border''' key is no longer used instead the manditory 'alignment' key is used, 'border' will be ignored if 'alignment' is set to any value.<br />
* '''alignment''': ({{DevFeature1.15|1}}, leaving out this key will fallback to 1.12 behaviour). possible values '''even''', '''odd''' or '''raw''', describes how the data in 'mask' is aligned, there is the even alignment (this is what the map editor produces thus you usually want to use `aligment=even`):<br />
<pre><br />
__/10\__/30\<br />
/00\__/20\__/<br />
\__/11\__/31\<br />
/01\__/21\__/<br />
\__/12\__/32\<br />
/02\__/22\__/<br />
\__/ \__/<br />
</pre><br />
and the odd alignment, (used by old mask files in wesnoth 1.10 and older):<br />
<pre><br />
/00\__/20\__ <br />
\__/10\__/30\<br />
/01\__/21\__/<br />
\__/11\__/31\<br />
/02\__/22\__/<br />
\__/12\__/32\<br />
\__/ \__/<br />
</pre><br />
. Using '''raw''' will assume the map data is aligned in the same way as the map square that starts at (x,y)<br />
* '''[rule]''': specifies a rule for blending the mask with the scenario.<br />
The terrain on each hex fitting the rule will be changed to the terrain specified in the rule.<br />
** '''old''': a comma-separated list of terrain codes. The rule fits only those hexes that have one of these terrains in the scenario. If omitted, matches any hex on the base map.<br />
** '''new''': a list of terrain letters. The rule fits only those hexes with this terrain specified in the mask. If omitted, matches any hex on the mask.<br />
** '''terrain''': the letter of the terrain to change hexes which fit this rule (i.e. for which the '''new''' terrain code in the mask falls on top of the '''old''' terrain in the scenario) into. If omitted, defaults to either the old or new terrain depending on the value of use_old.<br />
** '''layer''': (overlay|base|both, default=both) only change the specified layer.<br />
** '''replace_if_failed''': (default=no) When replacing just one layer failed, try to replace the whole terrain. If '''terrain''' is an overlay only terrain, use the default_base as base layer. If the terrain has no default base, do nothing.<br />
** '''use_old''': if yes, no change is done to hexes matching this rule. If no, the hex is changed to the new terrain or, if specified, the value of the terrain key.<br />
<br />
As an example, suppose you want to lay down a road somewhere. You could specify by hand the path the road takes using<br />
[terrain], or you could use<br />
[terrain_mask]:<br />
<br />
<pre><br />
[terrain_mask]<br />
x,y=12,10<br />
mask="border_size=1<br />
usage=map<br />
<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, Re, Re, _f, _f, _f, _f, _f<br />
_f, _f, _f, Re, Re, Re, _f, Re, Re, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, _f, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, Re, Re, Re<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, Re, Re, Re<br />
"<br />
[/terrain_mask]<br />
</pre><br />
<br />
For instance, suppose you want snow to fall in an area. You want villages on green grass (Gg^Vh) to turn into snowy villages on snow (Aa^Vha), pine forest on semi-dry grass (Gs^Fp) to turn into snowy pine forest on snow (Aa^Fpa), hills (Hh) to turn into snowy hills (Ha), and green grass (Gg) and regular dirt (Re) to turn into snow (Aa), while other terrain remains untouched. You could look over your destination map and work out which terrain type is which and draw your mask, but that's a lot of effort, you want to just draw a simple mask which has areas of snow and areas of no snow, and make the game work out the rest.<br />
<br />
You can do it like this:<br />
<br />
[terrain_mask]<br />
x,y=1,1<br />
mask="border_size=1<br />
usage=map<br />
<br />
_f, _f, Aa, _f, _f, _f, Aa, _f, _f<br />
_f, _f, Aa, _f, _f, _f, Aa, _f, _f<br />
_f, _f, Aa, _f, Aa, _f, Aa, _f, _f<br />
Aa, Aa, _f, _f, Aa, Aa, Aa, _f, _f<br />
_f, _f, Aa, Aa, Aa, Aa, Aa, Aa, Aa<br />
_f, _f, _f, Aa, Aa, Aa, Aa, Aa, Aa<br />
_f, _f, _f, _f, Aa, Aa, _f, _f, _f<br />
_f, _f, _f, _f, Aa, Aa, _f, _f, _f"<br />
[rule]<br />
old=Gg^Vh<br />
new=Aa<br />
terrain=Aa^Vha<br />
[/rule]<br />
[rule]<br />
old=Gs^Fp<br />
new=Aa<br />
terrain=Aa^Fpa<br />
[/rule]<br />
[rule]<br />
old=Hh<br />
new=Aa<br />
terrain=Ha<br />
[/rule]<br />
<br />
[rule]<br />
old=Gg,Re<br />
new=Aa<br />
#don't specify terrain and it just uses the new terrain<br />
[/rule]<br />
<br />
#default: Will match everything, since 'old' and 'new' aren't<br />
#specified. Set 'use_old=yes' to signal no change.<br />
[rule]<br />
use_old=yes<br />
[/rule]<br />
[/terrain_mask]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=TerrainMaskWML&diff=65442TerrainMaskWML2020-02-19T04:20:15Z<p>Gfgtdf: </p>
<hr />
<div>{{WML Tags}}<br />
<br />
The [terrain_mask] tag makes map manipulation from within WML much easier.<br />
It uses a Wesnoth map as a "mask" over a given location,<br />
placing it down on top of the scenario map.<br />
Fog ('_f') and Shroud ('_s') are used like alpha in an image; i.e. they cause the previous terrain to be used.<br />
<br />
* '''x,y''': the x,y location in the scenario map to place the top-left corner of the mask onto<br />
* '''mask''': a Wesnoth map; see [[BuildingMaps]].<br />
* '''border''': (default=no) Overlay on the border as well as the playable map area. The mask used must have a border_size equal to the map's border size (i.e. it must be a normal map), otherwise it will be ignored. {{DevFeature1.15|1}} the '''border''' key is no longer used instead the manditory 'alignment' kay is used:<br />
* '''alignment''': ({{DevFeature1.15|1}}, manditory, leaving out this key will fallback to 1.12 behviour which is strange). possible values '''even''', '''odd''' or '''raw''', describes how the data in 'mask' is aligned, there is the even alignment (this is what the map editor produces thus you usually want to use `aligment=even`):<br />
<pre><br />
__/10\__/30\<br />
/00\__/20\__/<br />
\__/11\__/31\<br />
/01\__/21\__/<br />
\__/12\__/32\<br />
/02\__/22\__/<br />
\__/ \__/<br />
</pre><br />
and the odd alignment, (used by old mask files in wesnoth 1.10 and older):<br />
<pre><br />
/00\__/20\__ <br />
\__/10\__/30\<br />
/01\__/21\__/<br />
\__/11\__/31\<br />
/02\__/22\__/<br />
\__/12\__/32\<br />
\__/ \__/<br />
</pre><br />
. Using '''raw''' will assume the map data is aligned in the same way as the map square that starts at (x,y)<br />
* '''[rule]''': specifies a rule for blending the mask with the scenario.<br />
The terrain on each hex fitting the rule will be changed to the terrain specified in the rule.<br />
** '''old''': a comma-separated list of terrain codes. The rule fits only those hexes that have one of these terrains in the scenario. If omitted, matches any hex on the base map.<br />
** '''new''': a list of terrain letters. The rule fits only those hexes with this terrain specified in the mask. If omitted, matches any hex on the mask.<br />
** '''terrain''': the letter of the terrain to change hexes which fit this rule (i.e. for which the '''new''' terrain code in the mask falls on top of the '''old''' terrain in the scenario) into. If omitted, defaults to either the old or new terrain depending on the value of use_old.<br />
** '''layer''': (overlay|base|both, default=both) only change the specified layer.<br />
** '''replace_if_failed''': (default=no) When replacing just one layer failed, try to replace the whole terrain. If '''terrain''' is an overlay only terrain, use the default_base as base layer. If the terrain has no default base, do nothing.<br />
** '''use_old''': if yes, no change is done to hexes matching this rule. If no, the hex is changed to the new terrain or, if specified, the value of the terrain key.<br />
<br />
As an example, suppose you want to lay down a road somewhere. You could specify by hand the path the road takes using<br />
[terrain], or you could use<br />
[terrain_mask]:<br />
<br />
<pre><br />
[terrain_mask]<br />
x,y=12,10<br />
mask="border_size=1<br />
usage=map<br />
<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, Re, Re, _f, _f, _f, _f, _f<br />
_f, _f, _f, Re, Re, Re, _f, Re, Re, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, _f, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, Re, Re, Re<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, Re, Re, Re<br />
"<br />
[/terrain_mask]<br />
</pre><br />
<br />
For instance, suppose you want snow to fall in an area. You want villages on green grass (Gg^Vh) to turn into snowy villages on snow (Aa^Vha), pine forest on semi-dry grass (Gs^Fp) to turn into snowy pine forest on snow (Aa^Fpa), hills (Hh) to turn into snowy hills (Ha), and green grass (Gg) and regular dirt (Re) to turn into snow (Aa), while other terrain remains untouched. You could look over your destination map and work out which terrain type is which and draw your mask, but that's a lot of effort, you want to just draw a simple mask which has areas of snow and areas of no snow, and make the game work out the rest.<br />
<br />
You can do it like this:<br />
<br />
[terrain_mask]<br />
x,y=1,1<br />
mask="border_size=1<br />
usage=map<br />
<br />
_f, _f, Aa, _f, _f, _f, Aa, _f, _f<br />
_f, _f, Aa, _f, _f, _f, Aa, _f, _f<br />
_f, _f, Aa, _f, Aa, _f, Aa, _f, _f<br />
Aa, Aa, _f, _f, Aa, Aa, Aa, _f, _f<br />
_f, _f, Aa, Aa, Aa, Aa, Aa, Aa, Aa<br />
_f, _f, _f, Aa, Aa, Aa, Aa, Aa, Aa<br />
_f, _f, _f, _f, Aa, Aa, _f, _f, _f<br />
_f, _f, _f, _f, Aa, Aa, _f, _f, _f"<br />
[rule]<br />
old=Gg^Vh<br />
new=Aa<br />
terrain=Aa^Vha<br />
[/rule]<br />
[rule]<br />
old=Gs^Fp<br />
new=Aa<br />
terrain=Aa^Fpa<br />
[/rule]<br />
[rule]<br />
old=Hh<br />
new=Aa<br />
terrain=Ha<br />
[/rule]<br />
<br />
[rule]<br />
old=Gg,Re<br />
new=Aa<br />
#don't specify terrain and it just uses the new terrain<br />
[/rule]<br />
<br />
#default: Will match everything, since 'old' and 'new' aren't<br />
#specified. Set 'use_old=yes' to signal no change.<br />
[rule]<br />
use_old=yes<br />
[/rule]<br />
[/terrain_mask]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=TerrainMaskWML&diff=65441TerrainMaskWML2020-02-19T04:20:01Z<p>Gfgtdf: </p>
<hr />
<div>{{WML Tags}}<br />
<br />
The [terrain_mask] tag makes map manipulation from within WML much easier.<br />
It uses a Wesnoth map as a "mask" over a given location,<br />
placing it down on top of the scenario map.<br />
Fog ('_f') and Shroud ('_s') are used like alpha in an image; i.e. they cause the previous terrain to be used.<br />
<br />
* '''x,y''': the x,y location in the scenario map to place the top-left corner of the mask onto<br />
* '''mask''': a Wesnoth map; see [[BuildingMaps]].<br />
* '''border''': (default=no) Overlay on the border as well as the playable map area. The mask used must have a border_size equal to the map's border size (i.e. it must be a normal map), otherwise it will be ignored. {{DevFeature1.15|1}} the '''border''' key is no longer used instead the manditory 'alignment' kay is used:<br />
* '''alignment''': (manditory, leaving out this key will fallback to 1.12 behviour which is strange). possible values '''even''', '''odd''' or '''raw''', describes how the data in 'mask' is aligned, there is the even alignment (this is what the map editor produces thus you usually want to use `aligment=even`):<br />
<pre><br />
__/10\__/30\<br />
/00\__/20\__/<br />
\__/11\__/31\<br />
/01\__/21\__/<br />
\__/12\__/32\<br />
/02\__/22\__/<br />
\__/ \__/<br />
</pre><br />
and the odd alignment, (used by old mask files in wesnoth 1.10 and older):<br />
<pre><br />
/00\__/20\__ <br />
\__/10\__/30\<br />
/01\__/21\__/<br />
\__/11\__/31\<br />
/02\__/22\__/<br />
\__/12\__/32\<br />
\__/ \__/<br />
</pre><br />
. Using '''raw''' will assume the map data is aligned in the same way as the map square that starts at (x,y)<br />
* '''[rule]''': specifies a rule for blending the mask with the scenario.<br />
The terrain on each hex fitting the rule will be changed to the terrain specified in the rule.<br />
** '''old''': a comma-separated list of terrain codes. The rule fits only those hexes that have one of these terrains in the scenario. If omitted, matches any hex on the base map.<br />
** '''new''': a list of terrain letters. The rule fits only those hexes with this terrain specified in the mask. If omitted, matches any hex on the mask.<br />
** '''terrain''': the letter of the terrain to change hexes which fit this rule (i.e. for which the '''new''' terrain code in the mask falls on top of the '''old''' terrain in the scenario) into. If omitted, defaults to either the old or new terrain depending on the value of use_old.<br />
** '''layer''': (overlay|base|both, default=both) only change the specified layer.<br />
** '''replace_if_failed''': (default=no) When replacing just one layer failed, try to replace the whole terrain. If '''terrain''' is an overlay only terrain, use the default_base as base layer. If the terrain has no default base, do nothing.<br />
** '''use_old''': if yes, no change is done to hexes matching this rule. If no, the hex is changed to the new terrain or, if specified, the value of the terrain key.<br />
<br />
As an example, suppose you want to lay down a road somewhere. You could specify by hand the path the road takes using<br />
[terrain], or you could use<br />
[terrain_mask]:<br />
<br />
<pre><br />
[terrain_mask]<br />
x,y=12,10<br />
mask="border_size=1<br />
usage=map<br />
<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
Re, Re, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f<br />
_f, _f, Re, _f, _f, Re, Re, _f, _f, _f, _f, _f<br />
_f, _f, _f, Re, Re, Re, _f, Re, Re, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, _f, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, _f, _f, _f<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, Re, Re, Re<br />
_f, _f, _f, _f, _f, _f, _f, Re, Re, Re, Re, Re<br />
"<br />
[/terrain_mask]<br />
</pre><br />
<br />
For instance, suppose you want snow to fall in an area. You want villages on green grass (Gg^Vh) to turn into snowy villages on snow (Aa^Vha), pine forest on semi-dry grass (Gs^Fp) to turn into snowy pine forest on snow (Aa^Fpa), hills (Hh) to turn into snowy hills (Ha), and green grass (Gg) and regular dirt (Re) to turn into snow (Aa), while other terrain remains untouched. You could look over your destination map and work out which terrain type is which and draw your mask, but that's a lot of effort, you want to just draw a simple mask which has areas of snow and areas of no snow, and make the game work out the rest.<br />
<br />
You can do it like this:<br />
<br />
[terrain_mask]<br />
x,y=1,1<br />
mask="border_size=1<br />
usage=map<br />
<br />
_f, _f, Aa, _f, _f, _f, Aa, _f, _f<br />
_f, _f, Aa, _f, _f, _f, Aa, _f, _f<br />
_f, _f, Aa, _f, Aa, _f, Aa, _f, _f<br />
Aa, Aa, _f, _f, Aa, Aa, Aa, _f, _f<br />
_f, _f, Aa, Aa, Aa, Aa, Aa, Aa, Aa<br />
_f, _f, _f, Aa, Aa, Aa, Aa, Aa, Aa<br />
_f, _f, _f, _f, Aa, Aa, _f, _f, _f<br />
_f, _f, _f, _f, Aa, Aa, _f, _f, _f"<br />
[rule]<br />
old=Gg^Vh<br />
new=Aa<br />
terrain=Aa^Vha<br />
[/rule]<br />
[rule]<br />
old=Gs^Fp<br />
new=Aa<br />
terrain=Aa^Fpa<br />
[/rule]<br />
[rule]<br />
old=Hh<br />
new=Aa<br />
terrain=Ha<br />
[/rule]<br />
<br />
[rule]<br />
old=Gg,Re<br />
new=Aa<br />
#don't specify terrain and it just uses the new terrain<br />
[/rule]<br />
<br />
#default: Will match everything, since 'old' and 'new' aren't<br />
#specified. Set 'use_old=yes' to signal no change.<br />
[rule]<br />
use_old=yes<br />
[/rule]<br />
[/terrain_mask]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=EffectWML&diff=65042EffectWML2019-11-05T15:24:59Z<p>Gfgtdf: </p>
<hr />
<div>{{WML Tags}}<br />
<br />
The tag [effect] is used to describe one modification to a unit. Any number of [effect] tags can be used to describe a complete modification. Modifications are permanent changes to a unit; currently there is no way of removing a modification.<br />
<br />
The following keys and subtags are always recognized:<br />
* '''[filter]''': only apply this effect if the affected unit matches. See [[StandardUnitFilter]] for details.<br />
* '''times''': describes how many times the effect is applied. The default is to apply the effect once. Other possible value : "per level" which means that the effect is applied level times, where level is the unit level. {{DevFeature1.13|5}} Integers are now supported for ''times''.<br />
* '''apply_to''': describes what the effect actually affects. New effect types can be added with [[LuaWML/Units#wesnoth.effects]].<br />
[effect] uses different keys depending on the value of '''apply_to'''. '''apply_to''' can take the following values:<br />
* '''new_attack''': will use all other keys and tags as the description of an attack that will be added to the unit. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]].<br />
* '''remove_attacks''': remove the matching attacks. All tags from the attack filter construct will be used to match the attack; see [[FilterWML#Filtering Weapons|FilterWML]]. Do not use a [filter] tag otherwise it will not work properly.<br />
* '''attack''': find an attack and modify it. All tags from the attack filter construct will be used to match the attack; see [[FilterWML#Filtering Weapons|FilterWML]]. After that, the following keys and tags can be used to modify the attack. Note: do not use a [filter] tag. Just put the keys you want to filter on inside the [effect] tag.<br />
** '''set_name''': change the attack's name (ie identifier).<br />
** '''set_description''': change the attack's description (ie displayed name). <br />
** '''set_type''': change the attack type. The standard values are '''blade''', '''pierce''', '''impact''', '''fire''', '''cold''', and '''arcane'''.<br />
** '''set_icon''': change the attack's icon.<br />
** '''[set_specials]''': change the attack's specials. The specials to add are given exactly as in the [specials] tag.<br />
*** '''mode''': if '''append''', adds the given specials to the attack. If '''replace''', replaces the existing specials with the given ones. Default '''replace'''.<br />
** '''remove_specials''': remove the listed specials. The value of this key is the coma-separated list of the id of the specials to remove. This key is always evaluated before a [set_specials] tags in the same [effect]<br />
** '''increase_damage''': increases the attack's damage. This can be positive or negative, so you can use it to decrease damage as well. If it ends in a percent(''''%''''), the change in damage will be a percentage ratio of the attack's original damage.<br />
** '''increase_attacks''': increases the number of attack strikes. Like '''increase_damage''', it can be positive or negative, or a percentage.<br />
** '''increase_accuracy''': increases the attack accuracy; can be positive or negative, or a percentage<br />
** '''increase_parry''': increases the attack parry bonus; can be positive or negative, or a percentage<br />
** '''increase_movement_used''': {{DevFeature1.13|2}} increases the movement points used by the attack; can be positive or negative, or a percentage<br />
** '''set_damage''' {{DevFeature1.13|2}} like increase_damage, but sets the damage to a specific value instead of setting it relative to its original value<br />
** '''set_attacks''' {{DevFeature1.13|2}} like increase_attacks, but sets the attacks to a specific value instead of setting it relative to its original value<br />
** '''set_accuracy''' {{DevFeature1.13|2}} like increase_accuracy, but sets the accuracy to a specific value instead of setting it relative to its original value<br />
** '''set_parry''' {{DevFeature1.13|2}} like increase_parry, but sets the parry to a specific value instead of setting it relative to its original value<br />
** '''set_movement_used''' {{DevFeature1.13|2}} like increase_movement_used, but sets the movement used to a specific value instead of setting it relative to its original value<br />
** '''attack_weight''': change the attack's attack_weight. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]] for explanations about attack_weight.<br />
** '''defense_weight''': change the attack's defense_weight. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]] for explanations about defense_weight.<br />
* '''max_attacks''': {{DevFeature1.13|2}} change the unit's maximum attacks per turn<br />
** '''increase''': how much to increase by; can be positive or negative, or a percentage<br />
* '''hitpoints''': modifies the unit's HP and/or max HP.<br />
** '''increase''': the amount to increase the unit's HP.<br />
** '''heal_full''': if present and not set to "no" the unit will be put back to full HP.<br />
** '''increase_total''': will increase the total HP of the unit. Can be specified either as a negative or a positive value. It can also be specified as a percentage of the current total; i.e. "-50%" will cut max HP in half.<br />
** '''violate_maximum''': it the unit ends up with more than its max HP after these modifications, and this key is present (set to any non-null value, ex. '''yes'''), the unit's HP won't be lowered to its max HP.<br />
* '''movement''': modifies the unit's movement points.<br />
** '''increase''': maximum movement is increased by this amount. It can be positive, negative, or specified as a percentage.<br />
** '''set''': maximum movement is set to a specific value.<br />
* '''vision''': {{DevFeature1.13|2}} modifies the unit's vision points. Note: this has side effects described in [[#Movement_and_Vision|Movement and Vision]].<br />
** '''increase''': maximum vision is increased by this amount. It can be positive, negative, or specified as a percentage.<br />
** '''set''': maximum vision is set to a specific value. <br />
* '''jamming''': {{DevFeature1.13|2}} modifies the unit's jamming points.<br />
** '''increase''': maximum jamming is increased by this amount. It can be positive, negative, or specified as a percentage.<br />
** '''set''': maximum jamming is set to a specific value.<br />
* '''experience''': affects the unit's current XP.<br />
** '''increase''': current XP is increased by this amount. It can be positive, negative, or specified as a percentage.<br />
** '''set''': current XP is set to a specific value.<br />
* '''max_experience''': affects the amount of XP the unit needs for the next level.<br />
** '''increase''': how to change the xp; again it can be negative, positive or a percentage.<br />
* '''loyal''': no keys associated. The affected unit will be loyal i.e have an upkeep of 0.<br />
* '''movement_costs''': speed through specific terrain is modified<br />
** '''replace''': If set to "yes", any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed).<br />
** '''[movement_costs]''': a subtag that describes the new movement costs just like in [[UnitsWML#.5Bmovetype.5D|UnitsWML]]<br />
* '''vision_costs''': vision through specific terrain is modified<br />
** '''replace''': If set to "yes", any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed).<br />
** '''[vision_costs]''': a subtag that describes the new vision costs just like in [[UnitsWML#.5Bmovetype.5D|UnitsWML]]<br />
* '''jamming_costs''': jamming through specific terrain is modified<br />
** '''replace''': If set to "yes", any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed).<br />
** '''[jamming_costs]''': a subtag that describes the new jamming costs just like in [[UnitsWML#.5Bmovetype.5D|UnitsWML]]<br />
* '''defense''': Sets the unit's chance to be hit in specific terrain (100 - the unit's defense as shown in-game). <br />
** '''replace''': If set to "yes", any new values replace the old ones. Otherwise, new values are added to old values. In most cases, adding a positive number makes the unit easier to hit, while adding a negative number makes the unit harder to hit. The new value is added to the absolute value of the old, and the sign of the old value is preserved.<br />
** '''[defense]''': a subtag that describes the new defense just like in [[UnitsWML#.5Bmovetype.5D|UnitsWML]]<br />
* '''resistance''': Sets percent damage taken from combat (100 - the unit's resistance as shown in-game)<br />
** '''replace''': If set to "yes", any new values replace the old ones. Otherwise, new values are added to old values. Adding a positive number makes the unit take more damage, while adding a negative number makes the unit take less damage.<br />
** '''[resistance]''': a subtag that describes the new resistance just like in [[UnitsWML#.5Bmovetype.5D|UnitsWML]]<br />
* '''variation''': switches the unit into one of its variations. Similar to the '''type''' effect below, this might not.behave properly outside of [advancement]<br />
** '''name''': the id of the variation to invoke. <br />
* '''type''': transforms the unit into a new unit_type. This does not work in [trait] and for in actionwml it's reccended to use [transform_unit] instead of an [object] with this effect. Also this effect cannot be undone with [remove_object]<br />
** '''name''': the id of the unit_type to invoke.<br />
* '''status''': modifies the status affecting the unit.<br />
** '''add''': a list of status modifications to add. Beware, these may be reapplied later, such as when the unit is recalled or levels up; if in an event, you can use [[InternalActionsWML|[store_unit]]] and [[DirectActionsWML|[unstore_unit]]], modifying unit.status.name directly, to avoid this, or if you are creating the unit, you can just add it to the unit's [status] tag in the [unit] tag. These are listed in [status], [[SingleUnitWML]].<br />
** '''remove''': a list of status modifications to remove.<br />
* '''zoc''': toggle the zone of control.<br />
** '''value''': new value for zoc (boolean).<br />
* '''profile''': customize the profile of the unit. See [[UnitTypeWML]].<br />
** '''portrait''': new image to display when the unit speaks.<br />
** '''small_portrait''': new image to display in unit reports.<br />
** '''description''': sets the text to display when hovering over the unit's type in the righthand pane.<br />
** '''[special_note]''': {{DevFeature1.15|2}} Adds or removes a special note in the unit's description.<br />
*** '''remove''': A boolean value specifying whether to add or remove a note. Defaults to '''no'''.<br />
*** '''note''' (translatable): The text of the note you want to add or remove. If removing a note, this must be an exact match, character-for-character, for the note you want to remove, and must also be in the same textdomain.<br />
*** Since the tag name is the same, notes can also be added using the standard special note macros, eg '''{NOTE_HEALS}'''.<br />
*** To remove a note, you can simply suffix '''{NOTE_REMOVE}''' to the regular note macro, eg '''{NOTE_HEALS}{NOTE_REMOVE}'''.<br />
* '''new_ability''': Adds one or more abilities to a unit.<br />
** '''[abilities]''': A subtag that contains the ability definitions.<br />
* '''remove_ability''': Removes one or more abilities from a unit. Abilities are not reference counted: added, added, removed = gone.<br />
** '''[abilities]''': A subtag that contains the ability definitions. Strictly speaking, all that is needed is the id= inside some tag.<br />
* '''new_animation''': contain animations that will be added to the unit, it can contain multiple animation blocks, and a single "id=" line. That Id should be unique for each effect block and is used by the engine to reuse WML parsing, making the loading faster. <br />
* '''image_mod''': modify the image path function ([[ImagePathFunctions]]) of all the unit's frames.<br />
** '''replace''': replaces the image path function(s) to be used, e.g. "RC(magenta>red)"<br />
** '''add''': adds an image path function without removing any existing ones.<br />
** If needed, you can also define new [[GameConfigWML#Color_Palettes|color palettes]] here.<br />
* '''ellipse''': Change the image used for the unit's ellipse.<br />
** '''ellipse''' : the new image to use. Can be set to "none" to disable the ellipse.<br />
* '''halo''': Change the image used for the unit's halo.<br />
** '''halo''': the new image to use.<br />
* '''overlay''': Change the unit's overlays.<br />
**'''add''': the specified overlay will be added to the unit's overlays. It can be a comma separated list with multiple overlays. ''Note: overlays added in this way cannot be removed by [remove_unit_overlay] until the effect's duration is over.''<br />
**'''replace''': all the unit's overlays will be removed and replaced with the specified one. Again, it can be a comma separated list. ''Note: overlays replaced in this way cannot be modified by [unit_overlay] or [remove_unit_overlay] until the effect's duration is over.''<br />
**'''remove''': {{DevFeature1.15|0}} the specified overlay will be removed from the unit's overlays. It can be a comma separated list with multiple overlays.<br />
** {{DevFeature1.15|0}} [unit_overlay] and [remove_unit_overlay] are now equivalent to adding a permanent object with this effect, after checking if the unit already has / already doesn't have the overlay (effects with temporary durations will cause false positives / false negatives in this check).<br />
* '''recall_cost''': {{DevFeature1.13|2}} change a unit's recall cost<br />
** '''set''': set recall cost to a specific value, or a percentage of original value<br />
** '''increase''': alter recall cost relative to original value; can be positive or negative, or a percentage<br />
* '''alignment''': {{DevFeature1.13|2}} change a unit's alignment<br />
** '''set''': the new alignment (one of chaotic, lawful, neutral, liminal)<br />
* '''new_advancement''': {{DevFeature1.13|2}} add new advancement choices to the unit<br />
** '''replace''': whether to replace existing advancement choices; if this key is set to yes, existing advancement choices are cleared only if you're adding a choice of the same type. (That is, unit type advancements are cleared only if you're adding a new unit advancement choice, and AMLA choices are cleared only if you're adding new AMLA choices.)<br />
** '''types''': a comma-separated list of additional unit types the unit can advance to. ('''Note:''' If using this, you probably want to include a filter to prevent the unit from being able to advance to this type once it has already done so.)<br />
** '''[advancement]''': an advancement choice to add, see [[UnitTypeWML#After_max_level_advancement_(AMLA)|AMLAs]]; you can have several of these tags to add multiple advancement choices at the same time.<br />
* '''remove_advancement''': {{DevFeature1.13|2}} remove existing advancement choices from the unit<br />
** '''types''': a list of unit type advancements to remove as a possibility<br />
** '''amlas''': a list of AMLA id attributes; any advancement possibility with the given id will be removed<br />
<br />
=== Movement and Vision ===<br />
<br />
Wesnoth 1.14 introduced vision points, which default to a reserved value (-1) which means "the same as the max movement points". Using an effect with apply_to=vision sets the number of vision points, and from then on they're no longer affected by the movement points.<br />
<br />
Consider a unit with 5 mp, and default vision:<br />
* It has (effectively) 5 mp and 5 vp.<br />
* After (mp + 1), it will have 6 mp and 6 vp.<br />
* After (vp + 2), it will have 5 mp and 7 vp.<br />
* After (mp + 1) (vp + 2), it will have 6 mp and 8 vp.<br />
* After (vp + 2) (mp + 1), it will have 6 mp and 7 vp.<br />
<br />
=== Examples ===<br />
== Effect: apply_to = new_animation ==<br />
This is the only way to change animations of units after they have been placed on the map.<br />
In this example, I add very simple idle animation (taken from Goblin Spearman) to the unit, which moves to hex (x=1, y=5). If you want something more complex, you need to check [[AnimationWML]] page.<br />
<br />
[event]<br />
name = moveto<br />
[filter]<br />
x,y = 1,5<br />
[/filter]<br />
[object]<br />
[filter]<br />
x,y = 1,5<br />
[/filter]<br />
[effect]<br />
apply_to = new_animation<br />
[idle_anim]<br />
{STANDARD_IDLE_FILTER}<br />
start_time=0<br />
[frame]<br />
image="units/goblins/spearman-idle-[1~12].png:[150*3,300,150*8]"<br />
[/frame]<br />
[/idle_anim]<br />
[/effect]<br />
[/object]<br />
[/event]<br />
<br />
If you are going to use '''advanced WML''' and want to add animation to unit, stored in variable, then following example might help you. '''This way is not efficient if you have no additional logic like inventoriy, shops, advanced unit modifications in your add-on.''' Is is preferred to use first variant or define all needed animation in unit_type.<br />
[event]<br />
name = moveto<br />
[filter]<br />
x,y = 1,5<br />
[/filter]<br />
[store_unit]<br />
[filter]<br />
x,y=1,5<br />
[/filter]<br />
variable = stored_unit<br />
[/store_unit]<br />
[set_variables]<br />
name = stored_unit.modifications.object<br />
[value]<br />
[effect]<br />
apply_to = new_animation<br />
[idle_anim]<br />
{STANDARD_IDLE_FILTER}<br />
start_time=0<br />
[frame]<br />
image="units/goblins/spearman-idle-[1~12].png:[150*3,300,150*8]"<br />
[/frame]<br />
[/idle_anim]<br />
[/effect]<br />
[/value]<br />
[/set_variables]<br />
[unstore_unit]<br />
variable = stored_unit<br />
[/unstore_unit]<br />
[/event]<br />
<br />
== See Also ==<br />
<br />
* [[UnitTypeWML]]<br />
* [[ReferenceWML]]<br />
* [[AnimationWML]]<br />
<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=DirectActionsWML&diff=60917DirectActionsWML2019-04-13T10:21:39Z<p>Gfgtdf: /* [remove_object] */</p>
<hr />
<div>{{WML Tags}}<br />
== Direct actions ==<br />
<br />
Direct actions are actions that have a direct effect on gameplay. They can be used inside of [[EventWML|events]].<br />
<br />
The following tags are actions:<br />
<br />
=== [endlevel] ===<br />
Ends the scenario.<br />
* '''result''': before the scenario is over, all events with ''name=result'' are triggered. If ''result=victory'', the player progresses to the next level (i.e., the next scenario in single player); if ''result=defeat'', the game returns to the main menu. <br />
<br />
When the result is "victory" the following keys can be used:<br />
* '''bonus''': whether the player should get bonus gold (maximum possible gold that could have been earned by waiting the level out). The default is bonus=yes. {{DevFeature1.13|2}} Alternatively, a number, defining the bonus multiple (1.0 meaning full).<br />
* '''carryover_report''': whether the player should receive a summary of the scenario outcome, the default is carryover_report=yes.<br />
* '''save''': whether a start-of-scenario save should be created for the next scenario, the default is save=yes. Do not confuse this with saving of replays for the current scenario.<br />
* '''replay_save''': whether a replay save for the current scenario is allowed, the default is replay_save=yes. If yes, the player's settings in preferences will be used to determine if a replay is saved. If no, will override and not save a replay.<br />
* '''linger_mode''': If ...=yes, the screen is greyed out and there's the possibility to save before advancing to the next scenario, the default is linger_mode=yes.<br />
* '''reveal_map''': (Multiplayer only) (Default is 'yes') If 'no', shroud doesn't disappear when game ended.<br />
* '''next_scenario''': (default specified in '''[scenario]''' tag) the ID of the next scenario that should be played. All units that side 1 controls at this point become available for recall in ''next_scenario''.<br />
* '''carryover_percentage''': by default 80% of the gold is carried over to the next scenario, with this key the amount can be changed.<br />
* '''carryover_add''': if yes the gold will be added to the starting gold the next scenario, if no the next scenario will start with the amount of the current scenario (after taxes) or the minimum in the next scenario. Default is no.<br />
* '''music''': (default specified in '''[scenario]''' or '''[game_config]''' tags) a comma-separated list of music tracks from which one will be chosen and played once after any events related to the end of level result are executed; by default, victory_music is used on victory, and defeat_music on defeat.<br />
* '''end_credits''': Whether to display the credits screen at the end of a single-player campaign. Defaults to ''yes''. Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* '''end_text''': (translatable) Text that is shown centered in a black screen at the end of a campaign. Defaults to "The End". Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* '''end_text_duration''': Delay, in milliseconds, before displaying the game credits at the end of a campaign. In other words, for how much time '''end_text''' is displayed on screen. Defaults to 3500. Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* <strike>'''[next_scenario_settings]''': Any tags or attribute children of this optional argument to [endlevel] are merged into the scenario/multiplayer tag of the *next* scenario. This allows you to e.g. reconfigure the [side] tags or settings, just before load. </strike> This feature was removed in 1.11.17, it might be redesigned and reintroduced.<br />
* <strike>'''[next_scenario_append]''': Any tags of this optional argument are appended at high level to the next scenario. This is most appropriate for [event] tags, although you may find other uses. Example test scenario for these features: https://gna.org/support/download.php?file_id=20119 </strike> This feature was removed in 1.11.17, it might be redesigned and reintroduced.<br />
* '''[result]''' {{DevFeature1.13|0}} Allows specification of a side specific result, this is for competitive multiplayer scenarios/campaigns where it might happen that one player wins but another player loses. The following attributes are accepted and have the same effect as in '''[endlevel]''':<br />
** '''result'''<br />
** '''bonus'''<br />
** '''carryover_percentage'''<br />
** '''carryover_add'''<br />
<br />
And there is also<br />
** '''side''' The number of the side for which these results should apply.<br />
<br />
=== [unit] ===<br />
Creates a unit (either on the map, on a recall list, or into a variable for later use.) For syntax see [[SingleUnitWML]].<br />
* {{Short Note:Predefined Macro|GENERIC_UNIT}}<br />
<br />
=== [recall] ===<br />
Recalls a unit taking into account any [http://wiki.wesnoth.org/SingleUnitWML filter_recall] of the leader. The unit is recalled free of charge, and is placed near its leader, e.g., if multiple leaders are present, near the first found which would be able to normally recall it.<br />
<br />
If neither a valid map location is provided nor a leader on the map would be able to recall it, the tag is ignored.<br />
<br />
* [[StandardUnitFilter]]: the first matching unit will be recalled. If no units match this tag is ignored. Do not use a [filter] tag. If a comma separated list is given, every unit currently considered for recall is checked against all the types (not each single one of the types against all units).<br />
* '''x,y''': the unit is placed here instead of next to the leader.<br />
* '''show''': yes/no, default yes: whether the unit is animated (faded in) or instantly displayed<br />
* '''fire_event''': boolean yes|no (default no); whether any according prerecall or recall events shall be fired.<br />
* '''check_passability''': (boolean yes|no, default yes): If yes, checks for terrain passability when placing the unit (a nearby passable hex is chosen).<br />
* '''[secondary_unit]''': {{DevFeature1.13|?}} If present and show=yes, a matching unit will be chosen and their recruiting animation played.<br />
<br />
=== [teleport] ===<br />
Teleports a unit on map. {{Short Note:Predefined Macro|TELEPORT_UNIT}}<br />
* '''[filter]''': [[StandardUnitFilter]] the first unit matching this filter will be teleported.<br />
* '''x,y''': the hex to teleport to. If that hex is occupied, the closest unoccupied hex will be used instead.<br />
* '''clear_shroud''': should shroud be cleared on arrival<br />
* '''animate''': should a teleport animation be played (if the unit doesn't have a teleport animation, it will fade out/fade in)<br />
* '''check_passability''': (boolean yes|no, default yes): normally, units will not be teleported into terrain that is impassable for them. Setting this attribute to "no" permits it.<br />
<br />
(Note: There is also a ability named teleport, see [[AbilitiesWML]].)<br />
<br />
=== [terrain_mask] ===<br />
Changes the terrain on the map. See [[TerrainMaskWML]].<br />
<br />
=== [terrain] ===<br />
Changes the terrain on the map.<br />
* '''terrain''': the character of the terrain to use. See [[TerrainCodesWML]] to see what letter a type of terrain uses.<br />
* [[StandardLocationFilter]]. This [[StandardLocationFilter]]'s terrain= key is used for the new terrain, filtering by terrain can be done with a nested [[StandardLocationFilter]]: [and]terrain=terrain_string_to_be_filtered_for.<br />
* '''layer''': (overlay|base|both, default=both) only change the specified layer.<br />
* '''replace_if_failed''': (default=no) When replacing just one layer failed, try to replace the whole terrain. If '''terrain''' is an overlay only terrain, use the default_base as base layer. If the terrain has no default base, do nothing.<br />
<br />
If you want to remove the overlays from a terrain and leave only the base, use:<br />
layer=overlay<br />
terrain="^"<br />
<br />
<b>Note:</b> When a hex changes from a village terrain to a non-village terrain, and a team owned that village it loses that village. When a hex changes from a non-village terrain to a village terrain and there is a unit on that hex it does not automatically capture the village. The reason for not capturing villages it that there are too many choices to make; should a unit lose its movement points, should capture events be fired. It is easier to do this as wanted by the author in WML.<br />
<br />
=== [gold] ===<br />
Gives sides gold.<br />
* '''amount''': the amount of gold to give.<br />
* '''side''': (default=1) the number of the side to give the gold to. Can be a comma-separated list of sides. note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [unstore_unit] ===<br />
Creates a unit from a game variable, and activates it on the playing field. This must be a specific variable describing a unit, and may not be an array -- to unstore an entire array, iterate over it. The variable is not cleared. See also [[InternalActionsWML#.5Bstore_unit.5D|[store_unit]]], [[ConditionalActionsWML#.5Bwhile.5D|[while]]] and [[InternalActionsWML#.5Bclear_variable.5D|[clear_variable]]].<br />
* '''variable''': the name of the variable.<br />
* '''find_vacant''': whether the unit should be placed on the nearest vacant tile to its specified location. If this is set to 'no'(default), then any unit on the same tile as the unit being unstored will be destroyed. <br />
* '''check_passability''': (boolean yes|no, default yes): If yes, checks for terrain passability when placing the unit. This key has no effect if find_vacant=no (no check performed then). Before 1.9 this key is always "no".<br />
* '''text''': (translatable) floating text to display above the unit, such as a damage amount<br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. You may find it convenient to use the {COLOR_HARM} or {COLOR_HEAL} macro instead. (Use {COLOR_HARM} or {COLOR_HEAL} instead of the whole red,green,blue= line.)<br />
* '''advance''': (default=yes) if yes the unit is advanced if it has enough XP. When modifying XP make sure to do it from inside a [[EventWML#Multiplayer_safety|synchronized event]] or it may lead to OOS errors especially when several advancement paths exist. Note that advance and post advance events are called, so infinite loops can happen.<br />
* '''fire_event''': (boolean yes|no, default no) Whether any advance/post advance events shall be fired if an advancement takes place, no effect otherwise.<br />
* '''animate''': (boolean yes|no, default yes) Whether "levelout" and "levelin" (or fade to white and back) animations shall be played if an advancement takes place, no effect otherwise.<br />
* '''x''' ,'''y''': override unit location, "x,y=recall,recall" will put the unit on the unit's side's recall list.<br />
Units can be unstored with negative (or zero) hit points. This can be useful if modifying a unit in its last_breath event (as the unit's death is already the next step), but tends to look wrong in other cases. In particular, it is possible to have units with negative hit points in play. Such units are aberrations, subject to unusual behavior as the game compensates for them. (For example, such units are currently automatically hit&ndash;and killed&ndash;in combat.) The details of the unusual behavior are subject to change between stable releases without warning.<br />
<br />
=== [allow_recruit] ===<br />
Allows a side to recruit units it couldn't previously recruit.<br />
* '''type''': the types of units that the side can now recruit.<br />
* '''side''': (default=1) the number of the side that is being allowed to recruit the units. This can be a comma-separated list note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [allow_extra_recruit] ===<br />
Allows a leader to recruit units it couldn't previously recruit.<br />
These types add to the types the leader can recruit because of [side]recruit=.<br />
* '''extra_recruit''': the types of units that the unit can now recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [disallow_recruit] ===<br />
Prevents a side from recruiting units it could previously recruit.<br />
* '''type''': the types of units that the side can no longer recruit. {{DevFeature1.13|0}} If omitted, all recruits for matching sides will be disallowed.<br />
* '''side''': (default=1) the number of the side that may no longer recruit the units. This can be a comma-separated list note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [disallow_extra_recruit] ===<br />
Prevents a leader from recruiting units it could previously recruit.<br />
* '''extra_recruit''': the types of units that the side can no longer recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [set_recruit] ===<br />
Sets the units a side can recruit.<br />
* '''recruit''': the types of units that the side can now recruit.<br />
* '''side''': (default=1) the number of the side that is having its recruitment set. This can be a comma-separated list. note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [set_extra_recruit] === <br />
Sets the units a leader can recruit.<br />
* '''extra_recruit''': the types of units that the leader can now recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [modify_side] ===<br />
Modifies some details of a given side in the middle of a scenario. '''The following listed properties are the only properties that [modify_side] can affect!'''<br />
* '''side''': (default=1) the number of the side that is to be changed. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* '''income''': the income given at the begining of each turn.<br />
* '''recruit''': a list of unit types, replacing the side's current recruitment list.<br />
* '''team_name''': the team in which the side plays the scenario.<br />
* '''user_team_name''': a translatable string representing the team's description. This has no effect on alliances. Defaults to ''team_name''.<br />
* '''side_name''': {{DevFeature1.13|?}} a translatable string representing the side leader's description.<br />
* '''gold''': the amount of gold the side owns.<br />
* '''village_gold''': the income setting per village for the side.<br />
* '''controller''': the identifier string of the side's controller. Uses the same syntax of the ''controller'' key in the [[SideWML|[side]]] tag. warning: in multiplayer, changing the controller of a side might result in OOS during some events like, for example 'side_turn_end'; see [https://github.com/wesnoth/wesnoth/issues/2563 issue #2563].<br />
* '''fog''': a boolean string (yes/no) describing the status of Fog for the side.<br />
* '''shroud''': a boolean string describing the status of Shroud for the side.<br />
* '''hidden''': a boolean string specifying whether side is shown in status table.<br />
* '''color''': a team color range specification, name (e.g. "red", "blue"), or number (e.g. "1", "2") for this side. The default color range names, numbers, and definitions can be found in data/core/team_colors.cfg.<br />
* '''[ai]''': sets/changes AI parameters for the side. Only parameters that are specified in the tag are changed, this does not reset others to their default values. Uses the same syntax as described in [[AiWML]]. Note that [modify_side][ai] works for all simple AI parameters and some, but not all, of the composite ones. If in doubt, use [http://wiki.wesnoth.org/AiWML#Adding_and_Deleting_Aspects_with_the_.5Bmodify_ai.5D_Tag [modify_ai]] instead, which always works. {{DevFeature1.13|?}} If this contains an '''ai_algorithm''', the AI parameters will be reset to those of the indicated AI before adding any additional parameters included in the tag. In other words, this allows replacing the AI config rather than appending to it.<br />
* '''switch_ai''': replaces a side ai with a new AI from specified file(ignoring those AI parameters above). Path to file follows the usual WML convention.<br />
* '''reset_maps''': If set to "yes", then the shroud is spread to all hexes, covering the parts of the map that had already been explored by the side, including hexes currently seen. (Seen hexes will be cleared at the end of most events; they can also be manually cleared with {{tag|InterfaceActionsWML|redraw}}.) This is only effective if shroud is on, but this is evaluated after shroud= (and before shroud_data=).<br />
* '''reset_view''': If set to "yes", then the fog of war is spread to all hexes, covering the parts of the map that had already been seen this turn by the side, including hexes currently seen, excluding hexes affected by multi-turn {{tag|DirectActionsWML|lift_fog}}. (Seen hexes will be cleared at the end of most events; they can also be manually cleared with {{tag|InterfaceActionsWML|redraw}}.) This is only effective if fog is on, but this is evaluated after fog=.<br />
* '''share_maps''': change the share_maps side attribute. Be sure to use shroud=yes for that side and have it as an ally<br />
* '''share_view''': change the share_view side attribute. Be sure to use fog=yes for that side and have it as an ally<br />
* '''share_vision''': change both the above at the same time<br />
* '''shroud_data''': changes to the side's shroud, using the same format as when defining the [side].<br />
* '''suppress_end_turn_confirmation''': Boolean value controlling whether or not a player is asked for confirmation when skipping a turn.<br />
* '''scroll_to_leader''': Boolean value controlling whether or not the game view scrolls to the side leader at the start of their turn when present.<br />
* '''flag''': Flag animation for villages owned by this side (see [[SideWML|[side]]]).<br />
* '''flag_icon''': Flag icon used for this side in the status bar (see [[SideWML|[side]]]).<br />
* '''village_support''': The number of unit levels this side is able to support (does not pay upkeep on) per village it controls.<br />
* '''defeat_condition''' {{DevFeature1.13|0}}: When the side is considered defeated (see [[SideWML|[side]]]).<br />
<br />
=== [modify_turns] ===<br />
Modifies the turn limit in the middle of a scenario.<br />
* '''value''': the new turn limit.<br />
* '''add''': if used instead of ''value'', specifies the number of turns to add to the current limit (can be negative).<br />
* '''current''': changes the current turn number after applying turn limit modifications, if any. It is not possible to change the turn number to exceed the turn limit (1 <= current turns <= max turns).<br />
<br />
=== [allow_end_turn] ===<br />
Allows human players to end their turn through the user interface if they were previously affected by the '''[disallow_end_turn]''' action. This action doesn't take any arguments.<br />
<br />
=== [disallow_end_turn] ===<br />
Disallows human players to end their turn through the user interface. This action doesn't take any arguments.<br />
<br />
=== [capture_village] ===<br />
Changes the ownership of a village.<br />
* [[StandardLocationFilter]]: all village locations matching the filter are affected.<br />
* '''side''': the side that takes control of the village. This side needs to have a leader (canrecruit=yes). If the side key is not given, the village will become neutral (unless [filter_side] is present, in which case that side fiter decides, see below).<br />
* '''[filter_side]''' with [[StandardSideFilter]] tags and keys as arguments; if both this tag and inline side= are present it's an error. Otherwise, the first matching side gets ownership (or the village becomes neutral if none match).<br />
* '''fire_event''' (boolean yes|no, default: no): Whether any capture events shall be fired.<br />
<br />
=== [kill] ===<br />
Removes all units (including units in a recall list) that match the filter from the game.<br />
* [[StandardUnitFilter]]: Selection criterion; do not use a [filter] tag.<br />
* '''animate''' (default 'no'): if 'yes', displays the unit dying (fading away). {{DevFeature1.13|8}} If '''[secondary_unit]''' is given, also plays the victory animation of that unit.<br />
* '''fire_event''' (default 'no'): if 'yes', triggers any appropriate 'die' events (See [[EventWML]]). Note that events are only fired for killed units that have been on the map (as opposed to recall list).<br />
* '''[secondary_unit]''' with a [[StandardUnitFilter]] as argument. Do not use a [filter] tag. Has an effect only if fire_event=yes ({{DevFeature1.13|8}} or if it has a victory animation and animate=yes). The first on-map unit matching the filter becomes second_unit in any fired die and last breath events. If an on-map unit matches and if there are several units killed with a single [kill] tag, second_unit is this same unit for all of them. If no on-map unit matches or [secondary_unit] isn't present, the variable second_unit in each of the die and last breath events is always the same as the variable unit (the dying unit).<br />
* '''[primary_attack]''', '''[secondary_attack]''' {{DevFeature1.13|8}} The attacks to use for matching the animation. Useful for example on the wose, whose death animation depends on the damage type it was killed by.<br />
<br />
=== [move_unit] ===<br />
Moves a unit along a path on the map. The path can be specified exactly, or as a series of waypoints that the unit will pass through.<br />
* [[StandardUnitFilter]] as argument; do not use a [filter] tag. All units matching the filter are moved. If the target location is occupied, the nearest free location is chosen.<br />
* '''to_x''' (unsigned integer): The units are moved to this x coordinate. Can be a comma-separated list, in which case the unit follows this given path during the move.<br />
* '''to_y''' (unsigned integer): The units are moved to this y coordinate. Can be a comma-separated list.<br />
* '''dir''' (string): {{DevFeature1.15|0}} Performs a relative movement instead of an absolute movement. For example, dir=n,n,nw will move two spaces north and then one space to the northwest. This is used instead of '''to_x''' and '''to_y'''.<br />
* '''to_location''': {{DevFeature1.15|0}} Moves matching units to locations placed in the map editor with the "New Location" button. Can be a comma-separated list. This is used instead of '''to_x''' and '''to_y'''.<br />
* '''fire_event''' (optional, boolean yes|no, default no): Whether any according moveto events shall be fired. The target location ($x1, $y1 in the event) may not be the same location that the unit was tried to be moved to, if the original target location is occupied or impassable.<br />
* '''check_passability''' (boolean yes|no, default yes): Whether the terrain the unit is moved to should be checked for suiting the unit. (If it does not, a nearby suitable hex is chosen.)<br />
* '''force_scroll''': Whether to scroll the map or not even when [[InterfaceActionsWML#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to using [[InterfaceActionsWML#.5Bmove_unit_fake.5D|[move_unit_fake]]]'s default value.<br />
<br />
=== [modify_ai] ===<br />
Changes AI objects (aspects, goals, candidate actions or stages) for a specified side. See [[Modifying_AI_Components#The_.5Bmodify_ai.5D_Tag|Modifying AI Components]] for full description.<br />
<br />
* '''action''' (string): Takes values 'add', 'change', 'delete' or 'try_delete' to do just that for the AI object.<br />
* '''path''' (string): Describes which AI object is to be modified. <br />
* '''[facet]''', '''[goal]''', '''[candidate_action]''' or '''[stage]''': Details about the AI object to be modified.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [modify_unit] ===<br />
works similar to the MODIFY_UNIT macro.<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument. All units matching this filter are modified. Matches on recall list units too.<br />
* '''[object]''', '''[trait]''', {{DevFeature1.13|5}} '''[advancement]''' - The given modifications will be immediately applied to all units matching the filter.<br />
** '''delayed_variable_substitution''' {{DevFeature1.13|5}} (boolean yes|no, default no): If set to "yes", the wml block contained in this [object], [trait], or [advancement] is not variable-substituted at execution time of the event containing this [modify_unit]. You need this for any effect that uses variable substitution or when using [effect][filter] with a $this_unit. {{DevFeature1.13|9}} This is no longer needed when adding ABILITY_TELEPORT, ABILITY_LEADERSHIP or SPECIAL_BACKSTAB.<br />
* '''[effect]''' {{DevFeature1.13|6}} Applies the effect directly to the unit.<br />
* Accepts generally the syntax inside of wml unit variables created by [store_unit] which can be viewed in a savefile or by using the [[CommandMode|inspect command]]. Cannot remove things or add/alter unit animations. Subtags with the same name must be written in the correct order to match them with the tag they are supposed to modify. Note that keys will be processed in arbitrary order, which may cause problems if you use formulas that depend on other formulas. To work around this you may need to use the tag twice with the same filter.<br />
example usage (see also the test scenario):<br />
<syntaxhighlight lang='wml'><br />
[modify_unit]<br />
[filter]<br />
x,y=38,6<br />
[/filter]<br />
hitpoints=10<br />
{TRAIT_HEALTHY}<br />
[/modify_unit]<br />
</syntaxhighlight><br />
<br />
The unit which is currently modified is accessible via $this_unit, e.g. hitpoints = "$($this_unit.hitpoints / 2)" to set the hitpoints of all units to half of their particular maxima. This this_unit variable is independent from the this_unit variable available in the SUF used to determine which units to modify (first all matching units are gathered, and then all those are modified).<br />
<br />
Some some peorperties of the units are reset sometimes for exmapel when the unit advances or when [remove_object] is called. So it's usually better to change them with [object] ([object] inside [modify_unit]) than to change those properties directly via [modify_unit], this list of properties that are _not_ reset in [remove_object] and are thus safe to use directly in [modify_unit] is:<br />
* '''side'''<br />
* '''gender'''<br />
* '''name'''<br />
* '''canrecruit'''<br />
* '''unrenamable'''<br />
* '''extra_recruit'''<br />
* '''[variables]'''<br />
* '''facing'''<br />
* '''goto_x, goto_y'''<br />
* '''hitpoints'''<br />
* '''experience'''<br />
* '''moves'''<br />
* '''[status]''' (not sure on this one)<br />
* '''attacks_left'''<br />
* '''role'''<br />
<br />
=== [transform_unit] ===<br />
Transforms every unit on the map matching the filter to the given unit type. Keeps intact hit points, experience and status. If the unit is transformed to a non-living type (undead or mechanical), it will be also unpoisoned. Hit points will be changed if necessary to respect the transformed unit's maximum hit points.<br />
* [[StandardUnitFilter]]: do not use a [filter] tag.<br />
* '''transform_to''': the unit type in which all the units matching the filter will be transformed. If missing, the units will follow their normal advancement.<br />
<br />
=== [petrify] ===<br />
<br />
* [[StandardUnitFilter]] as an argument. Do not use a [filter] tag. All units matching this filter are petrified. Recall list units are included.<br />
<br />
=== [unpetrify] ===<br />
* [[StandardUnitFilter]] as an argument. Do not use a [filter] tag. All units matching this filter are unpetrified. Recall list units are included.<br />
<br />
=== [object] ===<br />
Gives some unit an object which modifies their stats in some way.<br />
* '''id''': (Optional) allows the item to be removed later. By default, an object with a defined ID can only be picked up once per scenario, even if it is removed later or first_time_only=no is set for the event. You can remove this restriction by setting take_only_once=no. For filtering objects, it might be simpler to use a custom key such as item_id. The id string can contain only letters, numbers and underscores.<br />
* '''take_only_once''': (default yes) {{DevFeature1.13|6}} If set to "no", the object's ID does not prevent it from being taken more than once.<br />
* '''delayed_variable_substitution''' (boolean yes|no, default no): If set to "yes", the wml block contained in this [object] is not variable-substituted at execution time of the event where this [object] is within. You need this for any effect that uses variable substitution or when using [effect][filter] with a $this_unit. {{DevFeature1.13|9}} This is no longer needed when adding ABILITY_TELEPORT, ABILITY_LEADERSHIP or SPECIAL_BACKSTAB.<br />
* '''[effect]''': one or more effect elements may be listed. See [[EffectWML]] for a description of [effect].<br />
* '''duration''':<br />
**if 'scenario', effects only last until the end of the level (note : 'level' is the scenario, so this doesn't mean it last until the unit levels-up).<br />
**if 'forever' or not set, effects never wear off.<br />
** if 'turn', effects only last until the start of the unit's next turn (when the unit refreshes movement and attacks). (Like other start-of-turn behavior, objects with a duration of "turn" won't expire before turn 2.)<br />
** {{DevFeature1.13|1}} if 'turn end' or 'turn_end', effects only last until the end of the unit's next turn (exactly like the slowed status).<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument. The first unit found that matches the filter will be given the object. Only on-map units are considered. If no unit matches or no [filter] is supplied, it is tried to apply the object to the unit at the $x1,$y1 location of the event where this [object] is in. The case of no unit being at that spot is handled in the same way as no unit matching a given filter ([else] commands executed, cannot_use_message displayed). Note that units on the recall list will not be checked. To add an [object] to a unit on the recall list you have to use '''[modify_unit][object]'''.<br />
* '''[then]''': a subtag that lets you execute actions if the filter conditions are met. The most common action that should be inside here is a '''[remove_item]''' tag, but you could probably put any tags that otherwise work in a [then] tag.<br />
* '''[else]''': a subtag that lets you execute actions if the filter conditions are *not* met.<br />
* '''silent''': whether or not messages should be suppressed. Default is "no". {{DevFeature1.13|2}} If no description is provided, this defaults to yes, but can still be overridden.<br />
* '''image''': the displayed image of the object.<br />
* '''name''': (translatable) displayed as a caption of the image.<br />
<br />
* '''description''': (translatable) displayed as a message of the image.<br />
* '''cannot_use_message''': (translatable) displayed instead of '''description''' if no unit passes the filter test.<br />
<br />
=== [remove_object] ===<br />
<br />
{{DevFeature1.13|6}}<br />
<br />
Removes an object from matching units.<br />
<br />
* [[StandardUnitFilter]]: All units matching the filter have matching objects removed. Use no [filter] tag.<br />
* '''object_id''': The id of the object to be removed.<br />
<br />
Note that some unit properties are not restored ideally, e.g. current unit's health reversion might not work as expected (max_hitpoints will though). {{DevFeature1.15|0}} This was fixed.<br />
<br />
Note that remove_object worked the following way: Step1) remove thos objects from the unit wml, Step2) Rebuild the unit to make the changes effective. Step2 implies that changes done for example via [modify_unit] (or via the [store_unit] + [set_variable] + [unstore_unit] technique) will be reset if those changes change a property that is a property of the unit type. See the note under [modify_unit] to get a list of properties that can safely be changes via [modify_unit]<br />
<br />
=== [remove_shroud] ===<br />
Removes some shroud from the map for a certain side (only relevant for sides that have shroud=yes).<br />
* '''side''': (default=1) the side for which to remove shroud. This can be a comma-separated list of sides. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* [[StandardLocationFilter]]: the range of tiles for which shroud should be removed<br />
<br />
=== [place_shroud] ===<br />
Places some shroud on the map for a certain side (only relevant for sides that have shroud=yes).<br />
* '''side''': (default=1) the side for which to place shroud. This can be a comma-separated list. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* [[StandardLocationFilter]]: the range of tiles on which shroud should be placed<br />
<br />
=== [lift_fog] ===<br />
Lifts the fog of war from parts of the map for a certain side (only relevant for sides that have fog=yes), allowing a player to witness what occurs there even if that player has no units within vision range.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] indicating which sides should be affected.<br />
* [[StandardLocationFilter]]: the tiles from which fog should be lifted.<br />
* '''multiturn''': ''yes/no, default:no''. The default (not multiturn) causes fog to be removed in the same way that normal vision works; the cleared tiles will remain cleared until fog is recalculated (which normally happens when a side ends its turn). When multiturn is set to "yes", the cleared tiles remain clear until {{tag||reset_fog}} cancels the clearing. This allows tiles to remain clear for multiple turns, or to be refogged before the end of the current turn (without also refogging all tiles). Multiturn lifted fog is not shared with allies (even when share_view=yes).<br />
<br />
=== [reset_fog] ===<br />
The primary use of this tag is to remove multiturn lifted fog (created by {{tag||lift_fog}}), which causes the fog to reset to what it would have been had WML not interfered. (That is, hexes that a side's units could not see at any point this turn will be re-fogged, while seen hexes remain defogged.)<br />
* '''[filter_side]''' with a [[StandardSideFilter]] indicating which sides should be affected.<br />
* [[StandardLocationFilter]]: the fog reset will be restricted to these tiles.<br />
* '''reset_view''': ''yes/no, default: no'' If set to "yes", then in addition to removing multiturn fog, the side's current view is canceled (independent of the SLF). This means that all hexes will become fogged for the side unless multiturn fog exists outside the tiles selected by the SLF. Normally, one would want the currently seen hexes to become clear of fog; this is done automatically at the end of many events, and it can be done manually with {{tag|InterfaceActionsWML|redraw}}.<br />
Omitting both the SSF and the SLF would cancel all earlier uses of [lift_fog].<br />
Additionally setting reset_view="yes" would cause the side's entire map to be fogged (unless an ally keeps hexes clear by sharing its view).<br />
<br />
=== [allow_undo] ===<br />
Normally when an event with a handler fires, the player's undo stack is cleared, preventing all actions performed so far from being undone. Including this tag in the event handler prevents the stack from being cleared for this reason, allowing the player to undo actions. (However, the stack might still be cleared for other reasons, such as fog being cleared or combat occurring.) In the common cases, this means '''[allow_undo]''' allows the current action to be undone even though an event was handled. There is a less common case, though &mdash; specifically when handling a menu item, where there is no current action &mdash; and in this case, '''[allow_undo]''' means merely that earlier actions can still be undone.<br />
* Using this tag in a menu item has an additional side effect in 1.11. Starting with version 1.11.1, executing a WML menu item normally counts as doing something as far as the "you have not started your turn yet" dialog is concerned. However, a menu item whose handler includes '''[allow_undo]''' will not count.<br />
<br />
The types of actions that can be undone are movement, recalling, and dismissing a unit from the recall list. If an action is undone, only the position (or existence) of the involved unit will be restored; any altered variables or changes to the game will remain changed after the action is undone. It is up to the scenario designer to avoid abusing this command.<br />
* Technically, if '''[allow_undo]''' is inside an '''[event]''' with ''first_time_only=yes'' (the default setting), and the user undoes the event, then the state of the game has changed in this way: the event will not fire a second time, even though the user undid the action the first time.<br />
* Although recalling can be undone, recruitment can not be undone; this seems to apply even when the recruit's traits are not randomly-generated (tested on 1.12.6 and 1.14.4+dev).<br />
<br />
If an '''[event]''' uses both '''[allow_undo]''' and [[InternalActionsWML#.5Bfire_event.5D|'''[fire_event]''']] then the '''[allow_undo]''' must be after the '''[fire_event]'''.<br />
<br />
Due to a bug in 1.12 (https://gna.org/bugs/?23323) '''[allow_undo]''' should not be used in events that use one of the following things because it might cause OOS: <br />
* [message] with [option]s<br />
* [get_global_variable]<br />
* wesnoth.synchronize_choice<br />
<br />
While in 1.13 using '''[allow_undo]''' together with those things won't give you a guaranteed OOS, there are some non-obvious situations where it will, for example assume the following event:<br />
<br />
[event]<br />
name="moveto"<br />
[message]<br />
message = "message"<br />
[option]<br />
label = "option 1"<br />
[command]<br />
[/command]<br />
[/option]<br />
[option]<br />
label = "option 2"<br />
[command]<br />
[/command]<br />
[/option]<br />
[/message]<br />
[allow_undo]<br />
[/allow_undo]<br />
[/event]<br />
<br />
It will cause OOS when the message is undone: since the event is already executed (erased) on one client only , the clients will disagree about how many choices happen during the next moveto action.<br />
<br />
=== [on_undo] ===<br />
{{DevFeature1.13|2}}<br />
Contains commands to execute when the player undoes the action which triggered the parent event.<br />
*'''delayed_variable_substitution''' {{DevFeature1.13|5}}: ''yes/no, default no (always no before 1.13.5)'' As in [[EventWML]], specifies whether to perform variable substitution when the parent event is run, or when the contents are run. If delayed substitution is used, [[SyntaxWML#Automatically_Stored_Variables|automatically stored variables]] from the parent event context are available, but may occasionally have unexpected values. (In particular, $unit.x and $unit.y may not have the expected value when undoing a move event, though $x1 and $y1 should be correct.)<br />
<br />
Note:<br />
It is not clear where whether the actionwml in [on_undo] in exceuted before or after the action is undone. Also, specially for enter/leave_hex events the units position when executing the [on_undo] code is usually different than when executing the original event. The reccomended way to wokr around these issues is to refer to the unit by is instead of position and store all other needed information variables as 'upvalues'. You can also move the actual undo code to an external event. For example<br />
[event]<br />
name="undo_blah"<br />
first_time_only=no<br />
[store_unit]<br />
id="$moved_unit_id"<br />
[/store_unit]<br />
... do undo stuff stuff<br />
[/event]<br />
<br />
...<br />
... in some other event<br />
[on_undo]<br />
# store ''upvalues<br />
{VARIABLE moved_unit_id $unit.id}<br />
# call actual undo handler<br />
[fire_event]<br />
name = "undo_blah"<br />
[/fire_event]<br />
[on_undo]<br />
<br />
=== [on_redo] ===<br />
{{DevFeature1.13|2}}<br />
Same as [on_undo], except executes the commands on redo. Note that the parent event is not triggered again on a redo.<br />
<br />
{{DevFeature1.13|8}} [on_redo] is deprecated and has no effect anymore.<br />
<br />
Note that [on_redo] is not guaranteed to be called when redoing an action, the engine might also decide to just fire the original events again.<br />
<br />
=== [cancel_action] ===<br />
Although Wesnoth 1.12 does not have this tag, it is the default behavior of {{tag|EventWML|enter_hex}}/{{tag|EventWML|leave_hex}} events in that version.<br />
<br />
{{DevFeature1.13|9}} In this version, [cancel_action] is recognised, but has no effect (a bug).<br />
<br />
{{DevFeature1.13|11}}<br />
In an {{tag|EventWML|enter_hex}}/{{tag|EventWML|leave_hex}} event, interrupt the movement, leaving the unit where it is. This is intended to be used with an event that gives the player new information, to let the player choose whether to change their plans. For example, if the player has commanded a unit to move from (1,1) to (3,3) and attack a unit on (4,4); then a [cancel_action] inside an [enter_hex] event on (2,2) would make the unit stop on (2,2). A [cancel_action] inside an [enter_hex] on (3,3) would let the player choose whether to attack.<br />
<br />
=== [heal_unit] ===<br />
Heal a unit. The variable '''$heal_amount''' will be set to the exact number of points healed (i.e can be less than the parameter '''amount''' if the unit is fully healed). $heal_amount contains only the number of hitpoints the first unit that was found got healed.<br />
* '''[filter]''': [[StandardUnitFilter]] All matching on-map units are healed. If no filter is supplied, it is tried to take the unit at $x1, $y1.<br />
* '''[filter_second]''': [[StandardUnitFilter]] all the units matching the filter ''and'' having the ''heals'' ability will have their animation played (if ''animate'' is set to yes) for each of the units healed.<br />
* '''amount''': (integer, default full) the maximum points the unit(s) will be healed. Can't set below 1 or above max_hitpoints. If "full", sets hitpoints to max_hitpoints. Before 1.9 the default is 0.<br />
* '''animate''': a boolean which indicate if the healing animations must be played. (default no)<br />
* '''moves''': (integer, default 0) The maximum current movement points the units will be "healed". Can't set below 0 or above max_moves. If "full", sets moves to max_moves.<br />
* '''restore_attacks''': (boolean, default no) Whether the units' attacks_left should be reset to their max_attacks (usually 1).<br />
* '''restore_statuses''': (boolean, default yes) Whether standard statuses should be reset to "no". This affects poisoned, slowed, petrified and unhealable. Before 1.9 this is always "no".<br />
<br />
=== [harm_unit] ===<br />
Harms every unit matching the filter, for the specific damage amount.<br />
* '''[filter]''': [[StandardUnitFilter]] all matching units will be harmed (required).<br />
* '''[filter_second]''': [[StandardUnitFilter]] if present, the first matching unit will attack all the units matching the filter above.<br />
* '''amount''': the amount of damage that will be done (required).<br />
* '''alignment''': (default neutral) applies an alignment to the damage, this means that if alignment=chaotic, the damage will be increased at night and reduced at day.<br />
* '''damage_type''': if present, amount will be altered by unit resistance to the damage type specified.<br />
* '''kill''': (default yes) if yes, when a harmed unit goes to or below 0 HP, it is killed; if no its HP are set to 1.<br />
* '''fire_event''': (default no) if yes, when a unit is killed by harming, the corresponding events are fired. If yes, also the corresponding advance and post advance events are fired.<br />
* '''animate''': (default no) if yes, scrolls to each unit before harming it and plays its defense (or attack, if it's the harmer) and death animations. Special values supported, other than the usual yes and no, are "attacker", that means only the harmer will be animated, and "defender", that means only the harmed units will be animated. If the supplied value is yes, attacker or defender also advancement animations are played.<br />
* '''[primary_attack], [secondary_attack]''': these set the weapon against which the harmed units will defend, and that the harming unit will use to attack, respectively (notice this is the opposite of '''[filter]''' and '''[filter_second]''' above). This allows for playing specific defense and attack animations. Both tags are expected to contain a [[FilterWML#Filtering_Weapons|Standard Weapon Filter]].<br />
* '''delay''': if animate=yes, sets the delay (in milliseconds, default 500) between each unit harming.<br />
* '''variable''': if present, the damage caused to the unit, altered by resistances, will be stored in a WML array with the given name, under the "harm_amount" key.<br />
* '''poisoned, slowed, petrified, unhealable''': (default no) if yes, every harmed unit that doesn't already have such status will have it set.<br />
* '''experience''': if yes, and there is a harmer, experience will be attributed like in regular combat.<br />
* '''resistance_multiplier''': the harmed unit's resistance is multiplied by the supplied value; this means that a value lower than 1 increases it, and a value greater than 1 decreases it. Default value is 1, that means no modification.<br />
<br />
=== [time_area] ===<br />
How a day should progress in a given area. Everywhere not specified in a [time_area] tag is affected by the [time] tags in the [scenario] tag.<br />
* [[StandardLocationFilter]]: the locations to affect. ''note: only for [event][time_area]s - at scenario toplevel [time_area] does not support [[StandardLocationFilter]], only location ranges''<br />
* '''[time]''': one or more tags describing the new schedule, see [[TimeWML]].<br />
* '''id''': an unique identifier assigned to a time_area. Optional, unless you want to remove the time_area later. Can be a comma-separated list when removing time_areas, see below.<br />
* '''remove''': (boolean) yes/no value. Indicates whether the specified time_area should be removed. Requires an identifier. If no identifier is used, however, all time_areas are removed.<br />
* '''current_time''': The time slot number (starting with zero) active at the creation of the area.<br />
<br />
''Example:'' (caves in parts of a map)<br />
[time_area]<br />
x=1-2,4-5<br />
y=1-2,1-2<br />
{UNDERGROUND}<br />
[/time_area]<br />
<br />
=== [remove_time_area] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This is a syntactic shortcut for [time_area] remove=.<br />
* '''id''': Comma-separated list of time area ids to remove.<br />
<br />
=== [end_turn] ===<br />
End the current side's turn. The current event is finished before the turn is ended. Also, if the current event (where the tag appears) has been fired by another event, that event (and the complete stack of other possible parent events) is ended before [end_turn] comes into affect. Also, events following the event stack that fired [end_turn] are not omitted (e.g. [end_turn] is used by a side turn event and a turn refresh event does something afterwards).<br />
<br />
=== [replace_map] ===<br />
<br />
Replaces the entire map.<br />
* '''map''': Content of a wesnoth map file. example:<br />
map="{campaigns/Heir_To_The_Throne/maps/01_The_Elves_Besieged.map}"<br />
* '''map_file''': {{DevFeature1.13|?}} Path to a Wesnoth map file; can be used instead of '''map'''. The file will be loaded when the tag is executed, rather than being embedded wholesale in the preprocessed WML.<br />
* '''expand''': if 'yes', allows the map size to increase. The expansion direction is currently always bottom-right.<br />
* '''shrink''': if 'yes', allows the map size to decrease. If the map size is reduced, any units that would no longer be on the map due to its coordinates no longer existing will be put into the recall list.<br />
Note: When a hex changes from a village terrain to a non-village terrain, and a team owned that village it loses that village. When a hex changes from a non-village terrain to a village terrain and there is a unit on that hex it does not automatically capture the village. The reason for not capturing villages it that there are too many choices to make; should a unit lose its movement points, should capture events be fired. It is easier to do this as wanted by the author in WML.<br />
<br />
=== [replace_schedule] ===<br />
Replace the time of day schedule of the entire scenario.<br />
* [[TimeWML]]: the new schedule.<br />
* '''current_time''': The time slot number (starting with zero) active at schedule replacement.<br />
<br />
=== [tunnel] ===<br />
<br />
Create a tunnel between some locations, later usable by units to move from source hex to target hex (using the movement cost of unit on the target terrain).<br />
<br />
'''Behavior Change as of Wesnoth 1.13.6:''' Vision is now possible (and enabled by default) through tunnels and allied units on the exit hex do not block a tunnel by default any more. This is done in order for moves through tunnels to be consistent with other moves. The previous behavior can still be accomplished by using the new optional keys listed below.<br />
<br />
* '''[filter]''': (required) [[StandardUnitFilter]] the units which can use the tunnel. Leave empty for "all units".<br />
* '''[source]''': (required) [[StandardLocationFilter]] the source hex(es).<br />
* '''[target]''': (required) [[StandardLocationFilter]] the target hex(es).<br />
* '''id''': (optional) identifier for the tunnel, to allow removing.<br />
* '''remove''': (boolean, default: no) If yes, removes all defined tunnels with the same ID (then only id= is necessary).<br />
* '''bidirectional''': (boolean, default: yes) If yes, creates also a tunnel in the other direction. <br />
* '''always_visible''': (boolean, default: no) If yes, the possible movement of enemies under fog can be seen.<br />
* '''allow_vision''': (boolean, default: yes) {{DevFeature1.13|6}} If no, vision through a tunnel is not possible. Note that in that case the tunnel cannot be used if the tunnel exit is under shroud (which previously was ''always'' the case).<br />
* '''pass_allied_units''': (boolean, default: yes) {{DevFeature1.13|6}} If no, allied (including own) units on the exit hex block a tunnel.<br />
<br />
(Note: The tunnel tag can also be used inside the [[AbilitiesWML|[teleport]]] ability, without remove= and id=).<br />
<br />
=== [do_command] ===<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Executes a command, specified using the same syntax as a [command] tag in [[ReplayWML]]. Not all [command]'s are valid: only these are accepted<br />
<br />
* [attack]<br />
* [move]<br />
* [recruit]<br />
* [recall]<br />
* [disband]<br />
* [fire_event]<br />
* [lua_ai] {{DevFeature1.13|12}} This has been removed and is replaced with [custom_command]<br />
<br />
The tags corresponding to player actions generally use the same codepath as if a player had ordered it. That means for example that only moves that player would be allowed to do are possible, and movement is interrupted when sighting enemy unit.<br />
<br />
One purpose of this tag is to allow scripting of noninteractive scenarios -- without a tag like this, this might require elaborate mechanisms to coerce ais in order to test these code paths.<br />
<br />
This command should always be replay safe.<br />
<br />
=== [put_to_recall_list] ===<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Puts a unit to the recall list of its side.<br />
* '''[[StandardUnitFilter]]''': the unit(s) to get put to the recall list.<br />
* '''heal''': (default=no) Whether the unit should be refreshed, similar to the unit moving to the recall list at the end of a scenario.<br />
<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for direct actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{MOVE_UNIT}''': Moves a unit to another location in the map and the player sees the movement (unlike [teleport])<br />
* '''{FULL_HEAL}''': Brings a unit to full HP<br />
* '''{LOYAL_UNIT}''': Create a loyal unit<br />
* '''{MODIFY_TERRAIN_MASK}''': Modify an area of terrain<br />
<br />
== See Also ==<br />
<br />
* [[InternalActionsWML]]<br />
* [[InterfaceActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=DirectActionsWML&diff=60916DirectActionsWML2019-04-13T10:18:28Z<p>Gfgtdf: /* [modify_unit] */</p>
<hr />
<div>{{WML Tags}}<br />
== Direct actions ==<br />
<br />
Direct actions are actions that have a direct effect on gameplay. They can be used inside of [[EventWML|events]].<br />
<br />
The following tags are actions:<br />
<br />
=== [endlevel] ===<br />
Ends the scenario.<br />
* '''result''': before the scenario is over, all events with ''name=result'' are triggered. If ''result=victory'', the player progresses to the next level (i.e., the next scenario in single player); if ''result=defeat'', the game returns to the main menu. <br />
<br />
When the result is "victory" the following keys can be used:<br />
* '''bonus''': whether the player should get bonus gold (maximum possible gold that could have been earned by waiting the level out). The default is bonus=yes. {{DevFeature1.13|2}} Alternatively, a number, defining the bonus multiple (1.0 meaning full).<br />
* '''carryover_report''': whether the player should receive a summary of the scenario outcome, the default is carryover_report=yes.<br />
* '''save''': whether a start-of-scenario save should be created for the next scenario, the default is save=yes. Do not confuse this with saving of replays for the current scenario.<br />
* '''replay_save''': whether a replay save for the current scenario is allowed, the default is replay_save=yes. If yes, the player's settings in preferences will be used to determine if a replay is saved. If no, will override and not save a replay.<br />
* '''linger_mode''': If ...=yes, the screen is greyed out and there's the possibility to save before advancing to the next scenario, the default is linger_mode=yes.<br />
* '''reveal_map''': (Multiplayer only) (Default is 'yes') If 'no', shroud doesn't disappear when game ended.<br />
* '''next_scenario''': (default specified in '''[scenario]''' tag) the ID of the next scenario that should be played. All units that side 1 controls at this point become available for recall in ''next_scenario''.<br />
* '''carryover_percentage''': by default 80% of the gold is carried over to the next scenario, with this key the amount can be changed.<br />
* '''carryover_add''': if yes the gold will be added to the starting gold the next scenario, if no the next scenario will start with the amount of the current scenario (after taxes) or the minimum in the next scenario. Default is no.<br />
* '''music''': (default specified in '''[scenario]''' or '''[game_config]''' tags) a comma-separated list of music tracks from which one will be chosen and played once after any events related to the end of level result are executed; by default, victory_music is used on victory, and defeat_music on defeat.<br />
* '''end_credits''': Whether to display the credits screen at the end of a single-player campaign. Defaults to ''yes''. Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* '''end_text''': (translatable) Text that is shown centered in a black screen at the end of a campaign. Defaults to "The End". Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* '''end_text_duration''': Delay, in milliseconds, before displaying the game credits at the end of a campaign. In other words, for how much time '''end_text''' is displayed on screen. Defaults to 3500. Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* <strike>'''[next_scenario_settings]''': Any tags or attribute children of this optional argument to [endlevel] are merged into the scenario/multiplayer tag of the *next* scenario. This allows you to e.g. reconfigure the [side] tags or settings, just before load. </strike> This feature was removed in 1.11.17, it might be redesigned and reintroduced.<br />
* <strike>'''[next_scenario_append]''': Any tags of this optional argument are appended at high level to the next scenario. This is most appropriate for [event] tags, although you may find other uses. Example test scenario for these features: https://gna.org/support/download.php?file_id=20119 </strike> This feature was removed in 1.11.17, it might be redesigned and reintroduced.<br />
* '''[result]''' {{DevFeature1.13|0}} Allows specification of a side specific result, this is for competitive multiplayer scenarios/campaigns where it might happen that one player wins but another player loses. The following attributes are accepted and have the same effect as in '''[endlevel]''':<br />
** '''result'''<br />
** '''bonus'''<br />
** '''carryover_percentage'''<br />
** '''carryover_add'''<br />
<br />
And there is also<br />
** '''side''' The number of the side for which these results should apply.<br />
<br />
=== [unit] ===<br />
Creates a unit (either on the map, on a recall list, or into a variable for later use.) For syntax see [[SingleUnitWML]].<br />
* {{Short Note:Predefined Macro|GENERIC_UNIT}}<br />
<br />
=== [recall] ===<br />
Recalls a unit taking into account any [http://wiki.wesnoth.org/SingleUnitWML filter_recall] of the leader. The unit is recalled free of charge, and is placed near its leader, e.g., if multiple leaders are present, near the first found which would be able to normally recall it.<br />
<br />
If neither a valid map location is provided nor a leader on the map would be able to recall it, the tag is ignored.<br />
<br />
* [[StandardUnitFilter]]: the first matching unit will be recalled. If no units match this tag is ignored. Do not use a [filter] tag. If a comma separated list is given, every unit currently considered for recall is checked against all the types (not each single one of the types against all units).<br />
* '''x,y''': the unit is placed here instead of next to the leader.<br />
* '''show''': yes/no, default yes: whether the unit is animated (faded in) or instantly displayed<br />
* '''fire_event''': boolean yes|no (default no); whether any according prerecall or recall events shall be fired.<br />
* '''check_passability''': (boolean yes|no, default yes): If yes, checks for terrain passability when placing the unit (a nearby passable hex is chosen).<br />
* '''[secondary_unit]''': {{DevFeature1.13|?}} If present and show=yes, a matching unit will be chosen and their recruiting animation played.<br />
<br />
=== [teleport] ===<br />
Teleports a unit on map. {{Short Note:Predefined Macro|TELEPORT_UNIT}}<br />
* '''[filter]''': [[StandardUnitFilter]] the first unit matching this filter will be teleported.<br />
* '''x,y''': the hex to teleport to. If that hex is occupied, the closest unoccupied hex will be used instead.<br />
* '''clear_shroud''': should shroud be cleared on arrival<br />
* '''animate''': should a teleport animation be played (if the unit doesn't have a teleport animation, it will fade out/fade in)<br />
* '''check_passability''': (boolean yes|no, default yes): normally, units will not be teleported into terrain that is impassable for them. Setting this attribute to "no" permits it.<br />
<br />
(Note: There is also a ability named teleport, see [[AbilitiesWML]].)<br />
<br />
=== [terrain_mask] ===<br />
Changes the terrain on the map. See [[TerrainMaskWML]].<br />
<br />
=== [terrain] ===<br />
Changes the terrain on the map.<br />
* '''terrain''': the character of the terrain to use. See [[TerrainCodesWML]] to see what letter a type of terrain uses.<br />
* [[StandardLocationFilter]]. This [[StandardLocationFilter]]'s terrain= key is used for the new terrain, filtering by terrain can be done with a nested [[StandardLocationFilter]]: [and]terrain=terrain_string_to_be_filtered_for.<br />
* '''layer''': (overlay|base|both, default=both) only change the specified layer.<br />
* '''replace_if_failed''': (default=no) When replacing just one layer failed, try to replace the whole terrain. If '''terrain''' is an overlay only terrain, use the default_base as base layer. If the terrain has no default base, do nothing.<br />
<br />
If you want to remove the overlays from a terrain and leave only the base, use:<br />
layer=overlay<br />
terrain="^"<br />
<br />
<b>Note:</b> When a hex changes from a village terrain to a non-village terrain, and a team owned that village it loses that village. When a hex changes from a non-village terrain to a village terrain and there is a unit on that hex it does not automatically capture the village. The reason for not capturing villages it that there are too many choices to make; should a unit lose its movement points, should capture events be fired. It is easier to do this as wanted by the author in WML.<br />
<br />
=== [gold] ===<br />
Gives sides gold.<br />
* '''amount''': the amount of gold to give.<br />
* '''side''': (default=1) the number of the side to give the gold to. Can be a comma-separated list of sides. note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [unstore_unit] ===<br />
Creates a unit from a game variable, and activates it on the playing field. This must be a specific variable describing a unit, and may not be an array -- to unstore an entire array, iterate over it. The variable is not cleared. See also [[InternalActionsWML#.5Bstore_unit.5D|[store_unit]]], [[ConditionalActionsWML#.5Bwhile.5D|[while]]] and [[InternalActionsWML#.5Bclear_variable.5D|[clear_variable]]].<br />
* '''variable''': the name of the variable.<br />
* '''find_vacant''': whether the unit should be placed on the nearest vacant tile to its specified location. If this is set to 'no'(default), then any unit on the same tile as the unit being unstored will be destroyed. <br />
* '''check_passability''': (boolean yes|no, default yes): If yes, checks for terrain passability when placing the unit. This key has no effect if find_vacant=no (no check performed then). Before 1.9 this key is always "no".<br />
* '''text''': (translatable) floating text to display above the unit, such as a damage amount<br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. You may find it convenient to use the {COLOR_HARM} or {COLOR_HEAL} macro instead. (Use {COLOR_HARM} or {COLOR_HEAL} instead of the whole red,green,blue= line.)<br />
* '''advance''': (default=yes) if yes the unit is advanced if it has enough XP. When modifying XP make sure to do it from inside a [[EventWML#Multiplayer_safety|synchronized event]] or it may lead to OOS errors especially when several advancement paths exist. Note that advance and post advance events are called, so infinite loops can happen.<br />
* '''fire_event''': (boolean yes|no, default no) Whether any advance/post advance events shall be fired if an advancement takes place, no effect otherwise.<br />
* '''animate''': (boolean yes|no, default yes) Whether "levelout" and "levelin" (or fade to white and back) animations shall be played if an advancement takes place, no effect otherwise.<br />
* '''x''' ,'''y''': override unit location, "x,y=recall,recall" will put the unit on the unit's side's recall list.<br />
Units can be unstored with negative (or zero) hit points. This can be useful if modifying a unit in its last_breath event (as the unit's death is already the next step), but tends to look wrong in other cases. In particular, it is possible to have units with negative hit points in play. Such units are aberrations, subject to unusual behavior as the game compensates for them. (For example, such units are currently automatically hit&ndash;and killed&ndash;in combat.) The details of the unusual behavior are subject to change between stable releases without warning.<br />
<br />
=== [allow_recruit] ===<br />
Allows a side to recruit units it couldn't previously recruit.<br />
* '''type''': the types of units that the side can now recruit.<br />
* '''side''': (default=1) the number of the side that is being allowed to recruit the units. This can be a comma-separated list note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [allow_extra_recruit] ===<br />
Allows a leader to recruit units it couldn't previously recruit.<br />
These types add to the types the leader can recruit because of [side]recruit=.<br />
* '''extra_recruit''': the types of units that the unit can now recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [disallow_recruit] ===<br />
Prevents a side from recruiting units it could previously recruit.<br />
* '''type''': the types of units that the side can no longer recruit. {{DevFeature1.13|0}} If omitted, all recruits for matching sides will be disallowed.<br />
* '''side''': (default=1) the number of the side that may no longer recruit the units. This can be a comma-separated list note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [disallow_extra_recruit] ===<br />
Prevents a leader from recruiting units it could previously recruit.<br />
* '''extra_recruit''': the types of units that the side can no longer recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [set_recruit] ===<br />
Sets the units a side can recruit.<br />
* '''recruit''': the types of units that the side can now recruit.<br />
* '''side''': (default=1) the number of the side that is having its recruitment set. This can be a comma-separated list. note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [set_extra_recruit] === <br />
Sets the units a leader can recruit.<br />
* '''extra_recruit''': the types of units that the leader can now recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [modify_side] ===<br />
Modifies some details of a given side in the middle of a scenario. '''The following listed properties are the only properties that [modify_side] can affect!'''<br />
* '''side''': (default=1) the number of the side that is to be changed. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* '''income''': the income given at the begining of each turn.<br />
* '''recruit''': a list of unit types, replacing the side's current recruitment list.<br />
* '''team_name''': the team in which the side plays the scenario.<br />
* '''user_team_name''': a translatable string representing the team's description. This has no effect on alliances. Defaults to ''team_name''.<br />
* '''side_name''': {{DevFeature1.13|?}} a translatable string representing the side leader's description.<br />
* '''gold''': the amount of gold the side owns.<br />
* '''village_gold''': the income setting per village for the side.<br />
* '''controller''': the identifier string of the side's controller. Uses the same syntax of the ''controller'' key in the [[SideWML|[side]]] tag. warning: in multiplayer, changing the controller of a side might result in OOS during some events like, for example 'side_turn_end'; see [https://github.com/wesnoth/wesnoth/issues/2563 issue #2563].<br />
* '''fog''': a boolean string (yes/no) describing the status of Fog for the side.<br />
* '''shroud''': a boolean string describing the status of Shroud for the side.<br />
* '''hidden''': a boolean string specifying whether side is shown in status table.<br />
* '''color''': a team color range specification, name (e.g. "red", "blue"), or number (e.g. "1", "2") for this side. The default color range names, numbers, and definitions can be found in data/core/team_colors.cfg.<br />
* '''[ai]''': sets/changes AI parameters for the side. Only parameters that are specified in the tag are changed, this does not reset others to their default values. Uses the same syntax as described in [[AiWML]]. Note that [modify_side][ai] works for all simple AI parameters and some, but not all, of the composite ones. If in doubt, use [http://wiki.wesnoth.org/AiWML#Adding_and_Deleting_Aspects_with_the_.5Bmodify_ai.5D_Tag [modify_ai]] instead, which always works. {{DevFeature1.13|?}} If this contains an '''ai_algorithm''', the AI parameters will be reset to those of the indicated AI before adding any additional parameters included in the tag. In other words, this allows replacing the AI config rather than appending to it.<br />
* '''switch_ai''': replaces a side ai with a new AI from specified file(ignoring those AI parameters above). Path to file follows the usual WML convention.<br />
* '''reset_maps''': If set to "yes", then the shroud is spread to all hexes, covering the parts of the map that had already been explored by the side, including hexes currently seen. (Seen hexes will be cleared at the end of most events; they can also be manually cleared with {{tag|InterfaceActionsWML|redraw}}.) This is only effective if shroud is on, but this is evaluated after shroud= (and before shroud_data=).<br />
* '''reset_view''': If set to "yes", then the fog of war is spread to all hexes, covering the parts of the map that had already been seen this turn by the side, including hexes currently seen, excluding hexes affected by multi-turn {{tag|DirectActionsWML|lift_fog}}. (Seen hexes will be cleared at the end of most events; they can also be manually cleared with {{tag|InterfaceActionsWML|redraw}}.) This is only effective if fog is on, but this is evaluated after fog=.<br />
* '''share_maps''': change the share_maps side attribute. Be sure to use shroud=yes for that side and have it as an ally<br />
* '''share_view''': change the share_view side attribute. Be sure to use fog=yes for that side and have it as an ally<br />
* '''share_vision''': change both the above at the same time<br />
* '''shroud_data''': changes to the side's shroud, using the same format as when defining the [side].<br />
* '''suppress_end_turn_confirmation''': Boolean value controlling whether or not a player is asked for confirmation when skipping a turn.<br />
* '''scroll_to_leader''': Boolean value controlling whether or not the game view scrolls to the side leader at the start of their turn when present.<br />
* '''flag''': Flag animation for villages owned by this side (see [[SideWML|[side]]]).<br />
* '''flag_icon''': Flag icon used for this side in the status bar (see [[SideWML|[side]]]).<br />
* '''village_support''': The number of unit levels this side is able to support (does not pay upkeep on) per village it controls.<br />
* '''defeat_condition''' {{DevFeature1.13|0}}: When the side is considered defeated (see [[SideWML|[side]]]).<br />
<br />
=== [modify_turns] ===<br />
Modifies the turn limit in the middle of a scenario.<br />
* '''value''': the new turn limit.<br />
* '''add''': if used instead of ''value'', specifies the number of turns to add to the current limit (can be negative).<br />
* '''current''': changes the current turn number after applying turn limit modifications, if any. It is not possible to change the turn number to exceed the turn limit (1 <= current turns <= max turns).<br />
<br />
=== [allow_end_turn] ===<br />
Allows human players to end their turn through the user interface if they were previously affected by the '''[disallow_end_turn]''' action. This action doesn't take any arguments.<br />
<br />
=== [disallow_end_turn] ===<br />
Disallows human players to end their turn through the user interface. This action doesn't take any arguments.<br />
<br />
=== [capture_village] ===<br />
Changes the ownership of a village.<br />
* [[StandardLocationFilter]]: all village locations matching the filter are affected.<br />
* '''side''': the side that takes control of the village. This side needs to have a leader (canrecruit=yes). If the side key is not given, the village will become neutral (unless [filter_side] is present, in which case that side fiter decides, see below).<br />
* '''[filter_side]''' with [[StandardSideFilter]] tags and keys as arguments; if both this tag and inline side= are present it's an error. Otherwise, the first matching side gets ownership (or the village becomes neutral if none match).<br />
* '''fire_event''' (boolean yes|no, default: no): Whether any capture events shall be fired.<br />
<br />
=== [kill] ===<br />
Removes all units (including units in a recall list) that match the filter from the game.<br />
* [[StandardUnitFilter]]: Selection criterion; do not use a [filter] tag.<br />
* '''animate''' (default 'no'): if 'yes', displays the unit dying (fading away). {{DevFeature1.13|8}} If '''[secondary_unit]''' is given, also plays the victory animation of that unit.<br />
* '''fire_event''' (default 'no'): if 'yes', triggers any appropriate 'die' events (See [[EventWML]]). Note that events are only fired for killed units that have been on the map (as opposed to recall list).<br />
* '''[secondary_unit]''' with a [[StandardUnitFilter]] as argument. Do not use a [filter] tag. Has an effect only if fire_event=yes ({{DevFeature1.13|8}} or if it has a victory animation and animate=yes). The first on-map unit matching the filter becomes second_unit in any fired die and last breath events. If an on-map unit matches and if there are several units killed with a single [kill] tag, second_unit is this same unit for all of them. If no on-map unit matches or [secondary_unit] isn't present, the variable second_unit in each of the die and last breath events is always the same as the variable unit (the dying unit).<br />
* '''[primary_attack]''', '''[secondary_attack]''' {{DevFeature1.13|8}} The attacks to use for matching the animation. Useful for example on the wose, whose death animation depends on the damage type it was killed by.<br />
<br />
=== [move_unit] ===<br />
Moves a unit along a path on the map. The path can be specified exactly, or as a series of waypoints that the unit will pass through.<br />
* [[StandardUnitFilter]] as argument; do not use a [filter] tag. All units matching the filter are moved. If the target location is occupied, the nearest free location is chosen.<br />
* '''to_x''' (unsigned integer): The units are moved to this x coordinate. Can be a comma-separated list, in which case the unit follows this given path during the move.<br />
* '''to_y''' (unsigned integer): The units are moved to this y coordinate. Can be a comma-separated list.<br />
* '''dir''' (string): {{DevFeature1.15|0}} Performs a relative movement instead of an absolute movement. For example, dir=n,n,nw will move two spaces north and then one space to the northwest. This is used instead of '''to_x''' and '''to_y'''.<br />
* '''to_location''': {{DevFeature1.15|0}} Moves matching units to locations placed in the map editor with the "New Location" button. Can be a comma-separated list. This is used instead of '''to_x''' and '''to_y'''.<br />
* '''fire_event''' (optional, boolean yes|no, default no): Whether any according moveto events shall be fired. The target location ($x1, $y1 in the event) may not be the same location that the unit was tried to be moved to, if the original target location is occupied or impassable.<br />
* '''check_passability''' (boolean yes|no, default yes): Whether the terrain the unit is moved to should be checked for suiting the unit. (If it does not, a nearby suitable hex is chosen.)<br />
* '''force_scroll''': Whether to scroll the map or not even when [[InterfaceActionsWML#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to using [[InterfaceActionsWML#.5Bmove_unit_fake.5D|[move_unit_fake]]]'s default value.<br />
<br />
=== [modify_ai] ===<br />
Changes AI objects (aspects, goals, candidate actions or stages) for a specified side. See [[Modifying_AI_Components#The_.5Bmodify_ai.5D_Tag|Modifying AI Components]] for full description.<br />
<br />
* '''action''' (string): Takes values 'add', 'change', 'delete' or 'try_delete' to do just that for the AI object.<br />
* '''path''' (string): Describes which AI object is to be modified. <br />
* '''[facet]''', '''[goal]''', '''[candidate_action]''' or '''[stage]''': Details about the AI object to be modified.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [modify_unit] ===<br />
works similar to the MODIFY_UNIT macro.<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument. All units matching this filter are modified. Matches on recall list units too.<br />
* '''[object]''', '''[trait]''', {{DevFeature1.13|5}} '''[advancement]''' - The given modifications will be immediately applied to all units matching the filter.<br />
** '''delayed_variable_substitution''' {{DevFeature1.13|5}} (boolean yes|no, default no): If set to "yes", the wml block contained in this [object], [trait], or [advancement] is not variable-substituted at execution time of the event containing this [modify_unit]. You need this for any effect that uses variable substitution or when using [effect][filter] with a $this_unit. {{DevFeature1.13|9}} This is no longer needed when adding ABILITY_TELEPORT, ABILITY_LEADERSHIP or SPECIAL_BACKSTAB.<br />
* '''[effect]''' {{DevFeature1.13|6}} Applies the effect directly to the unit.<br />
* Accepts generally the syntax inside of wml unit variables created by [store_unit] which can be viewed in a savefile or by using the [[CommandMode|inspect command]]. Cannot remove things or add/alter unit animations. Subtags with the same name must be written in the correct order to match them with the tag they are supposed to modify. Note that keys will be processed in arbitrary order, which may cause problems if you use formulas that depend on other formulas. To work around this you may need to use the tag twice with the same filter.<br />
example usage (see also the test scenario):<br />
<syntaxhighlight lang='wml'><br />
[modify_unit]<br />
[filter]<br />
x,y=38,6<br />
[/filter]<br />
hitpoints=10<br />
{TRAIT_HEALTHY}<br />
[/modify_unit]<br />
</syntaxhighlight><br />
<br />
The unit which is currently modified is accessible via $this_unit, e.g. hitpoints = "$($this_unit.hitpoints / 2)" to set the hitpoints of all units to half of their particular maxima. This this_unit variable is independent from the this_unit variable available in the SUF used to determine which units to modify (first all matching units are gathered, and then all those are modified).<br />
<br />
Some some peorperties of the units are reset sometimes for exmapel when the unit advances or when [remove_object] is called. So it's usually better to change them with [object] ([object] inside [modify_unit]) than to change those properties directly via [modify_unit], this list of properties that are _not_ reset in [remove_object] and are thus safe to use directly in [modify_unit] is:<br />
* '''side'''<br />
* '''gender'''<br />
* '''name'''<br />
* '''canrecruit'''<br />
* '''unrenamable'''<br />
* '''extra_recruit'''<br />
* '''[variables]'''<br />
* '''facing'''<br />
* '''goto_x, goto_y'''<br />
* '''hitpoints'''<br />
* '''experience'''<br />
* '''moves'''<br />
* '''[status]''' (not sure on this one)<br />
* '''attacks_left'''<br />
* '''role'''<br />
<br />
=== [transform_unit] ===<br />
Transforms every unit on the map matching the filter to the given unit type. Keeps intact hit points, experience and status. If the unit is transformed to a non-living type (undead or mechanical), it will be also unpoisoned. Hit points will be changed if necessary to respect the transformed unit's maximum hit points.<br />
* [[StandardUnitFilter]]: do not use a [filter] tag.<br />
* '''transform_to''': the unit type in which all the units matching the filter will be transformed. If missing, the units will follow their normal advancement.<br />
<br />
=== [petrify] ===<br />
<br />
* [[StandardUnitFilter]] as an argument. Do not use a [filter] tag. All units matching this filter are petrified. Recall list units are included.<br />
<br />
=== [unpetrify] ===<br />
* [[StandardUnitFilter]] as an argument. Do not use a [filter] tag. All units matching this filter are unpetrified. Recall list units are included.<br />
<br />
=== [object] ===<br />
Gives some unit an object which modifies their stats in some way.<br />
* '''id''': (Optional) allows the item to be removed later. By default, an object with a defined ID can only be picked up once per scenario, even if it is removed later or first_time_only=no is set for the event. You can remove this restriction by setting take_only_once=no. For filtering objects, it might be simpler to use a custom key such as item_id. The id string can contain only letters, numbers and underscores.<br />
* '''take_only_once''': (default yes) {{DevFeature1.13|6}} If set to "no", the object's ID does not prevent it from being taken more than once.<br />
* '''delayed_variable_substitution''' (boolean yes|no, default no): If set to "yes", the wml block contained in this [object] is not variable-substituted at execution time of the event where this [object] is within. You need this for any effect that uses variable substitution or when using [effect][filter] with a $this_unit. {{DevFeature1.13|9}} This is no longer needed when adding ABILITY_TELEPORT, ABILITY_LEADERSHIP or SPECIAL_BACKSTAB.<br />
* '''[effect]''': one or more effect elements may be listed. See [[EffectWML]] for a description of [effect].<br />
* '''duration''':<br />
**if 'scenario', effects only last until the end of the level (note : 'level' is the scenario, so this doesn't mean it last until the unit levels-up).<br />
**if 'forever' or not set, effects never wear off.<br />
** if 'turn', effects only last until the start of the unit's next turn (when the unit refreshes movement and attacks). (Like other start-of-turn behavior, objects with a duration of "turn" won't expire before turn 2.)<br />
** {{DevFeature1.13|1}} if 'turn end' or 'turn_end', effects only last until the end of the unit's next turn (exactly like the slowed status).<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument. The first unit found that matches the filter will be given the object. Only on-map units are considered. If no unit matches or no [filter] is supplied, it is tried to apply the object to the unit at the $x1,$y1 location of the event where this [object] is in. The case of no unit being at that spot is handled in the same way as no unit matching a given filter ([else] commands executed, cannot_use_message displayed). Note that units on the recall list will not be checked. To add an [object] to a unit on the recall list you have to use '''[modify_unit][object]'''.<br />
* '''[then]''': a subtag that lets you execute actions if the filter conditions are met. The most common action that should be inside here is a '''[remove_item]''' tag, but you could probably put any tags that otherwise work in a [then] tag.<br />
* '''[else]''': a subtag that lets you execute actions if the filter conditions are *not* met.<br />
* '''silent''': whether or not messages should be suppressed. Default is "no". {{DevFeature1.13|2}} If no description is provided, this defaults to yes, but can still be overridden.<br />
* '''image''': the displayed image of the object.<br />
* '''name''': (translatable) displayed as a caption of the image.<br />
<br />
* '''description''': (translatable) displayed as a message of the image.<br />
* '''cannot_use_message''': (translatable) displayed instead of '''description''' if no unit passes the filter test.<br />
<br />
=== [remove_object] ===<br />
<br />
{{DevFeature1.13|6}}<br />
<br />
Removes an object from matching units.<br />
<br />
* [[StandardUnitFilter]]: All units matching the filter have matching objects removed. Use no [filter] tag.<br />
* '''object_id''': The id of the object to be removed.<br />
<br />
Note that some unit properties are not restored ideally, e.g. current unit's health reversion might not work as expected (max_hitpoints will though).<br />
<br />
=== [remove_shroud] ===<br />
Removes some shroud from the map for a certain side (only relevant for sides that have shroud=yes).<br />
* '''side''': (default=1) the side for which to remove shroud. This can be a comma-separated list of sides. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* [[StandardLocationFilter]]: the range of tiles for which shroud should be removed<br />
<br />
=== [place_shroud] ===<br />
Places some shroud on the map for a certain side (only relevant for sides that have shroud=yes).<br />
* '''side''': (default=1) the side for which to place shroud. This can be a comma-separated list. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* [[StandardLocationFilter]]: the range of tiles on which shroud should be placed<br />
<br />
=== [lift_fog] ===<br />
Lifts the fog of war from parts of the map for a certain side (only relevant for sides that have fog=yes), allowing a player to witness what occurs there even if that player has no units within vision range.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] indicating which sides should be affected.<br />
* [[StandardLocationFilter]]: the tiles from which fog should be lifted.<br />
* '''multiturn''': ''yes/no, default:no''. The default (not multiturn) causes fog to be removed in the same way that normal vision works; the cleared tiles will remain cleared until fog is recalculated (which normally happens when a side ends its turn). When multiturn is set to "yes", the cleared tiles remain clear until {{tag||reset_fog}} cancels the clearing. This allows tiles to remain clear for multiple turns, or to be refogged before the end of the current turn (without also refogging all tiles). Multiturn lifted fog is not shared with allies (even when share_view=yes).<br />
<br />
=== [reset_fog] ===<br />
The primary use of this tag is to remove multiturn lifted fog (created by {{tag||lift_fog}}), which causes the fog to reset to what it would have been had WML not interfered. (That is, hexes that a side's units could not see at any point this turn will be re-fogged, while seen hexes remain defogged.)<br />
* '''[filter_side]''' with a [[StandardSideFilter]] indicating which sides should be affected.<br />
* [[StandardLocationFilter]]: the fog reset will be restricted to these tiles.<br />
* '''reset_view''': ''yes/no, default: no'' If set to "yes", then in addition to removing multiturn fog, the side's current view is canceled (independent of the SLF). This means that all hexes will become fogged for the side unless multiturn fog exists outside the tiles selected by the SLF. Normally, one would want the currently seen hexes to become clear of fog; this is done automatically at the end of many events, and it can be done manually with {{tag|InterfaceActionsWML|redraw}}.<br />
Omitting both the SSF and the SLF would cancel all earlier uses of [lift_fog].<br />
Additionally setting reset_view="yes" would cause the side's entire map to be fogged (unless an ally keeps hexes clear by sharing its view).<br />
<br />
=== [allow_undo] ===<br />
Normally when an event with a handler fires, the player's undo stack is cleared, preventing all actions performed so far from being undone. Including this tag in the event handler prevents the stack from being cleared for this reason, allowing the player to undo actions. (However, the stack might still be cleared for other reasons, such as fog being cleared or combat occurring.) In the common cases, this means '''[allow_undo]''' allows the current action to be undone even though an event was handled. There is a less common case, though &mdash; specifically when handling a menu item, where there is no current action &mdash; and in this case, '''[allow_undo]''' means merely that earlier actions can still be undone.<br />
* Using this tag in a menu item has an additional side effect in 1.11. Starting with version 1.11.1, executing a WML menu item normally counts as doing something as far as the "you have not started your turn yet" dialog is concerned. However, a menu item whose handler includes '''[allow_undo]''' will not count.<br />
<br />
The types of actions that can be undone are movement, recalling, and dismissing a unit from the recall list. If an action is undone, only the position (or existence) of the involved unit will be restored; any altered variables or changes to the game will remain changed after the action is undone. It is up to the scenario designer to avoid abusing this command.<br />
* Technically, if '''[allow_undo]''' is inside an '''[event]''' with ''first_time_only=yes'' (the default setting), and the user undoes the event, then the state of the game has changed in this way: the event will not fire a second time, even though the user undid the action the first time.<br />
* Although recalling can be undone, recruitment can not be undone; this seems to apply even when the recruit's traits are not randomly-generated (tested on 1.12.6 and 1.14.4+dev).<br />
<br />
If an '''[event]''' uses both '''[allow_undo]''' and [[InternalActionsWML#.5Bfire_event.5D|'''[fire_event]''']] then the '''[allow_undo]''' must be after the '''[fire_event]'''.<br />
<br />
Due to a bug in 1.12 (https://gna.org/bugs/?23323) '''[allow_undo]''' should not be used in events that use one of the following things because it might cause OOS: <br />
* [message] with [option]s<br />
* [get_global_variable]<br />
* wesnoth.synchronize_choice<br />
<br />
While in 1.13 using '''[allow_undo]''' together with those things won't give you a guaranteed OOS, there are some non-obvious situations where it will, for example assume the following event:<br />
<br />
[event]<br />
name="moveto"<br />
[message]<br />
message = "message"<br />
[option]<br />
label = "option 1"<br />
[command]<br />
[/command]<br />
[/option]<br />
[option]<br />
label = "option 2"<br />
[command]<br />
[/command]<br />
[/option]<br />
[/message]<br />
[allow_undo]<br />
[/allow_undo]<br />
[/event]<br />
<br />
It will cause OOS when the message is undone: since the event is already executed (erased) on one client only , the clients will disagree about how many choices happen during the next moveto action.<br />
<br />
=== [on_undo] ===<br />
{{DevFeature1.13|2}}<br />
Contains commands to execute when the player undoes the action which triggered the parent event.<br />
*'''delayed_variable_substitution''' {{DevFeature1.13|5}}: ''yes/no, default no (always no before 1.13.5)'' As in [[EventWML]], specifies whether to perform variable substitution when the parent event is run, or when the contents are run. If delayed substitution is used, [[SyntaxWML#Automatically_Stored_Variables|automatically stored variables]] from the parent event context are available, but may occasionally have unexpected values. (In particular, $unit.x and $unit.y may not have the expected value when undoing a move event, though $x1 and $y1 should be correct.)<br />
<br />
Note:<br />
It is not clear where whether the actionwml in [on_undo] in exceuted before or after the action is undone. Also, specially for enter/leave_hex events the units position when executing the [on_undo] code is usually different than when executing the original event. The reccomended way to wokr around these issues is to refer to the unit by is instead of position and store all other needed information variables as 'upvalues'. You can also move the actual undo code to an external event. For example<br />
[event]<br />
name="undo_blah"<br />
first_time_only=no<br />
[store_unit]<br />
id="$moved_unit_id"<br />
[/store_unit]<br />
... do undo stuff stuff<br />
[/event]<br />
<br />
...<br />
... in some other event<br />
[on_undo]<br />
# store ''upvalues<br />
{VARIABLE moved_unit_id $unit.id}<br />
# call actual undo handler<br />
[fire_event]<br />
name = "undo_blah"<br />
[/fire_event]<br />
[on_undo]<br />
<br />
=== [on_redo] ===<br />
{{DevFeature1.13|2}}<br />
Same as [on_undo], except executes the commands on redo. Note that the parent event is not triggered again on a redo.<br />
<br />
{{DevFeature1.13|8}} [on_redo] is deprecated and has no effect anymore.<br />
<br />
Note that [on_redo] is not guaranteed to be called when redoing an action, the engine might also decide to just fire the original events again.<br />
<br />
=== [cancel_action] ===<br />
Although Wesnoth 1.12 does not have this tag, it is the default behavior of {{tag|EventWML|enter_hex}}/{{tag|EventWML|leave_hex}} events in that version.<br />
<br />
{{DevFeature1.13|9}} In this version, [cancel_action] is recognised, but has no effect (a bug).<br />
<br />
{{DevFeature1.13|11}}<br />
In an {{tag|EventWML|enter_hex}}/{{tag|EventWML|leave_hex}} event, interrupt the movement, leaving the unit where it is. This is intended to be used with an event that gives the player new information, to let the player choose whether to change their plans. For example, if the player has commanded a unit to move from (1,1) to (3,3) and attack a unit on (4,4); then a [cancel_action] inside an [enter_hex] event on (2,2) would make the unit stop on (2,2). A [cancel_action] inside an [enter_hex] on (3,3) would let the player choose whether to attack.<br />
<br />
=== [heal_unit] ===<br />
Heal a unit. The variable '''$heal_amount''' will be set to the exact number of points healed (i.e can be less than the parameter '''amount''' if the unit is fully healed). $heal_amount contains only the number of hitpoints the first unit that was found got healed.<br />
* '''[filter]''': [[StandardUnitFilter]] All matching on-map units are healed. If no filter is supplied, it is tried to take the unit at $x1, $y1.<br />
* '''[filter_second]''': [[StandardUnitFilter]] all the units matching the filter ''and'' having the ''heals'' ability will have their animation played (if ''animate'' is set to yes) for each of the units healed.<br />
* '''amount''': (integer, default full) the maximum points the unit(s) will be healed. Can't set below 1 or above max_hitpoints. If "full", sets hitpoints to max_hitpoints. Before 1.9 the default is 0.<br />
* '''animate''': a boolean which indicate if the healing animations must be played. (default no)<br />
* '''moves''': (integer, default 0) The maximum current movement points the units will be "healed". Can't set below 0 or above max_moves. If "full", sets moves to max_moves.<br />
* '''restore_attacks''': (boolean, default no) Whether the units' attacks_left should be reset to their max_attacks (usually 1).<br />
* '''restore_statuses''': (boolean, default yes) Whether standard statuses should be reset to "no". This affects poisoned, slowed, petrified and unhealable. Before 1.9 this is always "no".<br />
<br />
=== [harm_unit] ===<br />
Harms every unit matching the filter, for the specific damage amount.<br />
* '''[filter]''': [[StandardUnitFilter]] all matching units will be harmed (required).<br />
* '''[filter_second]''': [[StandardUnitFilter]] if present, the first matching unit will attack all the units matching the filter above.<br />
* '''amount''': the amount of damage that will be done (required).<br />
* '''alignment''': (default neutral) applies an alignment to the damage, this means that if alignment=chaotic, the damage will be increased at night and reduced at day.<br />
* '''damage_type''': if present, amount will be altered by unit resistance to the damage type specified.<br />
* '''kill''': (default yes) if yes, when a harmed unit goes to or below 0 HP, it is killed; if no its HP are set to 1.<br />
* '''fire_event''': (default no) if yes, when a unit is killed by harming, the corresponding events are fired. If yes, also the corresponding advance and post advance events are fired.<br />
* '''animate''': (default no) if yes, scrolls to each unit before harming it and plays its defense (or attack, if it's the harmer) and death animations. Special values supported, other than the usual yes and no, are "attacker", that means only the harmer will be animated, and "defender", that means only the harmed units will be animated. If the supplied value is yes, attacker or defender also advancement animations are played.<br />
* '''[primary_attack], [secondary_attack]''': these set the weapon against which the harmed units will defend, and that the harming unit will use to attack, respectively (notice this is the opposite of '''[filter]''' and '''[filter_second]''' above). This allows for playing specific defense and attack animations. Both tags are expected to contain a [[FilterWML#Filtering_Weapons|Standard Weapon Filter]].<br />
* '''delay''': if animate=yes, sets the delay (in milliseconds, default 500) between each unit harming.<br />
* '''variable''': if present, the damage caused to the unit, altered by resistances, will be stored in a WML array with the given name, under the "harm_amount" key.<br />
* '''poisoned, slowed, petrified, unhealable''': (default no) if yes, every harmed unit that doesn't already have such status will have it set.<br />
* '''experience''': if yes, and there is a harmer, experience will be attributed like in regular combat.<br />
* '''resistance_multiplier''': the harmed unit's resistance is multiplied by the supplied value; this means that a value lower than 1 increases it, and a value greater than 1 decreases it. Default value is 1, that means no modification.<br />
<br />
=== [time_area] ===<br />
How a day should progress in a given area. Everywhere not specified in a [time_area] tag is affected by the [time] tags in the [scenario] tag.<br />
* [[StandardLocationFilter]]: the locations to affect. ''note: only for [event][time_area]s - at scenario toplevel [time_area] does not support [[StandardLocationFilter]], only location ranges''<br />
* '''[time]''': one or more tags describing the new schedule, see [[TimeWML]].<br />
* '''id''': an unique identifier assigned to a time_area. Optional, unless you want to remove the time_area later. Can be a comma-separated list when removing time_areas, see below.<br />
* '''remove''': (boolean) yes/no value. Indicates whether the specified time_area should be removed. Requires an identifier. If no identifier is used, however, all time_areas are removed.<br />
* '''current_time''': The time slot number (starting with zero) active at the creation of the area.<br />
<br />
''Example:'' (caves in parts of a map)<br />
[time_area]<br />
x=1-2,4-5<br />
y=1-2,1-2<br />
{UNDERGROUND}<br />
[/time_area]<br />
<br />
=== [remove_time_area] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This is a syntactic shortcut for [time_area] remove=.<br />
* '''id''': Comma-separated list of time area ids to remove.<br />
<br />
=== [end_turn] ===<br />
End the current side's turn. The current event is finished before the turn is ended. Also, if the current event (where the tag appears) has been fired by another event, that event (and the complete stack of other possible parent events) is ended before [end_turn] comes into affect. Also, events following the event stack that fired [end_turn] are not omitted (e.g. [end_turn] is used by a side turn event and a turn refresh event does something afterwards).<br />
<br />
=== [replace_map] ===<br />
<br />
Replaces the entire map.<br />
* '''map''': Content of a wesnoth map file. example:<br />
map="{campaigns/Heir_To_The_Throne/maps/01_The_Elves_Besieged.map}"<br />
* '''map_file''': {{DevFeature1.13|?}} Path to a Wesnoth map file; can be used instead of '''map'''. The file will be loaded when the tag is executed, rather than being embedded wholesale in the preprocessed WML.<br />
* '''expand''': if 'yes', allows the map size to increase. The expansion direction is currently always bottom-right.<br />
* '''shrink''': if 'yes', allows the map size to decrease. If the map size is reduced, any units that would no longer be on the map due to its coordinates no longer existing will be put into the recall list.<br />
Note: When a hex changes from a village terrain to a non-village terrain, and a team owned that village it loses that village. When a hex changes from a non-village terrain to a village terrain and there is a unit on that hex it does not automatically capture the village. The reason for not capturing villages it that there are too many choices to make; should a unit lose its movement points, should capture events be fired. It is easier to do this as wanted by the author in WML.<br />
<br />
=== [replace_schedule] ===<br />
Replace the time of day schedule of the entire scenario.<br />
* [[TimeWML]]: the new schedule.<br />
* '''current_time''': The time slot number (starting with zero) active at schedule replacement.<br />
<br />
=== [tunnel] ===<br />
<br />
Create a tunnel between some locations, later usable by units to move from source hex to target hex (using the movement cost of unit on the target terrain).<br />
<br />
'''Behavior Change as of Wesnoth 1.13.6:''' Vision is now possible (and enabled by default) through tunnels and allied units on the exit hex do not block a tunnel by default any more. This is done in order for moves through tunnels to be consistent with other moves. The previous behavior can still be accomplished by using the new optional keys listed below.<br />
<br />
* '''[filter]''': (required) [[StandardUnitFilter]] the units which can use the tunnel. Leave empty for "all units".<br />
* '''[source]''': (required) [[StandardLocationFilter]] the source hex(es).<br />
* '''[target]''': (required) [[StandardLocationFilter]] the target hex(es).<br />
* '''id''': (optional) identifier for the tunnel, to allow removing.<br />
* '''remove''': (boolean, default: no) If yes, removes all defined tunnels with the same ID (then only id= is necessary).<br />
* '''bidirectional''': (boolean, default: yes) If yes, creates also a tunnel in the other direction. <br />
* '''always_visible''': (boolean, default: no) If yes, the possible movement of enemies under fog can be seen.<br />
* '''allow_vision''': (boolean, default: yes) {{DevFeature1.13|6}} If no, vision through a tunnel is not possible. Note that in that case the tunnel cannot be used if the tunnel exit is under shroud (which previously was ''always'' the case).<br />
* '''pass_allied_units''': (boolean, default: yes) {{DevFeature1.13|6}} If no, allied (including own) units on the exit hex block a tunnel.<br />
<br />
(Note: The tunnel tag can also be used inside the [[AbilitiesWML|[teleport]]] ability, without remove= and id=).<br />
<br />
=== [do_command] ===<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Executes a command, specified using the same syntax as a [command] tag in [[ReplayWML]]. Not all [command]'s are valid: only these are accepted<br />
<br />
* [attack]<br />
* [move]<br />
* [recruit]<br />
* [recall]<br />
* [disband]<br />
* [fire_event]<br />
* [lua_ai] {{DevFeature1.13|12}} This has been removed and is replaced with [custom_command]<br />
<br />
The tags corresponding to player actions generally use the same codepath as if a player had ordered it. That means for example that only moves that player would be allowed to do are possible, and movement is interrupted when sighting enemy unit.<br />
<br />
One purpose of this tag is to allow scripting of noninteractive scenarios -- without a tag like this, this might require elaborate mechanisms to coerce ais in order to test these code paths.<br />
<br />
This command should always be replay safe.<br />
<br />
=== [put_to_recall_list] ===<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Puts a unit to the recall list of its side.<br />
* '''[[StandardUnitFilter]]''': the unit(s) to get put to the recall list.<br />
* '''heal''': (default=no) Whether the unit should be refreshed, similar to the unit moving to the recall list at the end of a scenario.<br />
<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for direct actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{MOVE_UNIT}''': Moves a unit to another location in the map and the player sees the movement (unlike [teleport])<br />
* '''{FULL_HEAL}''': Brings a unit to full HP<br />
* '''{LOYAL_UNIT}''': Create a loyal unit<br />
* '''{MODIFY_TERRAIN_MASK}''': Modify an area of terrain<br />
<br />
== See Also ==<br />
<br />
* [[InternalActionsWML]]<br />
* [[InterfaceActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=ModificationWML&diff=60886ModificationWML2019-04-01T18:23:17Z<p>Gfgtdf: </p>
<hr />
<div>{{WML Tags}}<br />
== The [modification] toplevel tag ==<br />
<br />
This tag describes an SP or MP modification. A modification is, practically speaking, a bunch of events which get included into the scenario if the modification is enabled.<br />
<br />
The following keys/tags are recognized for '''[modification]''':<br />
<br />
* '''id''': identifier for the modification. Must be unique.<br />
* '''name''': the name of the modification, as displayed to the user.<br />
* '''type''': where the modification will be available for playing. Possible values are ''sp'', ''mp'', and ''hybrid''.<br />
* '''description''': a brief description for the modification.<br />
* '''allow_scenario''': a list of scenario ids. Only the scenarios with matching ids will be allowed to be played with this modification.<br />
* '''disallow_scenario''': a list of scenario ids. Only the scenarios with matching ids will not be allowed to be played with this modification. Cannot be used in parallel with allow_scenario.<br />
* '''allow_era''': same as allow_scenario, but for eras.<br />
* '''disallow_era''': same as disallow_scenario, but for eras. Can't be used with allow_era.<br />
* '''allow_modification''': same as allow_scenario, but for modifications.<br />
* '''disallow_modification''': same as disallow_scenario, but for modifications. Can't be used with allow_modification.<br />
* '''ignore_incompatible_scenario''': a list of scenario ids. The scenarios with matching ids will be considered compatible with this modification regardless their dependencies.<br />
* '''ignore_incompatible_era''': same as ignore_incompatible_scenario, but for eras.<br />
* '''ignore_incompatible_modification''': same as ignore_incompatible_scenario, but for modifications.<br />
* '''require_modification''': a boolean value; if set to yes, all players have to have this modification installed to join the game. Default no.<br />
* '''addon_min_version''': {{DevFeature1.13|0}} the minimum version of your add-on with which this content is backwards compatible. Compare with the version string given in [[PblWML]]. Clients in multiplayer must have add-on versions agreeing with the ''addon_min_versions'' of eachothers content in order to play, and will be prompted to update otherwise.<br />
* '''[event]''': any [event] children written inside the [modification] tag will get included into scenarios that are played with this modification enabled. See [[EventWML]].<br />
* '''[lua]''': any [lua] children written inside the [modification] tag will get included into scenarios that are played with this modification enabled.<br />
* '''[options]''': custom options. See [[OptionWML]] for details.<br />
* '''[ai]''': See [[AiWML]] for details.<br />
* '''[unit_type_fix]''' {{DevFeature1.15|0}}: Changes a unit type while this modification is active the supported arreibutes are:<br />
** '''type''' : the id of the unit type to change.<br />
** '''set_experience''' : changes the unit types max experience.<br />
** '''set_cost''' : changes the unit types recruit cost.<br />
** '''set_advances_to''' : changes the unit types advancements.<br />
** '''add_advancement''' : adds a unit type to the possibel advancements of this unit type.<br />
** '''remove_advancement''' : removes a unit type to the possible advancements of this unit type.<br />
<br />
== The [resource] toplevel tag ==<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
The '''[resource]''' toplevel tag is similar to [modification] in that it contains [event] and [lua] tags which are then copied into the scenario. However, unlike [modification], resources defined this way are completely hidden from the user. To load a resource, use '''[load_resource] id=<i><resource id></i>''' in [scenario], [multiplayer], [era], [campaign], [modification], or [resource].</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=ModificationWML&diff=60689ModificationWML2019-03-20T22:22:04Z<p>Gfgtdf: /* The [modification] toplevel tag */</p>
<hr />
<div>{{WML Tags}}<br />
== The [modification] toplevel tag ==<br />
<br />
This tag describes an SP or MP modification. A modification is, practically speaking, a bunch of events which get included into the scenario if the modification is enabled.<br />
<br />
The following keys/tags are recognized for '''[modification]''':<br />
<br />
* '''id''': identifier for the modification. Must be unique.<br />
* '''name''': the name of the modification, as displayed to the user.<br />
* '''type''': where the modification will be available for playing. Possible values are ''sp'', ''mp'', and ''hybrid''.<br />
* '''description''': a brief description for the modification.<br />
* '''allow_scenario''': a list of scenario ids. Only the scenarios with matching ids will be allowed to be played with this modification.<br />
* '''disallow_scenario''': a list of scenario ids. Only the scenarios with matching ids will not be allowed to be played with this modification. Cannot be used in parallel with allow_scenario.<br />
* '''allow_era''': same as allow_scenario, but for eras.<br />
* '''disallow_era''': same as disallow_scenario, but for eras. Can't be used with allow_era.<br />
* '''allow_modification''': same as allow_scenario, but for modifications.<br />
* '''disallow_modification''': same as disallow_scenario, but for modifications. Can't be used with allow_modification.<br />
* '''ignore_incompatible_scenario''': a list of scenario ids. The scenarios with matching ids will be considered compatible with this modification regardless their dependencies.<br />
* '''ignore_incompatible_era''': same as ignore_incompatible_scenario, but for eras.<br />
* '''ignore_incompatible_modification''': same as ignore_incompatible_scenario, but for modifications.<br />
* '''require_modification''': a boolean value; if set to yes, all players have to have this modification installed to join the game. Default no.<br />
* '''addon_min_version''': {{DevFeature1.13|0}} the minimum version of your add-on with which this content is backwards compatible. Compare with the version string given in [[PblWML]]. Clients in multiplayer must have add-on versions agreeing with the ''addon_min_versions'' of eachothers content in order to play, and will be prompted to update otherwise.<br />
* '''[event]''': any [event] children written inside the [modification] tag will get included into scenarios that are played with this modification enabled. See [[EventWML]].<br />
* '''[lua]''': any [lua] children written inside the [modification] tag will get included into scenarios that are played with this modification enabled.<br />
* '''[options]''': custom options. See [[OptionWML]] for details.<br />
* '''[ai]''': See [[AiWML]] for details.<br />
* '''[unit_type_fix]''' {{DevFeature1.15|0}}: Changes a unit type while this modification is active the supported arreibutes are:<br />
** '''set_experience''' : changes the unit types max experience.<br />
** '''set_cost''' : changes the unit types recruit cost.<br />
** '''set_advances_to''' : changes the unit types advancements.<br />
** '''add_advancement''' : adds a unit type to the possibel advancements of this unit type.<br />
** '''remove_advancement''' : removes a unit type to the possible advancements of this unit type.<br />
<br />
== The [resource] toplevel tag ==<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
The '''[resource]''' toplevel tag is similar to [modification] in that it contains [event] and [lua] tags which are then copied into the scenario. However, unlike [modification], resources defined this way are completely hidden from the user. To load a resource, use '''[load_resource] id=<i><resource id></i>''' in [scenario], [multiplayer], [era], [campaign], [modification], or [resource].</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=InterfaceActionsWML&diff=60601InterfaceActionsWML2019-03-13T12:41:50Z<p>Gfgtdf: /* [message] */</p>
<hr />
<div>{{WML Tags}}<br />
== Interface actions ==<br />
<br />
Part of [[ActionWML]], interface actions are actions that do not have a direct effect on gameplay;<br />
instead, they show something to the player. The main interface tags<br />
are '''[message]''' and '''[objectives]''', but several other tags affect<br />
the interface also.<br />
<br />
== [inspect] ==<br />
This user interface instantly displays the gamestate inspector dialog at the current scenario state (the same one that can be brought up with [[CommandMode|the ''':inspect''' command]]), which can be used to inspect the values of WML variables, AI configuration, recall lists, and more.<br />
<br />
* '''name''': optional attribute to specify the name of this gamestate inspector dialog. It is just a label to help differentiate between different invocations of gamestate inspector dialog.<br />
<br />
== [message] ==<br />
The most commonly used interface action is [message], which displays a message to the user in a dialog box. It can also be used to take input from the user.<br />
<br />
The following key/tags are accepted for [message]:<br />
* [[StandardUnitFilter]]: The unit whose profile and name are displayed. Do not use a [filter] tag. If no unit matching this filter is found, the message is not displayed (The unit has probably been killed).<br>[message] elements should be constructed so that it is either guaranteed that a certain unit is alive, or so that dialog flows smoothly even if the message isn't displayed.<br />
<br />
* '''speaker''': an alternative to standard unit filter. You may specify as the value of the speaker attribute a unit id or any of the following special values:<br />
** '''narrator''': the dialog box is displayed without a caption for the unit speaking or a unit image<br />
** '''unit''': the primary unit for the event is speaking<br />
** '''second_unit''': {{DevFeature1.13|6}} the secondary unit for the event is speaking<br />
<br />
* '''message''': (translatable) the text to display to the right of the image. ''message'' is sometimes multiple lines; if it is, be sure to use quotes(''' ' ''' or ''' " ''')<br />
* '''male_message''', '''female_message''': {{DevFeature1.13|2}} (translatable) Used instead of ''message'' if the unit's gender matches. Never used if there is no unit (ie ''speaker=narrator''). {{DevFeature1.13|6}} This matches the primary unit, not the secondary unit.<br />
* '''wait_description''': {{DevFeature1.13|2}} the description of this message displayed when other players in a mp game wait for one player doing input in a [message] (with [option]s or [text_input]).<br />
* '''[show_if]''': if present then this message will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
* '''side_for''': (default: all sides) comma-separated list of sides for who message is shown. This will <b>not</b> work with messages that take user input ([option]/[text_input]), which can only ever be shown to the current player. {{DevFeature1.13|0}} side_for= is now also accepted for messages with user input, it specifies on which side the message is shown (defaults to the currently playing side). For messages with input it does not accept a comma seperated list only a single number.<br />
* '''image''': (default: profile image of speaker) the image to display to the left of the message text. Append ~RIGHT() if you want the image to appear on the right side. <br />
** {{DevFeature1.13|0}} <b>none:</b> display no image<br />
* '''mirror''': {{DevFeature1.13|5}}whether to mirror the image specified by the '''image''' attribute.<br />
* '''second_image''': {{DevFeature1.13|6}}same as the '''image''' attribute, but the image is displayed on the right of the message text.<br />
* '''second_mirror''': {{DevFeature1.13|6}}same as '''mirror''', but for the '''second_image''' attribute.<br />
* '''image_pos''': {{DevFeature1.13|5}} whether to show the image on the left or right; supercedes the use of ~RIGHT() described above<br />
* '''caption''': (default: name of speaker) the caption to display beside the image. Name to be displayed. Note: use a translation mark to avoid wmllint errors.<br />
* '''scroll''': Boolean specifying whether the game view should scroll to the speaking unit. Defaults to ''yes''.<br />
* '''highlight''': {{DevFeature1.13|5}} Boolean specifying whether to highlight the speaker. Defaults to ''yes''.<br />
* '''sound''': a sound effect (wav file) to play as the message is displayed. This can be a comma-separated list, from which one will be randomly chosen.<br />
* '''voice''': {{DevFeature1.13|?}} a sound to be played as the message is displayed. This can also be a comma-separated list, from which one will be randomly chosen. This is intended for voiceovers for the message.<br />
* '''[option]''': No '''[option]''' elements have to be used. If '''[option]''' elements are present, then each option will be displayed in a menu for the user to select one option. ''Note: Messages with options will not be shown at all in prestart events''<br />
** '''message''': (translatable) the text displayed for the option (see [[DescriptionWML]]) {{DevFeature1.13|2}} This is now a synonym for '''label='''.<br />
** '''image''', '''label''', '''description''', '''default''': See [[DescriptionWML#WML_Format|DescriptionWML]].<br />
** '''value''': {{DevFeature1.13|?}} Gives the option a value to be stored in a variable, if this behavior is enabled. Does not work together with '''message=''', '''label=''' must be used instead.<br />
** '''[show_if]''': if present then this option will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
** '''[command]''': an element containing actions which are executed if the option is selected.<br />
* '''variable''': {{DevFeature1.13|?}} If present, either the index or the value of the chosen option will be stored in the specified variable.<br />
* '''[text_input]''': there can be only one [text_input] tag. this adds a text input field to the message. ''Note: Messages with text_input will not be shown at all in prestart events''<br />
** '''variable''': the variable that the user's input will be written to<br />
** '''label''': a text label to the left of the input field<br />
** '''max_length''': the maximum number of characters that may be typed into the field<br />
** '''text''': text that is written into the field in the beginning<br />
* Check [[EventWML#Multiplayer_safety]] to find out in which events you can safely use '''[option]''' and '''[text_input]''' without causing OOS.<br />
<br />
=== Formatting ===<br />
'''[message]''' and other tags such as unit names (user_description), objectives, and floating text can make use of [http://developer.gnome.org/pango/unstable/PangoMarkupFormat.html Pango markup formatting codes].<br />
<br />
Remember to use single quotes (') instead of double quotes (") within the formatting string, as double quotes cannot be escaped, and the string will appear fragmented and possibly cause errors. Escaping markup is described in https://github.com/wesnoth/wesnoth/blob/master/src/font/pango/escape.hpp#L35-L39.<br />
<br />
For example, if you wanted to write "You are victorious!" in large, italic, gold letters, you might write it this way:<br />
<br />
<nowiki><span color='#BCB088' size='large' font-style='italic'>You are victorious!</span></nowiki><br />
<br />
<br />
These are the codes taken from the Pango markup formatting guide:<br />
<br />
*'''font''', '''font_desc''': A font description string, such as "Sans Italic 12".<br />
*'''font_family''', '''face''': A font family name.<br />
*'''font_size''', '''size''': Font size in 1024ths of a point, or one of the absolute sizes 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', or one of the relative sizes 'smaller' or 'larger'.<br />
*'''font_style''', '''style''': One of 'normal', 'oblique', 'italic'.<br />
*'''font_weight''', '''weight''': One of 'ultralight', 'light', 'normal', 'bold', 'ultrabold', 'heavy', or a numeric weight.<br />
*'''font_variant''', '''variant''': One of 'normal' or 'smallcaps'.<br />
*'''font_stretch''', '''stretch''': One of 'ultracondensed', 'extracondensed', 'condensed', 'semicondensed', 'normal', 'semiexpanded', 'expanded', 'extraexpanded', 'ultraexpanded'.<br />
*'''foreground''', '''fgcolor''', '''color''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''background, bgcolor''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''underline''': One of 'none', 'single', 'double', 'low', 'error'.<br />
*'''underline_color''': The color of underlines; an RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''rise''': Vertical displacement, in 10000ths of an em. Can be negative for subscript, positive for superscript.<br />
*'''strikethrough''': 'true' or 'false' whether to strike through the text.<br />
*'''strikethrough_color''': The color of strikethrough lines; an RGB color specification such as '#00FF00' or a color name such as 'red'<br />
*'''fallback''': 'true' or 'false' whether to enable fallback. If disabled, then characters will only be used from the closest matching font on the system. No fallback will be done to other fonts on the system that might contain the characters in the text. Fallback is enabled by default. Most applications should not disable fallback.<br />
*'''letter_spacing''': Inter-letter spacing in 1024ths of a point.<br />
*'''gravity''': One of 'south', 'east', 'north', 'west', 'auto'.<br />
*'''gravity_hint''': One of 'natural', 'strong', 'line'.<br />
<br />
The following pango attributes are also available directly as attributes of the '''[message]''' tag:<br />
{{DevFeature1.13|4}}<br />
<br />
*'''font'''<br />
*'''font_family'''<br />
*'''font_size'''<br />
*'''font_style'''<br />
*'''font_weight'''<br />
*'''font_variant'''<br />
*'''font_stretch'''<br />
*'''color'''<br />
*'''bgcolor'''<br />
*'''underline'''<br />
*'''underline_color'''<br />
*'''rise'''<br />
*'''strikethrough'''<br />
*'''strikethrough_color'''<br />
*'''fallback'''<br />
*'''letter_spacing'''<br />
*'''gravity'''<br />
*'''gravity_hint'''<br />
<br />
== [objectives] ==<br />
The other tag used for plot development is '''[objectives]'''.<br />
The '''[objectives]''' tag overwrites any previously set objectives,<br />
and displays text which should describe the objectives of the scenario.<br />
Scenario objectives are displayed on the player's first turn after the tag is used,<br />
or as part of the event if it triggers during that player's turn.<br />
Objectives can also be accessed at any time in a scenario using the<br />
"Scenario Objectives" game menu option, making this tag useful for<br />
scenario-specific information that the player may need to refer to during play.<br />
<br />
Attributes of '''[objectives]''':<br />
* '''side''': Default '0'. The side to set the objectives for. A value of 0 sets objectives for all sides. note: There are side-specific objectives and default objectives, which are used in case a side doesn't have specific ones. Specifying 0 sets the default ones.<br />
* '''[[StandardSideFilter]]''' tags and keys: Sets the objectives of all matching sides to these passed specifications (the rest of this [objectives] tag). If no sides (such as when passing side=0) or all sides match, sets the default objectives, and the side specific ones for the matching sides otherwise.<br />
* '''bullet''': Default '• '. Replaces the default bullet, with whatever is passed, for all objectives, gold carryover notes, and notes defined with [note].<br />
* '''summary''': Displayed first in the objectives text, this should describe the basic objective for the overall scenario. Can be omitted.<br />
* '''note''': Displayed last in the objectives text, this is sometimes used for hints or additional information. Can be omitted.<br />
* '''victory_string''': Default ' _ "Victory:"', this text precedes the victory objectives. Can be set to "" too.<br />
* '''defeat_string''': Default ' _ "Defeat:"', this text precedes the defeat objectives. Can be set to "" too.<br />
* '''gold_carryover_string''': Default ' _ "Gold carryover:"', this text precedes the gold carryover information.<br />
* '''notes_string''': Default ' _ "Notes:"', this text precedes the notes.<br />
* '''silent''': Default: not present. If set to "yes", the objectives are silently changed. Else, they will be shown to the user when appropriate.<br />
* '''delayed_variable_substitution''': {{DevFeature1.13|8}} If set to yes, any variables or [insert_tag] are not substituted right away. Instead, they are substituted whenever the objectives are actually viewed.<br />
<br />
Tags of '''[objectives]''':<br />
* '''[objective]''': describes a win or loss condition. Most scenarios have multiple win or loss conditions, so use a separate [objective] subtag for each line; this helps with translations.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet, with whatever is provided, for the objective defined by the [objective] block.<br />
** '''red''': Default '0' for winning objectives, '255' for losing objectives. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255' for winning objectives, '0' for losing objectives. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '0'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''description''': text for the specific win or loss condition.<br />
** '''caption''': a text which will be displayed above the ''description''. This can be used to display a subcategory of objectives below ''victory_string'' or ''defeat_string''.<br />
** '''condition''': The color and placement of the text. Values are 'win'(colored green, placed after ''victory_string'') and 'lose'(colored red, placed after ''defeat_string'').<br />
** '''show_turn_counter''': If set to yes, displays the number of turns remaining in the scenario. Default is no.<br />
** '''[show_if]''': A condition that disables the objective if it doesn't hold. Conditional objectives are refreshed at '''[show_objectives]''' time only, or when manually opening the scenario objectives.<br />
* '''[gold_carryover]''': describes how the gold carryover works in this scenario. This is intended to be a more convenient way of displaying carryover information than using the note= key in [objectives].<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '192'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''bonus''' (boolean): whether an early finish bonus is granted. If omitted, early finish bonus is not mentioned.<br />
** '''carryover_percentage''': the amount of carryover gold. If omitted, the amount is not mentioned.<br />
** '''[show_if]''': {{DevFeature1.13|11}} Gold carryover will not be shown if the specified condition isn't met. Conditional gold carryover is refreshed at '''[show_objectives]''' time only.<br />
* '''[note]''': describes a note, usually used for hints or additional information. This is an easier way of adding several notes than concatenating them together into a single string to use with the ''note='' key.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided for the note defined by the [note] block.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire note, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire note, including the bullet.<br />
** '''blue''': Default '255'. Overrides the default blue coloring of the entire note, including the bullet.<br />
** '''description''': the text of the note.<br />
** '''[show_if]''': The note will not be shown if the specified condition isn't met. Conditional notes are refreshed at '''[show_objectives]''' time only.<br />
<br />
== [set_menu_item] ==<br />
This tag is used to add a custom option in the right-click context menu which can then be used to trigger arbitrary WML commands. The menu items can be set and modified during any event, for example during "start" or "prestart" events. The user can also assign hotkeys to these WML commands unless specified otherwise. When the hotkey is pressed the event will be fired/filtered at the current mouse position.<br />
<br />
'''Note:''' Due to limitations in portable devices where there are no scroll bars for context menus, there is a hard-coded limit of 7 custom WML menu items. If you really need to have more than 7 menu items, try combining some of them in a submenu. {{DevFeature1.13|0}} This limitation is being removed in a [http://forums.wesnoth.org/viewtopic.php?p=572554#p572554 future version] of Wesnoth.<br />
<br />
* '''id''': the unique id for this menu item. If a menu item with this id already exists, it allows you to set specific changes to that item.<br />
* '''description''': the in-game text that will appear for this item in the menu.<br />
* '''image''': the image to display next to this item.<br />
* '''needs_select''': if ''yes'' (default ''no''), then the latest select event (see [[EventWML]]) that triggered before this menu item was chosen will be transmitted over the network before this menu item action will be. This only has any effect in networked multiplayer, and is intended to allow more elaborate menu item behaviour there without causing out of sync errors. If you don't know what this means, just leave it. {{DevFeature1.13|6}} ''needs_select=yes'' is deprecated, consider using manual variable syncing with [sync_variable].<br />
* '''synced''' {{DevFeature1.13|1}}: if ''no'' (default ''yes'') the command handler will only be run on the client that invoked the menu item; this means that changing the gamestate in a command handler of a menu item with ''synced=no'' will cause OOS<br />
* '''use_hotkey''': if ''no'' (default ''yes''), then the user cannot assign hotkeys to this menu item. If ''only'', the menu item is only accessible via hotkeys, not via right-click context; you can use this in combination with [default_hotkey] if you want custom hotkeys in your campaign/mp. <br />
* '''[show_if]''': If present, the menu item will only be available if the conditional statement (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]]) within evaluates to true. When this is evaluated, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked, so it's possible to for example only enable the option on empty hexes or on a particular unit.<br />
* '''[filter_location]''': contains a location filter similar to the one found inside Single Unit Filters (see [[FilterWML]]). The menu item will only be available on matching locations.<br />
* '''[default_hotkey]''': contains a hotkey WML to specify what hotkey to assign to this, '''if the user has no hotkey assigned to this yet'''. (Unlike the rest of a menu item definition, modifying this tag has no effect on the game; it is only effective when initially defining a menu item.) Hotkey WML matches the format in the preferences file and contains the following keys:<br />
** '''key''': a string that contains the key to assign to this.<br />
** '''alt''', '''shift''', '''cmd'''(apple only), '''ctrl''': boolean values.<br />
** '''repeat_on_hold''' {{DevFeature1.13|12}}: if ''yes'' (default ''no''), holding the hotkey will repeat the action continuously, unless it blocks input with something like '''[message]'''. Due to a bug, versions older than 1.13.12 always repeat the action, with no way to disable it.<br />
* '''[command]''': contains the WML actions to be executed when the menu item is selected. Again, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked on.<br />
** '''delayed_variable_substitution ''' (boolean yes|no, default: yes): If no, forces a variable substitution run onto the wml included in this [command] block. Use this, if you want variables which are to substitute to get the values they have at execution time of the event where this set_menu_item appears. Other than that, they get the values they have at invocation time of the menu item.<br />
<br />
== [clear_menu_item] ==<br />
<br />
Removes a menu item from the scenario.<br />
Normally menu items are, including all their defining wml, automatically carried over between scenarios. This tag prevents this. (The behavior is comparable to set_variable/clear_variable).<br />
* '''id''': (string): id of the menu item to clear. Can be a comma-separated list.<br />
<br />
== Other interface tags ==<br />
<br />
The following tags are also action tags:<br />
<br />
=== [change_theme] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Change the current interface theme.<br />
<br />
* '''theme''': The ID of the new theme. Use <code>theme=</code> (empty key) to switch back to the theme that the player has selected in Preferences. On <b>1.14.2</b> and later it is also possible to omit the key entirely to achieve the same effect (on previous versions this will crash the Lua engine).<br />
<br />
=== [item] ===<br />
Makes a graphical item appear on a certain hex. Note this only places the graphics for an item. It does not make the item do anything. Use a moveto event to make moving onto the item do something. <tt>''('''Hint:''' There are a number of predefined items that are used in various campaigns that you can make use of. You can find [http://www.wesnoth.org/macro-reference.xhtml#file:items.cfg a list of them] if you look into the items.cfg file in the wesnoth install directory (under /data/core/macros).)''</tt><br />
* '''x''', '''y''': the location to place the item. (only for [event][item]: full [[StandardLocationFilter|SLF]] support)<br />
* '''image''': the image (in ''images/'' as .png) to place on the hex. This image is aligned with the top-left of the hex (which is 72 pixels wide and 72 pixels tall). It is drawn underneath units. ''('''Hint:''' If using an image smaller than 72x72, then it might be useful to [[ImagePathFunctions#Blit_Function|BLIT]] the image onto <tt>misc/blank-hex.png</tt> (a blank 72x72 image).)''<br />
* '''halo''': an image to place centered on the hex. It is drawn on top of units. Use this instead of ''image'' if the image is bigger than the hex or if you want to animate an image.<br />
* '''name''' an id that can be used to remove the item.<br />
''Example (where the integer after the colon is the duration of each frame or square bracket expansion as per AnimationWML is used): halo=scenery/fire1.png:100,scenery/fire2.png:100,scenery/fire3.png:100,scenery/fire4.png:100,scenery/fire5.png:100,scenery/fire6.png:100,scenery/fire7.png:100,scenery/fire8.png:100''<br />
or equivalently (requires Wesnoth 1.11.2+):<br />
''halo=scenery/fire[1~8].png:100''<br />
* '''team_name''': name of the team for which the item is to be displayed (hidden for others). For multiple teams just put all the names in one string, for example separated by commas. {{DevFeature1.15|0}} In 1.14 the '''[side]team_name''' attribute was expected to be a substring of this '''team_name'''. In 1.15 both are expected to be comma-separated lists of names and the item is visible if the lists intersect. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* '''visible_in_fog''': whether the item should be visible through fog or not. Default yes.<br />
* '''redraw''': (boolean yes|no, default: yes): If no, disables implicit calls to [[InterfaceActionsWML#.5Bredraw.5D|[redraw]]] when placing the items.<br />
* '''[filter_team]''': {{DevFeature1.15|0}} A [[StandardSideFilter]]. Set '''team_name''' to the union of all '''[side]team_name''' attributes of all sides that match the SSF. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* {{DevFeature1.15|0}} If both '''team_name''' and '''[filter_team]''' are set, '''team_name''' is ignored.<br />
<br />
=== [remove_item] ===<br />
Removes any graphical items on a given hex.<br />
* [[StandardLocationFilter]]: the hexes to remove items off<br />
* '''image''': if specified, only removes the given image item (This image name must include any [[ImagePathFunctions|image path functions]] appended to the original image name.)<br />
* '''name''': removes an item with a previously defined name.<br />
<br />
=== [print] ===<br />
Displays a message across the screen. The message will disappear after a certain time.<br />
* '''text''': (translatable) the text to display.<br />
* '''size''': (default=12) the pointsize of the font to use<br />
* '''duration''': (default=50) the length of time to display the text for. This is measured in the number of 'frames'. A frame in Wesnoth is usually displayed for around 30ms.<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. {{DevFeature1.13|x}} Use of red, green, blue is now deprecated; use color=0,0,0 instead.<br />
<br />
=== [move_unit_fake] ===<br />
Moves an image of a unit along a certain path on the map. The path does not need to be a continuous list of adjacent hexes, so for example only the start and end points can be given, in which case the straightest line between those points will be calculated and used.<br />
* '''type''': the type of the unit whose image to use<br />
* '''x''': a comma-separated list of x locations to move along<br />
* '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
* '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
* '''gender''': the gender of the fake unit. Example: gender=female<br />
* '''variation''': the variation of the fake unit. Example: variation=undead<br />
* '''image_mods''': [[ImagePathFunctions|image path functions]] sequence to be applied on the fake unit.<br />
* '''force_scroll''': Whether to scroll the map or not even when [[#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to ''yes'' starting with version '''1.11.6'''; the attribute did not exist in previous versions and this action behaved as if ''no'' was passed instead.<br />
<br />
=== [move_units_fake] ===<br />
moves multiple images of units along paths on the map. These units are moved in lockstep.<br />
* '''force_scroll''': {{DevFeature1.15|0}} Has the same meaning as in [move_unit_fake] but a different default.<br />
* '''[fake_unit]''': A fake unit to move<br />
** '''type''': the type of unit whose image to use<br />
** '''x''': a comma-separated list of x locations to move along<br />
** '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
** '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
** '''skip_steps''': the number of steps to skip before this unit starts moving<br />
<br />
=== [hide_unit] ===<br />
Temporarily prevents the engine from displaying the given unit. The unit does not become invisible, as it would be with the '''[hides]''' ability; it is still the same plain unit, but without an image. Useful in conjunction with '''[move_unit_fake]''': to move a leader unit into position on-screen. Until 1.8 each '''[hide_unit]''' tag only hides one unit.<br />
* [[StandardUnitFilter]]: All matching units will be hidden<br />
<br />
=== [unhide_unit] ===<br />
Stops the currently hidden units from being hidden.<br />
* [[StandardUnitFilter]]: Only the matching units will be unhidden<br />
<br />
=== [lock_view] ===<br />
Locks gamemap view scrolling for human players, so they cannot scroll the gamemap view until it is unlocked. WML or Lua actions such as '''[scroll_to]''' will continue to work normally, as they ignore this restriction; the locked/unlocked state is preserved when saving the current game.<br />
<br />
This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
{{DevFeature1.13|8}} This now also blocks the player from zooming the gamemap view. WML or Lua zoom will continue to work normally.<br />
<br />
=== [unlock_view] ===<br />
Unlocks gamemap view scrolling for human players.<br />
<br />
=== [scroll] ===<br />
Scroll a certain number of pixels in a given direction. Useful for earthquake/shaking effects.<br />
* '''x''', '''y''': the number of pixels to scroll along the x and y axis<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll] happens for everyone.<br />
<br />
=== [scroll_to] ===<br />
Scroll to a given hex<br />
* [[StandardLocationFilter]], do not use a [filter_location] sub-tag. If more than one location matches the filter, only the first matching location will be used.<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex being scrolled to (defaults to ''no'').<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
<br />
=== [scroll_to_unit] ===<br />
Scroll to a given unit<br />
* [[StandardUnitFilter]]<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex the unit is on (defaults to ''no'').<br />
* '''for_side''': the side or sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
* '''[for_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
<br />
=== [select_unit] ===<br />
Selects a given unit.<br />
* [[StandardUnitFilter]]: The first unit found will be selected.<br />
* '''fire_event''': whether a ''select'' event should be triggered or not (def. ''no''). (Note that select events aren't multiplayer save.)<br />
* '''highlight''': whether the unit's current hex should be highlighted (def. ''yes'').<br />
<br />
=== [sound]===<br />
Plays a sound<br />
* '''name''': the filename of the sound to play (in ''sounds/'' as .wav or .ogg). This can be a comma-separated list, from which one sound will be chosen randomly.<br />
* '''repeat''': repeats the sound for a specified additional number of times (default=0)<br />
<br />
=== [sound_source] ===<br />
Creates a sound source. "Sound sources" is a general name for a mechanism which makes possible for map elements to emit sounds according to some rules, where "map elements" can be specific locations or terrain types. For now, only sound sources tied to locations are supported.<br />
* '''id''': a unique identification key of the sound source<br />
* '''sounds''': a list of comma separated, randomly played sounds associated with the sound source<br />
* '''delay''': a numerical value (in milliseconds) of the minimal delay between two playbacks of the source's sound if the source remains visible on the screen; if one scrolls out and back in, the source will be considered as ready to play<br />
* '''chance''': a percentage (a value from 0 to 100) describing the chance of the source being activated every second after the delay has passed or when the source's location appears on the screen (note that it cannot play more than one file at the same time)<br />
* '''check_fogged''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are fogged<br />
* '''check_shrouded''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are shrouded<br />
* '''x,y''': similar to x,y as found in a [[StandardLocationFilter]], these are the locations associated with the sound source<br />
* '''fade_range''' (default = 3): distance in hexes that determines a "circular" area around the one specified by '''full_range''' where sound volume fades out linearly<br />
* '''full_range''' (default = 14): distance in hexes that determines a "circular" area where source plays with full volume, relative to screen center<br />
* '''loop''': number of times a sound sample should be looped if it stays visible. -1 means infinite (~65000)<br />
<br />
=== [story] ===<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the story screen.<br />
* '''title''': Default title used if a part does not specify one — unlike the intro storyscreen, the scenario name is not used as a default title.<br />
* '''[part]''': As [[IntroWML]].<br />
<br />
=== [remove_sound_source] ===<br />
Removes a previously defined sound source.<br />
* '''id''': the identification key of the sound source to remove<br />
<br />
=== [music]===<br />
Switches to playing different music<br />
* '''name''': the filename of the music to play (in ''music/'' as .ogg)<br />
* see [[MusicListWML]] for the correct syntax<br />
===[volume]===<br />
Changes the game volume to a percent of the preferences volume for the game being played. Values can go from 0 to 100: <br />
* '''music''': Changes the music volume.<br />
* '''sound''': Changes the sound volume.<br />
=== [color_adjust]===<br />
Tints the color of the screen.<br />
* '''red''', '''green''', '''blue''': values from -255 to 255, the amount to tint by for each color<br />
=== [delay] ===<br />
Pauses the game.<br />
* '''time''': the time to pause in milliseconds<br />
* '''accelerate ''' (boolean yes|no, default no): {{DevFeature1.13|0}} whether the delay is affected by acceleration. When [delay] is used to make an animation, this should be set to yes so that your animation matches the ones generated by the game.<br />
<br />
=== [redraw] ===<br />
Redraws the screen (this normally isn't done during events, although some of the other interface actions cause the screen or parts of it to be redrawn).<br />
* '''clear_shroud''' (boolean yes|no, default no): If yes, clears fog and shroud around existing units. Useful if you, for example, spawn friendly units in the middle of an event and want the shroud to update accordingly (otherwise units that spawn inside fog would remain invisible for the duration of the event, since the fog would not automatically get cleared around them).<br />
* '''[[StandardSideFilter]]''': the sides for which to recalculate fog and shroud.<br />
* '''side''': If used (forces clear_shroud=yes), clears fog and shroud for that side.<br />
<br />
=== [unit_overlay] ===<br />
Sets an image that will be drawn over a particular unit, and follow it around<br />
* [[StandardUnitFilter]]: All matching units will get the overlay (do not use [filter])<br />
* '''image''': the image to place on the unit<br />
<br />
=== [remove_unit_overlay] ===<br />
removes a particular overlayed image from a unit<br />
* [[StandardUnitFilter]]: The overlay will get removed from all matching units (do not use [filter])<br />
* '''image''': the image to remove from the unit<br />
<br />
=== [animate_unit] ===<br />
Uses an animation of a unit to animate it on screen (if the unit has the corresponding animation).<br />
* '''flag''': The key to find the custom animation in the unit description (see the '''[extra_anim]''' description in [[AnimationWML]]). Standard animations can be triggered with the following keywords: ''leading recruited standing idling levelout levelin healing healed poisoned movement defend attack death victory pre_teleport post_teleport''<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument, see [[FilterWML]]. By default, the unit at the event location will be animated. You can use this tag to choose any other unit to animate.<br />
* '''[primary_attack]''': If this tag is not present, the filter for animation will be triggered with no attack. If it is here, all attacks from the unit will be filtered, and a matching one will be used to filter the animation. Takes a weapon filter as argument, see [[FilterWML]].<br />
* '''[secondary_attack]''': Similar to '''[primary_attack]'''. May be needed to trigger a defense animation correctly, if there are more than one animations available for the defending unit.<br />
* '''hits''': yes/no/hit/miss/kill: which according variation of a attack/defense animation shall be chosen (required)<br />
* '''text''': a text to hover during the animation <br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''': red value for the text color (0-255)<br />
* '''green''': green value for the text color<br />
* '''blue''': blue value for the text color<br />
* '''with_bars''': yes/no: whether to display the status bars during the animation (e.g. the hitpoint bar)<br />
* '''[animate]''': a sub block with the same syntax as '''[animate_unit]''' except that the '''[filter]''' block is mandatory to find the unit. This block will find and animate another unit simultaneously.<br />
* '''[facing]''': a [[StandardLocationFilter]] specifying what direction the unit should be facing when animated<br />
<br />
=== [label] ===<br />
Places a label on the map.<br />
* '''x''', '''y''': the location of the label. {{DevFeature1.13|1}} (only for [event][label]: full [[StandardLocationFilter|SLF]] support)<br />
* '''text''': what the label should say<br />
* '''team_name''': if specified, the label will only be visible to the given team.<br />
* '''color''': color of the label. The format is r,g,b; r, g and b are numbers between 0 and 255.<br />
* '''visible_in_fog''': whether the label should be visible through fog or not. Default yes.<br />
* '''visible_in_shroud''': whether the label should be visible through shroud or not. Default no.<br />
* '''immutable''': whether this label is protected from being removed or changed by players. Default yes.<br />
* '''category''': the Show/Hide Labels dialog allows showing/hiding all labels of a given category by toggling a checkbox.<br />
* '''tooltip''': A tooltip visible when mouseovering the hex the label is on<br />
* '''side''': the number of the side that placed the label. Can be 0 for labels placed by WML.<br />
<br />
=== [floating_text]===<br />
Floats text (similar to the damage and healing numbers) on the given locations.<br />
* [[StandardLocationFilter]]: the text will be floated on all matching locations simultaneously.<br />
* '''text''': the text to display.<br />
<br />
The default text color is <span style="color: #6b8cff;">'''#6b8cff'''</span>. To change the color, use [[#Formatting|Pango markup]]. For example:<br />
<br />
<pre><br />
# Float some golden yellow text at 20,20.<br />
[floating_text]<br />
x,y=20,20<br />
text="<span color='#cccc33'>" + _ "Your text here" + "</span>"<br />
[/floating_text]<br />
</pre><br />
<br />
=== [deprecated_message] ===<br />
Shows a deprecated message in the message area, this feature is only intended to be used to warn about deprecated macros in mainline. The message is not translatable.<br />
* '''message''': the message to show.<br />
* '''level''': {{DevFeature1.13|10}} The deprecation level, a number from 1 to 3.<br />
* '''what''': {{DevFeature1.13|10}} The name of the thing being deprecated. Use this instead of '''message''' if possible; a stock message will be generated from it. Use '''message''' only if more information is required; it will be appended to the stock message. This should not be translatable<br />
* '''version''': {{DevFeature1.13|10}} For deprecation levels 2 and 3, this indicates the version in which the feature could be removed. It does ''not'' indicate the version in which it became deprecated. <br />
<br />
The meanings of the deprecation levels are as follows:<br />
<br />
# Deprecated, but will only be removed if absolutely necessary. The '''version''' key is ignored.<br />
# It will be removed no earlier than a specified version.<br />
# It will be removed in the next stable version<br />
# It has already been removed, leaving just a stub to inform users of how to update their code.<br />
<br />
Note that as of 1.13.11, deprecation messages show only in the log, not in the chat message area. The '''message''' can be translatable, but does not need to be.<br />
<br />
=== [wml_message] ===<br />
Outputs a message to Wesnoth's console output. Intended for campaign designers to output silent text to the console, without annoying the player; then, that text might contain information useful for later bug-reporting. The log domain for it is '''wml''', and the '''debug/dbg''' log level is available for use with the '''logger''' attribute. Depending on the current log level ('''error''' by default), which may be changed with the in-game :log command, or the --log-<level>=wml command line switch, the messages are echoed to the in-game chat.<br />
* '''message''': the message to show.<br />
* '''logger''': the Wesnoth engine output logger that should catch the text; this might be 'err' (the errors log level), 'warn'/'wrn' (the warnings log level) or anything else (the information log level). Not all information will be displayed depending on the log level chosen when starting Wesnoth.<br />
<br />
Note: As of 1.9.4/1.9.5 (r48805) the following "loggers" should work: If in [wml_message]: err/error, warn/wrn/warning, debug/dbg; using the :log command: Only the long forms error, warning, info and debug (this part gathered by trying rather than source inspecting). The long forms are most likely also the only ones working when starting wesnoth with --log-<level>=wml.<br />
For log level warning or error (as during normal play), only wml_messages with logger error or warning display (for both). With logger info or debug, additionally wml_messages with logger info or debug display (for both).<br />
<br />
=== [test_condition] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Evaluates the contained conditional tags. If they evaluate to the expected value, it prints out a message to the console explaining which part of the condition caused this result in a way similar to [wml_message]. This can be used if your conditional test is failing and you're not sure why.<br />
<br />
* '''result''': Whether you expect the conditions to fail or succeed. If no (the default), a message will be printed if the conditional tags fail. If yes, a message will instead be printed if the conditional tags pass.<br />
* '''logger''': Same as for [wml_message]. Defaults to "warning".<br />
<br />
=== [open_help] ===<br />
Opens the in-game help.<br />
* '''topic''': the id of the topic to open<br />
=== [show_objectives] ===<br />
refreshes the objectives defined by [objectives] and its [show_if] tags, and displays them. (It is also called whenever the user explicitly asks for the objectives; this matters only if the tag was overridden by a [[LuaWML#register_wml_action|Lua]] script.)<br />
* '''side''': the side to show the objectives. If not set, all sides are used.<br />
* '''[[StandardSideFilter]]''' tags and keys: Tag affects the matching sides instead of just all or the one given by the integer value of the side= key.<br />
<br />
=== [chat] ===<br />
Displays a message in the chat area, not visible for observers. Alternative unconditionally visible for everyone: [[LuaWML:Display#wesnoth.message]]. {{DevFeature1.13|9}} can be visible for observers.<br />
* '''speaker''': (default="WML") A string for the name of the sender of the message.<br />
* '''message''': The message that should be displayed.<br />
* '''observable''' (boolean yes|no, default yes): {{DevFeature1.13|9}} Whether the message is displayed for observers.<br />
* '''[[StandardSideFilter]]''' tags and keys as argument; if the same client controls multiple sides that match, then the message will only be displayed once.<br />
<br />
=== [zoom] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Changes the zoom level of the map.<br />
<br />
* '''factor''': The new zoom factor<br />
* '''relative''': If yes, zoom relative to current zoom level. Otherwise, set the absolute zoom level. Default no.<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for interface actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{HIGHLIGHT_UNIT}''' Highlight a unit on the map. Use this to show important units<br />
* '''{HIGHLIGHT_IMAGE}''' Places and highlights an image on the map. Use this to show important items or locations<br />
* '''{SET_IMAGE}''' Places an image on the map which has no other function.<br />
* '''{QUAKE <soundfile>}''' Creates a tremor-like screenshake and plays <soundfile>. For example, '''{QUAKE (rumble.ogg)}'''.<br />
* '''{FLASH_WHITE}''' Flash the screen white momentarily. You can also replace WHITE with RED, BLUE or GREEN for a different colour.<br />
<br />
== See Also ==<br />
* [[DirectActionsWML]]<br />
* [[InternalActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=OOS_(Out_of_Sync)&diff=60190OOS (Out of Sync)2019-02-12T03:19:06Z<p>Gfgtdf: /* List of Non Mp/Replay safe Wml/Lua functions */</p>
<hr />
<div>OOS is an error that occurs in a Wesnoth multiplayer scenario or a replay when two machines disagree (or one machine disagrees with a replay file) about the game state, i.e. which units are where, how much HP they have, how much gold each side has, etc. More precisely, OOS is announced when a client reads a command, such as "move Dwarf Fighter 8,4 -> 8,5 -> 8,6" or "recruit Gryphon Rider 9,7", which is illegal or nonsensical based on its understanding of the game state.<br />
<br />
OOS could in principle be caused by network issues such as dropped packets, by players having mismatched game files, or even by cheating, but it is commonly caused by scenario designers / add-on makers writing unsafe code. This page is about how to write WML that won't cause OOS. If you want to know what you should do if you get OOS in an online game, see [[http://forums.wesnoth.org/viewtopic.php?f=6&t=38881&p=554259 here]].<br />
<br />
== Why does OOS happen? ==<br />
<br />
=== Game begins out of sync ===<br />
<br />
At the beginning of an mp game the host sends the content of the [multiplayer] or [scenario] to the other clients (via the mp server). All other information, specially [unit]s [terrain]s and toplevel [lua] tags are not transmitted to other players. Instead it is expected that the other players have this data locally available and that their data matches the data of the host. If that is not the case it can cause OOS.<br />
<br />
This can happen if one of the players has modified their game files, or if the players don't have matching add-on versions.<br />
<br />
The OOS may still not appear until a mismatched resource actually appears and does something.<br />
<br />
=== Game becomes out of sync ===<br />
During the actual game all clients have their own local gamesate. The Clients communicate by sending 'player actions' like 'move unit at (3,4) to (5,5) with the route ((3,4),(3,5),(4,5),(5,5))'. These actions are evaluated on the other clients which should lead to the same local gamesate on all clients (asuming that they had the same local gamestate before that action). If at any time clients don't have the same local gamestate we call that OOS. The clients usually send these actions as soon as they know that they cannot be undone. Those actions that are sended to the other clients are called "synced user actions". For example move,recall,recuit ... are such actions. There are also unsynced user action like "select" that only happen on one client and are not sended to other clients. The consequence is that "select" events only run on one client, thus changing the gamestate from inside a select event results in OOS.<br />
<br />
A complete list of unsynchronized events can be found here: [[EventWML#Multiplayer_safety]].<br />
<br />
The replay works the same way: <br />
<br />
the replay begins with the start gamesate and then eveluates all the synced user actions it can find on the replay. If the resulted gamesate is different than the original gamesate we have an OOS. That's why in most times replay safety is the same as multiplayer safety.<br />
<br />
Generally speaking a replay file receives the same kind of information about the game that a multiplayer observer of a game would receive, so any technique which would cause OOS for multiplayer will also cause corrupted replays.<br />
<br />
If wml/lua code is invoked by a synced user action and thus runs on all clients we say "the code runs in a synced context" otherwise not. <br />
{{DevFeature1.13|0}} You can know whether the current code runs in a synced context by checking wesnoth.current.synced_state.<br />
<br />
In order to get the same local gamesate on all clients you should only make the gamesate depend on deterministic functions that return the same value on all clients, for example side.cotroller s getter or math.rand is no such function. If you want to call these functions you should use wesnoth.syncronize_choice which allows you to run code on one client and then return the result to all clients so all clients are guaranteed to get the same result. But note that becasue the code in synconize_choice only runs one one client it should only calculate the return value and not change the gamestate.<br />
<br />
=== The rng ===<br />
Wesnoth has a synced random number generator that returns the same value on all clients, this rng is uses by <br />
* [set_variable] rand=.. [/set_variable]<br />
* traits & name generation in [unit]<br />
* calculation whether an attack hits<br />
To keep the rng in sync it is important to call the rng the same number of times on all clients. Othwewise the random results will be of by one which causes OOS. Luckily the synced rand is smart enough to know whether we are in a synced context. An it redirects to an unsynced rng (like math.random) if it was called from outside a synced context so that calling this rng from outside teh synced context doesnt have an effect on the rng used in the synced context.<br />
<br />
This rng gets reseeded at the beginning of every "synced user action", the reason is, that otherwise players could know which random results they'll get next. Expecialy im MP this is very bad since it means players could know whether an attack will hit or not before they command it. In netwroked Mp the Client get their random seeds from the server. This happens layzly that means it doesn't happen at the beginning of the synced user action, but it happens as soon as the rng is used inside the synced context for this action (Especialy it doesn't happen if the rng isn't used). Since sending the "generate seed" to the server cannot be undone, an action that invoked the synced rng (for example attacks, but also moves with a [set_variable] rand=.. in a moveto event) cannot be undone. This is usually the intended behaviour since calling the rng usually implies a information gain that shouldn't be able to be undone. If you want a random number but don't want to make the gamestate depend on it (maybe just use it for visual features), and thus want the action to be undoable you should use the unsynced math.random from lua.<br />
<br />
=== Found dependent command ===<br />
<br />
It's posible to get a OOS eror with the message "Found (in-)dependent command" or siilar here is explained what this means: During the game the clients send each other packages ([command] see http://wiki.wesnoth.org/ReplayWML). There are 2 types of these packages: the 'normal' commands that contains new user actions like attack, recruit, recall, move... . And there are the 'dependent' packages that contains answer to questions asked to specific clients (the results of local choices). For example advancement choices. But also new random seeds (questions asked to the server) and get_global_variable are in this category. If a client received an answer to a local choice when none was expected the games gives a "Found dependent command when is_synced=false" OOS error message. The opposite sitation when a client expectes an answer to a local choice but receives a new user action also gives a OOs message.<br />
<br />
== Some examples ==<br />
<br />
If Player A changes the White Mage's magic attack from 9-3 to 10-3 while Player B did not, that would result in an OOS since as the game progresses each client would see a different amount of damage being done.<br />
<br />
Say that the White Mage attacks a Spearman with 30 HP left and hits all 3 times. To Player A, it would appear that the Spearman died. However Player B would see that unit as having 3 HP left. As a result...<br />
<br />
* What if Player A then tried to move another unit to where the Spearman was? To Player A's client, it would work fine. To Player B's client, that wouldn't make any sense, since it's not possible to have multiple units on the same hex.<br />
* What if Player B tried to attack one of Player A's units? To Player B's client it seems like a normal move, but to Player A's client it seems like an empty hex is trying to attack him.<br />
<br />
== Hints To Debug OOS Erros ==<br />
<br />
As noted before, OOS happens when two clients disagree about the current gamestate, So if ina game with clients A, B and C, client A got an OOS during the turn of client B it (often, not always) indicates that client A and B disagree about the gamstate, in this situation client C an often be used to decide which client did the wrong calculations, if client C also got an oos errormessage during the turn of client B, it probably client B that did the wrong calculations, otherwise its probably side A. The most common sources of OOS are:<br />
<br />
1. Bad add-ons: in particular you need to be aware of the fact that addons can change the gamestate and cause OOS even if they are not currently active (for example as a modification or a mp scenario ), add-ons can cause OOS by just having them installed even if the seem to be complteley unrelated to the current game.<br />
<br />
2. User changing the game/addons files : it often unclear to users which part of the data can be changed and which can not be changes without causing OOS. For example some mp scenarios include lua code via macro inclusion ''code={myluafile.lua}'' while others include lua code via dofile/require ''wesnoth.dofile("myluafile.lua")'', in the former case it is usually safe to change the lua files because the hosts sends the other client his version of the lua file along with the other scenario content, while in the later case it fill usually lead to OOS.<br />
<br />
3. Outdated wesnoth versions. While we try to keep the wesnoth versions mp compatible, it is still important to keep your wesnoth version up to date. In particular to avoid OOS erros casued by engine bug that were fixed in newer versions, you can use the mp server command ''/q version <playername>'' to figure out what wesnoth version another player is using.<br />
<br />
4. cheating players: not much to say, player can intentionally change wesnoth game files in a stupid way hoping it would give them an advantage when it will actually just cause OOS.<br />
<br />
5. Engine bugs: Wesnoth is not always bugfree, the main diffculty in investigating engine OOS errors is that most of the OOS erros reported actually come from one of the other posibilities above, so its somehow hard to find the 'real' oos engine bugs in the wild. Some features in particular 'delayed shroud updates' and 'multiplayer campaigns' have often casued OOS in the past though and it possible they they will be broken agian in the future due to their complex nature.<br />
<br />
== How to make your code safe ==<br />
<br />
* Make the WML run at a synchronized time instead, i.e. in a moveto event.<br />
* Use helper.rand instead of math.random, unless you know exactly what you are doing.<br />
* Use Lua wesnoth.synchronize_choice when gathering informaton to make sure that all clients match. Note that this function only works correct in syncronized events.<br />
<br />
=== List of Non Mp/Replay safe Wml/Lua functions ===<br />
These functions/values might return different values on different clients or in replays. To prevent OOS you must use wesnoth.synchronize_choice or {{DevFeature1.13|0}} [sync_variable] to query these values when you want to change the gamestate depending on these values.<br />
* Using functions that depend on other installed addons. For example, ''#wesnoth.unit_types'' will usually be different on each client.<br />
* Using translatable strings for gamestate calculations; obviously the value of these strings depends on each client's language setting.<br />
* Unsafe events, see [[EventWML#Multiplayer_safety|here]] for more detail<br />
* Unit attributes, accessible via stored units, lua proxy units, or unit filters (via <tt>[filter_wml]</tt>)<br />
** unit.goto_x and unit.goto_y (used by the ai and by multi turn moves internally)<br />
** unit.facing (in some cases like when unstoring units the unit facing might be set randomly)<br />
** unit.name (it is possible for players to rename units, also in mp the leaders names changes whenever a side controller changes, also see the point below about any attribute changing the visual appearance.)<br />
** any attribute describing the visual appearance of that unit (unit.overlays, unit.profile etc.). In default wesnoth they may be be the same on all clients, but people usually assume that they can change the visuals of wesnoth by modifying the cfg files or via [modification]s in add-ons without causing OOS.<br />
* Filters that cause side-effects, especially when used in unit abilities and weapon specials.<br />
** Clearly a filter should not change the gamestate in a unsynced context.<br />
** In the past the order in which filters are evaluated has been changed even during stable versions, so it is possible that even in a synced context a filter might be skipped on some clients only. In conclusion it is better to not rely on the order in which filters are evaluated or test in each wesnoth version. In particular:<br />
*** The <tt>lua_function</tt> key calls an arbitrary Lua function. If the function called causes ''any'' change to the gamestate, you could get an out-of-sync error. This includes simply generating a random number, even using synchronized functions.<br />
*** The <tt>formula</tt> is safe as long as you do not use the dice operator in the formula.<br />
* Variables/wml tags<br />
** side.controller (gained by [store_side] or wesnoth.sides) – this variable will be different for each client. An exception is when controller is "null" which happens if and only if it is "null" on all other clients as well.<br />
** [set_variable] time=stamp - obviously the result of this operation will be different for all clients<br />
* Lua functions:<br />
** math.random()<br />
** wesnoth.game_config.debug, .version have (possibly) different values<br />
** any dialog which queries input from a client (eg wesnoth.show_dialog)<br />
** wesnoth.sides[i].controller (same as with [store_side]), wesnoth.sides[i].is_local<br />
** any non mp-safe wml tag called by lua<br />
<br />
== Additional tricks and tips ==<br />
<br />
* You can modify some things. So while you shouldn't change the damage of a unit's attack, there's nothing wrong with changing it's portrait.<br />
<br />
== See Also ==<br />
<br />
[[MultiplayerContent]]<br />
<br />
[[Category:WML_Tips]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=UnitTypeWML&diff=60158UnitTypeWML2019-01-20T22:46:33Z<p>Gfgtdf: /* After max level advancement (AMLA) */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
__TOC__<br />
<br />
== Unit Type ==<br />
<br />
Each '''[unit_type]''' tag defines one unit type. (for the use of [unit] to create a unit, see [[SingleUnitWML]])<br />
<br />
Unit animation syntax is described in [[AnimationWML]]. In addition to the animation tags described there, the following key/tags are recognized:<br />
* '''[advancefrom]''': Defines the previous unit type on the advancement tree. Allows a campaign-specific unit to be spliced into an already existing advancement tree. It should generally be used only inside a campaign ifdef, to prevent changes to other campaigns. Since all multiplayer content shares MULTIPLAYER define, using advancefrom changes unit type even if the addon is not actively used. For that reason multiplayer advancefrom may only be used with unit types defined in the same addon - then everyone who has the unit has it with same advancements. This tag makes changes to the ''advances_to'' and ''experience'' keys of a base unit to make it advance into this unit. It takes these keys:<br />
** ''unit'': the id of the base unit from which this unit advances. This adds the unit into the list of units which ''unit'' can advance into.<br />
** ''experience'': (optional) If present the experience needed to advance is set to this value. If there are more than one [advancefrom] tags referencing the same base unit within the same preprocessor scope (e.g. a campaign #ifdef) with experience= keys, the lowest value of these is chosen. Note: this will also lower the experience required to advance to other units which the base unit can advance into.<br />
: If the previous unit type makes use of '''[male]''' and/or '''[female]''' tags, then the current (new) unit type is expected to also. That is, the subtypes defined by those tags will only receive this advancement if the new type has a corresponding tag.<br />
* '''advances_to''': When this unit has ''experience'' greater than or equal to ''experience'', it is replaced by a unit of the type that the value of ''advances_to'' refers to. All modifications that have been done to the unit are applied to the unit it is replaced by. The special value 'null' says that the unit does not advance but gets an AMLA instead. Can be a comma-separated list of units that can be chosen from upon advancing.<br />
* '''alignment''': one of lawful/neutral/chaotic/liminal (See [[TimeWML]]). Default is "neutral".<br />
* '''attacks''': the number of times that this unit can attack each turn.<br />
* '''cost''': when a player recruits a unit of this type, the player loses ''cost'' gold. If this would cause gold to drop below 0, the unit cannot be recruited.<br />
* '''recall_cost''': {{DevFeature1.13|0}} the default recall cost of units of this type, overriding the recall cost set in scenario [[SideWML|[side]]] tags or the global [[GameConfigWML|[game_config]]] value. Individual units may override this value in [[SingleUnitWML|[unit]]]. A value of -1 is equivalent to not specifying this attribute. {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
* '''description''': (translatable) the text displayed in the unit descriptor box for this unit. Default 'No description available...'. <br />
* '''do_not_list''': Not used by the game, but by tools for browsing and listing the unit tree. If this is 'yes', the unit will be ignored by these tools. {{DevFeature1.13|?}} When placing units in debug mode this unit isn't listed (but can still be placed using the :create command). This restriction is lifted in version <b>1.14.3</b>.<br />
* '''ellipse''': the ellipse image to display under the unit, which is normally team-colored. Default is "misc/ellipse". "-nozoc" and "-leader" are automatically appended for units without zone of control and with canrecruit=yes respectively. The [http://www.wesnoth.org/macro-reference.xhtml#IS_HERO IS_HERO]/[http://www.wesnoth.org/macro-reference.xhtml#MAKE_HERO MAKE_HERO]/[http://www.wesnoth.org/macro-reference.xhtml#UNMAKE_HERO UNMAKE_HERO] macros change the ellipse to/back from "misc/ellipse-hero". Finally, setting this to "none" will cause the unit to not have any ellipses displayed under it regardless of the user's preferences.<br />
::WARNING: Be aware that setting this to "misc/ellipse-hero" for a unit with canrecruit=yes will result in the ellipse being "misc/ellipse-hero-leader", which is not a supported combination (it doesn't have a graphic, and will cause error logs that the graphic is missing).<br />
* '''experience''': When this unit has experience greater than or equal to ''experience'', it is replaced by a unit with 0 experience of the type that the value of ''advances_to'' refers to. All modifications that have been done to the unit are applied to the unit it is replaced by.<br />
* '''flag_rgb''': usually set by [http://www.wesnoth.org/macro-reference.xhtml#MAGENTA_IS_THE_TEAM_COLOR MAGENTA_IS_THE_TEAM_COLOR]; specifies the colours in the base flag to use for team-colouring the unit, expressed as a colour name (such as magenta) or a comma-separated list of RGB values (in hex format).<br />
* '''gender''': has a value of either ''male'' or ''female'', and determines which of the keys ''male_names'' and ''female_names'' should be read. When a unit of this type is recruited, it will be randomly assigned a name by the random name generator, which will use these names as a base.<br />
* '''halo''': an image to place centered on the unit. It is drawn on top of the unit, and on top of surrounding units if the image is larger than one hex. It works similarly to the halo attribute of {{tag|InterfaceActionsWML|item}}, and it can be animated with a comma-separated list of images.<br />
* '''hide_help''': (yes|no) default=no. Determines if the unit type will appear in the in-game help.<br />
* '''hitpoints''': the maximum HP that the unit has, and the HP it has when it is created.<br />
* '''id''': the value of the ''type'' key for units of this type. This is required and must be unique among all [unit_type] tags. An ''id'' should consist only of alphanumerics and spaces (or underscores). ''type'' keys are found in [[SingleUnitWML]] and [[FilterWML]]. For example, id=Drake Flare<br />
::WARNING : characters "$", "&", "*", "-", "(" and ")" are illegal for use in the unit type id and must be avoided because they might lead to corrupted saved games<br />
*'''ignore_race_traits''': 'yes' or 'no' (default). Determines whether racial traits (see [[UnitsWML]]) are applied. <br />
* '''image''': sets the base image of the unit, which is used on the map.<br />
* '''image_icon''': sets the image used to represent the unit in areas such as the attack dialog and the unit image box in the sidebar. [[ImagePathFunctionWML#Crop_Function|~CROP]] function can be useful here. You can see Loyalists Paladin as an example.<br />
* '''level''': the amount of upkeep the unit costs. After this unit fights, its opponent gains ''level'' experience. See also kill_experience ([[GameConfigWML]]), and leadership ([[AbilitiesWML]]).<br />
* '''movement''': the number of move points that this unit receives each turn.<br />
* '''movement_type''': See [[UnitsWML#.5Bmovetype.5D|movetype]]. Note that the tags '''[movement_costs]''', '''[vision_costs]''', '''[defense]''', and '''[resistance]''' can be used to modify this movetype.<br />
* '''name''':(translatable) displayed in the Status Table for units of this type.<br />
* '''num_traits''': the number of traits that units of this type should receive when they are recruited, overriding the value set in the [race] tag.<br />
* '''profile''': the portrait image to use for this unit type. You can also set a portrait for an individual unit instead of the whole unit type (see [[SingleUnitWML]]). The engine first looks for the image in the transparent subdirectory and if found that image is used. If not found it will use the image as-is. Depending on the size the engine will or will not scale the image, the cutoff currently is at 300x300. For images which should only be shown on the right side in the dialog append ~RIGHT() to the image.<br />
** If "unit_image" is given instead of a filename, uses the unit's base image as the portrait (in the same manner that unit types without portraits do by default).<br />
* '''small_profile''': the image to use when a smaller portrait is needed than the one used for messages (e.g., in the help system). When this attribute is missing, the value of the '''profile''' attribute is used instead. When present, the heuristic for finding a transparent portrait is disabled for the '''profile''' attribute, so the correct '''profile''' should be set too. If '''profile''' is not present, '''small_profile''' is ignored. Note that image modifiers are allowed; they might be useful for cropping and rescaling a portrait:<br />
small_profile="portraits/elves/transparent/marksman+female.png~CROP(0,20,380,380)~SCALE(205,205)"<br />
profile="portraits/elves/transparent/marksman+female.png"<br />
* '''race''': See {{tag|UnitsWML|race}}. Also used in standard unit filter (see [[FilterWML]]). Mainline Wesnoth features following values: bats, drake, dwarf, elf, falcon, goblin, gryphon, human, khalifate, lizard, mechanical, merman, monster, naga, ogre, orc, troll, undead, wolf, wose. They are defined in /data/core/units.cfg.<br />
* '''undead_variation''': When a unit of this type is killed by a weapon with the plague special, this variation is applied to the new plague unit that is created, whatever its type. For example, if the plague special creates Walking Corpses and undead_variation is set to "troll", you'll get a troll Walking Corpse. Defaults to the undead_variation set in this unit type's race.<br />
* '''usage''': the way that the AI should recruit this unit, as determined by the scenario designer. (See ''recruitment_pattern'', [[AiWML]]). The following are conventions on usage:<br> ** ''scout'': Fast, mobile unit meant for exploration and village grabbing.<br> ** ''fighter'': Melee fighter, melee attack substantially more powerful than ranged.<br> ** ''archer'': Ranged fighter, ranged attack substantially more powerful than melee.<br> ** ''mixed fighter'': Melee and ranged fighter, melee and ranged attacks roughly equal.<br> ** ''healer'': Specialty 'heals' or 'cures'.<br>Note that this field primarily affects recruitment. It also has a small effect on unit movement (the AI tries to keep scouts away from enemies, to some extent). It does not affect the AI's behavior in combat; that is always computed from attack power and hitpoints. Non-standard usages may be used as well.<br />
* '''vision''': the number of vision points to calculate the unit's sight range. Defaults to ''movement'' if not present.<br />
* '''jamming''': the number of jamming points. Defaults to ''0'' if not present. See [[UnitsWML#.5Bmovetype.5D|[jamming_costs]]]<br />
* '''zoc''': if "yes" the unit will have a zone of control regardless of level. If present but set to anything other than "yes," the unit will have no zone of control. If the tag is omitted, zone of control is dictated by unit level (level 0 = no zoc, level 1+ = has zoc).<br />
* '''die_sound''': sets the sound, which is used when the unit dies.<br />
* '''healed_sound''': sets the sound used when the unit is healed in any way (default: heal.wav).<br />
* '''hp_bar_scaling''': Overrides the attribute in ([[GameConfigWML]]).<br />
* '''xp_bar_scaling''': Overrides the attribute in ([[GameConfigWML]]).<br />
* '''bar_offset_x''', '''bar_offset_y''': The offset of the hp and xp bars from the unit's sprite.<br />
<br />
== After max level advancement (AMLA) ==<br />
* '''[advancement]''': describes what happens to a unit when it reaches the XP required for advancement. It is considered as an advancement in the same way as advancement described by '''advances_to'''; however, if the player chooses this advancement, the unit will have one or more effects applied to it instead of advancing.<br />
** '''id''': unique identifier for this advancement; ''Required'' if there are multiple advancement options, or if ''strict_amla=no''.<br />
** '''always_display''': if set to true displays the AMLA option even if it is the only available one.<br />
** '''description''': a description displayed as the option for this advancement if there is another advancement option that the player must choose from; otherwise, the advancement is chosen automatically and this key is irrelevant.<br />
** '''image''': an image to display next to the description in the advancement menu.<br />
** '''max_times''': default 1. The maximum times the unit can be awarded this advancement. Pass -1 for "unlimited".<br />
** '''strict_amla''': (yes|no) default=no. Disable the AMLA if the unit can advance to another unit.<br />
** '''major_amla''': (yes|no) default=no. Sets whether the unit's XP bar is blue(=yes) or purple(=no). In case of more [advancement] tags, if there is one with major_amla=yes, the XP bar will be blue.<br />
** '''require_amla''': An optional list of AMLA ''id'' keys that act as prerequisites for this advancement to become available. Order is not important, and an AMLA id can be repeated any number of times to indicate that another advancement must be chosen several times before this advancement option will become available.<br />
*** example: <tt>require_amla=tough,tough,incr_damage</tt> assumes there exist other [advancement] options called ''id=tough'' and ''id=incr_damage''. Once ''tough'' is chosen twice and ''incr_damage'' is chosen once, then the current [advancement] will become available.<br />
*** ''require_amla=tough,incr_damage,tough'' is an equivalent way of expressing this.<br />
** '''exclude_amla''': {{DevFeature1.13|2}} An optional list of AMLA ''id'' keys that represent AMLAs that are mutually exclusive to this one. Order is not important, and an AMLA id can be repeated. If the unit already has any of the AMLAs that appear once in this list, then this AMLA will not be made available. If an AMLA id appears multiple times in the list, then this AMLA will be made available only if the other AMLA has been chosen less than the number of times it appears in the list. Of course, for this to really make two AMLAs mutually exclusive, you need to add ''exclude_amla'' to both AMLA defintions.<br />
** '''[effect]''': A modification applied to the unit whenever this advancement is chosen. See [[EffectWML]]<br />
<br />
== Attacks ==<br />
* '''[attack]''': one of the unit's attacks.<br />
** '''description''': a translatable text for name of the attack, to be displayed to the user.<br />
** '''name''': the name of the attack. Used as a default description, if ''description'' is not present, and to determine the default icon, if ''icon'' is not present (see below). Non-translatable. Used for the ''has_weapon'' key and animation filters; see [[StandardUnitFilter]] and [[AnimationWML]]<br />
** '''type''': the damage type of the attack. Used in determining resistance to this attack (see {{tag|UnitsWML|movetype|resistance}}).<br />
** '''[specials]''': contains the specials of the attack. See [[AbilitiesWML#The_.5Bspecials.5D_tag|AbilitiesWML]].<br />
** '''icon''': the image to use as an icon for the attack in the attack choice menu, as a path relative to the images directory. Defaults to the attack's name in the attacks directory (Ex. if ''name=sword'' then default is ''icon=attacks/sword.png''). <br />
** '''range''': the range of the attack. Used to determine the enemy's retaliation, which will be of the same type. Also displayed on the status table in parentheses; 'melee'(default) displays "melee", while 'ranged' displays "ranged". Range can be anything. Standard values are now "melee" and "ranged". From now on, ''short'' and ''long'' will be treated as totally different ranges. You can create any number of ranges now (with any name), and units can only retaliate against attacks for which they have a corresponding attack of the same range. This value is translatable.<br />
** '''damage''': the damage of this attack<br />
** '''number''': the number of strikes per attack this weapon has<br />
** '''accuracy''': a number added to the chance to hit whenever using this weapon offensively (i.e. during a strike with this attack, regardless of who initiated the combat); negative values work too<br />
** '''parry''': a number deducted from the enemy chance to hit whenever using this weapon defensively (i.e. during the enemy's strike, regardless of who initiated the combat); negative values work too<br />
** '''movement_used''': determines how many movement points using this attack expends. By default all movement is used up, set this to 0 to make attacking with this attack expend no movement.<br />
** '''attack_weight''': helps the AI to choose which attack to use when attacking; highly weighted attacks are more likely to be used. Setting it to 0 disables the attack on attack<br />
** '''defense_weight''': used to determine which attack is used for retaliation. This affects gameplay, as the player is not allowed to determine his unit's retaliation weapon. Setting it to 0 disable the attacks on defense <br />
For the weight settings, the engine usually chooses the attack with the best average total damages * weight (default weight = 1.0).<br />
<br />
== Other tags ==<br />
* '''[base_unit]''': Contains one attribute, '''id''', which must be the ID of a unit type. If specified, the UnitTypeWML for that unit is copied into this one, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Additionally, the unit will be marked as variation of the base unit in its own help page, but not in the help page of the base unit.<br />
<br />
* '''[portrait]''': Describes a unit portrait for dialogue. However, generally you should use the profile key instead; [portrait] is mostly for internal use.<br />
** '''size''': The size of the portrait, in pixels.<br />
** '''side''': One of left or right.<br />
** '''mirror''': Whether to flip the image horizontally.<br />
** '''image''': The image path.<br />
<br />
* '''[abilities]''': Defines the abilities of a unit. See [[AbilitiesWML]]<br />
<br />
* '''[event]''': Any [event] written inside the [unit_type] tag will get included into any scenario where a unit of this type appears in. Note that such events get included when a unit of this type first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[EventWML]] and [[WML_Abilities]]<br />
<br />
* '''[variation]''': Defines a variation of a unit. Variations are invoked with an [effect] tag or the variation= attribute in [[SingleUnitWML]]. They are currently used for graphical variations (giving character sprites new weapons) but theoretically you could do anything with it.<br />
** '''variation_id''': The id of this variation. Defaults to ''variation_name''.<br />
** '''variation_name''': Translatable. The name of the variation.<br />
** '''inherit''': if ''yes'', inherits all the properties of the base unit, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Defaults to no.<br />
*** The '''id''' key is always inherited, regardless of the value of '''inherit'''.<br />
** All keys and tags of '''[unit_type]''', except ''[advancefrom]'', ''[base_unit]'', ''[female]'', ''[male]'', and ''[variation]''.<br />
<br />
* '''[male]''', '''[female]''': These can specify a variation based on gender for a unit. If these are provided, they will automatically apply based upon the gender of a unit.<br />
** '''inherit''': if ''yes'', inherits all the properties of the base unit, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Defaults to yes.<br />
*** The '''id''' key is always inherited, regardless of the value of '''inherit'''.<br />
** All '''[unit_type]''' tags and keys, excluding ''[advancefrom]'', ''[base_unit]'', ''[female]'', and ''[male]''.<br />
<br />
== See Also ==<br />
<br />
* [[AnimationWML]]<br />
* [[ReferenceWML]]<br />
* [[TerrainWML]]<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=OOS_(Out_of_Sync)&diff=60152OOS (Out of Sync)2019-01-14T16:19:25Z<p>Gfgtdf: /* List of Non Mp/Replay safe Wml/Lua functions */</p>
<hr />
<div>OOS is an error that occurs in a Wesnoth multiplayer scenario or a replay when two machines disagree (or one machine disagrees with a replay file) about the game state, i.e. which units are where, how much HP they have, how much gold each side has, etc. More precisely, OOS is announced when a client reads a command, such as "move Dwarf Fighter 8,4 -> 8,5 -> 8,6" or "recruit Gryphon Rider 9,7", which is illegal or nonsensical based on its understanding of the game state.<br />
<br />
OOS could in principle be caused by network issues such as dropped packets, by players having mismatched game files, or even by cheating, but it is commonly caused by scenario designers / add-on makers writing unsafe code. This page is about how to write WML that won't cause OOS. If you want to know what you should do if you get OOS in an online game, see [[http://forums.wesnoth.org/viewtopic.php?f=6&t=38881&p=554259 here]].<br />
<br />
== Why does OOS happen? ==<br />
<br />
=== Game begins out of sync ===<br />
<br />
At the beginning of an mp game the host sends the content of the [multiplayer] or [scenario] to the other clients (via the mp server). All other information, specially [unit]s [terrain]s and toplevel [lua] tags are not transmitted to other players. Instead it is expected that the other players have this data locally available and that their data matches the data of the host. If that is not the case it can cause OOS.<br />
<br />
This can happen if one of the players has modified their game files, or if the players don't have matching add-on versions.<br />
<br />
The OOS may still not appear until a mismatched resource actually appears and does something.<br />
<br />
=== Game becomes out of sync ===<br />
During the actual game all clients have their own local gamesate. The Clients communicate by sending 'player actions' like 'move unit at (3,4) to (5,5) with the route ((3,4),(3,5),(4,5),(5,5))'. These actions are evaluated on the other clients which should lead to the same local gamesate on all clients (asuming that they had the same local gamestate before that action). If at any time clients don't have the same local gamestate we call that OOS. The clients usually send these actions as soon as they know that they cannot be undone. Those actions that are sended to the other clients are called "synced user actions". For example move,recall,recuit ... are such actions. There are also unsynced user action like "select" that only happen on one client and are not sended to other clients. The consequence is that "select" events only run on one client, thus changing the gamestate from inside a select event results in OOS.<br />
<br />
A complete list of unsynchronized events can be found here: [[EventWML#Multiplayer_safety]].<br />
<br />
The replay works the same way: <br />
<br />
the replay begins with the start gamesate and then eveluates all the synced user actions it can find on the replay. If the resulted gamesate is different than the original gamesate we have an OOS. That's why in most times replay safety is the same as multiplayer safety.<br />
<br />
Generally speaking a replay file receives the same kind of information about the game that a multiplayer observer of a game would receive, so any technique which would cause OOS for multiplayer will also cause corrupted replays.<br />
<br />
If wml/lua code is invoked by a synced user action and thus runs on all clients we say "the code runs in a synced context" otherwise not. <br />
{{DevFeature1.13|0}} You can know whether the current code runs in a synced context by checking wesnoth.current.synced_state.<br />
<br />
In order to get the same local gamesate on all clients you should only make the gamesate depend on deterministic functions that return the same value on all clients, for example side.cotroller s getter or math.rand is no such function. If you want to call these functions you should use wesnoth.syncronize_choice which allows you to run code on one client and then return the result to all clients so all clients are guaranteed to get the same result. But note that becasue the code in synconize_choice only runs one one client it should only calculate the return value and not change the gamestate.<br />
<br />
=== The rng ===<br />
Wesnoth has a synced random number generator that returns the same value on all clients, this rng is uses by <br />
* [set_variable] rand=.. [/set_variable]<br />
* traits & name generation in [unit]<br />
* calculation whether an attack hits<br />
To keep the rng in sync it is important to call the rng the same number of times on all clients. Othwewise the random results will be of by one which causes OOS. Luckily the synced rand is smart enough to know whether we are in a synced context. An it redirects to an unsynced rng (like math.random) if it was called from outside a synced context so that calling this rng from outside teh synced context doesnt have an effect on the rng used in the synced context.<br />
<br />
This rng gets reseeded at the beginning of every "synced user action", the reason is, that otherwise players could know which random results they'll get next. Expecialy im MP this is very bad since it means players could know whether an attack will hit or not before they command it. In netwroked Mp the Client get their random seeds from the server. This happens layzly that means it doesn't happen at the beginning of the synced user action, but it happens as soon as the rng is used inside the synced context for this action (Especialy it doesn't happen if the rng isn't used). Since sending the "generate seed" to the server cannot be undone, an action that invoked the synced rng (for example attacks, but also moves with a [set_variable] rand=.. in a moveto event) cannot be undone. This is usually the intended behaviour since calling the rng usually implies a information gain that shouldn't be able to be undone. If you want a random number but don't want to make the gamestate depend on it (maybe just use it for visual features), and thus want the action to be undoable you should use the unsynced math.random from lua.<br />
<br />
=== Found dependent command ===<br />
<br />
It's posible to get a OOS eror with the message "Found (in-)dependent command" or siilar here is explained what this means: During the game the clients send each other packages ([command] see http://wiki.wesnoth.org/ReplayWML). There are 2 types of these packages: the 'normal' commands that contains new user actions like attack, recruit, recall, move... . And there are the 'dependent' packages that contains answer to questions asked to specific clients (the results of local choices). For example advancement choices. But also new random seeds (questions asked to the server) and get_global_variable are in this category. If a client received an answer to a local choice when none was expected the games gives a "Found dependent command when is_synced=false" OOS error message. The opposite sitation when a client expectes an answer to a local choice but receives a new user action also gives a OOs message.<br />
<br />
== Some examples ==<br />
<br />
If Player A changes the White Mage's magic attack from 9-3 to 10-3 while Player B did not, that would result in an OOS since as the game progresses each client would see a different amount of damage being done.<br />
<br />
Say that the White Mage attacks a Spearman with 30 HP left and hits all 3 times. To Player A, it would appear that the Spearman died. However Player B would see that unit as having 3 HP left. As a result...<br />
<br />
* What if Player A then tried to move another unit to where the Spearman was? To Player A's client, it would work fine. To Player B's client, that wouldn't make any sense, since it's not possible to have multiple units on the same hex.<br />
* What if Player B tried to attack one of Player A's units? To Player B's client it seems like a normal move, but to Player A's client it seems like an empty hex is trying to attack him.<br />
<br />
== Hints To Debug OOS Erros ==<br />
<br />
As noted before, OOS happens when two clients disagree about the current gamestate, So if ina game with clients A, B and C, client A got an OOS during the turn of client B it (often, not always) indicates that client A and B disagree about the gamstate, in this situation client C an often be used to decide which client did the wrong calculations, if client C also got an oos errormessage during the turn of client B, it probably client B that did the wrong calculations, otherwise its probably side A. The most common sources of OOS are:<br />
<br />
1. Bad add-ons: in particular you need to be aware of the fact that addons can change the gamestate and cause OOS even if they are not currently active (for example as a modification or a mp scenario ), add-ons can cause OOS by just having them installed even if the seem to be complteley unrelated to the current game.<br />
<br />
2. User changing the game/addons files : it often unclear to users which part of the data can be changed and which can not be changes without causing OOS. For example some mp scenarios include lua code via macro inclusion ''code={myluafile.lua}'' while others include lua code via dofile/require ''wesnoth.dofile("myluafile.lua")'', in the former case it is usually safe to change the lua files because the hosts sends the other client his version of the lua file along with the other scenario content, while in the later case it fill usually lead to OOS.<br />
<br />
3. Outdated wesnoth versions. While we try to keep the wesnoth versions mp compatible, it is still important to keep your wesnoth version up to date. In particular to avoid OOS erros casued by engine bug that were fixed in newer versions, you can use the mp server command ''/q version <playername>'' to figure out what wesnoth version another player is using.<br />
<br />
4. cheating players: not much to say, player can intentionally change wesnoth game files in a stupid way hoping it would give them an advantage when it will actually just cause OOS.<br />
<br />
5. Engine bugs: Wesnoth is not always bugfree, the main diffculty in investigating engine OOS errors is that most of the OOS erros reported actually come from one of the other posibilities above, so its somehow hard to find the 'real' oos engine bugs in the wild. Some features in particular 'delayed shroud updates' and 'multiplayer campaigns' have often casued OOS in the past though and it possible they they will be broken agian in the future due to their complex nature.<br />
<br />
== How to make your code safe ==<br />
<br />
* Make the WML run at a synchronized time instead, i.e. in a moveto event.<br />
* Use helper.rand instead of math.random, unless you know exactly what you are doing.<br />
* Use Lua wesnoth.synchronize_choice when gathering informaton to make sure that all clients match. Note that this function only works correct in syncronized events.<br />
<br />
=== List of Non Mp/Replay safe Wml/Lua functions ===<br />
These functions/values might return different values on different clients or in replays. To prevent OOS you must use wesnoth.synchronize_choice or {{DevFeature1.13|0}} [sync_variable] so query these values when you want to change the gamestate depending on these values.<br />
* Using functions that depend on other installed addons, for example ''#wesnoth.unit_types'' will usually be different on each client.<br />
* Using translatable strings for gamestate calculations, obviously the value of these string depend on the each clients language setting.<br />
* Unsafe events, see https://wiki.wesnoth.org/EventWML#Multiplayer_safety<br />
* Unit attributes (accessible via stored units, lua proxy units of unit filters * Unit attributes (accessible via stored units, lua proxy units of unit filters ([filter_wml]))<br />
** unit.goto_x and unit.goto_y (used by the ai and by multi turn moves internally)<br />
** unit.facing (in some cases like when unstoring units the unit facing might be set randomly)<br />
** unit.name (it is possible for players to rename units, also in mp the leaders names changes whenever a side controller changes, also see the point below about any attribute changing the visual appearance.)<br />
** any attribute describing the visual appearance of that unit (unit.overlays, unit.profile etc.). In default wesnoth they may be be the same on all clients, but people usually assume that they can change the visuals of wesnoth by modifying the cfg files or via [modification]s in add-ons without causing OOS.<br />
* Variables/wml tags<br />
** side.controller (gained by [store_side] or wesnoth.sides) this variable will be different for each client. An exception is when controller is "null" which happens if and only if it is "null" on all other clients as well.<br />
** [set_variable] time=stamp - obviously the result of this operation will be different for all clients<br />
* Lua functions:<br />
** math.random()<br />
** wesnoth.game_config.debug, .version have (possibly) different values<br />
** any dialog wich queries input from a client (wesnoth.show_dialog)<br />
** wesnoth.sides[i].controller (same as with [store_side]), wesnoth.sides[i].is_local<br />
** any non mp-safe wml tag called by lua<br />
<br />
== Additional tricks and tips ==<br />
<br />
* You can modify some things. So while you shouldn't change the damage of a unit's attack, there's nothing wrong with changing it's portrait.<br />
<br />
== See Also ==<br />
<br />
[[MultiplayerContent]]<br />
<br />
[[Category:WML_Tips]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=DirectActionsWML&diff=60150DirectActionsWML2019-01-13T19:03:29Z<p>Gfgtdf: /* [object] */</p>
<hr />
<div>{{WML Tags}}<br />
== Direct actions ==<br />
<br />
Direct actions are actions that have a direct effect on gameplay. They can be used inside of [[EventWML|events]].<br />
<br />
The following tags are actions:<br />
<br />
=== [endlevel] ===<br />
Ends the scenario.<br />
* '''result''': before the scenario is over, all events with ''name=result'' are triggered. If ''result=victory'', the player progresses to the next level (i.e., the next scenario in single player); if ''result=defeat'', the game returns to the main menu. <br />
<br />
When the result is "victory" the following keys can be used:<br />
* '''bonus''': whether the player should get bonus gold (maximum possible gold that could have been earned by waiting the level out). The default is bonus=yes. {{DevFeature1.13|2}} Alternatively, a number, defining the bonus multiple (1.0 meaning full).<br />
* '''carryover_report''': whether the player should receive a summary of the scenario outcome, the default is carryover_report=yes.<br />
* '''save''': whether a start-of-scenario save should be created for the next scenario, the default is save=yes. Do not confuse this with saving of replays for the current scenario.<br />
* '''replay_save''': whether a replay save for the current scenario is allowed, the default is replay_save=yes. If yes, the player's settings in preferences will be used to determine if a replay is saved. If no, will override and not save a replay.<br />
* '''linger_mode''': If ...=yes, the screen is greyed out and there's the possibility to save before advancing to the next scenario, the default is linger_mode=yes.<br />
* '''reveal_map''': (Multiplayer only) (Default is 'yes') If 'no', shroud doesn't disappear when game ended.<br />
* '''next_scenario''': (default specified in '''[scenario]''' tag) the ID of the next scenario that should be played. All units that side 1 controls at this point become available for recall in ''next_scenario''.<br />
* '''carryover_percentage''': by default 80% of the gold is carried over to the next scenario, with this key the amount can be changed.<br />
* '''carryover_add''': if yes the gold will be added to the starting gold the next scenario, if no the next scenario will start with the amount of the current scenario (after taxes) or the minimum in the next scenario. Default is no.<br />
* '''music''': (default specified in '''[scenario]''' or '''[game_config]''' tags) a comma-separated list of music tracks from which one will be chosen and played once after any events related to the end of level result are executed; by default, victory_music is used on victory, and defeat_music on defeat.<br />
* '''end_credits''': Whether to display the credits screen at the end of a single-player campaign. Defaults to ''yes''. Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* '''end_text''': (translatable) Text that is shown centered in a black screen at the end of a campaign. Defaults to "The End". Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* '''end_text_duration''': Delay, in milliseconds, before displaying the game credits at the end of a campaign. In other words, for how much time '''end_text''' is displayed on screen. Defaults to 3500. Note that this has cumulative effects over the campaign - it persists even if the endlevel does not trigger the end of the campaign. See also [[CampaignWML]].<br />
* <strike>'''[next_scenario_settings]''': Any tags or attribute children of this optional argument to [endlevel] are merged into the scenario/multiplayer tag of the *next* scenario. This allows you to e.g. reconfigure the [side] tags or settings, just before load. </strike> This feature was removed in 1.11.17, it might be redesigned and reintroduced.<br />
* <strike>'''[next_scenario_append]''': Any tags of this optional argument are appended at high level to the next scenario. This is most appropriate for [event] tags, although you may find other uses. Example test scenario for these features: https://gna.org/support/download.php?file_id=20119 </strike> This feature was removed in 1.11.17, it might be redesigned and reintroduced.<br />
* '''[result]''' {{DevFeature1.13|0}} Allows specification of a side specific result, this is for competitive multiplayer scenarios/campaigns where it might happen that one player wins but another player loses. The following attributes are accepted and have the same effect as in '''[endlevel]''':<br />
** '''result'''<br />
** '''bonus'''<br />
** '''carryover_percentage'''<br />
** '''carryover_add'''<br />
<br />
And there is also<br />
** '''side''' The number of the side for which these results should apply.<br />
<br />
=== [unit] ===<br />
Creates a unit (either on the map, on a recall list, or into a variable for later use.) For syntax see [[SingleUnitWML]].<br />
* {{Short Note:Predefined Macro|GENERIC_UNIT}}<br />
<br />
=== [recall] ===<br />
Recalls a unit taking into account any [http://wiki.wesnoth.org/SingleUnitWML filter_recall] of the leader. The unit is recalled free of charge, and is placed near its leader, e.g., if multiple leaders are present, near the first found which would be able to normally recall it.<br />
<br />
If neither a valid map location is provided nor a leader on the map would be able to recall it, the tag is ignored.<br />
<br />
* [[StandardUnitFilter]]: the first matching unit will be recalled. If no units match this tag is ignored. Do not use a [filter] tag. If a comma separated list is given, every unit currently considered for recall is checked against all the types (not each single one of the types against all units).<br />
* '''x,y''': the unit is placed here instead of next to the leader.<br />
* '''show''': yes/no, default yes: whether the unit is animated (faded in) or instantly displayed<br />
* '''fire_event''': boolean yes|no (default no); whether any according prerecall or recall events shall be fired.<br />
* '''check_passability''': (boolean yes|no, default yes): If yes, checks for terrain passability when placing the unit (a nearby passable hex is chosen).<br />
* '''[secondary_unit]''': {{DevFeature1.13|?}} If present and show=yes, a matching unit will be chosen and their recruiting animation played.<br />
<br />
=== [teleport] ===<br />
Teleports a unit on map. {{Short Note:Predefined Macro|TELEPORT_UNIT}}<br />
* '''[filter]''': [[StandardUnitFilter]] the first unit matching this filter will be teleported.<br />
* '''x,y''': the hex to teleport to. If that hex is occupied, the closest unoccupied hex will be used instead.<br />
* '''clear_shroud''': should shroud be cleared on arrival<br />
* '''animate''': should a teleport animation be played (if the unit doesn't have a teleport animation, it will fade out/fade in)<br />
* '''check_passability''': (boolean yes|no, default yes): normally, units will not be teleported into terrain that is impassable for them. Setting this attribute to "no" permits it.<br />
<br />
(Note: There is also a ability named teleport, see [[AbilitiesWML]].)<br />
<br />
=== [terrain_mask] ===<br />
Changes the terrain on the map. See [[TerrainMaskWML]].<br />
<br />
=== [terrain] ===<br />
Changes the terrain on the map.<br />
* '''terrain''': the character of the terrain to use. See [[TerrainCodesWML]] to see what letter a type of terrain uses.<br />
* [[StandardLocationFilter]]. This [[StandardLocationFilter]]'s terrain= key is used for the new terrain, filtering by terrain can be done with a nested [[StandardLocationFilter]]: [and]terrain=terrain_string_to_be_filtered_for.<br />
* '''layer''': (overlay|base|both, default=both) only change the specified layer.<br />
* '''replace_if_failed''': (default=no) When replacing just one layer failed, try to replace the whole terrain. If '''terrain''' is an overlay only terrain, use the default_base as base layer. If the terrain has no default base, do nothing.<br />
<br />
If you want to remove the overlays from a terrain and leave only the base, use:<br />
layer=overlay<br />
terrain="^"<br />
<br />
<b>Note:</b> When a hex changes from a village terrain to a non-village terrain, and a team owned that village it loses that village. When a hex changes from a non-village terrain to a village terrain and there is a unit on that hex it does not automatically capture the village. The reason for not capturing villages it that there are too many choices to make; should a unit lose its movement points, should capture events be fired. It is easier to do this as wanted by the author in WML.<br />
<br />
=== [gold] ===<br />
Gives sides gold.<br />
* '''amount''': the amount of gold to give.<br />
* '''side''': (default=1) the number of the side to give the gold to. Can be a comma-separated list of sides. note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [unstore_unit] ===<br />
Creates a unit from a game variable, and activates it on the playing field. This must be a specific variable describing a unit, and may not be an array -- to unstore an entire array, iterate over it. The variable is not cleared. See also [[InternalActionsWML#.5Bstore_unit.5D|[store_unit]]], [[ConditionalActionsWML#.5Bwhile.5D|[while]]] and [[InternalActionsWML#.5Bclear_variable.5D|[clear_variable]]].<br />
* '''variable''': the name of the variable.<br />
* '''find_vacant''': whether the unit should be placed on the nearest vacant tile to its specified location. If this is set to 'no'(default), then any unit on the same tile as the unit being unstored will be destroyed. <br />
* '''check_passability''': (boolean yes|no, default yes): If yes, checks for terrain passability when placing the unit. This key has no effect if find_vacant=no (no check performed then). Before 1.9 this key is always "no".<br />
* '''text''': (translatable) floating text to display above the unit, such as a damage amount<br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. You may find it convenient to use the {COLOR_HARM} or {COLOR_HEAL} macro instead. (Use {COLOR_HARM} or {COLOR_HEAL} instead of the whole red,green,blue= line.)<br />
* '''advance''': (default=yes) if yes the unit is advanced if it has enough XP. When modifying XP make sure to do it from inside a [[EventWML#Multiplayer_safety|synchronized event]] or it may lead to OOS errors especially when several advancement paths exist. Note that advance and post advance events are called, so infinite loops can happen.<br />
* '''fire_event''': (boolean yes|no, default no) Whether any advance/post advance events shall be fired if an advancement takes place, no effect otherwise.<br />
* '''animate''': (boolean yes|no, default yes) Whether "levelout" and "levelin" (or fade to white and back) animations shall be played if an advancement takes place, no effect otherwise.<br />
* '''x''' ,'''y''': override unit location, "x,y=recall,recall" will put the unit on the unit's side's recall list.<br />
Units can be unstored with negative (or zero) hit points. This can be useful if modifying a unit in its last_breath event (as the unit's death is already the next step), but tends to look wrong in other cases. In particular, it is possible to have units with negative hit points in play. Such units are aberrations, subject to unusual behavior as the game compensates for them. (For example, such units are currently automatically hit&ndash;and killed&ndash;in combat.) The details of the unusual behavior are subject to change between stable releases without warning.<br />
<br />
=== [allow_recruit] ===<br />
Allows a side to recruit units it couldn't previously recruit.<br />
* '''type''': the types of units that the side can now recruit.<br />
* '''side''': (default=1) the number of the side that is being allowed to recruit the units. This can be a comma-separated list note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [allow_extra_recruit] ===<br />
Allows a leader to recruit units it couldn't previously recruit.<br />
These types add to the types the leader can recruit because of [side]recruit=.<br />
* '''extra_recruit''': the types of units that the unit can now recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [disallow_recruit] ===<br />
Prevents a side from recruiting units it could previously recruit.<br />
* '''type''': the types of units that the side can no longer recruit. {{DevFeature1.13|0}} If omitted, all recruits for matching sides will be disallowed.<br />
* '''side''': (default=1) the number of the side that may no longer recruit the units. This can be a comma-separated list note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [disallow_extra_recruit] ===<br />
Prevents a leader from recruiting units it could previously recruit.<br />
* '''extra_recruit''': the types of units that the side can no longer recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [set_recruit] ===<br />
Sets the units a side can recruit.<br />
* '''recruit''': the types of units that the side can now recruit.<br />
* '''side''': (default=1) the number of the side that is having its recruitment set. This can be a comma-separated list. note: Default side=1 for empty side= is deprecated.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [set_extra_recruit] === <br />
Sets the units a leader can recruit.<br />
* '''extra_recruit''': the types of units that the leader can now recruit.<br />
* '''[[StandardUnitFilter]]''': All units matching this filter are modified. Does not match on recall list units.<br />
<br />
=== [modify_side] ===<br />
Modifies some details of a given side in the middle of a scenario. '''The following listed properties are the only properties that [modify_side] can affect!'''<br />
* '''side''': (default=1) the number of the side that is to be changed. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* '''income''': the income given at the begining of each turn.<br />
* '''recruit''': a list of unit types, replacing the side's current recruitment list.<br />
* '''team_name''': the team in which the side plays the scenario.<br />
* '''user_team_name''': a translatable string representing the team's description. This has no effect on alliances. Defaults to ''team_name''.<br />
* '''side_name''': {{DevFeature1.13|?}} a translatable string representing the side leader's description.<br />
* '''gold''': the amount of gold the side owns.<br />
* '''village_gold''': the income setting per village for the side.<br />
* '''controller''': the identifier string of the side's controller. Uses the same syntax of the ''controller'' key in the [[SideWML|[side]]] tag. warning: in multiplayer, changing the controller of a side might result in OOS during some events like, for example 'side_turn_end'; see [https://github.com/wesnoth/wesnoth/issues/2563 issue #2563].<br />
* '''fog''': a boolean string (yes/no) describing the status of Fog for the side.<br />
* '''shroud''': a boolean string describing the status of Shroud for the side.<br />
* '''hidden''': a boolean string specifying whether side is shown in status table.<br />
* '''color''': a team color range specification, name (e.g. "red", "blue"), or number (e.g. "1", "2") for this side. The default color range names, numbers, and definitions can be found in data/core/team_colors.cfg.<br />
* '''[ai]''': sets/changes AI parameters for the side. Only parameters that are specified in the tag are changed, this does not reset others to their default values. Uses the same syntax as described in [[AiWML]]. Note that [modify_side][ai] works for all simple AI parameters and some, but not all, of the composite ones. If in doubt, use [http://wiki.wesnoth.org/AiWML#Adding_and_Deleting_Aspects_with_the_.5Bmodify_ai.5D_Tag [modify_ai]] instead, which always works. {{DevFeature1.13|?}} If this contains an '''ai_algorithm''', the AI parameters will be reset to those of the indicated AI before adding any additional parameters included in the tag. In other words, this allows replacing the AI config rather than appending to it.<br />
* '''switch_ai''': replaces a side ai with a new AI from specified file(ignoring those AI parameters above). Path to file follows the usual WML convention.<br />
* '''reset_maps''': If set to "yes", then the shroud is spread to all hexes, covering the parts of the map that had already been explored by the side, including hexes currently seen. (Seen hexes will be cleared at the end of most events; they can also be manually cleared with {{tag|InterfaceActionsWML|redraw}}.) This is only effective if shroud is on, but this is evaluated after shroud= (and before shroud_data=).<br />
* '''reset_view''': If set to "yes", then the fog of war is spread to all hexes, covering the parts of the map that had already been seen this turn by the side, including hexes currently seen, excluding hexes affected by multi-turn {{tag|DirectActionsWML|lift_fog}}. (Seen hexes will be cleared at the end of most events; they can also be manually cleared with {{tag|InterfaceActionsWML|redraw}}.) This is only effective if fog is on, but this is evaluated after fog=.<br />
* '''share_maps''': change the share_maps side attribute. Be sure to use shroud=yes for that side and have it as an ally<br />
* '''share_view''': change the share_view side attribute. Be sure to use fog=yes for that side and have it as an ally<br />
* '''share_vision''': change both the above at the same time<br />
* '''shroud_data''': changes to the side's shroud, using the same format as when defining the [side].<br />
* '''suppress_end_turn_confirmation''': Boolean value controlling whether or not a player is asked for confirmation when skipping a turn.<br />
* '''scroll_to_leader''': Boolean value controlling whether or not the game view scrolls to the side leader at the start of their turn when present.<br />
* '''flag''': Flag animation for villages owned by this side (see [[SideWML|[side]]]).<br />
* '''flag_icon''': Flag icon used for this side in the status bar (see [[SideWML|[side]]]).<br />
* '''village_support''': The number of unit levels this side is able to support (does not pay upkeep on) per village it controls.<br />
* '''defeat_condition''' {{DevFeature1.13|0}}: When the side is considered defeated (see [[SideWML|[side]]]).<br />
<br />
=== [modify_turns] ===<br />
Modifies the turn limit in the middle of a scenario.<br />
* '''value''': the new turn limit.<br />
* '''add''': if used instead of ''value'', specifies the number of turns to add to the current limit (can be negative).<br />
* '''current''': changes the current turn number after applying turn limit modifications, if any. It is not possible to change the turn number to exceed the turn limit (1 <= current turns <= max turns).<br />
<br />
=== [allow_end_turn] ===<br />
Allows human players to end their turn through the user interface if they were previously affected by the '''[disallow_end_turn]''' action. This action doesn't take any arguments.<br />
<br />
=== [disallow_end_turn] ===<br />
Disallows human players to end their turn through the user interface. This action doesn't take any arguments.<br />
<br />
=== [capture_village] ===<br />
Changes the ownership of a village.<br />
* [[StandardLocationFilter]]: all village locations matching the filter are affected.<br />
* '''side''': the side that takes control of the village. This side needs to have a leader (canrecruit=yes). If the side key is not given, the village will become neutral (unless [filter_side] is present, in which case that side fiter decides, see below).<br />
* '''[filter_side]''' with [[StandardSideFilter]] tags and keys as arguments; if both this tag and inline side= are present it's an error. Otherwise, the first matching side gets ownership (or the village becomes neutral if none match).<br />
* '''fire_event''' (boolean yes|no, default: no): Whether any capture events shall be fired.<br />
<br />
=== [kill] ===<br />
Removes all units (including units in a recall list) that match the filter from the game.<br />
* [[StandardUnitFilter]]: Selection criterion; do not use a [filter] tag.<br />
* '''animate''' (default 'no'): if 'yes', displays the unit dying (fading away). {{DevFeature1.13|8}} If '''[secondary_unit]''' is given, also plays the victory animation of that unit.<br />
* '''fire_event''' (default 'no'): if 'yes', triggers any appropriate 'die' events (See [[EventWML]]). Note that events are only fired for killed units that have been on the map (as opposed to recall list).<br />
* '''[secondary_unit]''' with a [[StandardUnitFilter]] as argument. Do not use a [filter] tag. Has an effect only if fire_event=yes ({{DevFeature1.13|8}} or if it has a victory animation and animate=yes). The first on-map unit matching the filter becomes second_unit in any fired die and last breath events. If an on-map unit matches and if there are several units killed with a single [kill] tag, second_unit is this same unit for all of them. If no on-map unit matches or [secondary_unit] isn't present, the variable second_unit in each of the die and last breath events is always the same as the variable unit (the dying unit).<br />
* '''[primary_attack]''', '''[secondary_attack]''' {{DevFeature1.13|8}} The attacks to use for matching the animation. Useful for example on the wose, whose death animation depends on the damage type it was killed by.<br />
<br />
=== [move_unit] ===<br />
works like the MOVE_UNIT macro.<br />
* [[StandardUnitFilter]] as argument; do not use a [filter] tag. All units matching the filter are moved. If the target location is occupied, the nearest free location is chosen.<br />
* '''to_x''' (unsigned integer): The units are moved to this x coordinate. Can be a comma-separated list, in which case the unit follows this given path during the move.<br />
* '''to_y''' (unsigned integer): The units are moved to this y coordinate. Can be a comma-separated list.<br />
* '''fire_event''' (optional, boolean yes|no, default no): Whether any according moveto events shall be fired. The target location ($x1, $y1 in the event) may not be the same location that the unit was tried to be moved to, if the original target location is occupied or impassable.<br />
* '''check_passability''' (boolean yes|no, default yes): Whether the terrain the unit is moved to should be checked for suiting the unit. (If it does not, a nearby suitable hex is chosen.)<br />
* '''force_scroll''': Whether to scroll the map or not even when [[InterfaceActionsWML#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to using [[InterfaceActionsWML#.5Bmove_unit_fake.5D|[move_unit_fake]]]'s default value.<br />
<br />
=== [modify_ai] ===<br />
Changes AI objects (aspects, goals, candidate actions or stages) for a specified side. See [[Modifying_AI_Components#The_.5Bmodify_ai.5D_Tag|Modifying AI Components]] for full description.<br />
<br />
* '''action''' (string): Takes values 'add', 'change', 'delete' or 'try_delete' to do just that for the AI object.<br />
* '''path''' (string): Describes which AI object is to be modified. <br />
* '''[facet]''', '''[goal]''', '''[candidate_action]''' or '''[stage]''': Details about the AI object to be modified.<br />
* [[StandardSideFilter]] tags and keys; default for empty side= is all sides, as usual in a SSF.<br />
<br />
=== [modify_unit] ===<br />
works similar to the MODIFY_UNIT macro.<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument. All units matching this filter are modified. Matches on recall list units too.<br />
* '''[object]''', '''[trait]''', {{DevFeature1.13|5}} '''[advancement]''' - The given modifications will be immediately applied to all units matching the filter.<br />
** '''delayed_variable_substitution''' {{DevFeature1.13|5}} (boolean yes|no, default no): If set to "yes", the wml block contained in this [object], [trait], or [advancement] is not variable-substituted at execution time of the event containing this [modify_unit]. You need this for any effect that uses variable substitution or when using [effect][filter] with a $this_unit. {{DevFeature1.13|9}} This is no longer needed when adding ABILITY_TELEPORT, ABILITY_LEADERSHIP or SPECIAL_BACKSTAB.<br />
* '''[effect]''' {{DevFeature1.13|6}} Applies the effect directly to the unit.<br />
* Accepts generally the syntax inside of wml unit variables created by [store_unit] which can be viewed in a savefile or by using the [[CommandMode|inspect command]]. Cannot remove things or add/alter unit animations. Subtags with the same name must be written in the correct order to match them with the tag they are supposed to modify. Note that keys will be processed in arbitrary order, which may cause problems if you use formulas that depend on other formulas. To work around this you may need to use the tag twice with the same filter.<br />
example usage (see also the test scenario):<br />
<syntaxhighlight lang='wml'><br />
[modify_unit]<br />
[filter]<br />
x,y=38,6<br />
[/filter]<br />
hitpoints=10<br />
{TRAIT_HEALTHY}<br />
[/modify_unit]<br />
</syntaxhighlight><br />
<br />
The unit which is currently modified is accessible via $this_unit, e.g. hitpoints = "$($this_unit.hitpoints / 2)" to set the hitpoints of all units to half of their particular maxima. This this_unit variable is independent from the this_unit variable available in the SUF used to determine which units to modify (first all matching units are gathered, and then all those are modified).<br />
<br />
=== [transform_unit] ===<br />
Transforms every unit on the map matching the filter to the given unit type. Keeps intact hit points, experience and status. If the unit is transformed to a non-living type (undead or mechanical), it will be also unpoisoned. Hit points will be changed if necessary to respect the transformed unit's maximum hit points.<br />
* [[StandardUnitFilter]]: do not use a [filter] tag.<br />
* '''transform_to''': the unit type in which all the units matching the filter will be transformed. If missing, the units will follow their normal advancement.<br />
<br />
=== [petrify] ===<br />
<br />
* [[StandardUnitFilter]] as an argument. Do not use a [filter] tag. All units matching this filter are petrified. Recall list units are included.<br />
<br />
=== [unpetrify] ===<br />
* [[StandardUnitFilter]] as an argument. Do not use a [filter] tag. All units matching this filter are unpetrified. Recall list units are included.<br />
<br />
=== [object] ===<br />
Gives some unit an object which modifies their stats in some way.<br />
* '''id''': (Optional) allows the item to be removed later. By default, an object with a defined ID can only be picked up once per scenario, even if it is removed later or first_time_only=no is set for the event. You can remove this restriction by setting take_only_once=no. For filtering objects, it might be simpler to use a custom key such as item_id. The id string can contain only letters, numbers and underscores.<br />
* '''take_only_once''': (default yes) {{DevFeature1.13|6}} If set to "no", the object's ID does not prevent it from being taken more than once.<br />
* '''delayed_variable_substitution''' (boolean yes|no, default no): If set to "yes", the wml block contained in this [object] is not variable-substituted at execution time of the event where this [object] is within. You need this for any effect that uses variable substitution or when using [effect][filter] with a $this_unit. {{DevFeature1.13|9}} This is no longer needed when adding ABILITY_TELEPORT, ABILITY_LEADERSHIP or SPECIAL_BACKSTAB.<br />
* '''[effect]''': one or more effect elements may be listed. See [[EffectWML]] for a description of [effect].<br />
* '''duration''':<br />
**if 'scenario', effects only last until the end of the level (note : 'level' is the scenario, so this doesn't mean it last until the unit levels-up).<br />
**if 'forever' or not set, effects never wear off.<br />
** if 'turn', effects only last until the start of the unit's next turn (when the unit refreshes movement and attacks). (Like other start-of-turn behavior, objects with a duration of "turn" won't expire before turn 2.)<br />
** {{DevFeature1.13|1}} if 'turn end' or 'turn_end', effects only last until the end of the unit's next turn (exactly like the slowed status).<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument. The first unit found that matches the filter will be given the object. Only on-map units are considered. If no unit matches or no [filter] is supplied, it is tried to apply the object to the unit at the $x1,$y1 location of the event where this [object] is in. The case of no unit being at that spot is handled in the same way as no unit matching a given filter ([else] commands executed, cannot_use_message displayed). Note that units on the recall list will not be checked. To add an [object] to a unit on the recall list you have to use '''[modify_unit][object]'''.<br />
* '''[then]''': a subtag that lets you execute actions if the filter conditions are met. The most common action that should be inside here is a '''[remove_item]''' tag, but you could probably put any tags that otherwise work in a [then] tag.<br />
* '''[else]''': a subtag that lets you execute actions if the filter conditions are *not* met.<br />
* '''silent''': whether or not messages should be suppressed. Default is "no". {{DevFeature1.13|2}} If no description is provided, this defaults to yes, but can still be overridden.<br />
* '''image''': the displayed image of the object.<br />
* '''name''': (translatable) displayed as a caption of the image.<br />
<br />
* '''description''': (translatable) displayed as a message of the image.<br />
* '''cannot_use_message''': (translatable) displayed instead of '''description''' if no unit passes the filter test.<br />
<br />
=== [remove_object] ===<br />
<br />
{{DevFeature1.13|6}}<br />
<br />
Removes an object from matching units.<br />
<br />
* [[StandardUnitFilter]]: All units matching the filter have matching objects removed. Use no [filter] tag.<br />
* '''object_id''': The id of the object to be removed.<br />
<br />
Note that some unit properties are not restored ideally, e.g. current unit's health reversion might not work as expected (max_hitpoints will though).<br />
<br />
=== [remove_shroud] ===<br />
Removes some shroud from the map for a certain side (only relevant for sides that have shroud=yes).<br />
* '''side''': (default=1) the side for which to remove shroud. This can be a comma-separated list of sides. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* [[StandardLocationFilter]]: the range of tiles for which shroud should be removed<br />
<br />
=== [place_shroud] ===<br />
Places some shroud on the map for a certain side (only relevant for sides that have shroud=yes).<br />
* '''side''': (default=1) the side for which to place shroud. This can be a comma-separated list. note: Default side=1 for empty side= is deprecated.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] as argument<br />
* [[StandardLocationFilter]]: the range of tiles on which shroud should be placed<br />
<br />
=== [lift_fog] ===<br />
Lifts the fog of war from parts of the map for a certain side (only relevant for sides that have fog=yes), allowing a player to witness what occurs there even if that player has no units within vision range.<br />
* '''[filter_side]''' with a [[StandardSideFilter]] indicating which sides should be affected.<br />
* [[StandardLocationFilter]]: the tiles from which fog should be lifted.<br />
* '''multiturn''': ''yes/no, default:no''. The default (not multiturn) causes fog to be removed in the same way that normal vision works; the cleared tiles will remain cleared until fog is recalculated (which normally happens when a side ends its turn). When multiturn is set to "yes", the cleared tiles remain clear until {{tag||reset_fog}} cancels the clearing. This allows tiles to remain clear for multiple turns, or to be refogged before the end of the current turn (without also refogging all tiles). Multiturn lifted fog is not shared with allies (even when share_view=yes).<br />
<br />
=== [reset_fog] ===<br />
The primary use of this tag is to remove multiturn lifted fog (created by {{tag||lift_fog}}), which causes the fog to reset to what it would have been had WML not interfered. (That is, hexes that a side's units could not see at any point this turn will be re-fogged, while seen hexes remain defogged.)<br />
* '''[filter_side]''' with a [[StandardSideFilter]] indicating which sides should be affected.<br />
* [[StandardLocationFilter]]: the fog reset will be restricted to these tiles.<br />
* '''reset_view''': ''yes/no, default: no'' If set to "yes", then in addition to removing multiturn fog, the side's current view is canceled (independent of the SLF). This means that all hexes will become fogged for the side unless multiturn fog exists outside the tiles selected by the SLF. Normally, one would want the currently seen hexes to become clear of fog; this is done automatically at the end of many events, and it can be done manually with {{tag|InterfaceActionsWML|redraw}}.<br />
Omitting both the SSF and the SLF would cancel all earlier uses of [lift_fog].<br />
Additionally setting reset_view="yes" would cause the side's entire map to be fogged (unless an ally keeps hexes clear by sharing its view).<br />
<br />
=== [allow_undo] ===<br />
Normally when an event with a handler fires, the player's undo stack is cleared, preventing all actions performed so far from being undone. Including this tag in the event handler prevents the stack from being cleared for this reason, allowing the player to undo actions. (However, the stack might still be cleared for other reasons, such as fog being cleared or combat occurring.) In the common cases, this means '''[allow_undo]''' allows the current action to be undone even though an event was handled. There is a less common case, though &mdash; specifically when handling a menu item, where there is no current action &mdash; and in this case, '''[allow_undo]''' means merely that earlier actions can still be undone.<br />
* Using this tag in a menu item has an additional side effect in 1.11. Starting with version 1.11.1, executing a WML menu item normally counts as doing something as far as the "you have not started your turn yet" dialog is concerned. However, a menu item whose handler includes '''[allow_undo]''' will not count.<br />
<br />
The types of actions that can be undone are movement, recalling, and dismissing a unit from the recall list. If an action is undone, only the position (or existence) of the involved unit will be restored; any altered variables or changes to the game will remain changed after the action is undone. It is up to the scenario designer to avoid abusing this command.<br />
* Technically, if '''[allow_undo]''' is inside an '''[event]''' with ''first_time_only=yes'' (the default setting), and the user undoes the event, then the state of the game has changed in this way: the event will not fire a second time, even though the user undid the action the first time.<br />
* Although recalling can be undone, recruitment can not be undone; this seems to apply even when the recruit's traits are not randomly-generated (tested on 1.12.6 and 1.14.4+dev).<br />
<br />
If an '''[event]''' uses both '''[allow_undo]''' and [[InternalActionsWML#.5Bfire_event.5D|'''[fire_event]''']] then the '''[allow_undo]''' must be after the '''[fire_event]'''.<br />
<br />
Due to a bug in 1.12 (https://gna.org/bugs/?23323) '''[allow_undo]''' should not be used in events that use one of the following things because it might cause OOS: <br />
* [message] with [option]s<br />
* [get_global_variable]<br />
* wesnoth.synchronize_choice<br />
<br />
While in 1.13 using '''[allow_undo]''' together with those things won't give you a guaranteed OOS, there are some non-obvious situations where it will, for example assume the following event:<br />
<br />
[event]<br />
name="moveto"<br />
[message]<br />
message = "message"<br />
[option]<br />
label = "option 1"<br />
[command]<br />
[/command]<br />
[/option]<br />
[option]<br />
label = "option 2"<br />
[command]<br />
[/command]<br />
[/option]<br />
[/message]<br />
[allow_undo]<br />
[/allow_undo]<br />
[/event]<br />
<br />
It will cause OOS when the message is undone: since the event is already executed (erased) on one client only , the clients will disagree about how many choices happen during the next moveto action.<br />
<br />
=== [on_undo] ===<br />
{{DevFeature1.13|2}}<br />
Contains commands to execute when the player undoes the action which triggered the parent event.<br />
*'''delayed_variable_substitution''' {{DevFeature1.13|5}}: ''yes/no, default no (always no before 1.13.5)'' As in [[EventWML]], specifies whether to perform variable substitution when the parent event is run, or when the contents are run. If delayed substitution is used, [[SyntaxWML#Automatically_Stored_Variables|automatically stored variables]] from the parent event context are available, but may occasionally have unexpected values. (In particular, $unit.x and $unit.y may not have the expected value when undoing a move event, though $x1 and $y1 should be correct.)<br />
<br />
Note:<br />
It is not clear where whether the actionwml in [on_undo] in exceuted before or after the action is undone. Also, specially for enter/leave_hex events the units position when executing the [on_undo] code is usually different than when executing the original event. The reccomended way to wokr around these issues is to refer to the unit by is instead of position and store all other needed information variables as 'upvalues'. You can also move the actual undo code to an external event. For example<br />
[event]<br />
name="undo_blah"<br />
first_time_only=no<br />
[store_unit]<br />
id="$moved_unit_id"<br />
[/store_unit]<br />
... do undo stuff stuff<br />
[/event]<br />
<br />
...<br />
... in some other event<br />
[on_undo]<br />
# store ''upvalues<br />
{VARIABLE moved_unit_id $unit.id}<br />
# call actual undo handler<br />
[fire_event]<br />
name = "undo_blah"<br />
[/fire_event]<br />
[on_undo]<br />
<br />
=== [on_redo] ===<br />
{{DevFeature1.13|2}}<br />
Same as [on_undo], except executes the commands on redo. Note that the parent event is not triggered again on a redo.<br />
<br />
{{DevFeature1.13|8}} [on_redo] is deprecated and has no effect anymore.<br />
<br />
Note that [on_redo] is not guaranteed to be called when redoing an action, the engine might also decide to just fire the original events again.<br />
<br />
=== [cancel_action] ===<br />
Although Wesnoth 1.12 does not have this tag, it is the default behavior of {{tag|EventWML|enter_hex}}/{{tag|EventWML|leave_hex}} events in that version.<br />
<br />
{{DevFeature1.13|9}} In this version, [cancel_action] is recognised, but has no effect (a bug).<br />
<br />
{{DevFeature1.13|11}}<br />
In an {{tag|EventWML|enter_hex}}/{{tag|EventWML|leave_hex}} event, interrupt the movement, leaving the unit where it is. This is intended to be used with an event that gives the player new information, to let the player choose whether to change their plans. For example, if the player has commanded a unit to move from (1,1) to (3,3) and attack a unit on (4,4); then a [cancel_action] inside an [enter_hex] event on (2,2) would make the unit stop on (2,2). A [cancel_action] inside an [enter_hex] on (3,3) would let the player choose whether to attack.<br />
<br />
=== [heal_unit] ===<br />
Heal a unit. The variable '''$heal_amount''' will be set to the exact number of points healed (i.e can be less than the parameter '''amount''' if the unit is fully healed). $heal_amount contains only the number of hitpoints the first unit that was found got healed.<br />
* '''[filter]''': [[StandardUnitFilter]] All matching on-map units are healed. If no filter is supplied, it is tried to take the unit at $x1, $y1.<br />
* '''[filter_second]''': [[StandardUnitFilter]] all the units matching the filter ''and'' having the ''heals'' ability will have their animation played (if ''animate'' is set to yes) for each of the units healed.<br />
* '''amount''': (integer, default full) the maximum points the unit(s) will be healed. Can't set below 1 or above max_hitpoints. If "full", sets hitpoints to max_hitpoints. Before 1.9 the default is 0.<br />
* '''animate''': a boolean which indicate if the healing animations must be played. (default no)<br />
* '''moves''': (integer, default 0) The maximum current movement points the units will be "healed". Can't set below 0 or above max_moves. If "full", sets moves to max_moves.<br />
* '''restore_attacks''': (boolean, default no) Whether the units' attacks_left should be reset to their max_attacks (usually 1).<br />
* '''restore_statuses''': (boolean, default yes) Whether standard statuses should be reset to "no". This affects poisoned, slowed, petrified and unhealable. Before 1.9 this is always "no".<br />
<br />
=== [harm_unit] ===<br />
Harms every unit matching the filter, for the specific damage amount.<br />
* '''[filter]''': [[StandardUnitFilter]] all matching units will be harmed (required).<br />
* '''[filter_second]''': [[StandardUnitFilter]] if present, the first matching unit will attack all the units matching the filter above.<br />
* '''amount''': the amount of damage that will be done (required).<br />
* '''alignment''': (default neutral) applies an alignment to the damage, this means that if alignment=chaotic, the damage will be increased at night and reduced at day.<br />
* '''damage_type''': if present, amount will be altered by unit resistance to the damage type specified.<br />
* '''kill''': (default yes) if yes, when a harmed unit goes to or below 0 HP, it is killed; if no its HP are set to 1.<br />
* '''fire_event''': (default no) if yes, when a unit is killed by harming, the corresponding events are fired. If yes, also the corresponding advance and post advance events are fired.<br />
* '''animate''': (default no) if yes, scrolls to each unit before harming it and plays its defense (or attack, if it's the harmer) and death animations. Special values supported, other than the usual yes and no, are "attacker", that means only the harmer will be animated, and "defender", that means only the harmed units will be animated. If the supplied value is yes, attacker or defender also advancement animations are played.<br />
* '''[primary_attack], [secondary_attack]''': these set the weapon against which the harmed units will defend, and that the harming unit will use to attack, respectively (notice this is the opposite of '''[filter]''' and '''[filter_second]''' above). This allows for playing specific defense and attack animations. Both tags are expected to contain a [[FilterWML#Filtering_Weapons|Standard Weapon Filter]].<br />
* '''delay''': if animate=yes, sets the delay (in milliseconds, default 500) between each unit harming.<br />
* '''variable''': if present, the damage caused to the unit, altered by resistances, will be stored in a WML array with the given name, under the "harm_amount" key.<br />
* '''poisoned, slowed, petrified, unhealable''': (default no) if yes, every harmed unit that doesn't already have such status will have it set.<br />
* '''experience''': if yes, and there is a harmer, experience will be attributed like in regular combat.<br />
* '''resistance_multiplier''': the harmed unit's resistance is multiplied by the supplied value; this means that a value lower than 1 increases it, and a value greater than 1 decreases it. Default value is 1, that means no modification.<br />
<br />
=== [time_area] ===<br />
How a day should progress in a given area. Everywhere not specified in a [time_area] tag is affected by the [time] tags in the [scenario] tag.<br />
* [[StandardLocationFilter]]: the locations to affect. ''note: only for [event][time_area]s - at scenario toplevel [time_area] does not support [[StandardLocationFilter]], only location ranges''<br />
* '''[time]''': one or more tags describing the new schedule, see [[TimeWML]].<br />
* '''id''': an unique identifier assigned to a time_area. Optional, unless you want to remove the time_area later. Can be a comma-separated list when removing time_areas, see below.<br />
* '''remove''': (boolean) yes/no value. Indicates whether the specified time_area should be removed. Requires an identifier. If no identifier is used, however, all time_areas are removed.<br />
* '''current_time''': The time slot number (starting with zero) active at the creation of the area.<br />
<br />
''Example:'' (caves in parts of a map)<br />
[time_area]<br />
x=1-2,4-5<br />
y=1-2,1-2<br />
{UNDERGROUND}<br />
[/time_area]<br />
<br />
=== [remove_time_area] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This is a syntactic shortcut for [time_area] remove=.<br />
* '''id''': Comma-separated list of time area ids to remove.<br />
<br />
=== [end_turn] ===<br />
End the current side's turn. The current event is finished before the turn is ended. Also, if the current event (where the tag appears) has been fired by another event, that event (and the complete stack of other possible parent events) is ended before [end_turn] comes into affect. Also, events following the event stack that fired [end_turn] are not omitted (e.g. [end_turn] is used by a side turn event and a turn refresh event does something afterwards).<br />
<br />
=== [replace_map] ===<br />
<br />
Replaces the entire map.<br />
* '''map''': Content of a wesnoth map file. example:<br />
map="{campaigns/Heir_To_The_Throne/maps/01_The_Elves_Besieged.map}"<br />
* '''map_file''': {{DevFeature1.13|?}} Path to a Wesnoth map file; can be used instead of '''map'''. The file will be loaded when the tag is executed, rather than being embedded wholesale in the preprocessed WML.<br />
* '''expand''': if 'yes', allows the map size to increase. The expansion direction is currently always bottom-right.<br />
* '''shrink''': if 'yes', allows the map size to decrease. If the map size is reduced, any units that would no longer be on the map due to its coordinates no longer existing will be put into the recall list.<br />
Note: When a hex changes from a village terrain to a non-village terrain, and a team owned that village it loses that village. When a hex changes from a non-village terrain to a village terrain and there is a unit on that hex it does not automatically capture the village. The reason for not capturing villages it that there are too many choices to make; should a unit lose its movement points, should capture events be fired. It is easier to do this as wanted by the author in WML.<br />
<br />
=== [replace_schedule] ===<br />
Replace the time of day schedule of the entire scenario.<br />
* [[TimeWML]]: the new schedule.<br />
* '''current_time''': The time slot number (starting with zero) active at schedule replacement.<br />
<br />
=== [tunnel] ===<br />
<br />
Create a tunnel between some locations, later usable by units to move from source hex to target hex (using the movement cost of unit on the target terrain).<br />
<br />
'''Behavior Change as of Wesnoth 1.13.6:''' Vision is now possible (and enabled by default) through tunnels and allied units on the exit hex do not block a tunnel by default any more. This is done in order for moves through tunnels to be consistent with other moves. The previous behavior can still be accomplished by using the new optional keys listed below.<br />
<br />
* '''[filter]''': (required) [[StandardUnitFilter]] the units which can use the tunnel. Leave empty for "all units".<br />
* '''[source]''': (required) [[StandardLocationFilter]] the source hex(es).<br />
* '''[target]''': (required) [[StandardLocationFilter]] the target hex(es).<br />
* '''id''': (optional) identifier for the tunnel, to allow removing.<br />
* '''remove''': (boolean, default: no) If yes, removes all defined tunnels with the same ID (then only id= is necessary).<br />
* '''bidirectional''': (boolean, default: yes) If yes, creates also a tunnel in the other direction. <br />
* '''always_visible''': (boolean, default: no) If yes, the possible movement of enemies under fog can be seen.<br />
* '''allow_vision''': (boolean, default: yes) {{DevFeature1.13|6}} If no, vision through a tunnel is not possible. Note that in that case the tunnel cannot be used if the tunnel exit is under shroud (which previously was ''always'' the case).<br />
* '''pass_allied_units''': (boolean, default: yes) {{DevFeature1.13|6}} If no, allied (including own) units on the exit hex block a tunnel.<br />
<br />
(Note: The tunnel tag can also be used inside the [[AbilitiesWML|[teleport]]] ability, without remove= and id=).<br />
<br />
=== [do_command] ===<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Executes a command, specified using the same syntax as a [command] tag in [[ReplayWML]]. Not all [command]'s are valid: only these are accepted<br />
<br />
* [attack]<br />
* [move]<br />
* [recruit]<br />
* [recall]<br />
* [disband]<br />
* [fire_event]<br />
* [lua_ai] {{DevFeature1.13|12}} This has been removed and is replaced with [custom_command]<br />
<br />
The tags corresponding to player actions generally use the same codepath as if a player had ordered it. That means for example that only moves that player would be allowed to do are possible, and movement is interrupted when sighting enemy unit.<br />
<br />
One purpose of this tag is to allow scripting of noninteractive scenarios -- without a tag like this, this might require elaborate mechanisms to coerce ais in order to test these code paths.<br />
<br />
This command should always be replay safe.<br />
<br />
=== [put_to_recall_list] ===<br />
<br />
{{DevFeature1.13|0}}<br />
<br />
Puts a unit to the recall list of its side.<br />
* '''[[StandardUnitFilter]]''': the unit(s) to get put to the recall list.<br />
* '''heal''': (default=no) Whether the unit should be refreshed, similar to the unit moving to the recall list at the end of a scenario.<br />
<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for direct actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{MOVE_UNIT}''': Moves a unit to another location in the map and the player sees the movement (unlike [teleport])<br />
* '''{FULL_HEAL}''': Brings a unit to full HP<br />
* '''{LOYAL_UNIT}''': Create a loyal unit<br />
* '''{MODIFY_TERRAIN_MASK}''': Modify an area of terrain<br />
<br />
== See Also ==<br />
<br />
* [[InternalActionsWML]]<br />
* [[InterfaceActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60148LuaWML2019-01-09T02:42:40Z<p>Gfgtdf: </p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
[lua] is now also allowed in [era], [modification] and [resource], those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). Unlike other parts of the configurable gamestate the Lua state is not stored in savefiles, thus [lua] tags in [scenario] are executed not only before the scenario starts but also each time the game is loaded. Funtions defined in [lua] tags in [scenario] can be used in all [lua] tags in [event]s.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
...<br />
[/scenario]<br />
<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
<br />
local event_data = wesnoth.current.event_context<br />
if wml.variables["target_hex.is_set"] and<br />
(event_data.x1 ~= wml.variables["target_hex.x"] or event_data.y1 ~= wml.variables["target_hex.y"])<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if wml.variables["target_hex.is_set"] and<br />
(event_data.x1 ~= wml.variables["target_hex.x"] or event_data.y1 ~= wml.variables["target_hex.y"])<br />
</syntaxhighlight><br />
<br />
whether the variable ''wml.variables["target_hex"]'' matches the event parameters. Since ''wml.variables'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent but the wesnoth engine maps the variable wml.variables to the storage of WML variables.<br />
<br />
Without using wml.variables, the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
This short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
W = H.set_wml_action_metatable {}<br />
>><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
or<br />
<syntaxhighlight lang='lua'><br />
wesnoth.wml_actions.redraw {}<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data either in lua tables encoding wmloject or as a userdata object which has the exact same structure as above. Those userdata objects are called vconfig. vconfig objects are read-only however. Accessing fields or children on vconfig performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = helper.literal(cfg)<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
(Note2: You should not do that since it will break other addons that rely on the first_time_only=no default value.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
'''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#wesnoth.random|wesnoth.random]] function to synchronize random values. It has the same interface as math.random but is multiplayer-safe.<br />
<br />
Also available is [[LuaWML:Misc#helper.rand|helper.rand()]], which takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60147LuaWML2019-01-09T02:10:08Z<p>Gfgtdf: /* Encoding WML objects into Lua tables */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
[lua] is now also allowed in [era], [modification] and [resource], those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). Unlike other parts of the configurable gamestate the Lua state is not stored in savefiles, thus [lua] tags in [senario] are executed not only before the scenario starts but also each time the game is loaded. Funtions defined in [lua] tags in [scenario] can be used in all [lua] tags in [event]s.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
...<br />
[/scenario]<br />
<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
<br />
local event_data = wesnoth.current.event_context<br />
if wml.variables["target_hex.is_set"] and<br />
(event_data.x1 ~= wml.variables["target_hex.x"] or event_data.y1 ~= wml.variables["target_hex.y"])<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if wml.variables["target_hex.is_set"] and<br />
(event_data.x1 ~= wml.variables["target_hex.x"] or event_data.y1 ~= wml.variables["target_hex.y"])<br />
</syntaxhighlight><br />
<br />
whether the variable ''wml.variables["target_hex"]'' matches the event parameters. Since ''wml.variables'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent but the wesnoth engine maps the variable wml.variables to the storage of WML variables.<br />
<br />
Without using wml.variables, the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
This short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
W = H.set_wml_action_metatable {}<br />
>><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
or<br />
<syntaxhighlight lang='lua'><br />
wesnoth.wml_actions.redraw {}<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data either in lua tables encoding wmloject or as a userdata object which has the exact same structure as above. Those userdata objects are called vconfig. vconfig objects are read-only however. Accessing fields or children on vconfig performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = helper.literal(cfg)<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
(Note2: You should not do that since it will break other addons that rely on the first_time_only=no default value.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
'''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#wesnoth.random|wesnoth.random]] function to synchronize random values. It has the same interface as math.random but is multiplayer-safe.<br />
<br />
Also available is [[LuaWML:Misc#helper.rand|helper.rand()]], which takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60146LuaWML2019-01-09T01:58:46Z<p>Gfgtdf: /* Examples */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
[lua] is now also allowed in [era], [modification] and [resource], those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). Unlike other parts of the configurable gamestate the Lua state is not stored in savefiles, thus [lua] tags in [senario] are executed not only before the scenario starts but also each time the game is loaded. Funtions defined in [lua] tags in [scenario] can be used in all [lua] tags in [event]s.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
...<br />
[/scenario]<br />
<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
<br />
local event_data = wesnoth.current.event_context<br />
if wml.variables["target_hex.is_set"] and<br />
(event_data.x1 ~= wml.variables["target_hex.x"] or event_data.y1 ~= wml.variables["target_hex.y"])<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if wml.variables["target_hex.is_set"] and<br />
(event_data.x1 ~= wml.variables["target_hex.x"] or event_data.y1 ~= wml.variables["target_hex.y"])<br />
</syntaxhighlight><br />
<br />
whether the variable ''wml.variables["target_hex"]'' matches the event parameters. Since ''wml.variables'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent but the wesnoth engine maps the variable wml.variables to the storage of WML variables.<br />
<br />
Without using wml.variables, the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
This short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
W = H.set_wml_action_metatable {}<br />
>><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
or<br />
<syntaxhighlight lang='lua'><br />
wesnoth.wml_actions.redraw {}<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data in a userdata object which has the exact same structure as above. It is read-only however. Accessing fields or children performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = cfg.__literal<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
Note that, since the object is a userdata and not a table, '''pairs''' and '''ipairs''' are unfortunately not usable on it. So scripts have to work at a lower level. For instance, the following function returns the first sub-tag with a given name and it works both on WML tables and WML userdata:<br />
<br />
<syntaxhighlight lang=lua><br />
function get_child(cfg, name)<br />
for i = 1, #cfg do<br />
local v = cfg[i]<br />
if v[1] == name then return v[2] end<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
{{DevFeature1.13|2}} '''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#wesnoth.random|wesnoth.random]] function to synchronize random values. It has the same interface as math.random but is multiplayer-safe.<br />
<br />
Also available is [[LuaWML:Misc#helper.rand|helper.rand()]], which takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60145LuaWML2019-01-09T01:46:32Z<p>Gfgtdf: /* Global environment */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
[lua] is now also allowed in [era], [modification] and [resource], those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). Unlike other parts of the configurable gamestate the Lua state is not stored in savefiles, thus [lua] tags in [senario] are executed not only before the scenario starts but also each time the game is loaded. Funtions defined in [lua] tags in [scenario] can be used in all [lua] tags in [event]s.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
...<br />
[/scenario]<br />
<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
local event_data = wesnoth.current.event_context<br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
</syntaxhighlight><br />
<br />
whether the variable ''V.target_hex'' matches the event parameters. Since ''V'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent (they get lost on reloading), so it shouldn't be used to store data. In order to have an easy way to access the usual persistent Wml variables, the global variable ''V'' was mapped to the storage of WML variables by the following ''preload'' event.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
-- skipping some other initializations<br />
-- ...<br />
V = H.set_wml_var_metatable {}<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Without a prelude redirecting ''V'', the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
Again, this short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
W = H.set_wml_action_metatable {}<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data in a userdata object which has the exact same structure as above. It is read-only however. Accessing fields or children performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = cfg.__literal<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
Note that, since the object is a userdata and not a table, '''pairs''' and '''ipairs''' are unfortunately not usable on it. So scripts have to work at a lower level. For instance, the following function returns the first sub-tag with a given name and it works both on WML tables and WML userdata:<br />
<br />
<syntaxhighlight lang=lua><br />
function get_child(cfg, name)<br />
for i = 1, #cfg do<br />
local v = cfg[i]<br />
if v[1] == name then return v[2] end<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
{{DevFeature1.13|2}} '''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#wesnoth.random|wesnoth.random]] function to synchronize random values. It has the same interface as math.random but is multiplayer-safe.<br />
<br />
Also available is [[LuaWML:Misc#helper.rand|helper.rand()]], which takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60144LuaWML2019-01-09T01:34:23Z<p>Gfgtdf: /* The [lua] tag */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
[lua] is now also allowed in [era], [modification] and [resource], those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). For instance, a function defined in an event can be used in all the events that happen after it.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
local event_data = wesnoth.current.event_context<br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
</syntaxhighlight><br />
<br />
whether the variable ''V.target_hex'' matches the event parameters. Since ''V'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent (they get lost on reloading), so it shouldn't be used to store data. In order to have an easy way to access the usual persistent Wml variables, the global variable ''V'' was mapped to the storage of WML variables by the following ''preload'' event.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
-- skipping some other initializations<br />
-- ...<br />
V = H.set_wml_var_metatable {}<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Without a prelude redirecting ''V'', the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
Again, this short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
W = H.set_wml_action_metatable {}<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data in a userdata object which has the exact same structure as above. It is read-only however. Accessing fields or children performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = cfg.__literal<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
Note that, since the object is a userdata and not a table, '''pairs''' and '''ipairs''' are unfortunately not usable on it. So scripts have to work at a lower level. For instance, the following function returns the first sub-tag with a given name and it works both on WML tables and WML userdata:<br />
<br />
<syntaxhighlight lang=lua><br />
function get_child(cfg, name)<br />
for i = 1, #cfg do<br />
local v = cfg[i]<br />
if v[1] == name then return v[2] end<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
{{DevFeature1.13|2}} '''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#wesnoth.random|wesnoth.random]] function to synchronize random values. It has the same interface as math.random but is multiplayer-safe.<br />
<br />
Also available is [[LuaWML:Misc#helper.rand|helper.rand()]], which takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60143LuaWML2019-01-08T23:23:03Z<p>Gfgtdf: /* Remarks on Random Numbers */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
{{DevFeature1.13|0}}<br />
[lua] is now also allowed in [era] and [modification] those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). For instance, a function defined in an event can be used in all the events that happen after it.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
local event_data = wesnoth.current.event_context<br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
</syntaxhighlight><br />
<br />
whether the variable ''V.target_hex'' matches the event parameters. Since ''V'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent (they get lost on reloading), so it shouldn't be used to store data. In order to have an easy way to access the usual persistent Wml variables, the global variable ''V'' was mapped to the storage of WML variables by the following ''preload'' event.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
-- skipping some other initializations<br />
-- ...<br />
V = H.set_wml_var_metatable {}<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Without a prelude redirecting ''V'', the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
Again, this short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
W = H.set_wml_action_metatable {}<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data in a userdata object which has the exact same structure as above. It is read-only however. Accessing fields or children performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = cfg.__literal<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
Note that, since the object is a userdata and not a table, '''pairs''' and '''ipairs''' are unfortunately not usable on it. So scripts have to work at a lower level. For instance, the following function returns the first sub-tag with a given name and it works both on WML tables and WML userdata:<br />
<br />
<syntaxhighlight lang=lua><br />
function get_child(cfg, name)<br />
for i = 1, #cfg do<br />
local v = cfg[i]<br />
if v[1] == name then return v[2] end<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
{{DevFeature1.13|2}} '''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#wesnoth.random|wesnoth.random]] function to synchronize random values. It has the same interface as math.random but is multiplayer-safe.<br />
<br />
Also available is [[LuaWML:Misc#helper.rand|helper.rand()]], which takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML&diff=60142LuaWML2019-01-08T20:24:22Z<p>Gfgtdf: /* Skeleton of a preload event */</p>
<hr />
<div>{{WML Tags}}<br />
<br />
== The '''[lua]''' tag ==<br />
<br />
This tag is a part of [[ActionWML]], thus can be used inside [event] and at other places where [[ActionWML]] can be used. It makes it possible to write actions with the [http://www.lua.org Lua 5.3] language.<br />
<br />
It is also possible to put this tag inside a [scenario] [[ScenarioWML]], those tags will be executed immediately when the lua engine loads which is even before the scenario preload event is fired.<br />
<br />
{{DevFeature1.13|0}}<br />
[lua] is now also allowed in [era] and [modification] those [lua] tags are then copied into the [scenario]/[multiplayer] when it is played just like [event]s inside [era] or [modification]<br />
<br />
The tag supports only the '''code''' key, which is a string containing the Lua scripts. Since Lua makes usage of the quotes and the { and } symbols, it is certainly wise to enclose the script between stronger quotes, as they prevent the preprocessor from performing macro expansion and tokenization.<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << wesnoth.message "Hello World!" >><br />
[/lua]<br />
</syntaxhighlight><br />
<br />
The Lua kernel can also be accessed from the [[CommandMode|command mode]]:<br />
<br />
:lua local u = wesnoth.get_units({ id = "Konrad" })[1]; u.moves = 5<br />
<br />
The '''[args]''' sub-tag can be used to pass a WML object to the script via its variadic local variable "'''...'''".<br />
<br />
<syntaxhighlight lang='wml'><br />
[lua]<br />
code = << local t = ...; wesnoth.message(tostring(t.text)) >><br />
[args]<br />
text = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
</syntaxhighlight><br />
<br />
== Global environment ==<br />
<br />
All the Lua scripts of a scenario share the same global environment (aka Lua state). For instance, a function defined in an event can be used in all the events that happen after it.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
function narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "Hello world!"<br />
[/args]<br />
[/lua]<br />
[lua]<br />
code = << narrator(...) >><br />
[args]<br />
sentence = _ "How are you today?"<br />
[/args]<br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
In the example above, the redundant structure could be hidden behind macros. But it may be better to simply define a new WML tag.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name = preload<br />
first_time_only = no<br />
[lua]<br />
code = <<<br />
-- The function is now placed in the wesnoth.wml_actions table<br />
-- The tag is [narrator], same as the function name<br />
function wesnoth.wml_actions.narrator(t)<br />
-- Behave like the [message] tag.<br />
wesnoth.fire("message",<br />
{ speaker = "narrator", message = t.sentence })<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
<br />
[event]<br />
name = turn 1<br />
[narrator]<br />
sentence = _ "Hello world!"<br />
[/narrator]<br />
[narrator]<br />
sentence = _ "How are you today?"<br />
[/narrator]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
The global environment is not preserved over save/load cycles. Therefore, storing values in the global environment is generally a bad idea. The only time assigning global variables (including function definitions) makes sense is in a [lua] block directly in [scenario] or during a [[EventWML#Predefined 'name' Key Values|preload]] event, as this event is always run. Therefore, helper functions defined at that time will be available to all the later scripts.<br />
<br />
The global environment initially contains the following modules: [http://www.lua.org/manual/5.1/manual.html#5.1 basic] (no name), [http://www.lua.org/manual/5.1/manual.html#5.4 string], [http://www.lua.org/manual/5.1/manual.html#5.5 table], and [http://www.lua.org/manual/5.1/manual.html#5.6 math]. A '''wesnoth''' module is also available, it provides access to the [[#Interface to the C++ engine|C++ engine]]. Additionally, the functions clock, date, time and difftime from the [http://www.lua.org/manual/5.1/manual.html#5.8 os] library (keep in mind that they aren't multiplayer- and replay-safe), as well as traceback from the [http://www.lua.org/manual/5.1/manual.html#5.9 debug] library are also available.<br />
<br />
At the start of a script, the variadic local variable '''...''' (three dots) is a proxy table representing [[#Encoding WML objects into Lua tables|WML data]]. This table is the content of the '''[args]''' sub-tag of the '''[lua]''' tag, if any.<br />
<br />
== Examples ==<br />
<br />
The following WML event is taken from Wesnoth' tutorial. It will serve as an example to present how Lua scripts are embedded into Wesnoth. The event is fired whenever a unit from side 1 (that is, the hero controlled by the user) moves to a tile that is not the one set in the WML variable ''target_hex''.<br />
<br />
<syntaxhighlight lang='wml'><br />
# General catch for them moving to the wrong place.<br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[if]<br />
[variable]<br />
name=target_hex.is_set<br />
equals=yes<br />
[/variable]<br />
[then]<br />
[if]<br />
[variable]<br />
name=x1<br />
equals=$target_hex.x<br />
[/variable]<br />
[variable]<br />
name=y1<br />
equals=$target_hex.y<br />
[/variable]<br />
[then]<br />
[/then]<br />
[else]<br />
[redraw][/redraw]<br />
[message]<br />
speaker=narrator<br />
message=_ "*Oops!<br />
You moved to the wrong place! After this message, you can press 'u' to undo, then try again." +<br />
_ "<br />
*Left click or press spacebar to continue..."<br />
[/message]<br />
[/else]<br />
[/if]<br />
[/then]<br />
[/if]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
A Lua script that performs the same action is presented below.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=moveto<br />
first_time_only=no<br />
[allow_undo][/allow_undo]<br />
[filter]<br />
side=1<br />
[/filter]<br />
<br />
[lua]<br />
code = <<<br />
local event_data = wesnoth.current.event_context<br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
then<br />
W.redraw()<br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
end<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Here is a more detailed explanation of the Lua code. Its first line<br />
<br />
<syntaxhighlight lang='lua'><br />
local event_data = wesnoth.current.event_context<br />
</syntaxhighlight><br />
<br />
puts the event data into the ''event_data'' local variable. Since it is a ''moveto'' event, the ''event_data'' table contains the destination of the unit in the ''x1'' and ''y1'' fields.<br />
<br />
The next two lines then test<br />
<br />
<syntaxhighlight lang='lua'><br />
if V.target_hex.is_set and<br />
(event_data.x1 ~= V.target_hex.x or event_data.y1 ~= V.target_hex.y)<br />
</syntaxhighlight><br />
<br />
whether the variable ''V.target_hex'' matches the event parameters. Since ''V'' is not a local variable, it is taken from the global environment. Usually, variables from the global environment are not persistent (they get lost on reloading), so it shouldn't be used to store data. In order to have an easy way to access the usual persistent Wml variables, the global variable ''V'' was mapped to the storage of WML variables by the following ''preload'' event.<br />
<br />
<syntaxhighlight lang='wml'><br />
[event]<br />
name=preload<br />
first_time_only=no<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
-- skipping some other initializations<br />
-- ...<br />
V = H.set_wml_var_metatable {}<br />
>><br />
[/lua]<br />
[/event]<br />
</syntaxhighlight><br />
<br />
Without a prelude redirecting ''V'', the conditional would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
if wesnoth.get_variable("target_hex.is_set") and<br />
(event_data.x1 ~= wesnoth.get_variable("target_hex.x") or event_data.y1 ~= wesnoth.get_variable("target_hex.y")<br />
</syntaxhighlight><br />
<br />
The body of the conditional then performs the [[InterfaceActionsWML#Other interface tags|[redraw]]] action.<br />
<br />
<syntaxhighlight lang='lua'><br />
W.redraw()<br />
</syntaxhighlight><br />
<br />
Again, this short syntax is made possible by a line of the prelude that makes ''W'' a proxy for performing WML actions.<br />
<br />
<syntaxhighlight lang='lua'><br />
W = H.set_wml_action_metatable {}<br />
</syntaxhighlight><br />
<br />
Without this shortcut, the first statement would have been written<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.fire("redraw")<br />
</syntaxhighlight><br />
<br />
Finally the script displays a message by<br />
<br />
<syntaxhighlight lang='lua'><br />
narrator_says(_ "*Oops!\nYou moved to the wrong place! After this message, you can press 'u' to undo, then try again.")<br />
</syntaxhighlight><br />
<br />
The ''narrator_says'' function is defined in the prelude too, since the construct behind it occurs several times in the tutorial. In plain WML, macros would have been used instead. The definition of the function is<br />
<br />
<syntaxhighlight lang='lua'><br />
function narrator_says(m)<br />
W.message { speaker="narrator",<br />
message = m .. _ "\n*Left click or press spacebar to continue..." }<br />
end<br />
</syntaxhighlight><br />
<br />
The function fires a [[InterfaceActionsWML#.5Bmessage.5D|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the ''_'' symbol to mark them as translatable. (Note that ''_'' is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:<br />
<br />
<syntaxhighlight lang='lua'><br />
_ = wesnoth.textdomain "wesnoth-tutorial"<br />
</syntaxhighlight><br />
<br />
A longer translation of the tutorial is available at [https://gna.org/patch/download.php?file_id=5483].<br />
<br />
== Interface to the engine and helper functions ==<br />
<br />
<br><div class="navtemplate" style="width: auto; max-width: 75%; margin: 0 auto; border: 1px solid #c60; border-left-width: 8px"><div style="float:left;position:relative;top:-14px;left:-6px">https://raw.github.com/wesnoth/wesnoth/master/data/core/images/items/bones.png</div><p style="margin:0"><strong>This section is in the process of being moved.</strong> The information here remains accurate as of 1.14.0, but for 1.15.0 and later, [[LuaAPI]] is planned to be the definitive source.</p></div><br><br />
<br />
Functionalities of the game engine are available through the functions contained in the '''wesnoth''' global table. Some of these functions return proxy tables. Writes to fields marked "read-only" are ignored. The '''__cfg''' fields return plain tables; in particular, writes do not modify the original object, and reads return the values from the time the dump was performed.<br />
<br />
Some helper functions are provided by the '''lua/helper.lua''' library. They are stored inside a table that is returned when loading the library with [[LuaWML:Files#wesnoth.require|wesnoth.require]].<br />
<br />
<syntaxhighlight lang='lua'><br />
helper = wesnoth.require "lua/helper.lua"<br />
</syntaxhighlight><br />
<br />
=== WML variables ===<br />
<br />
* [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]]<br />
* [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]]<br />
* [[LuaWML:Variables#wesnoth.get_all_vars|wesnoth.get_all_vars]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Variables#wesnoth.wml_matches_filter|wesnoth.wml_matches_filter]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Variables#helper.set_wml_var_metatable|helper.set_wml_var_metatable]]<br />
* [[LuaWML:Variables#helper.get_child|helper.get_child]]<br />
* [[LuaWML:Variables#helper.get_nth_child|helper.get_nth_child]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_count|helper.child_count]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.child_range|helper.child_range]]<br />
* [[LuaWML:Variables#helper.child_array|helper.child_array]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Variables#helper.get_variable_array|helper.get_variable_array]]<br />
* [[LuaWML:Variables#helper.get_variable_proxy_array|helper.get_variable_proxy_array]]<br />
* [[LuaWML:Variables#helper.set_variable_array|helper.set_variable_array]]<br />
<br />
=== Events and WML actions ===<br />
<br />
* [[LuaWML:Events#wesnoth.fire|wesnoth.fire]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]]<br />
* [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_conditionals]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.game_events|wesnoth.game_events]]<br />
* [[LuaWML:Events#wesnoth.persistent_tags|wesnoth.persistent_tags]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Events#wesnoth.fire_event|wesnoth.fire_event]]<br />
* [[LuaWML:Events#wesnoth.fire_event_by_id|wesnoth.fire_event_by_id]] {{DevFeature1.13|6}}<br />
* [[LuaWML:Events#wesnoth.add_event_handler|wesnoth.add_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.remove_event_handler|wesnoth.remove_event_handler]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Events#wesnoth.eval_conditional|wesnoth.eval_conditional]]<br />
* [[LuaWML:Events#wesnoth.tovconfig|wesnoth.tovconfig]]<br />
* [[LuaWML:Events#helper.set_wml_action_metatable|helper.set_wml_action_metatable]]<br />
* [[LuaWML:Events#helper.wml_error|helper.wml_error]]<br />
* [[LuaWML:Events#helper.literal|helper.literal]]<br />
* [[LuaWML:Events#helper.parsed|helper.parsed]]<br />
* [[LuaWML:Events#helper.shallow_literal|helper.shallow_literal]]<br />
* [[LuaWML:Events#helper.shallow_parsed|helper.shallow_parsed]]<br />
* [[LuaWML:Events#on_event.lua|on_event.on_event]] {{DevFeature1.13|6}}<br />
<br />
=== User interface ===<br />
* [[LuaWML:Display#wesnoth.get_viewing_side|wesnoth.get_viewing_side]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Display#wesnoth.message|wesnoth.message]]<br />
* [[LuaWML:Display#wesnoth.clear_messages|wesnoth.clear_messages]]<br />
* [[LuaWML:Display#wesnoth.textdomain|wesnoth.textdomain]]<br />
* [[LuaWML:Display#wesnoth.delay|wesnoth.delay]]<br />
* [[LuaWML:Display#wesnoth.float_label|wesnoth.float_label]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_hex]]<br />
* [[LuaWML:Display#wesnoth.select_unit|wesnoth.select_unit]]<br />
* [[LuaWML:Display#wesnoth.highlight_hex|wesnoth.highlight_hex]]<br />
* [[LuaWML:Display#wesnoth.deselect_hex|wesnoth.deselect_hex]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.scroll_to_tile|wesnoth.scroll_to_tile]]<br />
* [[LuaWML:Display#wesnoth.lock_view|wesnoth.lock_view]]<br />
* [[LuaWML:Display#wesnoth.view_locked|wesnoth.view_locked]]<br />
* [[LuaWML:Display#wesnoth.play_sound|wesnoth.play_sound]]<br />
* [[LuaWML:Display#wesnoth.set_music|wesnoth.set_music]]<br />
* [[LuaWML:Display#wesnoth.music_list|wesnoth.music_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.sound_volume|wesnoth.sound_volume]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_dialog|wesnoth.show_message_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_popup_dialog|wesnoth.show_popup_dialog]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.show_story|wesnoth.show_story]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.show_message_box]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_menu|wesnoth.show_menu]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.alert]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_message_box|wesnoth.confirm]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Display#wesnoth.show_dialog|wesnoth.show_dialog]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_value|wesnoth.set_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.get_dialog_value|wesnoth.get_dialog_value]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_active|wesnoth.set_dialog_active]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_callback|wesnoth.set_dialog_callback]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_markup|wesnoth.set_dialog_markup]]<br />
* [[LuaWML:Display#wesnoth.set_dialog_focus|wesnoth.set_dialog_focus]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_visible|wesnoth.set_dialog_visible]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.set_dialog_canvas|wesnoth.set_dialog_canvas]]<br />
* [[LuaWML:Display#wesnoth.add_dialog_tree_node|wesnoth.add_dialog_tree_node]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Display#wesnoth.remove_dialog_item|wesnoth.remove_dialog_item]] {{DevFeature1.13|1}}<br />
* [[LuaWML:Display#wesnoth.get_displayed_unit|wesnoth.get_displayed_unit]]<br />
* [[LuaWML:Display#wesnoth.theme_items|wesnoth.theme_items]]<br />
* [[LuaWML:Display#helper.get_user_choice|helper.get_user_choice]]<br />
* [[LuaWML:Display#wesnoth.is_skipping_messages|wesnoth.is_skipping_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.skip_messages|wesnoth.skip_messages]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Display#wesnoth.log|wesnoth.log]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Display#wesnoth.zoom|wesnoth.zoom]] {{DevFeature1.13|8}}<br />
<br />
=== Map and terrains ===<br />
<br />
* [[LuaWML:Tiles#wesnoth.get_map_size|wesnoth.get_map_size]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain|wesnoth.get_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.set_terrain|wesnoth.set_terrain]]<br />
* [[LuaWML:Tiles#wesnoth.get_terrain_info|wesnoth.get_terrain_info]]<br />
* [[LuaWML:Tiles#wesnoth.get_selected_tile|wesnoth.get_selected_tile]]<br />
* [[LuaWML:Tiles#wesnoth.get_locations|wesnoth.get_locations]]<br />
* [[LuaWML:Tiles#wesnoth.get_villages|wesnoth.get_villages]]<br />
* [[LuaWML:Tiles#wesnoth.match_location|wesnoth.match_location]]<br />
* [[LuaWML:Tiles#wesnoth.add_tile_overlay|wesnoth.add_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.remove_tile_overlay|wesnoth.remove_tile_overlay]]<br />
* [[LuaWML:Tiles#wesnoth.add_fog|wesnoth.add_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_fog|wesnoth.remove_fog]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.add_sound_source|wesnoth.add_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.remove_sound_source|wesnoth.remove_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.get_sound_source|wesnoth.get_sound_source]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_direction|wesnoth.map.get_direction]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_relative_dir|wesnoth.map.get_relative_dir]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.rotate_right_around_center|wesnoth.map.rotate_right_around_center]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.get_adjacent_tiles|wesnoth.map.get_adjacent_tiles]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.tiles_adjacent|wesnoth.map.tiles_adjacent]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.map.distance_between|wesnoth.map.distance_between]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Tiles#wesnoth.label|wesnoth.label]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Tiles#wesnoth.special_locations|wesnoth.special_locations]] {{DevFeature1.13|12}}<br />
* [[LuaWML:Tiles#items.place_image|items.place_image]]<br />
* [[LuaWML:Tiles#items.place_halo|items.place_halo]]<br />
* [[LuaWML:Tiles#items.remove|items.remove]]<br />
<br />
=== Time of day schedule ===<br />
<br />
* [[LuaWML:Time#wesnoth.get_time_of_day|wesnoth.get_time_of_day]]<br />
* [[LuaWML:Time#wesnoth.add_time_area|wesnoth.add_time_area]] {{DevFeature1.13|0}}<br />
* [[LuaWML:Time#wesnoth.remove_time_area|wesnoth.remove_time_area]] {{DevFeature1.13|0}}<br />
<br />
=== Units ===<br />
<br />
* [[LuaWML:Units#wesnoth.get_units|wesnoth.get_units]]<br />
* [[LuaWML:Units#wesnoth.get_unit|wesnoth.get_unit]]<br />
* [[LuaWML:Units#wesnoth.match_unit|wesnoth.match_unit]]<br />
* [[LuaWML:Units#wesnoth.put_unit|wesnoth.put_unit]]<br />
* [[LuaWML:Units#wesnoth.erase_unit|wesnoth.erase_unit]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Units#wesnoth.get_recall_units|wesnoth.get_recall_units]]<br />
* [[LuaWML:Units#wesnoth.put_recall_unit|wesnoth.put_recall_unit]]<br />
* [[LuaWML:Units#wesnoth.create_unit|wesnoth.create_unit]]<br />
* [[LuaWML:Units#wesnoth.copy_unit|wesnoth.copy_unit]]<br />
* [[LuaWML:Units#wesnoth.extract_unit|wesnoth.extract_unit]]<br />
* [[LuaWML:Units#wesnoth.add_modification|wesnoth.add_modification]]<br />
* [[LuaWML:Units#wesnoth.remove_modifications|wesnoth.remove_modifications]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.unit_resistance|wesnoth.unit_resistance]]<br />
* [[LuaWML:Units#wesnoth.unit_defense|wesnoth.unit_defense]]<br />
* [[LuaWML:Units#wesnoth.unit_movement_cost|wesnoth.unit_movement_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_vision_cost|wesnoth.unit_vision_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_jamming_cost|wesnoth.unit_jamming_cost]]<br />
* [[LuaWML:Units#wesnoth.unit_ability|wesnoth.unit_ability]]<br />
* [[LuaWML:Units#wesnoth.unit_types|wesnoth.unit_types]]<br />
* [[LuaWML:Units#wesnoth.races|wesnoth.races]]<br />
* [[LuaWML:Units#wesnoth.get_traits|wesnoth.get_traits]]<br />
* [[LuaWML:Units#wesnoth.advance_unit|wesnoth.advance_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.add_known_unit|wesnoth.add_known_unit]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Units#wesnoth.simulate_combat|wesnoth.simulate_combat]]<br />
* [[LuaWML:Units#wesnoth.transform_unit|wesnoth.transform_unit]]<br />
* [[LuaWML:Units#wesnoth.create_animator|wesnoth.create_animator]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Units#wesnoth.effects|wesnoth.effects]] {{DevFeature1.13|2}}<br />
<br />
=== Sides ===<br />
<br />
* [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]]<br />
* [[LuaWML:Sides#wesnoth.get_sides|wesnoth.get_sides]]<br />
* [[LuaWML:Sides#wesnoth.get_village_owner|wesnoth.get_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.set_village_owner|wesnoth.set_village_owner]]<br />
* [[LuaWML:Sides#wesnoth.is_enemy|wesnoth.is_enemy]]<br />
* [[LuaWML:Sides#wesnoth.match_side|wesnoth.match_side]]<br />
* [[LuaWML:Sides#wesnoth.get_starting_location|wesnoth.get_starting_location]]<br />
* [[LuaWML:Sides#wesnoth.set_side_id|wesnoth.set_side_id]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.place_shroud|wesnoth.place_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.remove_shroud|wesnoth.remove_shroud]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_fogged|wesnoth.is_fogged]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.is_shrouded|wesnoth.is_shrouded]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.switch_ai|wesnoth.switch_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.append_ai|wesnoth.append_ai]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.add_ai_component|wesnoth.add_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.change_ai_component|wesnoth.change_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#wesnoth.delete_ai_component|wesnoth.delete_ai_component]] {{DevFeature1.13|7}}<br />
* [[LuaWML:Sides#helper.all_teams|helper.all_teams]]<br />
* [[LuaWML:Sides#helper.get_side_variable|helper.get_side_variable]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Sides#helper.set_side_variable|helper.set_side_variable]] {{DevFeature1.13|?}}<br />
<br />
=== Pathfinder ===<br />
<br />
* [[LuaWML:Pathfinder#wesnoth.find_path|wesnoth.find_path]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_vacant_tile|wesnoth.find_vacant_tile]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_reach|wesnoth.find_reach]]<br />
* [[LuaWML:Pathfinder#wesnoth.find_cost_map|wesnoth.find_cost_map]]<br />
* [[LuaWML:Pathfinder#helper.distance_between|helper.distance_between]]<br />
* [[LuaWML:Pathfinder#helper.adjacent_tiles|helper.adjacent_tiles]]<br />
<br />
=== Lua files ===<br />
<br />
* [[LuaWML:Files#wesnoth.dofile|wesnoth.dofile]]<br />
* [[LuaWML:Files#wesnoth.require|wesnoth.require]]<br />
* [[LuaWML:Files#wesnoth.have_file|wesnoth.have_file]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Files#wesnoth.read_file|wesnoth.read_file]] {{DevFeature1.13|5}}<br />
<br />
=== Location sets ===<br />
<br />
* [[LuaWML:Location_set#location_set.create|location_set.create]]<br />
* [[LuaWML:Location_set#location_set.of_pairs|location_set.of_pairs]]<br />
* [[LuaWML:Location_set#location_set.of_wml_var|location_set.of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:empty|location_set:empty]]<br />
* [[LuaWML:Location_set#location_set:size|location_set:size]]<br />
* [[LuaWML:Location_set#location_set:clear|location_set:clear]]<br />
* [[LuaWML:Location_set#location_set:get|location_set:get]]<br />
* [[LuaWML:Location_set#location_set:insert|location_set:insert]]<br />
* [[LuaWML:Location_set#location_set:remove|location_set:remove]]<br />
* [[LuaWML:Location_set#location_set:of_pairs|location_set:of_pairs]]<br />
* [[LuaWML:Location_set#location_set:of_wml_var|location_set:of_wml_var]]<br />
* [[LuaWML:Location_set#location_set:to_pairs|location_set:to_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_stable_pairs|location_set:to_stable_pairs]]<br />
* [[LuaWML:Location_set#location_set:to_wml_var|location_set:to_wml_var]]<br />
* [[LuaWML:Location_set#location_set:union|location_set:union]]<br />
* [[LuaWML:Location_set#location_set:inter|location_set:inter]]<br />
* [[LuaWML:Location_set#location_set:iter|location_set:iter]]<br />
* [[LuaWML:Location_set#location_set:stable_iter|location_set:stable_iter]]<br />
* [[LuaWML:Location_set#location_set:filter|location_set:filter]]<br />
* [[LuaWML:Location_set#location_set:union_merge|location_set:union_merge]]<br />
* [[LuaWML:Location_set#location_set:inter_merge|location_set:inter_merge]]<br />
<br />
=== Miscellaneous ===<br />
<br />
* [[LuaWML:Misc#wesnoth.game_config|wesnoth.game_config]]<br />
* [[LuaWML:Misc#wesnoth.get_era|wesnoth.get_era]]<br />
* [[LuaWML:Misc#wesnoth.current|wesnoth.current]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choice|wesnoth.synchronize_choice]]<br />
* [[LuaWML:Misc#wesnoth.synchronize_choices|wesnoth.synchronize_choices]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.unsynced|wesnoth.unsynced]] {{DevFeature1.13|?}}<br />
* [[LuaWML:Misc#wesnoth.get_image_size|wesnoth.get_image_size]]<br />
* [[LuaWML:Misc#wesnoth.compare_versions|wesnoth.compare_versions]]<br />
* [[LuaWML:Misc#wesnoth.have_file|wesnoth.have_file]]<br />
* [[LuaWML:Misc#wesnoth.debug|wesnoth.debug]]<br />
* [[LuaWML:Misc#wesnoth.get_time_stamp|wesnoth.get_time_stamp]]<br />
* [[LuaWML:Misc#wesnoth.random|wesnoth.random]] {{DevFeature1.13|2}}<br />
* [[LuaWML:Misc#wesnoth.eval_formula|wesnoth.eval_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.compile_formula|wesnoth.compile_formula]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.name_generator|wesnoth.name_generator]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.set_next_scenario|wesnoth.set_next_scenario]] {{DevFeature1.13|5}}<br />
* [[LuaWML:Misc#wesnoth.format|wesnoth.format]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_conjunct_list|wesnoth.format_conjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.format_disjunct_list|wesnoth.format_disjunct_list]] {{DevFeature1.13|8}}<br />
* [[LuaWML:Misc#wesnoth.wesnoth.end_turn|wesnoth.end_turn]] {{DevFeature1.13|ß}}<br />
* [[LuaWML:Misc#wml.tag|wml.tag]]<br />
* [[LuaWML:Misc#helper.modify_unit|helper.modify_unit]]<br />
* [[LuaWML:Misc#helper.move_unit_fake|helper.move_unit_fake]]<br />
* [[LuaWML:Misc#helper.rand|helper.rand]]<br />
* [[LuaWML:Misc#helper.round|helper.round]]<br />
* [[LuaWML:Misc#helper.shuffle|helper.shuffle]]<br />
<br />
=== Functions that should not be used ===<br />
<br />
If you take a look at Wesnoth's own lua files, you might find some undocumented functions use in the implementations of WML tags. Where possible, you should avoid using them, as they might be changed or removed with no compatibility for further releases. Instead, use the corresponding wml tags (in lua you can use <tt>wesnoth.wml_actions.tag_name(cfg)</tt>, though keep in mind that this won't substitute variables in the config).<br />
<br />
If uncertain whether an undocumented feature is safe to use, ask on the forums, Discord, or IRC. It may turn out that someone simply forgot to add it to the wiki.<br />
<br />
* wesnoth.redraw<br />
* wesnoth.set_menu_item<br />
* wesnoth.clear_menu_item<br />
* wesnoth.modify_ai<br />
* wesnoth.print<br />
* wesnoth.end_level<br />
<br />
== Encoding WML objects into Lua tables ==<br />
<br />
Function [[LuaWML:Events#wesnoth.fire|wesnoth.fire]] expects a table representing a WML object as its second argument (if needed). Function [[LuaWML:Variables#wesnoth.set_variable|wesnoth.set_variable]] allows to modify whole WML objects, again by passing it a table. Function [[LuaWML:Variables#wesnoth.get_variable|wesnoth.get_variable]] transforms a WML object into a table, if its second argument is not set to ''true''. All these tables have the same format.<br />
<br />
Scalar fields are transformed into WML attributes. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
a_bool = true,<br />
an_int = 42,<br />
a_float = 1.25,<br />
a_string = "scout",<br />
a_translation = _ "Hello World!"<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
a_bool = "yes"<br />
an_int = "42"<br />
a_float = "1.25"<br />
a_string = "scout"<br />
a_translation = _ "Hello World!"<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
WML child objects are not stored as Lua named fields, since several of them can have the same tag. Moreover, their tags can conflict with the attribute keys. So child objects are stored as pairs string + table in the unnamed fields in definition order. This means that for every subtag appearing in the wml code there is an additional table "layer" in the corresponding WML table of the form <code>{[1] = "tag_name", [2] = {}}</code> which is equivalent to <code>{"tag_name", {}}</code>. [1] etc are the unnamed fields (as opposed to wml attributes). The table under [2] in this subtable then holds the wml attributes from inside the wml subtag. So every subtag other than the toplevel tag corresponds to two nested tables each. For instance, the following Lua table<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
{ "bar", { v = 1, w = 2 } },<br />
{ "foo", { x = false } },<br />
{ "bar", { y = "foo" } },<br />
{ "foobar", { z = 5, { "barfoo", {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
is equivalent to the content of the following WML object<br />
<br />
<syntaxhighlight lang='wml'><br />
[dummy]<br />
foo = 42<br />
[bar]<br />
v = 1<br />
w = 2<br />
[/bar]<br />
[foo]<br />
x = no<br />
[/foo]<br />
[bar]<br />
y = foo<br />
[bar]<br />
[foobar]<br />
z = 5<br />
[barfoo]<br />
[/barfoo]<br />
[/foobar]<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Both tables above are also equivalent to this WML table, where all unnamed fields are displayed:<br />
<br />
<syntaxhighlight lang='lua'><br />
{<br />
foo = 42,<br />
[1] = { [1] = "bar", [2] = { v = 1, w = 2 } },<br />
[2] = { [1] = "foo", [2] = { x = false } },<br />
[3] = { [1] = "bar", [2] = { y = "foo" } },<br />
[4] = { [1] = "foobar", [2] = { z = 5, [1] = { [1] = "barfoo", [2] = {} } } }<br />
}<br />
</syntaxhighlight><br />
<br />
So assuming ''cfg'' contains the above WML object, the following accesses are possible:<br />
<br />
<syntaxhighlight lang=lua><br />
a_int = cfg.foo -- "dummy.foo", 42<br />
a_string = cfg[3][2].y -- "dummy.bar[1].y", "foo"<br />
a_table = cfg[4][2] -- "dummy.foobar", { z = 5, { "barfoo", {} } }<br />
</syntaxhighlight><br />
<br />
For creating valid wml table in lua it is usully easier to use ''T = helper.set_wml_tag_metatable {}'' asuming you did that you can create the above wml document with<br />
<syntaxhighlight lang=lua><br />
{<br />
foo = 42,<br />
T.bar {<br />
v = 1,<br />
w = 1,<br />
},<br />
T.foo {<br />
x = false,<br />
},<br />
T.bar {<br />
y = "foo",<br />
},<br />
T.foobar {<br />
z = 5,<br />
T.barfoo {<br />
},<br />
},<br />
}<br />
</syntaxhighlight><br />
<br />
Consider using the [[LuaWML:Variables#helper.get_child|helper.get_child]] and [[LuaWML:Variables#helper.child_range|helper.child_range]] to ease the access to subtags.<br />
<br />
{{DevFeature1.13|5}} As a convenience, attributes with array values (tables with only integer keys) are concatenated into a string when converting a Lua table into WML. For example, the following Lua code:<br />
<br />
<syntaxhighlight lang=lua><br />
{<br />
x = {1, 2, 3, 4},<br />
y = {7, 8, 9, 10}<br />
}<br />
</syntaxhighlight><br />
<br />
produces the following WML table:<br />
<br />
<syntaxhighlight lang=wml><br />
[dummy]<br />
x=1,2,3,4<br />
y=7,8,9,10<br />
[/dummy]<br />
</syntaxhighlight><br />
<br />
Functions registered in [[LuaWML:Events#wesnoth.wml_actions|wesnoth.wml_actions]] receive their data in a userdata object which has the exact same structure as above. It is read-only however. Accessing fields or children performs variable substitution on the fly. Its '''__parsed''' and '''__literal''' fields provide translations to plain tables (therefore writable). '''__literal''' returns the original text of the data (including dollar symbols in attributes and [insert_tag] children), while '''__parsed''' performs a variable substitution.<br />
<br />
For instance, if you cannot stand any longer the fact that '''first_time_only''' is set to yes by default for the '''[event]''' tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.<br />
<br />
<syntaxhighlight lang=lua><br />
local old_event_handler = wesnoth.wml_actions.event<br />
function wesnoth.wml_actions.event(cfg)<br />
-- Get the plain text from the user.<br />
local new_cfg = cfg.__literal<br />
-- The expression below is equivalent to cfg.__parsed.first_time_only,<br />
-- only faster. It is needed, since the first_time_only attribute may<br />
-- reference variables.<br />
local first = cfg.first_time_only<br />
-- Modify the default behavior of first_time_only.<br />
if first == nil then first = false end<br />
new_cfg.first_time_only = first<br />
-- Call the engine handler.<br />
old_event_handler(new_cfg)<br />
end<br />
</syntaxhighlight><br />
<br />
(Note: The above example will only affect nested events. Toplevel events will still default to ''first_time_only=yes''.)<br />
<!-- This should probably be replaced with a better example. --><br />
<br />
Note that, since the object is a userdata and not a table, '''pairs''' and '''ipairs''' are unfortunately not usable on it. So scripts have to work at a lower level. For instance, the following function returns the first sub-tag with a given name and it works both on WML tables and WML userdata:<br />
<br />
<syntaxhighlight lang=lua><br />
function get_child(cfg, name)<br />
for i = 1, #cfg do<br />
local v = cfg[i]<br />
if v[1] == name then return v[2] end<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
{{DevFeature1.13|2}} '''pairs''' and '''ipairs''' now work on vconfig objects (contrary to the above statement). However, '''pairs''' works a little differently than on plain configs (tables) - it returns only string keys (attributes in WML terms) and not integer keys (tags in WML terms).<br />
<br />
Another approach for handling userdata and tables in the same way, would be to convert the former into the latter beforehand:<br />
<br />
<syntaxhighlight lang=lua><br />
if getmetatable(cfg) == "wml object" then cfg = cfg.__parsed end<br />
</syntaxhighlight><br />
<br />
The WML userdata provides two other special fields: '''__shallow_parsed''' and '''__shallow_literal'''. They return a table corresponding to the WML userdata with variable substitution performed on the attributes (or not). [insert_tag] tags have also been parsed, so the number of children is faithful. But contrarily to '''__parsed''' and '''__literal''', the process is not recursive: all the children are still WML userdata and variable substitution can still happen for them. These shallow translators are meant as optimized versions of the deep ones, when only the toplevel attributes need to be writable.<br />
<br />
== Skeleton of a lua tag ==<br />
<br />
The following [lua] tag is a skeleton for a prelude enabling Lua in your WML events. It creates a table ''H'' containing the functions from helper.lua . It sets up a table ''T'' so be used for easier creation of valid WML tables. It also sets up a table ''V'' so that any access to it is redirected to the persistent WML storage. Finally, it loads a textdomain to be accessed through the ''_'' variable. <br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = <<<br />
H = wesnoth.require "lua/helper.lua"<br />
T = wml.tag<br />
V = wml.variables<br />
local _ = wesnoth.textdomain "my-campaign"<br />
<br />
-- Define your global constants here.<br />
-- ...<br />
<br />
<br />
-- Define your global functions here.<br />
-- ...<br />
>><br />
[/lua]<br />
... <br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
It may be worth putting the whole Lua script above inside a separate file and having the [lua] tag load it:<br />
<br />
<syntaxhighlight lang='wml'><br />
[scenario]<br />
[lua]<br />
code = << wesnoth.dofile "~add-ons/Whatever/file.lua" >><br />
[/lua]<br />
...<br />
[/scenario]<br />
</syntaxhighlight><br />
<br />
== Remarks on Random Numbers ==<br />
<br />
The math.random function is not safe for replays and multiplayer games, since the random values will be different each time and on all the clients. Instead, the Lua code should use the [[LuaWML:Misc#helper.rand|helper.rand()]] function to synchronize random values. It takes the same argument in the same format as [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]] rand=.<br />
<br />
<syntaxhighlight lang='lua'><br />
local random_variable = helper.rand("1,2,3")<br />
</syntaxhighlight><br />
<br />
Also available is [[LuaWML:Misc#wesnoth.random|wesnoth.random]], which has the same interface as math.random but is multiplayer-safe.<br />
<br />
== Random Lua table iteration ==<br />
<br />
Table iteration order ('''pairs''') is not strictly defined in Lua. If your code depends on the order of iteration, different clients may have different data in a multiplayer game. For example:<br />
<br />
<syntaxhighlight lang='lua'><br />
local table = { ["Mage"] = true, ["Wose"] = true }<br />
local concat = ""<br />
local bad_usage = next(table) -- wrong, leads to OOS<br />
for k, _ in pairs(table) do -- wrong, leads to OOS<br />
concat = concat .. k<br />
end<br />
</syntaxhighlight><br />
<br />
To avoid the problem, sort the table keys before iterating. Or alternatively, use Lua "arrays" and the '''ipairs''' function, which have a strictly defined order and never lead to OOS. Example of correct code:<br />
<br />
<syntaxhighlight lang='lua'><br />
local array = { "Mage", "Wose" }<br />
local good_usage = table[1] -- correct<br />
local concat = ""<br />
for _, v in ipairs(array) do -- correct<br />
concat = concat .. v<br />
end<br />
</syntaxhighlight><br />
<br />
[[Category: Lua Reference|*]]<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaWML/Units&diff=60141LuaWML/Units2019-01-08T20:19:14Z<p>Gfgtdf: /* wesnoth.effects */</p>
<hr />
<div>This page describes the [[LuaWML]] functions for handling units.<br />
<br />
A unit is a proxy table with the following fields:<br />
* '''x''', '''y''': integers (read only, read/write if the unit is not on the map. {{DevFeature1.13|11}} These are now read/write under all circumstances, including for on-map units)<br />
* '''loc''': {{DevFeature1.13|11}} shortcut to get/set both x and y at once (read/write). Setting x and y individually would result in two moves, and there's the possibility that the intermediate move fails if the hex is occupied by another unit. In general, note that moving a unit by changing the proxy unit's coordinates does not work if the goal hex is occupied (it is not executed), so it is necessary to check if the hex is available first.<br />
* '''side''': integer (read/write)<br />
* '''id''': string (read only)<br />
* '''type''': string (read only)<br />
* '''name''': translatable string (read only)<br />
* '''cost''' {{DevFeature1.13|10}}: integer (read)<br />
* '''max_hitpoints''', '''max_experience''', '''max_moves''': integers (read only)<br />
* '''max_attacks''': integer (read only)<br />
* '''attacks_left''': integer (read/write) Setting below 0 is limited to 0.<br />
* '''extra_recruit''': table (read/write)<br />
* '''advances_to''': table (read/write)<br />
* '''hitpoints''', '''experience''': integer (read/write)<br />
* '''moves''': integer (read/write)<br />
* '''level''': {{DevFeature1.13|5}} integer (read/write)<br />
* '''resting''': boolean (read/write)<br />
* '''hidden''': boolean (read/write)<br />
* '''petrified''', '''canrecruit''': booleans (read only)<br />
* '''role''', '''facing''': strings (read/write)<br />
* '''status''': proxy associative table (read only, read/write fields), provides fields like [[SingleUnitWML#Unit_State|poisoned, slowed, petrified, uncovered, guardian, unhealable, invulnerable]]<br />
* '''image_mods''': string (read only)<br />
* '''upkeep''' {{DevFeature1.13|5}}: one of 'loyal', 'full' or a number (read/writre)<br />
* '''variables''': proxy associative table (read only, read/write fields, including ''variables.__cfg''), only toplevel named fields are proxied. {{DevFeature1.13|2}} subcontainers can be accessed by using the usual variable syntax: <syntaxhighlight inline lang='lua'>unit.variables["a.b.c[6].d"]</syntaxhighlight><br />
* '''attacks''': {{DevFeature1.13|0}}an object to access the units attacks, you can use the attacks index or the attacks name to index an attack. every attack has the following members:<br />
** '''description''': translatable string (read/write)<br />
** '''name''': string (read)<br />
** '''type''': string (read/write)<br />
** '''range''': string (read/write)<br />
** '''damage''': number(read/write)<br />
** '''number''': number(read/write)<br />
** '''movement_used''': number(read/write)<br />
** '''attack_weight''': number(read/write)<br />
** '''defense_weight''': number(read/write)<br />
** '''specials''' wml table(read/write)<br />
* '''valid''': string or nil (read only)<br />
* '''advancements''': {{DevFeature1.13|2}} an array of wml tables (read/write)<br />
* '''__cfg''': WML table (dump) ([[SingleUnitWML]])<br />
* {{DevFeature1.13|2}} The following fields are unit methods synonymous to one of the functions described on this page:<br />
** '''[[#wesnoth.match_unit|matches]]'''<br />
** '''[[#wesnoth.put_recall_unit|to_recall]]'''<br />
** '''[[#wesnoth.put_unit|to_map]]'''<br />
** '''[[#wesnoth.erase_unit|erase]]'''<br />
** '''[[#wesnoth.copy_unit|clone]]'''<br />
** '''[[#wesnoth.extract_unit|extract]]'''<br />
** '''[[#wesnoth.advance_unit|advance]]'''<br />
** '''[[#wesnoth.add_modification|add_modification]]'''<br />
** '''[[#wesnoth.remove_modifications|remove_modifications]]'''<br />
** '''[[#wesnoth.unit_resistance|resistance]]'''<br />
** '''[[#wesnoth.unit_defense|defense]]'''<br />
** '''[[#wesnoth.unit_movement_cost|movement]]'''<br />
** '''[[#wesnoth.unit_vision_cost|vision]]'''<br />
** '''[[#wesnoth.unit_jamming_cost|jamming]]'''<br />
** '''[[#wesnoth.unit_ability|ability]]'''<br />
** '''[[#wesnoth.transform_unit|transform]]'''<br />
The metatable of these proxy tables appears as '''"unit"'''.<br />
<br />
A unit can be either visible on the map ([[#wesnoth.get_units]], [[#wesnoth.put_unit]]), or on a recall list ([[#wesnoth.get_recall_units]], [[#wesnoth.put_recall_unit]]), or private to the Lua code ([[#wesnoth.create_unit]], [[#wesnoth.copy_unit]], [[#wesnoth.extract_unit]]). The Lua code has complete control over the private units; they will not be modified unless accessed through the proxy unit. Units on the map and on the recall lists, however, can be modified by the user, the engine, WML, independently of the Lua code. In particular, if a unit is killed, any further use of the proxy unit will cause an error. For units on the map, the proxy unit is valid as long as there is a unit on the map that has the same "underlying_id" WML field as the original one. The behavior is similar for units on the recall lists. The ''valid'' field reflects the unit availability by returning '''"map"''', '''"recall"''', '''"private"''', or ''nil''. The latter value is used for units that were removed (e.g. killed). In that case, the ''valid'' field is the only one that can be read without causing an error.<br />
<br />
The term "proxy", here in particular "proxy unit", means that the variable retrieved in the lua code (with get_units for example) is an accessor (reference) to the C++ object which represents that unit. This is very different from unit variables obtained by [store_unit] in wml. The fields marked as "writable" above can be modified without the need to use put_unit afterwards. This same reason explains that modifications to the unit from outside the lua code (like [kill] invalidating the proxy unit) have immediate effect on the lua code's proxy unit variable (with the exception of private proxy units).<br />
<br />
<br />
==== wesnoth.get_units ====<br />
<br />
* '''wesnoth.get_units(''filter'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''fake_location'')'''<br />
* {{DevFeature1.13|12}} '''wesnoth.get_units(''filter'', ''other_unit'')'''<br />
<br />
Returns an array of all the units on the map matching the WML filter passed as the first argument. See [[StandardUnitFilter]] for details about filters. If a second unit is passed, it can be referenced via the $other_unit variable in the main filter as well as via the "other" variable in WFL formulas used in the main filter. If a location is passed, the filter is run as if the unit were at that location (rather than its real location). This affects things such as [filter_adjacent] and ability_active, and should work even for a unit on the recall list.<br />
<br />
<syntaxhighlight lang='lua'><br />
local leaders_on_side_two = wesnoth.get_units { side = 2, canrecruit = true }<br />
local name_of_leader = leaders_on_side_two[1].name<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_unit ====<br />
<br />
* '''wesnoth.get_unit(''x'', ''y'')'''<br />
* '''wesnoth.get_unit(''id'')'''<br />
<br />
Returns the unit at the given location or with the given ID.<br />
<br />
<syntaxhighlight lang='lua'><br />
local args = ...<br />
local unit = wesnoth.get_unit(args.x1, args.y1)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.match_unit ====<br />
<br />
* '''wesnoth.match_unit(''unit'', ''filter'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''other_unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''other_unit''])'''<br />
* {{DevFeature1.13|2}} '''wesnoth.match_unit(''unit'', ''filter'', ''location'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':matches(''filter'', [''location''])'''<br />
<br />
Returns true if the given unit matches the WML filter passed as the second argument. If ''other_unit'' is specified, it is used for the ''$other_unit'' auto-stored variable in the filter. Otherwise, this variable is not stored for the filter. If an extra ''location'' is specified, the filter matches as if the unit were at that location.<br />
<br />
<syntaxhighlight lang='lua'><br />
assert(unit.canrecruit == wesnoth.match_unit(unit, { canrecruit = true }))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.put_unit ====<br />
<br />
* '''wesnoth.put_unit(''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'', ''unit'')'''<br />
* '''wesnoth.put_unit(''x'', ''y'')'''<br />
* {{DevFeature1.13|2}} '''wesnoth.put_unit(''unit'', ''x'', ''y'')''' -- The above two forms are also deprecated.<br />
* {{DevFeature1.13|2}} '''''unit'':to_map([''x'', ''y''])<br />
<br />
Places a unit on the map. This unit is described either by a WML table or by a proxy unit. Coordinates can be passed as the first two arguments, otherwise the table is expected to have two fields '''x''' and '''y''', which indicate where the unit will be placed. If the function is called with coordinates only, the unit on the map at the given coordinates is removed instead. {{DevFeature1.13|2}} This use is now deprecated; use wesnoth.erase_unit instead.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- create a unit with random traits, then erase it<br />
wesnoth.put_unit(17, 42, { type = "Elvish Lady" })<br />
wesnoth.put_unit(17, 42)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on a recall list, it no longer is; and if the unit was on the map, it has been moved to the new location. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on the map.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- move the leader back to the top-left corner<br />
wesnoth.put_unit(1, 1, wesnoth.get_units({ canrecruit = true })[1])<br />
</syntaxhighlight><br />
<br />
==== wesnoth.erase_unit ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
* '''wesnoth.erase_unit(''unit'')'''<br />
* '''wesnoth.erase_unit(''x'', ''y'')'''<br />
* '''''unit'':erase()'''<br />
<br />
Erases a unit from the map. After calling this on a unit, the unit is no longer valid.<br />
<br />
==== wesnoth.get_recall_units ====<br />
<br />
* '''wesnoth.get_recall_units()'''<br />
<br />
Returns an array of all the units on the recall lists matching the WML filter passed as the first argument.<br />
<br />
==== wesnoth.put_recall_unit ====<br />
<br />
* '''wesnoth.put_recall_unit(''unit'', [''side''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':to_recall([''side''])'''<br />
<br />
Places a unit on a recall list. This unit is described either by a WML table or by a proxy unit. The side of the recall list is given by the second argument, or by the side of the unit if missing.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- put the unit at location 17,42 on the recall list for side 2<br />
wesnoth.put_recall_unit(wesnoth.get_units({ x= 17, y = 42 })[1], 2)<br />
</syntaxhighlight><br />
<br />
When the argument is a proxy unit, no duplicate is created. In particular, if the unit was private or on the map, it no longer is. Note: passing a WML table is just a shortcut for calling [[#wesnoth.create_unit]] and then putting the resulting unit on a recall list.<br />
<br />
==== wesnoth.create_unit ====<br />
<br />
* '''wesnoth.create_unit(''unit_info'')'''<br />
<br />
Creates a private unit from a WML table.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.create_unit { type = "White Mage", gender = "female" }<br />
</syntaxhighlight><br />
<br />
==== wesnoth.copy_unit ====<br />
<br />
* '''wesnoth.copy_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':clone()'''<br />
<br />
Creates a private unit from another unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- extract a unit from the map<br />
local u = wesnoth.copy_unit(wesnoth.get_units({ type = "Thug" })[1])<br />
wesnoth.erase_unit(u.x, u.y)<br />
-- u is still valid at this point<br />
</syntaxhighlight><br />
<br />
==== wesnoth.extract_unit ====<br />
<br />
* '''wesnoth.extract_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':extract()'''<br />
<br />
Removes a unit from the map or from a recall list and makes it private.<br />
<br />
<syntaxhighlight lang='lua'><br />
-- remove all the units from the recall list of side 1 and put them in a WML container<br />
local l = {}<br />
for i,u in ipairs(wesnoth.get_recall_units { side = 1 }) do<br />
wesnoth.extract_unit(u)<br />
table.insert(l, u.__cfg)<br />
end<br />
helper.set_variable_array("player_recall_list", l)<br />
</syntaxhighlight><br />
<br />
Note: if the unit is on the map, it is just a shortcut for calling [[#wesnoth.copy_unit]] and then [[#wesnoth.put_unit]] without a unit. It is, however, the only way for removing a unit from a recall list without putting it on the map.<br />
<br />
<br />
==== wesnoth.advance_unit ====<br />
<br />
* '''wesnoth.advance_unit(''unit'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':advance()'''<br />
<br />
{{DevFeature1.13|0}} Advances the unit (and shows the advance unit dialog if needed) if the unit has enough xp. This function should be called after modifying the units experience directly. A similar function is called by wesnoth internally after unit combat. The second argument is a boodean value that specifies whether the advancement should be animated. The third agrument is a boodean value that specifies whether advancement related events should be fired.<br />
<br />
<br />
This function only works for units on the map.<br />
<br />
This function can also trigger multiple advancements if the unit has enough xp.<br />
<br />
==== wesnoth.add_modification ====<br />
<br />
* '''wesnoth.add_modification(''unit'', ''type'', ''effects'', [''write_to_mods''])'''<br />
* {{DevFeature1.13|2}} '''''unit'':add_modification(''type'', ''effects'', [''write_to_mods''])'''<br />
<br />
Modifies a given unit. It needs to be a proxy unit. The second argument is the type of the modification (one of "trait", "object", or "advance"). The option "advance" applies effects as if the unit would advance (e.g. AMLA effects). The third argument is a WML table describing the effect, so mostly containing '''[effect]''' children. See [[EffectWML]] for details about effects.<br />
<br />
{{DevFeature1.13|2}} In 1.13.2 and later, the "advance" type is replaced with "advancement", to match the equivalent tag in [[UnitTypeWML|[unit_type]]]. Also, it takes a fourth argument which, if false, causes it to not write the modification tag to the unit's [modifications] (as would be done with an [object] with no_write=true).<br />
<br />
<syntaxhighlight lang='lua'><br />
local T = wml.tag<br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
local effects = {<br />
id = "my_effect_id",<br />
T.effect { <br />
apply_to = "image_mod", <br />
replace = "RC(red>blue)" <br />
},<br />
T.effect {<br />
apply_to = "new_animation",<br />
T.standing_animation {<br />
-- AnimationWML<br />
}<br />
}<br />
} <br />
wesnoth.add_modification(u, "object", effects)<br />
</syntaxhighlight><br />
<br />
==== wesnoth.remove_modifications ====<br />
<br />
* {{DevFeature1.13|?}} '''wesnoth.remove_modifications(''unit'', ''cfg'' [, ''type''])'''<br />
* {{DevFeature1.13|?}} '''''unit'':remove_modifications(''cfg'' [, ''type''])'''<br />
<br />
Modifies a given unit. The unit needs to be a proxy unit. The second argument is a filter for the modifications to remove. It takes the same syntax as [[FilterWML#Filtering_on_WML_data|[filter_wml]]]; all matching modifications will be removed. The third argument is the type (tag name) of the modifications to search for; it defaults to <tt>"object"</tt>, but you can also pass <tt>"trait"</tt> or <tt>"advancement"</tt>.<br />
<br />
<syntaxhighlight lang='lua'><br />
local u = wesnoth.get_units { canrecruit = true }[1]<br />
wesnoth.remove_modifications(u, { id = "my_effect_id" })<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_resistance ====<br />
<br />
* '''wesnoth.unit_resistance(''unit'', ''damage_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':resistance(''damage_type'')'''<br />
<br />
Returns the resistance of a unit against an attack type. (Note: it is a WML resistance. So the higher it is, the weaker the unit is.) The third argument indicates whether the unit is the attacker. Last arguments are the coordinates of an optional map location (for the purpose of taking abilities into account).<br />
<br />
<syntaxhighlight lang='lua'><br />
local fire_resistance = 100 - wesnoth.unit_resistance(u, "fire")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_defense ====<br />
<br />
* '''wesnoth.unit_defense(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':defense(''terrain_code'')'''<br />
<br />
Returns the defense of a unit on a particular terrain. (Note: it is a WML defense. So the higher it is, the weaker the unit is.)<br />
<br />
<syntaxhighlight lang='lua'><br />
local flat_defense = 100 - wesnoth.unit_defense(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_movement_cost ====<br />
<br />
* '''wesnoth.unit_movement_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':movement(''terrain_code'')'''<br />
<br />
Returns the movement cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local move_cost = wesnoth.unit_movement_cost(u, "Gt")<br />
<syntaxhighlight><br />
<br />
==== wesnoth.unit_vision_cost ====<br />
<br />
* '''wesnoth.unit_vision_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':vision(''terrain_code'')'''<br />
<br />
Returns the vision cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local see_cost = wesnoth.unit_vision_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_jamming_cost ====<br />
<br />
* '''wesnoth.unit_jamming_cost(''unit'', ''terrain_code'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':jamming(''terrain_code'')'''<br />
<br />
Returns the jamming cost of a unit on a particular terrain.<br />
<br />
<syntaxhighlight lang='lua'><br />
local jam_cost = wesnoth.unit_jamming_cost(u, "Gt")<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_ability ====<br />
<br />
* '''wesnoth.unit_ability(''unit'', ''ability_tag'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':ability(''ability_tag'')'''<br />
<br />
Returns true if the unit is currently under effect by an ability with this given TAG NAME. This means that the ability could be owned by the unit itself, or by an adjacent unit.<br />
<br />
<syntaxhighlight lang='lua'><br />
function has_teleport(u)<br />
return wesnoth.unit_ability(u, "teleport")<br />
end<br />
</syntaxhighlight><br />
<br />
==== wesnoth.unit_types ====<br />
<br />
This is not a function but a read-only table indexed by unit type ids. Its elements are proxy tables with these fields:<br />
<br />
* '''id''': string<br />
* '''name''': translatable string (read only)<br />
* '''max_moves''', '''max_experience''', '''max_hitpoints''', '''level''', '''cost''': integers (read only)<br />
* '''abilities''': array of ability keys (strings), e.g. {"curing", "regenerates"}<br />
* {{DevFeature1.13|11}} '''advances_to''': array of unit types to which unit can advance<br />
* {{DevFeature1.13|11}} '''advances_from''': array of unit types from which unit can advance. Note: this is OOS-unsafe in Multiplayer games. Different clients may have additional Era-s with units upgradable to this unit type.<br />
* '''__cfg''': WML table (dump), see [[UnitTypeWML]]<br />
<br />
The metatable of these proxy tables appears as '''"unit type"'''.<br />
<br />
<syntaxhighlight lang='lua'><br />
local lich_cost = wesnoth.unit_types["Ancient Lich"].cost<br />
</syntaxhighlight><br />
<br />
Note that different clients have different set of available units in a Multiplayer game. It is OOS-unsafe to e.g. count the number of units.<br />
Presuming correctly written add-ons, it is still safe to e.g. access any given unit or its properties.<br />
<br />
==== wesnoth.races ====<br />
<br />
This is not a function but a table indexed by race ids. Its elements are proxy tables for all races the engine knows about.<br />
known fields of each element:<br />
* '''id''': string<br />
* '''description''', '''name''', '''plural_name''' (translatable strings)<br />
* '''num_traits''' (integer)<br />
* '''ignore_global_traits''' (boolean)<br />
* '''undead_variation''' (string)<br />
(all read only)<br />
* '''__cfg''': WML table (dump)<br />
<br />
<syntaxhighlight lang='lua'><br />
wesnoth.message(tostring(wesnoth.races["lizard"].name))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.get_traits ====<br />
<br />
* '''wesnoth.get_traits()'''<br />
<br />
Returns a table with named fields (trait id strings) holding the wml tables defining the traits. arguments: none. All global traits the engine knows about, race-specific traits are not included.<br />
Known fields and subtags of each element are the ones which were given in the wml definition of the [[SingleUnitWML|trait]].<br />
wesnoth.message(tostring(wesnoth.get_traits().strong.male_name))<br />
<br />
==== wesnoth.simulate_combat ====<br />
<br />
* '''wesnoth.simulate_combat(''attacker'', [''attacker_weapon_index''], ''defender'', [''defender_weapon_index''])'''<br />
<br />
Computes the hitpoint distribution and status chance after a combat between two units. The first unit is the attacker; it does not have to be on the map, though its location should be meaningful. The second unit is the defender; it has to be on the map.<br />
<br />
Optional integers can be passed after each unit to select a particular weapon, otherwise the "best" one is selected. When giving the weapon, the parameter is the weapon number (integer, starting at 1) and not an element from the table returned by helper.child_range(att, "attack").<br />
<br />
<syntaxhighlight lang='lua'><br />
local function display_stats(n, t)<br />
wesnoth.message(string.format(<br />
"Chance for the %s\n to be slowed: %f,\n to be poisoned: %f,\n to die: %f.\nAverage HP: %f.",<br />
n, t.slowed, t.poisoned, t.hp_chance[0], t.average_hp))<br />
end<br />
local att_stats, def_stats = wesnoth.simulate_combat(att, att_weapon, def, def_weapon)<br />
display_stats("attacker", att_stats)<br />
display_stats("defender", def_stats)<br />
</syntaxhighlight><br />
<br />
Returns 2 additional tables which contain information about the weapons and the effect of single hits with these keys: num_blows, damage, chance_to_hit, poisons, slows, petrifies, plagues, plague_type, backstabs, rounds, firststrike, drains, drain_constant, drain_percent, attack_num, name. <br />
Name is the wml name not the description. If there is no weapon, then name will be nil<br />
<br />
<syntaxhighlight lang='lua'><br />
local att_stats, def_stats, att_weapon, def_weapon = wesnoth.simulate_combat(attacker, att_weapon_number, defender)<br />
wesnoth.message(string.format(<br />
"The attack %s should be countered with %s, which does %d damage, has %d%% chance to hit and forces %d attack rounds due to its berserk ability.",<br />
att_weapon.name, def_weapon.name or "no weapon", def_weapon.damage, def_weapon.chance_to_hit, def_weapon.rounds))<br />
</syntaxhighlight><br />
<br />
==== wesnoth.transform_unit ====<br />
<br />
* '''wesnoth.transform_unit(''unit'', ''to_type'')'''<br />
* {{DevFeature1.13|2}} '''''unit'':transform(''to_type'')'''<br />
<br />
Changes the type of a unit and adjust attributes accordingly. Note that hit points are only changed if necessary to accommodate the new maximum hit points. Poison is automatically removed if the transformed unit is immune.<br />
<br />
<syntaxhighlight lang='lua'><br />
local ev = wesnoth.current.event_context<br />
local u = wesnoth.get_units{x=ev.x1, y=ev.y1}[1]<br />
wesnoth.transform_unit(u, "Spearman")<br />
-- If a full heal is desired:<br />
u.hitpoints = u.max_hitpoints<br />
u.status.poisoned = false<br />
</syntaxhighlight><br />
<br />
==== wesnoth.add_known_unit ====<br />
<br />
* {{DevFeature1.13|10}} '''wesnoth.add_known_unit(''unit_type_id'')'''<br />
<br />
adds the unit type with the given id to the list of known units (so that they appear in the help)<br />
<br />
==== wesnoth.create_animator ====<br />
<br />
{{DevFeature1.13|7}}<br />
<br />
* '''wesnoth.create_animator()'''<br />
<br />
Returns an object that can be used to set up and run an animation. The object has three methods:<br />
<br />
* '''animator:run()'''<br />
<br />
Runs the animation. {{DevFeature1.15|0}} Implicitly clears the animator.<br />
<br />
* '''animator:clear()'''<br />
<br />
Clears any units previously added to the animation.<br />
<br />
* '''animator:add(''unit'', ''flag'', ''hits'', ''params'')'''<br />
<br />
Adds a unit to the animation. The ''flag'' specifies which animation to play, and the ''hits'' parameter is required for attack animations to specify which variant of the animation to play. Possibly keys in ''params'' are:<br />
<br />
* '''facing''': A location. The animation will be played with the unit facing that location.<br />
* '''value''': Either a number or a list of two numbers. Use this to pass ''value'' and/or ''value_second'' to default animations that use them.<br />
* '''with_bars''': Whether to show HP bars and such while the animation plays.<br />
* '''text''': Text to float as the animation plays.<br />
* '''color''': Color of the floating text - a list of red, green, blue.<br />
* '''primary''': The primary weapon to use for the animation. Must be a Lua unit attack proxy.<br />
* '''secondary''': The secondary weapon to use for the animation.<br />
<br />
Normal usage would be to create it, call '''add''' one or more times, then call '''run'''.<br />
<br />
==== wesnoth.effects ====<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
This table contains the implementation of custom [[EffectWML|[effect]]]s. Each value is a function that takes a unit and the effect config. Note that the default effects defined by the Wesnoth engine are not in this table. <br />
<br />
<syntaxhighlight lang='lua'><br />
function wesnoth.effects.min_resistance(u, cfg)<br />
local resistance_new = {}<br />
local resistance_old = helper.parsed(helper.get_child(cfg, "resistance"))<br />
for k,v in pairs(resistance_old) do<br />
if type(k) == "string" and type(v) == "number" and wesnoth.unit_resistance(u, k) >= v then<br />
resistance_new[k] = v<br />
end<br />
end<br />
--important: use wesnoth.add_modification(..., false) so that the function will only execute the effects of that object and not store the object in the unit.<br />
wesnoth.add_modification(u, "object", {<br />
T.effect {<br />
apply_to = "resistance",<br />
replace = true,<br />
T.resistance (resistance_new),<br />
},<br />
}, false)<br />
end<br />
</syntaxhighlight><br />
<br />
The code above adds a new <code>min_resistance</code> effect that will set the resistances to specific values if they are currently below that value. It can then be used like this (for example, in [[DirectActionsWML#.5Bobject.5D|[object]]]):<br />
<br />
<syntaxhighlight lang='wml'><br />
[effect]<br />
apply_to=min_resistance<br />
[resistance]<br />
cold=50<br />
[/resistance]<br />
[/effect]<br />
</syntaxhighlight><br />
<br />
Note that in order work properly effects must be registered before any units are created. This means it must be places into toplevel or scenaro/era/modification level [lua] tag and in particular must not be done from within a preload event.<br />
<br />
<br />
{{DevFeature1.13|5}}<br />
<br />
Built-in effects are now present in the <code>wesnoth.effects</code> table and can be called by custom effects or by other Lua code. They take the same two arguments that a custom effect function does - the unit, and the effect WML.<br />
<br />
In addition, you can now specify description modifiers to be used if a custom effect is placed in a <code>[trait]</code> tag. Instead of setting a function as the effect, you set a table with a <code>__call</code> metafunction which does what the function would have done. The table can then have an additional <code>__descr</code> metafunction which updates descriptions as necessary. The built-in effects all use this structure. This metafunction takes the same arguments as the regular effect function, but should not modify the unit. Instead, it returns a string to be appended to the trait's effect description.<br />
<br />
[[Category: Lua Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=SingleUnitWML&diff=60134SingleUnitWML2019-01-03T14:27:18Z<p>Gfgtdf: document mods subtable to unit variables</p>
<hr />
<div>{{WML Tags}}<br />
The '''[unit]''' tag describes a single unit on the map or in memory, for example Konrad.<br />
It is different from the [unit_type] in [units], which describes a class of units. However it takes many of the same keys and thus can generally override the inherited properties from the associated [unit_type].<br />
<br />
[unit] can be used inside [side] ([[SideWML]]) for units present at start of the scenario, or as [[DirectActionsWML]] for units created during the game. (It is also used in save-files.)<br />
<br />
This contains keys and tags which describe the unit's [[#Unit Data|persistent data]], as well as certain [[#Unit State|state variables]] which will also persist with the unit but will change frequently as gameplay progresses. Finally, there are some keys to set certain [[#Creation Options|one-time options]] for how the unit will be initially created, which will ''not'' persist beyond initial creation.<br />
<br />
== Unit Data ==<br />
The following keys and tags describe the unit itself, and will persist with the unit (though some may change automatically when the unit advances):<br />
* <span id="type">'''type'''</span>: the ID of the unit's unit type. This key is mandatory. See [[UnitTypeWML]].<br />
<br />
* '''variation''': the [variation] of the [unit_type] as which the unit will appear.<br />
<br />
* '''parent_type''': overrides '''type''' if this is present. This is likely of little use to WML authors; it is automatically generated when needed by the game (to keep track of some [unit_type][variation]s).<br />
<br />
* '''side''': the side that the unit is on. It has to be an existing side, even if the unit is created in a variable. Defaults to 1, except when the [unit] tag appears inside a [side], in which case the unit always belongs to that side, and this key is ignored.<br />
<br />
* '''id''': a unique identifier for the unit. This is (usually) not displayed to the player, but is to be used only for identifying and filtering units. If not specified, a random one will be generated for the unit to ensure that each unit has a unique '''id''' attribute (as will happen when a unit is recruited normally). In older versions, the '''description''' attribute specified a unique ID. (The one instance when an id is displayed to the player is when the leader's id is used as the default for a [[SideWML|side]]'s '''current_player''' attribute.) Note: While it IS technically possible to create multiple units with the same ID, doing so may produce unpredictable results in many cases. WML should therefore be structured in such a way that no two units in existence ever end up with the same ID.<br />
<br />
* '''gender''': can be set to male or female to designate the gender of the unit. Default is male (unless [[#random_gender|'''random_gender''']] is set to "yes"), but if the unit has only a female variant it will be female.<br />
<br />
* '''name''': the user-visible name of the unit. Note that the player may use the "rename unit" action to change this (unless '''unrenamable''' is also set).<br />
<br />
* <span id="unrenamable">'''unrenamable'''</span>: if 'yes', the user-visible name of the unit cannot be changed by the player (which is only possible when the unit is on the player's side anyway).<br />
<br />
* '''canrecruit''': a special key for leaders.<br />
** '''no''': default. Unit cannot recruit.<br />
** '''yes''': unit can recruit.<br />
: Normally when a team controls no units with '''canrecruit=yes''', that team loses. However, even if your team has lost you continue to play with whatever units you still have until the scenario is over. Usually scenarios end when only one team is left with a leader that can recruit, but special victory conditions can be set up in campaigns. Normally you want to set the leader of a side with '''canrecruit=yes'''. If you don't want the leader to recruit, it is usually better to just not give him any unit types to recruit, than to make a special victory condition. Units with '''canrecruit=yes''' are exempt from upkeep costs. So that leaders do not need to be given the ''loyal'' trait.<br />
: More than one unit with '''canrecruit=yes''' for the same side (see [[SideWML]]) are allowed in single player, if the side is human-controlled.<br />
<br />
* '''extra_recruit''': a list of unit types which this unit can recruit in addition to the ones given by its [side]recruit= (only relevant for units with '''canrecruit=yes''').<br />
<br />
* '''[filter_recall]''' A leader can only recall those units which pass the SUF. (Meaningful only if canrecruit=yes.)<br />
**'''[[StandardUnitFilter]]''' tags and keys<br />
<br />
* '''level''': the unit's current level. Defaults to the level of the [unit_type] described by [[#type|'''type''']]. This is generally not set manually.<br />
<br />
* '''upkeep''': the amount of upkeep the unit will require each turn.<br />
** '''loyal''': no upkeep cost. Can be changed by the effect 'loyal' (see [[EffectWML]])<br />
** '''free''': synonymous with "loyal".<br />
** '''full''': unit costs ''level'' upkeep (see [[UnitTypeWML]]).<br />
** An integer can be used to set the upkeep cost to that number.<br />
** The default is "full".<br />
** Leaders (units with '''canrecruit=yes''') never pay upkeep no matter what upkeep is set to.<br />
** Normally you don't want to muck with this value. If you want to give a side units without upkeep costs, give those units the 'loyal' trait.<br />
<br />
* {{DevFeature1.13|0}} '''recall_cost''': the recall cost of this unit. Overrides the values specified by the unit's type ([[UnitTypeWML|[unit_type]]]), its side ([[SideWML|[side]]]), and the global [[GameConfigWML|[game_config]]] value. A value of -1 is equivalent to not specifying this attribute. {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.<br />
<br />
* '''overlays''': a comma-separated list of images that are overlayed on the unit.<br />
<br />
* <span id="max_hitpoints">'''max_hitpoints'''</span>: The maximum hitpoints the unit has when at full health. Default is the max HP set for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''max_experience''': The experience the unit needs to advance. Default is the experience required for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* <span id="max_moves">'''max_moves'''</span>: The maximum number of movement points the unit has. Default is the number of movement specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''vision''': The the number of vision points to calculate the unit's sight range. Default is the number of vision points specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''jamming''': {{DevFeature1.15|0}} The number of jamming points for the unit. Default is the number of jamming points specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* <span id="max_attacks">'''max_attacks'''</span>: The number of attacks the unit can have per turn. Default is the number of attacks specified for the [unit_type] described by [[#type|'''type''']].<br />
<br />
* '''profile''': sets a portrait image for this unit. Default is the portrait image set for the [unit_type] described by [[#type|'''type''']]. When the unit advances, if the value of profile is different from the unit-type portrait, that value is preserved. If the profile field is empty or the same as the unit-type portrait, the level-advance changes the unit portrait to the default for the new level and type. See [[UnitTypeWML]] for the rules used for locating files.<br />
** If "unit_image" is given instead of a filename, uses the unit's base image as the portrait (in the same manner that unit types without portraits do by default).<br />
<br />
* '''small_profile''': sets a small portrait image for this unit. See the '''profile''' attribute above for advancement and special values. As with [[UnitTypeWML]], the location heuristic of the '''profile''' attribute is disabled when the '''small_profile''' attribute is provided.<br />
<br />
* '''role''': used in standard unit filter ([[FilterWML]]). Can be set using [role] (see [[InternalActionsWML]]).<br />
<br />
* '''[variables]''' a set of variables that will be stored when this unit is stored (See [store_unit], [[InternalActionsWML]]). The attribute '''variable'''='''value''' means that when the unit is stored in the array ''unit'', the variable '''unit'''.variables.''variable'' will have the value ''value'' (See [[VariablesWML]]). The subnode '''mods''' is special as it is deleted on every unit rebuild (for example when the unit advances or when an [object] is removed). This makes it possible to implement [effect]s that change variables, as those will also be reapplied whenever the unit is reset. (so in particular if your effect changes the variables mods.<whatever> [remove_object] will work properly for those objects.) For example the following code will define a apply_to=moves_on_recruits effect that gives units with that effect full movement when recruited<br />
<br />
<syntaxhighlight lang='lua'><br />
function wesnoth.effects.move_on_recruit(u, cfg)<br />
-- maybe better use a status than a variable ?<br />
u.variables["mods.move_on_recruit"] = true<br />
end<br />
on_event("recruit,recall", function(ec)<br />
local unit = wesnoth.get_unit(ec.x1, ec.y1)<br />
if unit and unit.variables["mods.move_on_recruit"] then<br />
unit.attacks_left = 1<br />
unit.moves = unit.max_moves<br />
end<br />
end)<br />
</syntaxhighlight><br />
And since we used the mods subtable, [remove_object] will work properly for objects that give this effect.<br />
<br />
* '''[modifications]''' changes that have been made to the unit.<br />
** '''[trait]''' a trait the unit has. Same format as [[UnitsWML#.5Btrait.5D|[trait], UnitsWML]].<br />
** '''[object]''' an object the unit has. Same format as [[DirectActionsWML#.5Bobject.5D|[object], DirectActionsWML]].<br />
** '''[advance]''' an advancement that has already been applied to the unit. Same format as [[UnitTypeWML#After max level advancement (AMLA)|AMLA [advancement], UnitTypeWML]]. These are automatically added as the unit has AMLA advancements applied to it, but can also be specified manually to indicate that the unit already has a particular advancement applied, or to disable certain advancements (by ID). {{DevFeature1.13|2}} In 1.13.2 and later this has been renamed to [advancement], to match the UnitTypeWML tag of the same name.<br />
<br />
* '''[event]''' The event is copied from this unit's WML description into the scenario. The event is carried along with the unit (even during advancement) and inserted into a scenario whenever this unit is first included. A [unit][event] requires a non-empty id= attribute.<br />
<br />
* '''unit_description''': overrides the unit type description for this unit. Note that this will be reset when the unit advances. To avoid this, one can either set up a ''post_advance'' [[EventWML|event]] to override the default description after promotion, or use an [object] with a profile [[EffectWML|effect]] to change the unit description.<br />
<br />
* '''hp_bar_scaling''': Overrides the attribute in [[GameConfigWML]] (and the [unit_type], if present).<br />
<br />
* '''xp_bar_scaling''': Overrides the attribute in [[GameConfigWML]] (and the [unit_type], if present).<br />
<br />
* '''ai_special''': causes the unit to act differently<br />
** "guardian" the unit will not move, except to attack something in the turn it moves (so, it only can move if an enemy unit gets within range of it). Does the same as '''[status] guardian = 'yes''''.<br />
<br />
* '''[ai]''' This affects how the computer will control this unit (currently only used by [[FormulaAI]]).<br />
** '''formula''': if set, the unit will execute this code during the "unit_formulas" stage, assuming that the "unit_formulas" stage has been enabled for this side<br />
** '''priority''', '''loop_formula''', '''[vars]''': see the [[FormulaAI]] documentation for details<br />
<br />
* '''traits_description''': the description of the unit's traits which is displayed. However if it is not specified explicitly, the unit's actual traits' names will be used instead, so it is normally not necessary to set this.<br />
<br />
*'''alignment''': one of lawful/neutral/chaotic/liminal (See [[TimeWML]]). Default is the alignment of the [unit_type] described by [[#type|'''type''']]. This is generally not set manually.<br />
<br />
*'''advances_to''': comma-separated list of unit types to which this unit can advance. Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''race''': See {{tag|UnitsWML|race}}. Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''undead_variation''': Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''usage''': Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''zoc''': whether the unit has a zone of control. Will override the default provided by the [unit_type]. This is generally not set manually.<br />
<br />
*'''[movement_costs]''', '''[vision_costs]''', '''[defense]''', and '''[resistance]''': Can be used to modify [[UnitsWML#.5Bmovetype.5D|existing values]].<br />
<br />
*'''[attack]''': Takes the same syntax as [[UnitTypeWML#Attacks|[unit_type][attack]]]. By default, the attacks from the [unit_type] will be included. '''Note:''' using this tag will replace ''all'' [attack] tags with the new one.<br />
<br />
== Unit State ==<br />
The following keys and tags describe the current state of the unit, and will change regularly as gameplay progresses:<br />
* '''x''', '''y''': the location of the unit. By default (unless modified by [[#placement|'''placement''']] below) if a location isn't provided and the side the unit will belong to has a recall list, the unit will be created on the recall list. The recall list can also be explicitly specified as the location with "recall,recall".<br />
<br />
* '''location_id''': {{DevFeature1.13|8}} the location of the unit, referencing one of the special locations defined by the map. This overrides '''x''' and '''y''' if present but otherwise has the same effect and can be modified by the placement options.<br />
<br />
* '''facing''': which way the unit is facing (this only affects how the unit is displayed).<br />
** Possible values are '''se''', '''s''', '''sw''', '''nw''', '''n''', '''ne'''. Note that some unit types may not have distinct animations for each direction.<br />
<br />
* '''goto_x''':, '''goto_y''': the unit's current movement destination. Default is 0,0 i.e. the unit is not on a course.<br />
<br />
* '''hitpoints''': the HP of the unit. Default [[#max_hitpoints|'''max_hitpoints''']].<br />
<br />
* '''experience''': the XP of the unit. Default is 0.<br />
<br />
* '''moves''': number of movement points the unit has left. Default is [[#max_moves|'''max_moves''']].<br />
: '''Note:''' Do not assume that moves=max_moves on turns when the unit doesn't move. The wesnoth AIs sometimes manipulate the moves variable during its turn, for internal reasons.<br />
<br />
* '''resting''': whether the unit has not moved yet this turn. Used to decide whether to give the unit rest healing. Note that this can be true even if moves is not equal to max_moves.<br />
<br />
* '''attacks_left''': number of attacks the unit has left. Default is '''max_attacks'''.<br />
<br />
* '''[status]''' the status of the unit. This affects different features of the unit, for example whether the unit loses health each turn. Default for all keys is 'no', but this can be changed by the scenario or by special abilities (see [[AbilitiesWML]]). The Status Table displays the status of each unit using the three images '''misc/poisoned.png''', '''misc/slowed.png''' and '''misc/petrified.png'''; other keys do not appear in the Status Table.<br />
** '''poisoned''': if 'yes', the unit loses 8 HP each turn. See also ''heals'', ''cures'', [[AbilitiesWML]].<br />
** '''slowed''': if 'yes', the unit has 50% of its normal movement and does half damage. When the controller of the unit's turn is over, '''slowed''' is set to 'no'. <br />
** '''petrified''': if 'yes', the unit cannot move, attack, or be attacked.<br />
** '''uncovered''': if 'yes', the unit has performed an action (e.g. attacking) that causes it to no longer be hidden until the next turn.<br />
** '''guardian''': if 'yes', the unit will not move, except to attack something in the turn it moves (so, it only can move if an enemy unit gets within range of it). Does the same as '''ai_special = "guardian"'''.<br />
** '''unhealable''': if set to 'yes', the unit cannot be healed.<br />
** {{DevFeature1.13|6}} '''invulnerable''': if 'yes', attacks can't hit the unit.<br />
** One can add other keys to [status], but they must have boolean values, and they will not do anything meaningful on their own (but can be checked from events and acted upon accordingly). For example, a scenario can set unit.status.''my_custom_key'' to 'yes' or 'no'.<br />
<br />
* {{DevFeature1.13|6}} '''invulnerable''': a shorthand to set the ''invulnerable'' status.<br />
<br />
== Creation Options ==<br />
In addition to the unit's persistent data itself, there are several options for controlling how the unit will be created, as follows:<br />
* <span id="placement">'''placement'''</span>: How the unit should be placed: can be one value or a comma-separated list of values. Default value is 'map,leader' for a leader given directly in [side], "" otherwise. By default, 'map,recall' is implicitly appended to the end of the list.<br />
** '''map''': If x,y (or location_id) are explicitly given and point to a valid on-map location - try to place the unit at the nearest free location to there, never overwriting existing units. Successful if x,y (or location_id) are given and a valid on-map vacant location near it can be found.<br />
** '''leader''': Try to place unit near the leader, if leader is not present or is in recall list - try to place unit near the start location for this side. Successful if a valid on-map vacant location can be found near leader or near start location.<br />
** '''recall''': Place unit on recall list. Always successful. <br />
** '''map_overwrite''': If x,y are explicitly given and point to a valid on-map location - try to place unit at this location, if there was a unit there - overwriting it, without firing events. {{DevFeature1.13|8}} Deprecated, use placement=map and overwrite=yes instead.<br />
** '''map_passable''': If x,y are explicitly given and point to a valid on-map location - try to place unit at this location; if the hex is of an impassable terrain for the unit being placed, or is already occupied by another unit, the new unit will be placed in the nearest vacant hex. {{DevFeature1.13|8}} Deprecated, use placement=map and passable=yes instead.<br />
** '''leader_passable''': Similar to "leader", with the additional restriction that the selected location is not impassable for the unit being placed. {{DevFeature1.13|8}} Deprecated, use placement=leader and passable=yes instead.<br />
* '''passable''': {{DevFeature1.13|8}} (default=no) If yes, and the specified location is of an impassable terrain for the unit being placed, the new unit will be placed in the nearest hex that is of a passable terrain for it.<br />
* '''overwrite''': {{DevFeature1.13|8}} (default=no) If yes, always place the unit at the exact specified location, overwriting the existing unit if there is one. Generally you don't want to use this together with placement=leader.<br />
<br />
* '''generate_name''': (default=yes) will generate a new '''name''' if there isn't one specified for the unit, as if the unit were a freshly-recruited one.<br />
* '''random_traits''': "no" will prevent random trait generation for units. You should only need to set this for placed nonleaders in multiplayer games or if you want to give the unit fewer traits than it would normally get for its unit type. When generating traits for a unit, first traits the unit has already been given are excluded. Then "musthave" traits (undead, mechanical) for the unit type are given. Then for leaders ('''canrecruit=yes''') traits that are not available to "any" (currently that's all of them to avoid a multiplayer OOS issue, but later will be restricted based on multiplayer play balance issues) are removed from consideration. Then traits are added randomly until the maximum allowed for the unit type is reached or there are no more available traits. Random traits can now be used in MP games but only when spawned in an event, so not for leaders and other units in the [side] definition.<br />
<br />
* <span id="random_gender">'''random_gender'''</span>: "yes" will cause the gender of the unit with male and female variations to be male 50% of the time, female 50% of the time. If the unit has only one gender variant it will always be given the correct one.<br />
<br />
* '''to_variable''': (only for [event][unit]) creates the unit into the given variable instead of placing it on the map.<br />
<br />
* '''animate''': whether to display the recruitment animation for this unit as if it were being recruited/recalled. Defaults to "no". Irrelevant when the [unit] tag appears inside a [side].<br />
<br />
== See Also ==<br />
<br />
* [[UnitTypeWML]]<br />
* [[InternalActionsWMLUnitTags]]<br />
* [[ReferenceWML]]<br />
<br />
[[Category:WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=InterfaceActionsWML&diff=60096InterfaceActionsWML2018-12-12T22:29:34Z<p>Gfgtdf: /* [item] */</p>
<hr />
<div>{{WML Tags}}<br />
== Interface actions ==<br />
<br />
Part of [[ActionWML]], interface actions are actions that do not have a direct effect on gameplay;<br />
instead, they show something to the player. The main interface tags<br />
are '''[message]''' and '''[objectives]''', but several other tags affect<br />
the interface also.<br />
<br />
== [inspect] ==<br />
This user interface instantly displays the gamestate inspector dialog at the current scenario state (the same one that can be brought up with [[CommandMode|the ''':inspect''' command]]), which can be used to inspect the values of WML variables, AI configuration, recall lists, and more.<br />
<br />
* '''name''': optional attribute to specify the name of this gamestate inspector dialog. It is just a label to help differentiate between different invocations of gamestate inspector dialog.<br />
<br />
== [message] ==<br />
The most commonly used interface action is [message], which displays a message to the user in a dialog box. It can also be used to take input from the user.<br />
<br />
The following key/tags are accepted for [message]:<br />
* [[StandardUnitFilter]]: The unit whose profile and name are displayed. Do not use a [filter] tag. If no unit matching this filter is found, the message is not displayed (The unit has probably been killed).<br>[message] elements should be constructed so that it is either guaranteed that a certain unit is alive, or so that dialog flows smoothly even if the message isn't displayed.<br />
<br />
* '''speaker''': an alternative to standard unit filter. You may specify as the value of the speaker attribute a unit id or any of the following special values:<br />
** '''narrator''': the dialog box is displayed without a caption for the unit speaking or a unit image<br />
** '''unit''': the primary unit for the event is speaking<br />
** '''second_unit''': {{DevFeature1.13|6}} the secondary unit for the event is speaking<br />
<br />
* '''message''': (translatable) the text to display to the right of the image. ''message'' is sometimes multiple lines; if it is, be sure to use quotes(''' ' ''' or ''' " ''')<br />
* '''male_message''', '''female_message''': {{DevFeature1.13|2}} (translatable) Used instead of ''message'' if the unit's gender matches. Never used if there is no unit (ie ''speaker=narrator''). {{DevFeature1.13|6}} This matches the primary unit, not the secondary unit.<br />
* '''wait_description''': {{DevFeature1.13|2}} the description of this message displayed when other players in a mp game wait for one player doing input in a [message] (with [option]s or [text_input]).<br />
* '''[show_if]''': if present then this message will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
* '''side_for''': (default: all sides) comma-separated list of sides for who message is shown. This will <b>not</b> work with messages that take user input ([option]/[text_input]), which can only ever be shown to the current player. {{DevFeature1.13|0}} side_for= is now also accepted for messages with user input, it specifies on which side the message is shown (defaults to the currently playing side). For messages with input it does not accept a comma seperated list only a single number.<br />
* '''image''': (default: profile image of speaker) the image to display to the left of the message text. Append ~RIGHT() if you want the image to appear on the right side. <br />
** {{DevFeature1.13|0}} <b>none:</b> display no image<br />
* '''mirror''': {{DevFeature1.13|5}}whether to mirror the image specified by the '''image''' attribute.<br />
* '''second_image''': {{DevFeature1.13|6}}same as the '''image''' attribute, but the image is displayed on the right of the message text.<br />
* '''second_mirror''': {{DevFeature1.13|6}}same as '''mirror''', but for the '''second_image''' attribute.<br />
* '''image_pos''': {{DevFeature1.13|5}} whether to show the image on the left or right; supercedes the use of ~RIGHT() described above<br />
* '''caption''': (default: name of speaker) the caption to display beside the image. Name to be displayed. Note: use a translation mark to avoid wmllint errors.<br />
* '''scroll''': Boolean specifying whether the game view should scroll to the speaking unit. Defaults to ''yes''.<br />
* '''highlight''': {{DevFeature1.13|5}} Boolean specifying whether to highlight the speaker. Defaults to ''yes''.<br />
* '''sound''': a sound effect (wav file) to play as the message is displayed. This can be a comma-separated list, from which one will be randomly chosen.<br />
* '''voice''': {{DevFeature1.13|?}} a sound to be played as the message is displayed. This can also be a comma-separated list, from which one will be randomly chosen. This is intended for voiceovers for the message.<br />
* '''[option]''': No '''[option]''' elements have to be used. If '''[option]''' elements are present, then each option will be displayed in a menu for the user to select one option. ''Note: Messages with options will not be shown at all in prestart events''<br />
** '''message''': (translatable) the text displayed for the option (see [[DescriptionWML]]) {{DevFeature1.13|2}} This is now a synonym for '''label='''.<br />
** '''image''', '''label''', '''description''', '''default''': See [[DescriptionWML#WML_Format|DescriptionWML]].<br />
** '''value''': {{DevFeature1.13|?}} Gives the option a value to be stored in a variable, if this behavior is enabled.<br />
** '''[show_if]''': if present then this option will only be displayed if the conditional statement in this tag is passed (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]])<br />
** '''[command]''': an element containing actions which are executed if the option is selected.<br />
* '''variable''': {{DevFeature1.13|?}} If present, either the index or the value of the chosen option will be stored in the specified variable.<br />
* '''[text_input]''': there can be only one [text_input] tag. this adds a text input field to the message. ''Note: Messages with text_input will not be shown at all in prestart events''<br />
** '''variable''': the variable that the user's input will be written to<br />
** '''label''': a text label to the left of the input field<br />
** '''max_length''': the maximum number of characters that may be typed into the field<br />
** '''text''': text that is written into the field in the beginning<br />
* Check [[EventWML#Multiplayer_safety]] to find out in which events you can safely use '''[option]''' and '''[text_input]''' without causing OOS.<br />
<br />
=== Formatting ===<br />
'''[message]''' and other tags such as unit names (user_description), objectives, and floating text can make use of [http://developer.gnome.org/pango/unstable/PangoMarkupFormat.html Pango markup formatting codes].<br />
<br />
Remember to use single quotes (') instead of double quotes (") within the formatting string, as double quotes cannot be escaped, and the string will appear fragmented and possibly cause errors. Escaping markup is described in https://github.com/wesnoth/wesnoth/blob/master/src/font/pango/escape.hpp#L35-L39.<br />
<br />
For example, if you wanted to write "You are victorious!" in large, italic, gold letters, you might write it this way:<br />
<br />
<nowiki><span color='#BCB088' size='large' font-style='italic'>You are victorious!</span></nowiki><br />
<br />
<br />
These are the codes taken from the Pango markup formatting guide:<br />
<br />
*'''font''', '''font_desc''': A font description string, such as "Sans Italic 12".<br />
*'''font_family''', '''face''': A font family name.<br />
*'''font_size''', '''size''': Font size in 1024ths of a point, or one of the absolute sizes 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', or one of the relative sizes 'smaller' or 'larger'.<br />
*'''font_style''', '''style''': One of 'normal', 'oblique', 'italic'.<br />
*'''font_weight''', '''weight''': One of 'ultralight', 'light', 'normal', 'bold', 'ultrabold', 'heavy', or a numeric weight.<br />
*'''font_variant''', '''variant''': One of 'normal' or 'smallcaps'.<br />
*'''font_stretch''', '''stretch''': One of 'ultracondensed', 'extracondensed', 'condensed', 'semicondensed', 'normal', 'semiexpanded', 'expanded', 'extraexpanded', 'ultraexpanded'.<br />
*'''foreground''', '''fgcolor''', '''color''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''background, bgcolor''': An RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''underline''': One of 'none', 'single', 'double', 'low', 'error'.<br />
*'''underline_color''': The color of underlines; an RGB color specification such as '#00FF00' or a color name such as 'red'.<br />
*'''rise''': Vertical displacement, in 10000ths of an em. Can be negative for subscript, positive for superscript.<br />
*'''strikethrough''': 'true' or 'false' whether to strike through the text.<br />
*'''strikethrough_color''': The color of strikethrough lines; an RGB color specification such as '#00FF00' or a color name such as 'red'<br />
*'''fallback''': 'true' or 'false' whether to enable fallback. If disabled, then characters will only be used from the closest matching font on the system. No fallback will be done to other fonts on the system that might contain the characters in the text. Fallback is enabled by default. Most applications should not disable fallback.<br />
*'''letter_spacing''': Inter-letter spacing in 1024ths of a point.<br />
*'''gravity''': One of 'south', 'east', 'north', 'west', 'auto'.<br />
*'''gravity_hint''': One of 'natural', 'strong', 'line'.<br />
<br />
The following pango attributes are also available directly as attributes of the '''[message]''' tag:<br />
{{DevFeature1.13|4}}<br />
<br />
*'''font'''<br />
*'''font_family'''<br />
*'''font_size'''<br />
*'''font_style'''<br />
*'''font_weight'''<br />
*'''font_variant'''<br />
*'''font_stretch'''<br />
*'''color'''<br />
*'''bgcolor'''<br />
*'''underline'''<br />
*'''underline_color'''<br />
*'''rise'''<br />
*'''strikethrough'''<br />
*'''strikethrough_color'''<br />
*'''fallback'''<br />
*'''letter_spacing'''<br />
*'''gravity'''<br />
*'''gravity_hint'''<br />
<br />
== [objectives] ==<br />
The other tag used for plot development is '''[objectives]'''.<br />
The '''[objectives]''' tag overwrites any previously set objectives,<br />
and displays text which should describe the objectives of the scenario.<br />
Scenario objectives are displayed on the player's first turn after the tag is used,<br />
or as part of the event if it triggers during that player's turn.<br />
Objectives can also be accessed at any time in a scenario using the<br />
"Scenario Objectives" game menu option, making this tag useful for<br />
scenario-specific information that the player may need to refer to during play.<br />
<br />
Attributes of '''[objectives]''':<br />
* '''side''': Default '0'. The side to set the objectives for. A value of 0 sets objectives for all sides. note: There are side-specific objectives and default objectives, which are used in case a side doesn't have specific ones. Specifying 0 sets the default ones.<br />
* '''[[StandardSideFilter]]''' tags and keys: Sets the objectives of all matching sides to these passed specifications (the rest of this [objectives] tag). If no sides (such as when passing side=0) or all sides match, sets the default objectives, and the side specific ones for the matching sides otherwise.<br />
* '''bullet''': Default '• '. Replaces the default bullet, with whatever is passed, for all objectives, gold carryover notes, and notes defined with [note].<br />
* '''summary''': Displayed first in the objectives text, this should describe the basic objective for the overall scenario. Can be omitted.<br />
* '''note''': Displayed last in the objectives text, this is sometimes used for hints or additional information. Can be omitted.<br />
* '''victory_string''': Default ' _ "Victory:"', this text precedes the victory objectives. Can be set to "" too.<br />
* '''defeat_string''': Default ' _ "Defeat:"', this text precedes the defeat objectives. Can be set to "" too.<br />
* '''gold_carryover_string''': Default ' _ "Gold carryover:"', this text precedes the gold carryover information.<br />
* '''notes_string''': Default ' _ "Notes:"', this text precedes the notes.<br />
* '''silent''': Default: not present. If set to "yes", the objectives are silently changed. Else, they will be shown to the user when appropriate.<br />
* '''delayed_variable_substitution''': {{DevFeature1.13|8}} If set to yes, any variables or [insert_tag] are not substituted right away. Instead, they are substituted whenever the objectives are actually viewed.<br />
<br />
Tags of '''[objectives]''':<br />
* '''[objective]''': describes a win or loss condition. Most scenarios have multiple win or loss conditions, so use a separate [objective] subtag for each line; this helps with translations.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet, with whatever is provided, for the objective defined by the [objective] block.<br />
** '''red''': Default '0' for winning objectives, '255' for losing objectives. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255' for winning objectives, '0' for losing objectives. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '0'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''description''': text for the specific win or loss condition.<br />
** '''caption''': a text which will be displayed above the ''description''. This can be used to display a subcategory of objectives below ''victory_string'' or ''defeat_string''.<br />
** '''condition''': The color and placement of the text. Values are 'win'(colored green, placed after ''victory_string'') and 'lose'(colored red, placed after ''defeat_string'').<br />
** '''show_turn_counter''': If set to yes, displays the number of turns remaining in the scenario. Default is no.<br />
** '''[show_if]''': A condition that disables the objective if it doesn't hold. Conditional objectives are refreshed at '''[show_objectives]''' time only, or when manually opening the scenario objectives.<br />
* '''[gold_carryover]''': describes how the gold carryover works in this scenario. This is intended to be a more convenient way of displaying carryover information than using the note= key in [objectives].<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire objective, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire objective, including the bullet.<br />
** '''blue''': Default '192'. Overrides the default blue coloring of the entire objective, including the bullet.<br />
** '''bonus''' (boolean): whether an early finish bonus is granted. If omitted, early finish bonus is not mentioned.<br />
** '''carryover_percentage''': the amount of carryover gold. If omitted, the amount is not mentioned.<br />
** '''[show_if]''': {{DevFeature1.13|11}} Gold carryover will not be shown if the specified condition isn't met. Conditional gold carryover is refreshed at '''[show_objectives]''' time only.<br />
* '''[note]''': describes a note, usually used for hints or additional information. This is an easier way of adding several notes than concatenating them together into a single string to use with the ''note='' key.<br />
** '''bullet''': Default '• ' or whatever is set in the parent [objectives] block. Replaces the default bullet with whatever is provided for the note defined by the [note] block.<br />
** '''red''': Default '255'. Overrides the default red coloring of the entire note, including the bullet.<br />
** '''green''': Default '255'. Overrides the default green coloring of the entire note, including the bullet.<br />
** '''blue''': Default '255'. Overrides the default blue coloring of the entire note, including the bullet.<br />
** '''description''': the text of the note.<br />
** '''[show_if]''': The note will not be shown if the specified condition isn't met. Conditional notes are refreshed at '''[show_objectives]''' time only.<br />
<br />
== [set_menu_item] ==<br />
This tag is used to add a custom option in the right-click context menu which can then be used to trigger arbitrary WML commands. The menu items can be set and modified during any event, for example during "start" or "prestart" events. The user can also assign hotkeys to these WML commands unless specified otherwise. When the hotkey is pressed the event will be fired/filtered at the current mouse position.<br />
<br />
'''Note:''' Due to limitations in portable devices where there are no scroll bars for context menus, there is a hard-coded limit of 7 custom WML menu items. If you really need to have more than 7 menu items, try combining some of them in a submenu. {{DevFeature1.13|0}} This limitation is being removed in a [http://forums.wesnoth.org/viewtopic.php?p=572554#p572554 future version] of Wesnoth.<br />
<br />
* '''id''': the unique id for this menu item. If a menu item with this id already exists, it allows you to set specific changes to that item.<br />
* '''description''': the in-game text that will appear for this item in the menu.<br />
* '''image''': the image to display next to this item.<br />
* '''needs_select''': if ''yes'' (default ''no''), then the latest select event (see [[EventWML]]) that triggered before this menu item was chosen will be transmitted over the network before this menu item action will be. This only has any effect in networked multiplayer, and is intended to allow more elaborate menu item behaviour there without causing out of sync errors. If you don't know what this means, just leave it. {{DevFeature1.13|6}} ''needs_select=yes'' is deprecated, consider using manual variable syncing with [sync_variable].<br />
* '''synced''' {{DevFeature1.13|1}}: if ''no'' (default ''yes'') the command handler will only be run on the client that invoked the menu item; this means that changing the gamestate in a command handler of a menu item with ''synced=no'' will cause OOS<br />
* '''use_hotkey''': if ''no'' (default ''yes''), then the user cannot assign hotkeys to this menu item. If ''only'', the menu item is only accessible via hotkeys, not via right-click context; you can use this in combination with [default_hotkey] if you want custom hotkeys in your campaign/mp. <br />
* '''[show_if]''': If present, the menu item will only be available if the conditional statement (see [[ConditionalActionsWML#Condition_Tags|ConditionalActionsWML]]) within evaluates to true. When this is evaluated, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked, so it's possible to for example only enable the option on empty hexes or on a particular unit.<br />
* '''[filter_location]''': contains a location filter similar to the one found inside Single Unit Filters (see [[FilterWML]]). The menu item will only be available on matching locations.<br />
* '''[default_hotkey]''': contains a hotkey WML to specify what hotkey to assign to this, '''if the user has no hotkey assigned to this yet'''. (Unlike the rest of a menu item definition, modifying this tag has no effect on the game; it is only effective when initially defining a menu item.) Hotkey WML matches the format in the preferences file and contains the following keys:<br />
** '''key''': a string that contains the key to assign to this.<br />
** '''alt''', '''shift''', '''cmd'''(apple only), '''ctrl''': boolean values.<br />
** '''repeat_on_hold''' {{DevFeature1.13|12}}: if ''yes'' (default ''no''), holding the hotkey will repeat the action continuously, unless it blocks input with something like '''[message]'''. Due to a bug, versions older than 1.13.12 always repeat the action, with no way to disable it.<br />
* '''[command]''': contains the WML actions to be executed when the menu item is selected. Again, the WML variables ''$x1'' and ''$y1'' will point to the location on which the context menu was invoked on.<br />
** '''delayed_variable_substitution ''' (boolean yes|no, default: yes): If no, forces a variable substitution run onto the wml included in this [command] block. Use this, if you want variables which are to substitute to get the values they have at execution time of the event where this set_menu_item appears. Other than that, they get the values they have at invocation time of the menu item.<br />
<br />
== [clear_menu_item] ==<br />
<br />
Removes a menu item from the scenario.<br />
Normally menu items are, including all their defining wml, automatically carried over between scenarios. This tag prevents this. (The behavior is comparable to set_variable/clear_variable).<br />
* '''id''': (string): id of the menu item to clear. Can be a comma-separated list.<br />
<br />
== Other interface tags ==<br />
<br />
The following tags are also action tags:<br />
<br />
=== [change_theme] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Change the current interface theme.<br />
<br />
* '''theme''': The ID of the new theme. Use <code>theme=</code> (empty key) to switch back to the theme that the player has selected in Preferences. On <b>1.14.2</b> and later it is also possible to omit the key entirely to achieve the same effect (on previous versions this will crash the Lua engine).<br />
<br />
=== [item] ===<br />
Makes a graphical item appear on a certain hex. Note this only places the graphics for an item. It does not make the item do anything. Use a moveto event to make moving onto the item do something. <tt>''('''Hint:''' There are a number of predefined items that are used in various campaigns that you can make use of. You can find [http://www.wesnoth.org/macro-reference.xhtml#file:items.cfg a list of them] if you look into the items.cfg file in the wesnoth install directory (under /data/core/macros).)''</tt><br />
* '''x''', '''y''': the location to place the item. (only for [event][item]: full [[StandardLocationFilter|SLF]] support)<br />
* '''image''': the image (in ''images/'' as .png) to place on the hex. This image is aligned with the top-left of the hex (which is 72 pixels wide and 72 pixels tall). It is drawn underneath units. ''('''Hint:''' If using an image smaller than 72x72, then it might be useful to [[ImagePathFunctionWML#Blit_Function|BLIT]] the image onto <tt>misc/blank-hex.png</tt> (a blank 72x72 image).)''<br />
* '''halo''': an image to place centered on the hex. It is drawn on top of units. Use this instead of ''image'' if the image is bigger than the hex or if you want to animate an image.<br />
* '''name''' an id that can be used to remvoe the item.<br />
''Example (where the integer after the colon is the duration of each frame or square bracket expansion as per AnimationWML is used): halo=scenery/fire1.png:100,scenery/fire2.png:100,scenery/fire3.png:100,scenery/fire4.png:100,scenery/fire5.png:100,scenery/fire6.png:100,scenery/fire7.png:100,scenery/fire8.png:100''<br />
or equivalently (requires Wesnoth 1.11.2+):<br />
''halo=scenery/fire[1~8].png:100''<br />
* '''team_name''': name of the team for which the item is to be displayed (hidden for others). For multiple teams just put all the names in one string, for example separated by commas. {{DevFeature1.15|0}} In 1.14 the '''[side]team_name''' attribute was expected to be a substring of this '''team_name'''. In 1.15 both are expected to be comma-separated lists of names and the item is visible if the lists intersect. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* '''visible_in_fog''': whether the item should be visible through fog or not. Default yes.<br />
* '''redraw''': (boolean yes|no, default: yes): If no, disables implicit calls to [[InterfaceActionsWML#.5Bredraw.5D|[redraw]]] when placing the items.<br />
* '''[filter_team]''': {{DevFeature1.15|0}} A [[StandardSideFilter]]. Set '''team_name''' to the union of all '''[side]team_name''' attributes of all sides that match the SSF. ([[https://github.com/wesnoth/wesnoth/pull/3533|#3533]])<br />
* {{DevFeature1.15|0}} If both '''team_name''' and '''[filter_team]''' are set, '''team_name''' is ignored.<br />
<br />
=== [remove_item] ===<br />
Removes any graphical items on a given hex.<br />
* [[StandardLocationFilter]]: the hexes to remove items off<br />
* '''image''' if specified, only removes the given image item (This image name must include any [[ImagePathFunctionWML|image path functions]] appended to the original image name.)<br />
<br />
=== [print] ===<br />
Displays a message across the screen. The message will disappear after a certain time.<br />
* '''text''': (translatable) the text to display.<br />
* '''size''': (default=12) the pointsize of the font to use<br />
* '''duration''': (default=50) the length of time to display the text for. This is measured in the number of 'frames'. A frame in Wesnoth is usually displayed for around 30ms.<br />
* '''red''', '''green''', '''blue''': (default=0,0,0) the color to display the text in. Values vary from 0-255. {{DevFeature1.13|x}} Use of red, green, blue is now deprecated; use color=0,0,0 instead.<br />
<br />
=== [move_unit_fake] ===<br />
Moves an image of a unit along a certain path on the map. The path does not need to be a continuous list of adjacent hexes, so for example only the start and end points can be given, in which case the straightest line between those points will be calculated and used.<br />
* '''type''': the type of the unit whose image to use<br />
* '''x''': a comma-separated list of x locations to move along<br />
* '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
* '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
* '''gender''': the gender of the fake unit. Example: gender=female<br />
* '''variation''': the variation of the fake unit. Example: variation=undead<br />
* '''image_mods''': [[ImagePathFunctionWML|image path functions]] sequence to be applied on the fake unit.<br />
* '''force_scroll''': Whether to scroll the map or not even when [[#.5Block_view.5D|[lock_view]]] is in effect or ''Follow Unit Actions'' is disabled in ''Advanced Preferences''. Defaults to ''yes'' starting with version '''1.11.6'''; the attribute did not exist in previous versions and this action behaved as if ''no'' was passed instead.<br />
<br />
=== [move_units_fake] ===<br />
moves multiple images of units along paths on the map. These units are moved in lockstep.<br />
* '''force_scroll''': {{DevFeature1.15|0}} Has the same meaning as in [move_unit_fake] but a different default.<br />
* '''[fake_unit]''': A fake unit to move<br />
** '''type''': the type of unit whose image to use<br />
** '''x''': a comma-separated list of x locations to move along<br />
** '''y''': a comma-separated list of y locations to move along (x and y values are matched pairs)<br />
** '''side''': the side of the fake unit, used for team-coloring the fake unit<br />
** '''skip_steps''': the number of steps to skip before this unit starts moving<br />
<br />
=== [hide_unit] ===<br />
Temporarily prevents the engine from displaying the given unit. The unit does not become invisible, as it would be with the '''[hides]''' ability; it is still the same plain unit, but without an image. Useful in conjunction with '''[move_unit_fake]''': to move a leader unit into position on-screen. Until 1.8 each '''[hide_unit]''' tag only hides one unit.<br />
* [[StandardUnitFilter]]: All matching units will be hidden<br />
<br />
=== [unhide_unit] ===<br />
Stops the currently hidden units from being hidden.<br />
* [[StandardUnitFilter]]: Only the matching units will be unhidden<br />
<br />
=== [lock_view] ===<br />
Locks gamemap view scrolling for human players, so they cannot scroll the gamemap view until it is unlocked. WML or Lua actions such as '''[scroll_to]''' will continue to work normally, as they ignore this restriction; the locked/unlocked state is preserved when saving the current game.<br />
<br />
This feature is generally intended to be used in cutscenes to prevent the player scrolling away from scripted actions.<br />
<br />
{{DevFeature1.13|8}} This now also blocks the player from zooming the gamemap view. WML or Lua zoom will continue to work normally.<br />
<br />
=== [unlock_view] ===<br />
Unlocks gamemap view scrolling for human players.<br />
<br />
=== [scroll] ===<br />
Scroll a certain number of pixels in a given direction. Useful for earthquake/shaking effects.<br />
* '''x''', '''y''': the number of pixels to scroll along the x and y axis<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll] happens for everyone.<br />
<br />
=== [scroll_to] ===<br />
Scroll to a given hex<br />
* [[StandardLocationFilter]], do not use a [filter_location] sub-tag. If more than one location matches the filter, only the first matching location will be used.<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex being scrolled to (defaults to ''no'').<br />
* '''side''': the side or sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
* '''[filter_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to] happens for everyone.<br />
<br />
=== [scroll_to_unit] ===<br />
Scroll to a given unit<br />
* [[StandardUnitFilter]]<br />
* '''check_fogged''': whether to scroll even to locations covered in fog or shroud. Possible values ''yes'' (don't scroll to fog) and ''no'' (scroll even to fog), with ''no'' as the default.<br />
* '''immediate''': whether to instantly warp to the target hex regardless of the scroll speed setting in Preferences (defaults to ''no'').<br />
* '''highlight''': {{DevFeature1.13|5}} Whether to highlight the hex the unit is on (defaults to ''no'').<br />
* '''for_side''': the side or sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
* '''[for_side]''': a [[StandardSideFilter]] to select the sides for which this should happen. By default, the [scroll_to_unit] happens for everyone.<br />
<br />
=== [select_unit] ===<br />
Selects a given unit.<br />
* [[StandardUnitFilter]]: The first unit found will be selected.<br />
* '''fire_event''': whether a ''select'' event should be triggered or not (def. ''no''). (Note that select events aren't multiplayer save.)<br />
* '''highlight''': whether the unit's current hex should be highlighted (def. ''yes'').<br />
<br />
=== [sound]===<br />
Plays a sound<br />
* '''name''': the filename of the sound to play (in ''sounds/'' as .wav or .ogg). This can be a comma-separated list, from which one sound will be chosen randomly.<br />
* '''repeat''': repeats the sound for a specified additional number of times (default=0)<br />
<br />
=== [sound_source] ===<br />
Creates a sound source. "Sound sources" is a general name for a mechanism which makes possible for map elements to emit sounds according to some rules, where "map elements" can be specific locations or terrain types. For now, only sound sources tied to locations are supported.<br />
* '''id''': a unique identification key of the sound source<br />
* '''sounds''': a list of comma separated, randomly played sounds associated with the sound source<br />
* '''delay''': a numerical value (in milliseconds) of the minimal delay between two playbacks of the source's sound if the source remains visible on the screen; if one scrolls out and back in, the source will be considered as ready to play<br />
* '''chance''': a percentage (a value from 0 to 100) describing the chance of the source being activated every second after the delay has passed or when the source's location appears on the screen (note that it cannot play more than one file at the same time)<br />
* '''check_fogged''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are fogged<br />
* '''check_shrouded''': possible values ''yes'' and ''no'' - ''yes'' means the source will not play if its locations are shrouded<br />
* '''x,y''': similar to x,y as found in a [[StandardLocationFilter]], these are the locations associated with the sound source<br />
* '''fade_range''' (default = 3): distance in hexes that determines a "circular" area around the one specified by '''full_range''' where sound volume fades out linearly<br />
* '''full_range''' (default = 14): distance in hexes that determines a "circular" area where source plays with full volume, relative to screen center<br />
* '''loop''': number of times a sound sample should be looped if it stays visible. -1 means infinite (~65000)<br />
<br />
=== [story] ===<br />
{{DevFeature1.13|8}}<br />
<br />
Shows the story screen.<br />
* '''title''': Default title used if a part does not specify one — unlike the intro storyscreen, the scenario name is not used as a default title.<br />
* '''[part]''': As [[IntroWML]].<br />
<br />
=== [remove_sound_source] ===<br />
Removes a previously defined sound source.<br />
* '''id''': the identification key of the sound source to remove<br />
<br />
=== [music]===<br />
Switches to playing different music<br />
* '''name''': the filename of the music to play (in ''music/'' as .ogg)<br />
* see [[MusicListWML]] for the correct syntax<br />
===[volume]===<br />
Changes the game volume to a percent of the preferences volume for the game being played. Values can go from 0 to 100: <br />
* '''music''': Changes the music volume.<br />
* '''sound''': Changes the sound volume.<br />
=== [color_adjust]===<br />
Tints the color of the screen.<br />
* '''red''', '''green''', '''blue''': values from -255 to 255, the amount to tint by for each color<br />
=== [delay] ===<br />
Pauses the game.<br />
* '''time''': the time to pause in milliseconds<br />
* '''accelerate ''' (boolean yes|no, default no): {{DevFeature1.13|0}} whether the delay is affected by acceleration. When [delay] is used to make an animation, this should be set to yes so that your animation matches the ones generated by the game.<br />
<br />
=== [redraw] ===<br />
Redraws the screen (this normally isn't done during events, although some of the other interface actions cause the screen or parts of it to be redrawn).<br />
* '''clear_shroud''' (boolean yes|no, default no): If yes, clears fog and shroud around existing units. Useful if you, for example, spawn friendly units in the middle of an event and want the shroud to update accordingly (otherwise units that spawn inside fog would remain invisible for the duration of the event, since the fog would not automatically get cleared around them).<br />
* '''[[StandardSideFilter]]''': the sides for which to recalculate fog and shroud.<br />
* '''side''': If used (forces clear_shroud=yes), clears fog and shroud for that side.<br />
<br />
=== [unit_overlay] ===<br />
Sets an image that will be drawn over a particular unit, and follow it around<br />
* [[StandardUnitFilter]]: All matching units will get the overlay (do not use [filter])<br />
* '''image''': the image to place on the unit<br />
<br />
=== [remove_unit_overlay] ===<br />
removes a particular overlayed image from a unit<br />
* [[StandardUnitFilter]]: The overlay will get removed from all matching units (do not use [filter])<br />
* '''image''': the image to remove from the unit<br />
<br />
=== [animate_unit] ===<br />
Uses an animation of a unit to animate it on screen (if the unit has the corresponding animation).<br />
* '''flag''': The key to find the custom animation in the unit description (see the '''[extra_anim]''' description in [[AnimationWML]]). Standard animations can be triggered with the following keywords: ''leading recruited standing idling levelout levelin healing healed poisoned movement defend attack death victory pre_teleport post_teleport''<br />
* '''[filter]''' with a [[StandardUnitFilter]] as argument, see [[FilterWML]]. By default, the unit at the event location will be animated. You can use this tag to choose any other unit to animate.<br />
* '''[primary_attack]''': If this tag is not present, the filter for animation will be triggered with no attack. If it is here, all attacks from the unit will be filtered, and a matching one will be used to filter the animation. Takes a weapon filter as argument, see [[FilterWML]].<br />
* '''[secondary_attack]''': Similar to '''[primary_attack]'''. May be needed to trigger a defense animation correctly, if there are more than one animations available for the defending unit.<br />
* '''hits''': yes/no/hit/miss/kill: which according variation of a attack/defense animation shall be chosen (required)<br />
* '''text''': a text to hover during the animation <br />
* '''male_text''', '''female_text''': {{DevFeature1.13|2}} (translatable) gender-specific versions of the above<br />
* '''red''': red value for the text color (0-255)<br />
* '''green''': green value for the text color<br />
* '''blue''': blue value for the text color<br />
* '''with_bars''': yes/no: whether to display the status bars during the animation (e.g. the hitpoint bar)<br />
* '''[animate]''': a sub block with the same syntax as '''[animate_unit]''' except that the '''[filter]''' block is mandatory to find the unit. This block will find and animate another unit simultaneously.<br />
* '''[facing]''': a [[StandardLocationFilter]] specifying what direction the unit should be facing when animated<br />
<br />
=== [label] ===<br />
Places a label on the map.<br />
* '''x''', '''y''': the location of the label. {{DevFeature1.13|1}} (only for [event][label]: full [[StandardLocationFilter|SLF]] support)<br />
* '''text''': what the label should say<br />
* '''team_name''': if specified, the label will only be visible to the given team.<br />
* '''color''': color of the label. The format is r,g,b; r, g and b are numbers between 0 and 255.<br />
* '''visible_in_fog''': whether the label should be visible through fog or not. Default yes.<br />
* '''visible_in_shroud''': whether the label should be visible through shroud or not. Default no.<br />
* '''immutable''': whether this label is protected from being removed or changed by players. Default yes.<br />
* '''category''': the Show/Hide Labels dialog allows showing/hiding all labels of a given category by toggling a checkbox.<br />
* '''tooltip''': A tooltip visible when mouseovering the hex the label is on<br />
* '''side''': the number of the side that placed the label. Can be 0 for labels placed by WML.<br />
<br />
=== [floating_text]===<br />
Floats text (similar to the damage and healing numbers) on the given locations.<br />
* [[StandardLocationFilter]]: the text will be floated on all matching locations simultaneously.<br />
* '''text''': the text to display.<br />
<br />
The default text color is <span style="color: #6b8cff;">'''#6b8cff'''</span>. To change the color, use [[#Formatting|Pango markup]]. For example:<br />
<br />
<pre><br />
# Float some golden yellow text at 20,20.<br />
[floating_text]<br />
x,y=20,20<br />
text="<span color='#cccc33'>" + _ "Your text here" + "</span>"<br />
[/floating_text]<br />
</pre><br />
<br />
=== [deprecated_message] ===<br />
Shows a deprecated message in the message area, this feature is only intended to be used to warn about deprecated macros in mainline. The message is not translatable.<br />
* '''message''': the message to show.<br />
* '''level''': {{DevFeature1.13|10}} The deprecation level, a number from 1 to 3.<br />
* '''what''': {{DevFeature1.13|10}} The name of the thing being deprecated. Use this instead of '''message''' if possible; a stock message will be generated from it. Use '''message''' only if more information is required; it will be appended to the stock message. This should not be translatable<br />
* '''version''': {{DevFeature1.13|10}} For deprecation levels 2 and 3, this indicates the version in which the feature could be removed. It does ''not'' indicate the version in which it became deprecated. <br />
<br />
The meanings of the deprecation levels are as follows:<br />
<br />
# Deprecated, but will only be removed if absolutely necessary. The '''version''' key is ignored.<br />
# It will be removed no earlier than a specified version.<br />
# It will be removed in the next stable version<br />
# It has already been removed, leaving just a stub to inform users of how to update their code.<br />
<br />
Note that as of 1.13.11, deprecation messages show only in the log, not in the chat message area. The '''message''' can be translatable, but does not need to be.<br />
<br />
=== [wml_message] ===<br />
Outputs a message to Wesnoth's console output. Intended for campaign designers to output silent text to the console, without annoying the player; then, that text might contain information useful for later bug-reporting. The log domain for it is '''wml''', and the '''debug/dbg''' log level is available for use with the '''logger''' attribute. Depending on the current log level ('''error''' by default), which may be changed with the in-game :log command, or the --log-<level>=wml command line switch, the messages are echoed to the in-game chat.<br />
* '''message''': the message to show.<br />
* '''logger''': the Wesnoth engine output logger that should catch the text; this might be 'err' (the errors log level), 'warn'/'wrn' (the warnings log level) or anything else (the information log level). Not all information will be displayed depending on the log level chosen when starting Wesnoth.<br />
<br />
Note: As of 1.9.4/1.9.5 (r48805) the following "loggers" should work: If in [wml_message]: err/error, warn/wrn/warning, debug/dbg; using the :log command: Only the long forms error, warning, info and debug (this part gathered by trying rather than source inspecting). The long forms are most likely also the only ones working when starting wesnoth with --log-<level>=wml.<br />
For log level warning or error (as during normal play), only wml_messages with logger error or warning display (for both). With logger info or debug, additionally wml_messages with logger info or debug display (for both).<br />
<br />
=== [test_condition] ===<br />
<br />
{{DevFeature1.13|2}}<br />
<br />
Evaluates the contained conditional tags. If they evaluate to the expected value, it prints out a message to the console explaining which part of the condition caused this result in a way similar to [wml_message]. This can be used if your conditional test is failing and you're not sure why.<br />
<br />
* '''result''': Whether you expect the conditions to fail or succeed. If no (the default), a message will be printed if the conditional tags fail. If yes, a message will instead be printed if the conditional tags pass.<br />
* '''logger''': Same as for [wml_message]. Defaults to "warning".<br />
<br />
=== [open_help] ===<br />
Opens the in-game help.<br />
* '''topic''': the id of the topic to open<br />
=== [show_objectives] ===<br />
refreshes the objectives defined by [objectives] and its [show_if] tags, and displays them. (It is also called whenever the user explicitly asks for the objectives; this matters only if the tag was overridden by a [[LuaWML#register_wml_action|Lua]] script.)<br />
* '''side''': the side to show the objectives. If not set, all sides are used.<br />
* '''[[StandardSideFilter]]''' tags and keys: Tag affects the matching sides instead of just all or the one given by the integer value of the side= key.<br />
<br />
=== [chat] ===<br />
Displays a message in the chat area, not visible for observers. Alternative unconditionally visible for everyone: [[LuaWML:Display#wesnoth.message]]. {{DevFeature1.13|9}} can be visible for observers.<br />
* '''speaker''': (default="WML") A string for the name of the sender of the message.<br />
* '''message''': The message that should be displayed.<br />
* '''observable''' (boolean yes|no, default yes): {{DevFeature1.13|9}} Whether the message is displayed for observers.<br />
* '''[[StandardSideFilter]]''' tags and keys as argument; if the same client controls multiple sides that match, then the message will only be displayed once.<br />
<br />
=== [zoom] ===<br />
<br />
{{DevFeature1.13|8}}<br />
<br />
Changes the zoom level of the map.<br />
<br />
* '''factor''': The new zoom factor<br />
* '''relative''': If yes, zoom relative to current zoom level. Otherwise, set the absolute zoom level. Default no.<br />
<br />
== Useful Macros ==<br />
There are some predefined macros that you find useful for interface actions. You can find a complete list along with a detailed explanation of how they work [http://www.wesnoth.org/macro-reference.xhtml here].<br />
* '''{HIGHLIGHT_UNIT}''' Highlight a unit on the map. Use this to show important units<br />
* '''{HIGHLIGHT_IMAGE}''' Places and highlights an image on the map. Use this to show important items or locations<br />
* '''{SET_IMAGE}''' Places an image on the map which has no other function.<br />
* '''{QUAKE <soundfile>}''' Creates a tremor-like screenshake and plays <soundfile>. For example, '''{QUAKE (rumble.ogg)}'''.<br />
* '''{FLASH_WHITE}''' Flash the screen white momentarily. You can also replace WHITE with RED, BLUE or GREEN for a different colour.<br />
<br />
== See Also ==<br />
* [[DirectActionsWML]]<br />
* [[InternalActionsWML]]<br />
* [[EventWML]]<br />
* [[ReferenceWML]]<br />
<br />
<br />
[[Category: WML Reference]]<br />
[[Category: ActionsWML]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaMapGenerator&diff=60091LuaMapGenerator2018-12-11T23:37:49Z<p>Gfgtdf: </p>
<hr />
<div>{{DevFeature1.15}} The page describes the api available for lua map generators that is differnt from the ingame lua api.<br />
<br />
<br />
<br />
==== wesnoth.find_path ====<br />
* '''wesnoth.find_path(''src'', ''dst'', ''cost_function'', ''mapsize_x'', ''mapsize_y'', ''include_border'')'''<br />
<br />
Behaves slightly differntly than in the ingame lua api with the same name in particular it no longer accepts unit arguments and explicitly nees the map size.<br />
<br />
<br />
==== wesnoth.create_map ====<br />
* '''wesnoth.create_map (''map_data'')'''<br />
* '''wesnoth.find_path(''width'', ''height'', ''terrain'')'''<br />
<br />
Creates a gamemap object, which has the following functions and properties<br />
* '''get_terrain(loc)'''<br />
* '''set_terrain(loc, terrain)'''<br />
* '''get_locations(filter, locs_to_check)'''<br />
* '''get_tiles_radius(locations, filter_radius)'''<br />
* '''terrain_mask(x_offset, y_offset, data, optional_argeument_table)'''<br />
* '''width''' number<br />
* '''height''' number<br />
* '''data''' string<br />
<br />
The filters about use custom lua filter objects that can be constructed via wesnoth.create_filter<br />
<br />
==== wesnoth.create_filter ====<br />
creates a lua filter object from a table describing a lua terrainfilter, this is similar but not the same as wml filters, compiling these into lua objects makes it much faster. A lua filtertable is a table which at index 1 has the type of the filter and the rest depends on the type of the filter, for example ''wesnoth.create_filter { "terrain", "K*"} " will create a filter that matches keeps. THe follwing types of theilter are known:<br />
* '''{ "terrain", terraincode }''' matches for terrain terraincode<br />
* '''{ "all", <filter1>, <filter2>, <filter3>, ... }''' matches when all the subfilters match<br />
* '''{ "any", <filter1>, <filter2>, <filter3>, ... }''' matches when any the subfilters match<br />
* '''{ "none", <filter1>, <filter2>, <filter3>, ... }''' matches when none the subfilters match<br />
* '''{ "notall", <filter1>, <filter2>, <filter3>, ... }''' matches when not all the subfilters match<br />
* '''{ "adjacent", <subfilter>, [count = <count>], [adjacent = <adjacent>]}''' matches when count adjacent tiles matchthe subfilter ('adjacent=' defaults to 'n,nw,sw,s,se,ne')<br />
* '''{ "radius", <radius>, <subfilter>, filter_radius = <filter_radius> }''' radius: number, filter_radius: subfilter.<br />
<br />
It is reccomended to create a helper function for filter construction for example:<br />
<br />
<syntaxhighlight lang='lua'><br />
f = {<br />
terrain = function(terrain)<br />
return { "terrain", terrain }<br />
end,<br />
all = function(...)<br />
return { "all", ... }<br />
end,<br />
any = function(...)<br />
return { "any", ... }<br />
end,<br />
none = function(...)<br />
return { "none", ... }<br />
end,<br />
adjacent = function(f, ad, count)<br />
return { "adjacent", f, adjacent = ad, count = count }<br />
end,<br />
radius = function(r, f, f_r)<br />
return { "radius", r, f, filter_radius = f_r}<br />
end,<br />
}<br />
<br />
wesnoth.create_filter(<br />
f.all(<br />
f.terrain("K*"),<br />
f.radius(4, f.terrain("^V*"))<br />
)<br />
)<br />
</syntaxhighlight><br />
for a filter that matches keepos that are at most distance 4 to a village<br />
<br />
==== wesnoth.generate_default_map ====<br />
'''wesnoth.generate_default_map(''width'', ''height'', ''cfg'')'''<br />
''cfg'' is a wml table similar to the default map generators argument it supports the wml subtables as the defautl map generator and the following attributes:<br />
<br />
<br />
* '''nplayers''' the number of players-<br />
* '''nvillages''' the prefered number of villgaes on the map, unlike the default mapgen this is not 'per thousand'<br />
* '''iterations''' like the [generator] attribute the with same name, note that unliek the original value this is not divided by 10 for island maps.<br />
* '''hill_size''' like the [generator] attribute the with same name. <br />
* '''castle_size''' like the [generator] attribute the with same name.<br />
* '''island_size''' The size of the island usually up to half the width of the map.<br />
* '''island_off_center''' offset to place the island, used in particular for coastal maps.<br />
* '''max_lakes''' like the [generator] attribute the with same name, note that unliek the original value this is not divided by 10 for island maps.<br />
* '''link_castles''' whether to connect castles by roads<br />
* '''show_labels''' whether to generate labels.<br />
* '''seed''' the random seed.</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaMapGenerator&diff=60090LuaMapGenerator2018-12-11T14:06:59Z<p>Gfgtdf: </p>
<hr />
<div>{{DevFeature1.15}} The page describes the api available for lua map generators that is differnt from the ingame lua api.<br />
<br />
<br />
<br />
==== wesnoth.find_path ====<br />
* '''wesnoth.find_path(''src'', ''dst'', ''cost_function'', ''mapsize_x'', ''mapsize_y'', ''include_border'')'''<br />
<br />
Behaves slightly differntly than in the ingame lua api with the same name in particular it no longer accepts unit arguments and explicitly nees the map size.<br />
<br />
<br />
==== wesnoth.create_map ====<br />
* '''wesnoth.create_map (''map_data'')'''<br />
* '''wesnoth.find_path(''width'', ''height'', ''terrain'')'''<br />
<br />
Creates a gamemap object, which has the following functions and properties<br />
* '''get_terrain(loc)'''<br />
* '''set_terrain(loc, terrain)'''<br />
* '''get_locations(filter, locs_to_check)'''<br />
* '''get_tiles_radius(locations, filter_radius)'''<br />
* '''terrain_mask(x_offset, y_offset, data, optional_argeument_table)'''<br />
* '''width''' number<br />
* '''height''' number<br />
* '''data''' string<br />
<br />
The filters about use custom lua filter objects that can be constructed via wesnoth.create_filter<br />
<br />
==== wesnoth.create_filter ====<br />
creates a lua filter object from a table describing a lua terrainfilter, this is similar but not the same as wml filters, compiling these into lua objects makes it much faster. A lua filtertable is a table which at index 1 has the type of the filter and the rest depends on the type of the filter, for example ''wesnoth.create_filter { "terrain", "K*"} " will create a filter that matches keeps. THe follwing types of theilter are known:<br />
* '''{ "terrain", terraincode }''' matches for terrain terraincode<br />
* '''{ "all", <filter1>, <filter2>, <filter3>, ... }''' matches when all the subfilters match<br />
* '''{ "any", <filter1>, <filter2>, <filter3>, ... }''' matches when any the subfilters match<br />
* '''{ "none", <filter1>, <filter2>, <filter3>, ... }''' matches when none the subfilters match<br />
* '''{ "notall", <filter1>, <filter2>, <filter3>, ... }''' matches when not all the subfilters match<br />
* '''{ "adjacent", <subfilter>, [count = <count>], [adjacent = <adjacent>]}''' matches when count adjacent tiles matchthe subfilter ('adjacent=' defaults to 'n,nw,sw,s,se,ne')<br />
* '''{ "radius", <radius>, <subfilter>, filter_radius = <filter_radius> }''' radius: number, filter_radius: subfilter.<br />
<br />
It is reccomended to create a helper function for filter construction for example:<br />
<br />
<syntaxhighlight lang='lua'><br />
f = {<br />
terrain = function(terrain)<br />
return { "terrain", terrain }<br />
end,<br />
all = function(...)<br />
return { "all", ... }<br />
end,<br />
any = function(...)<br />
return { "any", ... }<br />
end,<br />
none = function(...)<br />
return { "none", ... }<br />
end,<br />
adjacent = function(f, ad, count)<br />
return { "adjacent", f, adjacent = ad, count = count }<br />
end,<br />
radius = function(r, f, f_r)<br />
return { "radius", r, f, filter_radius = f_r}<br />
end,<br />
}<br />
<br />
wesnoth.create_filter(<br />
f.all(<br />
f.terrain("K*"),<br />
f.radius(4, f.terrain("^V*"))<br />
)<br />
)<br />
</syntaxhighlight><br />
for a filter that matches keepos that are at most distance 4 to a village</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=MapGeneratorWML&diff=60089MapGeneratorWML2018-12-11T14:06:16Z<p>Gfgtdf: /* See Also */</p>
<hr />
<div>Map Generator WML is used to create scenarios which are randomly generated. Of course, any scenario may reconfigure itself during a start / prestart event as much as it likes, using randomness, but the Map Generator WML has the following advantages:<br />
<br />
* Wesnoth has several built-in map generators which can be configured with options, and these are much better developed than any existing pure WML options.<br />
* Map generation occurs before the scenario is even loaded, something which is not possible for WML events. In an mp game, the map generator code will run only on the host, side-stepping any synchronization issues, and keeping your scenario code as simple as possible.<br />
* For scenarios with "allow_new_game=yes" and which use map generators, the generator may be reconfigured in the mp create screen (assuming that someone has coded a dialog for it). The user can also select to regenerate the map and get instant feedback from the minimap display.<br />
<br />
== Scenario vs map generation ==<br />
<br />
Every map generator can be used in either '''scenario_generation''' mode or '''map_generation''' mode. In map_generation mode, the generator is only used to replace the map_data of your scenario. In scenario_generation mode, the entire [scenario] tag is replaced.<br />
<br />
To select a map generator and mode, in your [scenario] tag you must place '''one of'''<br />
* '''scenario_generation=algorithm'''<br />
* '''map_generation=algorithm'''<br />
where '''algorithm''' is the generator algorithm you want to use. Note that not every algorithm is designed to be use with both of these options.<br />
<br />
You must additionally place a [generator] tag in your scenario, which contains the options to the map generator.<br />
<br />
== [generator] ==<br />
<br />
The exact things that should be placed in [generator] depend on what algorithm you pick. There are three kinds of generators, '''default''', '''cave''' (cave is removed in wesnoth 1.13.6), '''lua''' {{DevFeature1.13|0}}<br />
<br />
For which key to use and what value, see the section for the generator you want to use.<br />
<br />
===The lua generator===<br />
The lua generator type specifies a custom map generator, which you provide via lua scripts.<br />
<br />
The following keys are recognized for '''[generator]''' when the lua generator is used:<br />
* '''create_map''' : A lua routine which returns a string containing the new map_data. The entire contents of the '''[generator]''' are passed to the script in a lua table (see [[LuaWML]]), via the argument '''...''' (see http://www.lua.org/pil/5.2.html).<br />
* '''create_scenario''' : The same, but returning a '''[scenario]''' tag for the new scenario, as a lua table.<br />
<br />
Any other keys are used only by the lua script.<br />
<br />
The following keys of the output [scenario] are specifically watched by the mp create screen:<br />
* '''id'''<br />
* '''name'''<br />
* '''description'''<br />
* '''error_message'''<br />
<br />
====Available Lua API====<br />
Most of the usual in-game API, in the table '''wesnoth''', is not available to lua scripts. However the usual standard lua libs are available, and a random number generator object is available from the Rng table. This is an instance of the Mersenne Twister 19937 random number generator from the C++11 standard.<br />
<br />
* '''rng = Rng:create()''' : creates a new rng object<br />
* '''rng:seed()''' : seed an rng, expects a string in hexadecimal format<br />
* '''rng:draw()''' : draw a 32-bit random integer from the rng<br />
<br />
It is highly recomended NOT to use the math.random function in random map generators, becasue math.random breaks the 'seed' function for random map generators in the editor.<br />
<br />
{{DevFeature1.13}} In 1.13.x, this is no longer the case; much of the '''wesnoth''' table is available, including (but not limited to) '''wesnoth.random''' and '''wesnoth.find_path'''. However, there are still many things that are not available. You can open a Lua console to experiment and find out what's allowed by calling '''wesnoth.show_lua_console''' at some point in your map generator script. The '''Rng''' table no longer exists, having been superceded by '''wesnoth.random'''.<br />
<br />
===The Default Generator===<br />
The default generator can be used to generate map data for any scenario. The data in this section is inferred from “data/multiplayer/scenarios/Random_Scenario.cfg”, usage in add-on content, and inspection of mapgen.cpp<br />
<br />
'''Excerpt from mapgenerator comments:'''<br />
<br />
* Basically we generate alot of hills, each hill being centered at a certain point, with a certain radius - being a half sphere. Hills are combined additively to form a bumpy surface. The size of each hill varies randomly from 1-hill_size. We generate 'iterations' hills in total. The range of heights is normalized to 0-1000. 'island_size' controls whether or not the map should tend toward an island shape, and if so, how large the island should be. Hills with centers that are more than 'island_size' away from the center of the map will be inverted (i.e. be valleys). 'island_size' as 0 indicates no island.<br />
<br />
To use the default '''[generator]''' your '''[scenario]''' tag must contain one of the following keys:<br />
* '''scenario_generation=default'''<br />
* '''map_generation=default'''<br />
If ‘scenario_generation’ is used, the engine will expect for your entire '''[scenario]''' sub tags to be inside a '''[scenario]''' tag inside '''[generator]'''. Tags outside of this will be ignored. There may be value in this, but at this writing, it’s not clear.<br />
‘map_generation=default’ is simpler and more commonly used. It is also necessary to use this key so that you can regenerate a map in MP game creation.<br />
In its use only generator data is in the '''[generator]''' tag, all other '''[scenario]''' data is placed outside of it. The exception is if you are making an initial MP scenario available in MP game creation, for this a '''[scenario]''' tag must appear inside of '''[generator]''', containing the '''[scenario]''' subtags you want to use. See “data/multiplayer/scenarios/Random_Scenario.cfg” for an example.<br />
<br />
The following key/tags are recognized for '''[generator]''' when the default generator is used:<br />
* '''[scenario]''': See [[ScenarioWML]]<br />
* '''name'''<br />
** '''default'''<br />
* '''map_width''','''map_height''': size of the map to generate<br />
* '''iterations''': the number of times an attempt is being made to generate a hill<br />
* '''hill_size''': hills will have a random size between 1 and ''hill_size''<br />
* '''max_lakes''': the number of times an attempt is being made to generate a lake<br />
* '''min_lake_height''': lakes are the starting point of rivers and need to start above a certain height<br />
* '''lake_size''': the size of a lake still randomly generated<br />
* '''river_frequency''': determine how much a river can run uphill and thus generate more rivers<br />
<br />
* '''villages''': villages per 1,000 hexes<br />
* '''players''': Number of starting locations for the map.<br />
* '''castle_size''': Number of castle tiles (including the keep), per player.<br />
* '''temperature_iterations''': Same as iterations, but for the temperature map.<br />
* '''temperature_size''': Same as hill_size, but for the temperature map. (Temperature map is generated the same way as a hill map, but is hard coded with a island_size of 0.)<br />
* '''roads''': number of roads the generator will attempt to make<br />
* '''road_windiness''': Use 1 for the road to be made using the cheapest path (based on [road_cost] tags), higher values introduce randomness to make the road wind a bit.<br />
* '''island_size''': Use 1-5 for coastal maps and 6-10 for island maps. Bigger values may crash map generation process. Bigger numbers makes more water (and less land)<br />
* '''default_flatland''': If not specified, is Grassland. If your height tags don't go down to 0, the default_flatland will be used (possibly in other cases as well).<br />
* '''[height]''': list of common terrain types that come in at different heights, from highest to lowest. Good WML will have the range of 1000-0 covered.<br />
** '''height''': the terrain specified below will appear at this height and up.<br />
** '''terrain''': 1 terrain code<br />
* '''[convert]''': used to make terrain conversions. For example, water becomes ice at low temperatures, grass snow, etc. If the terrain is between the min_x and max_x it will be converted. If min_x is not defined it will default to a large negative number. If max_x is not defined it will default to a large positive number<br />
** '''min_height'''<br />
** '''max_height'''<br />
** '''min_temperature'''<br />
** '''max_temperature'''<br />
** '''from''': a comma separated terrains to convert from<br />
** '''to''': The terrain to convert these terrains to<br />
* '''[road_cost]'''<br />
** '''terrain''' 1 terrain code<br />
** '''cost''': how expensive it is the create a road on this terrain, this influences the odds of this terrain getting a road<br />
** '''convert_to_bridge''': a comma separated list of terrains; N/S, then NE/SW, then NW/SE.<br />
** '''convert_to''': 1 terrain code (note using both ''convert_to_bridge'' and ''convert_to'' might result in unwanted results)<br />
* '''[village]''': The conversion of terrains to villages<br />
** '''terrain''': 1 terrain code which will be converted to a village<br />
** '''convert_to''': 1 terrain code for the village<br />
** '''adjacent_liked''': a comma separated terrain list. This list increases the rating for a certain location, every tile around the location will be tested against this list and for every match the rating of the location is increased. The same terrain twice in the list will double the rating increase for that location.<br />
** '''rating''': chance of appearing<br />
* '''[castle]''': the conversion of castles<br />
** '''valid_terrain''': a comma-separated terrain list with terrains which are allowed to be converted to a castle.<br />
** '''min_distance''': all castles generated must be this number of hexes apart from each other<br />
* '''[naming]''': The names used to label landscape features (forests, lakes, etc.). This controls, for example, the "Sal" part of "Sal's Crossing". If this tag is empty, those labels should be suppressed. (Due to a bug, they are not suppressed prior to 1.11.1.) The predefined macro VILLAGE_NAMES is one option for the contents of this tag. If that macro is not used, this tag takes one key.<br />
** {{DevFeature1.13|5}}<br />
*** The new [[Context-free grammar|Context-free grammar name]] (CFG) generator is now supported<br />
*** '''male_names''' is now deprecated. Use '''base_names''' for the Markov-chain based or '''base_name_generator''' for the CFG generator instead<br />
*** It is now possible to have generator-specific overrides of the default naming rules which are defined in "data/english.cfg". You may override the following naming rules by adding them to the [naming] tag of your generator instance:<br />
{| class="wikitable"<br />
!Key<br />
!Supported variables<br />
|-<br />
|bridge_name_generator=<br />
|$base<br />
|-<br />
|road_name_generator=<br />
|$base<br />
|-<br />
|river_name_generator=<br />
|$base<br />
|-<br />
|forest_name_generator=<br />
|$base<br />
|-<br />
|lake_name_generator=<br />
|$base<br />
|-<br />
|mountain_name_generator=<br />
|$base<br />
|-<br />
|swamp_name_generator=<br />
|$base<br />
|}<br />
<br />
* '''[village_naming]''': The names used to label villages. This controls, for example, the "Fox" part of "Foxham". If this tag is empty, those labels should be suppressed. (Due to a bug, they are not suppressed prior to 1.11.1.) The predefined macro VILLAGE_NAMES is one option for the contents of this tag. If that macro is not used, this tag takes one key. The village naming depends on the adjacent landscape features, e.g. a village near a forest with the name "Rock Forest" may be named "Rockwood".<br />
** '''male_names'''<br />
** {{DevFeature1.13|5}}<br />
*** The new [[Context-free grammar|Context-free grammar name]] (CFG) generator is now supported<br />
*** '''male_names''' is now deprecated. Use '''base_names''' for the Markov-chain based or '''base_name_generator''' for the CFG generator instead<br />
*** It is now possible to have generator-specific overrides of the default village naming rules which are defined in "data/english.cfg". You may override the following village naming rules by adding them to the [village_naming] tag of your generator instance:<br />
{| class="wikitable"<br />
!Key<br />
!Supported variables<br />
|-<br />
|name_generator=<br />
|$base<br />
|-<br />
|lake_name_generator=<br />
|$base, $lake<br />
|-<br />
|river_name_generator=<br />
|$base, $river<br />
|-<br />
|bridge_name_generator=<br />
|$base, $river, $bridge<br />
|-<br />
|grassland_name_generator=<br />
|$base<br />
|-<br />
|forest_name_generator=<br />
|$base, $forest<br />
|-<br />
|hill_name_generator=<br />
|$base<br />
|-<br />
|mountain_name_generator=<br />
|$base, $mountain<br />
|-<br />
|mountain_anon_name_generator=<br />
|$base<br />
|-<br />
|road_name_generator=<br />
|$base, $road<br />
|-<br />
|swamp_name_generator=<br />
|$base, $swamp<br />
|}<br />
<br />
===The Cave Generator===<br />
The cave generator generates a system of chambers and passages similar to the levels in dungeon crawling games like Rogue. It does not appear to have been written for multiplayer scenario game creation like the default generator was. It is used in '''campaigns\Sceptre_of_Fire\scenarios\4_Gathering_Materials.cfg''' & '''campaigns\Heir_To_The_Throne\scenarios\ 17_Scepter_of_Fire.cfg '''. The data here is inferred from those scenarios and an inspection of cavegen.cpp<br />
<br />
To use the cave '''[generator]''' your '''[scenario]''' tag must contain one of the following keys:<br />
* '''scenario_generation=cave'''<br />
* '''map_generation=cave'''<br />
Here it is recommend you use ‘scenario_generation’ as there are examples to follow, though it may be possible to use’ map_generation’.<br />
<br />
<br />
The following key/tags are recognized for '''[generator]''' when the cave generator is used:<br />
* '''[settings]''': behaves as if '''[scenario]''', See [[ScenarioWML]]<br />
* '''map_width''','''map_height''': size of the map to generate<br />
* '''village_density''': influences number of villages<br />
* '''flipx_chance''': Chance to flip x coordinates, that meens the map is mirrored at the vertical axis in its midth.<br />
* '''flipy_chance''': Chance to flip y coordinates, that meens the map is mirrored at the horizontal axis in its midth.<br />
* '''[chamber]''': for underground maps<br />
** '''id''': a name used to identify where the passages lead. See the [passage] tag, below.<br />
** '''x''','''y''': approximate location of the center hex of the chamber. Unfortunately it isn't always exact. Can be a single number (x=5) or a range (x=10-20)<br />
** '''size''': circular radius of the chamber, including the center hex<br />
** '''jagged''': a good value is probably between 0-50 (not sure exactly)<br />
** '''chance''': chance for the chamber to be generated, between 0 and 100, 100 if key not present<br />
** '''[items]''': See [[ScenarioWML]]. This can contain tags normally found under [scenario] like [side], [item], and [event]. Moveto events definitely work here (using the same_location_as_previous key instead of a location filter). Other events can be placed in the [settings] tag, above. Locations of items will be generated randomly. The attribute '''same_location_as_previous=yes''' means that the filter for a moveto event (see [[EventWML]]) is the same as the location of the previous item.<br />
** '''[passage]''': defines a pathway between chambers<br />
*** '''destination''': the id key of the destination chamber<br />
*** '''windiness''': a good value is probably between 1-10<br />
*** '''laziness''':<br />
*** '''width''': number of hexes<br />
*** '''jagged''': a good value is probably between 1-10<br />
*** '''chance''': chance for the passage to be generated, between 0 and 100, 100 if key not present<br />
{{DevFeature1.13|6}}<br />
'''scenario_generation=cave''' and '''map_generation=cave''' is no longer supported, instead use <br />
map_generation=lua with code = << params = ...; return wesnoth.dofile("lua/cave_map_generator.lua") >>, the [generator] has a similar syntax, the difference is that<br />
* '''[items]''' is no longer supported, use one or multiple '''[item_location]''' instead, this will generate starting locations or other special locations in the map data with the given id, '''place_castle = yes''' can be set in '''[item_location]''' to make the generator create a castle at this location.<br />
* since the lua generator now prefers '''map_generation''' (instead of '''scenario_generation''') '[event]s' and '[side]s' now go directly in '''[scenario]''', '''[settings]''' is no longer supported.<br />
<br />
=== YAMG generator ===<br />
<br />
*** Please document me! ***<br />
<br />
== Infrastructure ==<br />
<br />
* The default generator settings are loaded from a scenario file under data/multiplayer/scenarios.<br />
* mapgen_dialog overwrites these values if necessary.<br />
* The create_map / create_scenario function is called by one of the following<br />
** multiplayer_create_engine.cpp:394<br />
** context_manager.cpp:648<br />
** map_create.cpp:56<br />
* A map buffer is written to res["map_data"]<br />
* the config res is passed to the calling function.<br />
<br />
== See Also ==<br />
<br />
* [[ScenarioWML]]<br />
* [[ReferenceWML]]<br />
* [[LuaMapGeneratorWML]]<br />
<br />
[[Category: WML Reference]]</div>Gfgtdfhttps://wiki.wesnoth.org/index.php?title=LuaMapGenerator&diff=60088LuaMapGenerator2018-12-11T14:05:40Z<p>Gfgtdf: Created page with "The page describes the api available for lua map generators that is differnt from the ingame lua api. ==== wesnoth.find_path ==== * '''wesnoth.find_path(''src'', ''dst'', '..."</p>
<hr />
<div>The page describes the api available for lua map generators that is differnt from the ingame lua api.<br />
<br />
<br />
<br />
==== wesnoth.find_path ====<br />
* '''wesnoth.find_path(''src'', ''dst'', ''cost_function'', ''mapsize_x'', ''mapsize_y'', ''include_border'')'''<br />
<br />
Behaves slightly differntly than in the ingame lua api with the same name in particular it no longer accepts unit arguments and explicitly nees the map size.<br />
<br />
<br />
==== wesnoth.create_map ====<br />
* '''wesnoth.create_map (''map_data'')'''<br />
* '''wesnoth.find_path(''width'', ''height'', ''terrain'')'''<br />
<br />
Creates a gamemap object, which has the following functions and properties<br />
* '''get_terrain(loc)'''<br />
* '''set_terrain(loc, terrain)'''<br />
* '''get_locations(filter, locs_to_check)'''<br />
* '''get_tiles_radius(locations, filter_radius)'''<br />
* '''terrain_mask(x_offset, y_offset, data, optional_argeument_table)'''<br />
* '''width''' number<br />
* '''height''' number<br />
* '''data''' string<br />
<br />
The filters about use custom lua filter objects that can be constructed via wesnoth.create_filter<br />
<br />
==== wesnoth.create_filter ====<br />
creates a lua filter object from a table describing a lua terrainfilter, this is similar but not the same as wml filters, compiling these into lua objects makes it much faster. A lua filtertable is a table which at index 1 has the type of the filter and the rest depends on the type of the filter, for example ''wesnoth.create_filter { "terrain", "K*"} " will create a filter that matches keeps. THe follwing types of theilter are known:<br />
* '''{ "terrain", terraincode }''' matches for terrain terraincode<br />
* '''{ "all", <filter1>, <filter2>, <filter3>, ... }''' matches when all the subfilters match<br />
* '''{ "any", <filter1>, <filter2>, <filter3>, ... }''' matches when any the subfilters match<br />
* '''{ "none", <filter1>, <filter2>, <filter3>, ... }''' matches when none the subfilters match<br />
* '''{ "notall", <filter1>, <filter2>, <filter3>, ... }''' matches when not all the subfilters match<br />
* '''{ "adjacent", <subfilter>, [count = <count>], [adjacent = <adjacent>]}''' matches when count adjacent tiles matchthe subfilter ('adjacent=' defaults to 'n,nw,sw,s,se,ne')<br />
* '''{ "radius", <radius>, <subfilter>, filter_radius = <filter_radius> }''' radius: number, filter_radius: subfilter.<br />
<br />
It is reccomended to create a helper function for filter construction for example:<br />
<br />
<syntaxhighlight lang='lua'><br />
f = {<br />
terrain = function(terrain)<br />
return { "terrain", terrain }<br />
end,<br />
all = function(...)<br />
return { "all", ... }<br />
end,<br />
any = function(...)<br />
return { "any", ... }<br />
end,<br />
none = function(...)<br />
return { "none", ... }<br />
end,<br />
adjacent = function(f, ad, count)<br />
return { "adjacent", f, adjacent = ad, count = count }<br />
end,<br />
radius = function(r, f, f_r)<br />
return { "radius", r, f, filter_radius = f_r}<br />
end,<br />
}<br />
<br />
wesnoth.create_filter(<br />
f.all(<br />
f.terrain("K*"),<br />
f.radius(4, f.terrain("^V*"))<br />
)<br />
)<br />
</syntaxhighlight><br />
for a filter that matches keepos that are at most distance 4 to a village</div>Gfgtdf