Difference between revisions of "EventWML"
(→Custom events: Fix the example (it needed [primary_unit]), and add another example to show that they're like function calls) |
(→Multiplayer safety) |
||
(30 intermediate revisions by 9 users not shown) | |||
Line 2: | Line 2: | ||
== The [event] Tag == | == The [event] Tag == | ||
− | This tag is a subtag of the [scenario], [unit_type] and [era] tags which is used to describe a set of [[ActionWML|actions]] which trigger at a certain point in a scenario. When used in a [scenario] tag (also includes [multiplayer | + | This tag is a subtag of the [scenario], [unit_type] and [era] tags which is used to describe a set of [[ActionWML|actions]] which trigger at a certain point in a scenario. When used in a [scenario] tag (also includes [multiplayer] and [test]), the event only occurs in that scenario. When used in a [unit_type] tag, the event will occur in all scenarios in which a unit of that type appears in (only after such a unit appears during the scenario, however). When used in an [era], the event will occur in any scenario which is played using that era. |
This tag has keys and child tags that control when and if the event actions will be triggered. Most important of these is the '''name''' key. Without it, no error will be raised but the event will never fire. Therefore, from a practical standpoint, it can be considered mandatory. All of the others can be used or not and the event actions will fire either way. | This tag has keys and child tags that control when and if the event actions will be triggered. Most important of these is the '''name''' key. Without it, no error will be raised but the event will never fire. Therefore, from a practical standpoint, it can be considered mandatory. All of the others can be used or not and the event actions will fire either way. | ||
− | '''Lexicon side note:''' ''The word "event" in the [event] tag itself may be considered an abbreviation of the | + | '''Lexicon side note:''' ''The word "event" in the [event] tag itself may be considered an abbreviation of the term "event handler" because it is technically not a game "event" but an event '''handler''' for the game events fired with the given 'name'. However, this distinction is usually unimportant in most discussions and the event handlers are therefore simply referred to as "events" in this documentation.'' |
=== The 'name' Key (Mandatory) === | === The 'name' Key (Mandatory) === | ||
Line 27: | Line 27: | ||
''* Note that unless you use [[#first_time_only|first_time_only=no]], the event will fire only once, '''not''' once for each listed type.'' | ''* Note that unless you use [[#first_time_only|first_time_only=no]], the event will fire only once, '''not''' once for each listed type.'' | ||
− | All predefined event types are listed | + | All predefined event types are listed below, along with a description of when this value will cause the event to be triggered, in the [[#Predefined_Events_Without_Filters|Predefined Events Without Filters]] and [[#Predefined_Events_With_Filters|Predefined Events With Filters]] sections. Any value ''not'' listed there is a custom event name which can be triggered only by a '''[fire_event]''' tag somewhere else. |
Spaces in event names can be interchanged with ''underscores'' (for example, '''name=new turn''' and '''name=new_turn''' are equivalent). | Spaces in event names can be interchanged with ''underscores'' (for example, '''name=new turn''' and '''name=new_turn''' are equivalent). | ||
− | ==== | + | ==== Variables in the name ==== |
− | + | If the name contains variables, they will be substituted each time the event is triggered. For example, '''name=turn $disaster_turn''' will only trigger if the turn number is currently equal to whatever number is stored in the variable '''$disaster_turn'''; updating the variable will adjust the turn that the event triggers on. However, if the variable contents contains a comma, it won't be parsed after substitution. Since an event name can't contain a comma, this means the event will never trigger. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | {{DevFeature1.17|6}} | |
− | + | Commas resulting from variable substitution are now parsed. If you write '''name=$important_event''' and the variable '''$important_event''' contains the text "capture,die", the event will trigger on either a death or a village capture. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
==== Custom events ==== | ==== Custom events ==== | ||
Line 365: | Line 124: | ||
==== remove ==== | ==== remove ==== | ||
− | : | + | : Removes an event instead of adding a new one. This key takes a [[ConditionalActionsWML#Boolean_Values|boolean]]; if yes, does the same as a [[InternalActionsWML#.5Bremove_event.5D|[remove_event]]] with the same id= value, and the other attributes of this event tag are ignored. |
− | + | {{DevFeature1.13|0}} May be a comma separated list. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | {{DevFeature1.15|7}} Prints a deprecation warning recommending to use [remove_event] instead. | |
− | + | ==== priority ==== | |
− | + | : {{DevFeature1.17|20}} If several '[event]' tags have the same name, then any with a high priority value will be triggered before events with a lower priority value. Negative numbers are also supported, to run after events without a priority (as the attribute defaults to zero). For events with equal priority, the order is determined by the order in which the events were added. | |
− | |||
− | [ | ||
− | |||
==== [filter] ==== | ==== [filter] ==== | ||
Line 394: | Line 145: | ||
:* '''name''': the name of the weapon used. | :* '''name''': the name of the weapon used. | ||
:* '''range''': the range of the weapon used. | :* '''range''': the range of the weapon used. | ||
− | :* '''special''': filter on the attack's special | + | :* '''special_id''': filter on the attack's weapon special id. |
+ | :* '''special_type''': filter on the attack's weapon special type. | ||
+ | :* {{DevFeature1.17|15}} '''special_id_active''': filter on the attack's weapon special id active(encoded in [specials] or [abilities] tags). | ||
+ | :* {{DevFeature1.17|15}} '''special_type_active''': filter on the attack's weapon special type active(encoded in [specials] or [abilities] tags). | ||
==== [filter_second_attack] ==== | ==== [filter_second_attack] ==== | ||
Line 408: | Line 162: | ||
:* SSF tags and keys as arguments as described in [[StandardSideFilter]]. | :* SSF tags and keys as arguments as described in [[StandardSideFilter]]. | ||
: note: This tag makes most sense in side turn and turn refresh events. However, all wml events have a current side so one could also prevent e.g. a moveto event from firing if you put a [filter_side] tag there and the moving unit's side doesn't match. | : note: This tag makes most sense in side turn and turn refresh events. However, all wml events have a current side so one could also prevent e.g. a moveto event from firing if you put a [filter_side] tag there and the moving unit's side doesn't match. | ||
+ | |||
+ | ==== [insert_tag] ==== | ||
+ | : An '''[insert_tag]''' that expands to any of the above filter tags will result in the filter being loaded from the variable each time the game checks if the event should fire. This can result in the event's filter varying from turn to turn. | ||
+ | |||
+ | ==== filter_formula ==== | ||
+ | :{{DevFeature1.17|6}} | ||
+ | : Similar to [filter_condition], but the condition is expressed in [[Wesnoth Formula Language]]. The formula has access to the following keys: | ||
+ | :*Event information: | ||
+ | :**'''event''' - the event name | ||
+ | :**'''event_id''' - the event's unique ID | ||
+ | :**'''event_data''' - additional information specific to the event, such as owner_side or damage_inflicted, or anything passed in '''[fire_event][data]'''. | ||
+ | :**'''loc''', '''unit''' - primary event location and unit | ||
+ | :**'''second_loc''', '''second_unit''' - secondary event location and unit | ||
+ | :**'''weapon''', '''second_weapon''' - primary and secondary weapon | ||
+ | :*Gamestate information: | ||
+ | :**'''turn_number''' | ||
+ | :**'''time_of_day''' - the time of day ID | ||
+ | :**'''side_number''' - currently active side | ||
+ | :**'''sides''' - a list of all sides | ||
+ | :**'''units''' - a list of all units on the map | ||
+ | :**'''map''' - the entire game map as a two-dimensional array | ||
==== delayed_variable_substitution ==== | ==== delayed_variable_substitution ==== | ||
− | : This key is only relevant inside of a [[#Delayed Variable | + | : This key is only relevant inside of a [[#Delayed Variable Substitution_2|nested event]] and controls when variable substitution will occur in those special case actions. |
=== Actions triggered by [event] === | === Actions triggered by [event] === | ||
Line 421: | Line 196: | ||
* internal actions ([[InternalActionsWML]]) which are used by WML internally | * internal actions ([[InternalActionsWML]]) which are used by WML internally | ||
− | More details in [[ActionWML]]. | + | More details in [[ActionWML]]. Actions can also be dynamically inserted via '''[insert_tag]'''. |
Several actions use standard filters to find out which units | Several actions use standard filters to find out which units | ||
Line 469: | Line 244: | ||
* defender hits | * defender hits | ||
* defender misses | * defender misses | ||
+ | * unit hits | ||
+ | * unit misses | ||
* start | * start | ||
* prestart (prestart are synced but [message][option] & [unstore_unit] advancement choices will do a random decision because UI things don't work during prestart events.) | * prestart (prestart are synced but [message][option] & [unstore_unit] advancement choices will do a random decision because UI things don't work during prestart events.) | ||
Line 487: | Line 264: | ||
* {{DevFeature1.13|10}} victory | * {{DevFeature1.13|10}} victory | ||
* {{DevFeature1.13|10}} defeat | * {{DevFeature1.13|10}} defeat | ||
+ | * {{DevFeature1.13|0}} scenario_end | ||
The following are <b>not</b> synced: | The following are <b>not</b> synced: | ||
* select | * select | ||
Line 548: | Line 326: | ||
After that WML is encountered (at toplevel or after created from another event), the event with this ID is removed from the scenario wml, thus firing it has no effect. After an event is removed, it can still be re-added later. | After that WML is encountered (at toplevel or after created from another event), the event with this ID is removed from the scenario wml, thus firing it has no effect. After an event is removed, it can still be re-added later. | ||
+ | |||
+ | == Predefined Events Without Filters == | ||
+ | |||
+ | These events do not take filter parameters (except [filter_condition] which works for all events). | ||
+ | |||
+ | === preload === | ||
+ | |||
+ | Triggers before a scenario 'prestarts' and when loading a savegame -- before anything is shown on the screen at all. Can be used to set up the [[LuaWML|Lua]] environment: loading libraries, defining helper functions, etc. | ||
+ | |||
+ | '''Note:''' If a game is started, saved, and then reloaded, the preload event will fire two times while playing. However, it will only fire once when viewing the replay. If the preload event alters the gamestate the second time it fired while playing (when loading the saved game) then it can result in Out Of Sync errors. | ||
+ | |||
+ | '''Note:''' Unlike prestart and start, the preload event '''must be able to fire more than once!''' This is because it is triggered each time a savegame is loaded in addition to the initial time when it loads before the scenario 'prestart'. This means that it is effectively ''mandatory'' to have the [[#first_time_only|first_time_only=no]] key value in a preload event. | ||
+ | |||
+ | === prestart === | ||
+ | |||
+ | Triggers before a scenario 'starts' -- before anything is shown on the screen at all. Can be used to set up things like village ownership. For things displayed on-screen such as character dialog, use '''start''' instead. | ||
+ | |||
+ | '''Note:''' ''This value makes the [[#first_time_only|first_time_only]] key irrelevant since, by definition, it can only fire once.'' | ||
+ | |||
+ | === start === | ||
+ | |||
+ | Triggers after the map is shown but before the scenario begins -- before players can 'do' anything. | ||
+ | |||
+ | '''Note:''' ''This value makes the [[#first_time_only|first_time_only]] key irrelevant since, by definition, it can only fire once.'' | ||
+ | |||
+ | === new turn === | ||
+ | |||
+ | Triggers at the start of every turn (not side turn). See also [[#first_time_only|first_time_only=no]]. Before any events of this type trigger, the value of the WML variable '''turn_number''' is set to the number of the turn that is beginning. | ||
+ | |||
+ | === turn end === | ||
+ | |||
+ | Triggers at the end of every turn (not side turn). See also [[#first_time_only|first_time_only=no]]. The WML variable '''side_number''' will contain the side that ended their turn. | ||
+ | |||
+ | === turn ''X'' end === | ||
+ | |||
+ | Triggers at the end of turn ''X''. | ||
+ | |||
+ | === side turn === | ||
+ | |||
+ | Triggers when a side is about to start its turn. Before events of this type trigger, the value of the WML variable '''side_number''' is set to the number of the side of the player about to take their turn. This is before any healing takes place for that side, before calculating income, and before restoring unit movement and status. | ||
+ | |||
+ | === ai turn === | ||
+ | |||
+ | Triggered just before the AI is invoked for a side. This is called after ''side turn'', and thus the WML variable '''side_number''' still holds the number of this side. Note that this event might be called several times per turn in case that fallbacks to human or droiding is involved. I.e. it happens at the middle of turn of human side 1 if the human player droids his side. It happens after the selection of ai to play the turn but before AI is told that new turn has come. | ||
+ | |||
+ | '''Note:''' ''This event can break replays if it is used improperly. The ai turn event does not fire during replays. The intention is only to guide the AI to make choices (movements, attacks) which are then saved to the replay.'' | ||
+ | |||
+ | === turn refresh === | ||
+ | |||
+ | Like '''side turn''', triggers just before a side is taking control but '''after''' healing, calculating income, and restoring unit movement and status. WML variable '''side_number''' holds the number of this side. | ||
+ | |||
+ | Note that the turn refresh event does occur on turn 1, even though healing, income and unit refreshing do not. | ||
+ | |||
+ | === turn ''X'' === | ||
+ | |||
+ | Triggers at the start of turn ''X''. It's the first side initialization event. | ||
+ | |||
+ | Side initialization events go in the order of: | ||
+ | |||
+ | # '''turn ''X''''' | ||
+ | # '''new turn''' | ||
+ | # '''side turn''' | ||
+ | # '''side ''X'' turn''' | ||
+ | # '''side turn ''X''''' | ||
+ | # '''side ''X'' turn ''Y''''' | ||
+ | # '''turn refresh''' | ||
+ | # '''side ''X'' turn refresh''' | ||
+ | # '''turn ''X'' refresh''' | ||
+ | # '''side ''X'' turn ''Y'' refresh''' | ||
+ | |||
+ | === side ''X'' turn ''Y'' === | ||
+ | |||
+ | This event triggers at the start of turn ''Y'' of side X | ||
+ | |||
+ | === side ''X'' turn === | ||
+ | |||
+ | This event triggers at the start of any turn of side X | ||
+ | |||
+ | '''Note:''' ''Of course, [[#first_time_only|first_time_only=no]] is needed for this event to be triggered more than once.'' | ||
+ | |||
+ | === side turn ''X'' === | ||
+ | |||
+ | This event triggers at the start of any side on turn X | ||
+ | |||
+ | '''Note:''' ''Of course, [[#first_time_only|first_time_only=no]] is needed for this event to be triggered more than once.'' | ||
+ | |||
+ | === side X turn Y refresh === | ||
+ | |||
+ | This event triggers at the turn refresh for side X on turn Y | ||
+ | |||
+ | === side ''X'' turn refresh === | ||
+ | |||
+ | This event triggers at the turn refresh for side X | ||
+ | |||
+ | '''Note:''' ''Of course, [[#first_time_only|first_time_only=no]] is needed for this event to be triggered more than once.'' | ||
+ | |||
+ | === turn ''X'' refresh === | ||
+ | |||
+ | This event triggers for any side at the refresh of turn X. | ||
+ | |||
+ | '''Note:''' ''Of course, [[#first_time_only|first_time_only=no]] is needed for this event to be triggered more than once.'' | ||
+ | |||
+ | === side turn end === | ||
+ | |||
+ | Triggers after a side ends its turn. Like side turn, there are also some variations for specific combinations of side number and turn number. Here is the order in which the turn end events trigger: | ||
+ | |||
+ | # '''side turn end''' | ||
+ | # '''side ''X'' turn end''' | ||
+ | # '''side turn ''X'' end''' | ||
+ | # '''side ''X'' turn ''Y'' end''' | ||
+ | # '''turn end''' | ||
+ | # '''turn ''X'' end''' | ||
+ | |||
+ | === time over === | ||
+ | |||
+ | Triggers on turn ''turns''. (''turns'' is specified in [scenario]) | ||
+ | |||
+ | === enemies defeated === | ||
+ | |||
+ | Triggers when all sides that are not defeated are allied and if there is at least one human (or human networked) side among them. Especially this event triggers in a situaltion that would normaly cause a victory due to enemies defeated. (regardless of whether this was disabled with victory_when_enemies_defeated=no). | ||
+ | |||
+ | === local_victory === | ||
+ | |||
+ | In Wesnoth 1.12 and earlier, the event described here is '''victory''', {{DevFeature1.13|10}} in 1.14 the event described here is '''local_victory'''. | ||
+ | |||
+ | This event will be fired at the end of a scenario, if the player's side won. If it fires as a result of an '''[endlevel]''' tag, the event is processed before the line after the '''[endlevel]]''' tag. The event is not synchronized, as in networked mp it is possible to have different results for different players. | ||
+ | |||
+ | === local_defeat === | ||
+ | |||
+ | In Wesnoth 1.12 are earlier, the event described here is '''defeat''', {{DevFeature1.13|10}} in 1.14 the event described here is '''local_defeat'''. | ||
+ | |||
+ | Functions identically to '''local_victory''', except that the player's side lost. | ||
+ | |||
+ | === victory === | ||
+ | |||
+ | This section describes a new event Wesnoth 1.14. In 1.12 and earlier, the '''victory''' event is equivalent to 1.14's '''local_victory'''. | ||
+ | |||
+ | This event will be fired at the end of a scenario, if the game will proceed to the next scenario. In multiplayer, this means that it will fire on all players' clients, even for players who received a '''local_defeat''', as long as the game continues to the next scenario. This event is synchronized. | ||
+ | |||
+ | It helps debugging if the victory event allows you to safely advance to any of the possible next maps after using the ":next_level" command. Scenarios where key units are picked up before the victory, or where some action chosen earlier determines which map to advance to, make it hard to quickly test scenarios in a campaign. | ||
+ | |||
+ | === defeat === | ||
+ | |||
+ | This section describes a new event Wesnoth 1.14. In 1.12 and earlier, the '''defeat''' event is equivalent to 1.14's '''local_defeat'''. | ||
+ | |||
+ | This event will be fired at the end of a scenario, if the game resulted in a game-over other than victoriously reaching the end of a campaign (including single-scenario campaigns). Synchronization (including bug #4667) is the same as '''victory'''. | ||
+ | |||
+ | === scenario_end === | ||
+ | |||
+ | {{DevFeature1.13|10}} This event fires immediately after '''victory''' or '''defeat'''; it is synchronized, but is also affected by bug #4667. | ||
+ | |||
+ | Note: in 1.13.0 - 1.13.9 this event was added as a synchronized alternative to the events that are, since 1.13.10, called local_victory or local_defeat. | ||
+ | |||
+ | == Predefined Events With Filters == | ||
+ | |||
+ | Filters (except [filter_condition] which is for all sorts of events) can be applied to the following event triggers (see [[FilterWML]]; see also below). The actions specified in the event tag will be executed only if the filter returns true. | ||
+ | These event triggers are all actions by units ('''moveto''', '''attack''') or things that happen to units ('''recruit''', '''advance'''). When one of these events is triggered, the position of the active unit (referred to as the '''primary unit''') is stored in the variables '''x1''' and '''y1''' and the position of any unit that primary unit does something to is stored in the variables '''x2''' and '''y2''' (this unit is referred to as the '''secondary unit''' below). '' These units are also automatically stored in the variables '''unit''' and '''second_unit''' as if they had been stored using the '''[store_unit]''' tag. see [[SingleUnitWML]]. weapon and second_weapon variables are available inside attack, attacker_hits, defender_hits, unit_hits, die and last_breath events. See [[VariablesWML#Automatically_Stored_Variables|automatically stored variables]] for more information. | ||
+ | |||
+ | === moveto === | ||
+ | |||
+ | Triggers after the primary unit moves. Typically this is used when the primary unit gets to a particular location and a filter for the location of the primary unit is included; remember that this is the location that the primary unit lands on, not the location it started on or any location it travels on. If the unit moves to a village, the capture event will be fired before this event. <br />''An '''[allow_undo]''' tag anywhere within a moveto event will cancel any lack of undo functionality the event would have caused. Note that undo functionality will only move the unit back to its former location; it will not undo other changes to the game caused by the event. Thus it is up to the scenario designer to use this tag correctly.'' $x2 and $y2 refer to the hex the unit came from. | ||
+ | |||
+ | === sighted === | ||
+ | |||
+ | A '''sighted''' event is triggered by a unit becoming visible to a side (other than the unit's own side). This is mostly useful when the side seeing the unit uses [[fog of war]] or [[shroud]], but they still fire even when fog/shroud is not in use, and they do take into account the {{tag2|AbilitiesWML#The_.5Babilities.5D_tag|hides}} ability (for a moving unit and for ambushers). The ''primary unit'' is the unit that became visible, and the ''secondary unit'' belongs to the side that now sees the primary unit. In some cases, sighted events can be delayed from when they "should" occur. If that happens, the secondary unit will be filtered as if it was at the location where the event "should" have occurred, and ''x2,y2'' will store that location (not the current position of the secondary unit). To understand when sighted events fire, it is helpful to distinguish the times the acting unit sights other units from the times when the acting unit is sighted. | ||
+ | |||
+ | An acting unit can sight other units when it is recruited, recalled, leveled, or moved, and when fog or shroud is cleared from occupied hexes as a result. In these cases, the acting unit is always the ''secondary unit''. For the first three actions, there are two events associated with the action; clearing occurs between these events, but any sighted events are fired after the second event. (For example, when a unit is recruited, the ''prerecruit'' event fires, then fog is cleared, then the ''recruit'' event fires, then ''sighted'' events fire.) For movement, the sighted events fire between ''enter_hex'' and ''exit_hex'' events, but sometimes sighted events are postponed until the moving unit reaches a good place to stop (e.g. not in an occupied hex). As a major exception to the above, players have the option to delay shroud (and fog) updates. If the player delays shroud updates, sighted events are also delayed until the shroud is updated. | ||
+ | |||
+ | An acting unit can be sighted by other sides when it is recruited, recalled, leveled (in rare cases), or moved. In these cases, the acting unit is always the ''primary unit''. These events fire after sightings by the acting unit (unless the player delayed shroud updates). For the first two, the sighted event fires for all sides that can see the unit, other than the unit's own side (even if those sides use neither fog nor shroud). For leveling units, sides that could see the unit before it leveled are excluded. (This is why these events are rare – the leveling unit must have lost a [hides] ability as a result of leveling in order to be seen after, but not before, leveling.) For movement, a sighted event is fired for each side that could see the unit after movement, but not before. In particular, only the starting and ending hexes are considered; a unit that moves through seen hexes but ends movement in a fogged hex does not trigger a sighted event for itself. In all cases where the acting unit is sighted, a (single) ''secondary unit'' is chosen from the sighting team. This choice should be considered arbitrary, but units within their sight range of the acting unit are chosen in preference to units further away. You may want to use [filter_second] in order to restrict a sighted event in a single player scenario to only being triggered by the player and not by other non-allied sides. | ||
+ | |||
+ | Sighted events are not triggered by a ''hides'' ability becoming inactive, unless it becomes inactive due to that unit's movement or to that unit ambushing another. (To detect a ''nightstalk'' ability becoming inactive due to time of day, use a ''new_turn'' event. Custom ''hides'' abilities might need similar handling.) | ||
+ | |||
+ | Sighted events have some special caveats for WML authors. First and foremost, {{tag|DirectActionsWML|allow_undo}} should generally be avoided in sighted events. It can be used if current unit positions have no bearing on the event, but otherwise it could cause a replay to go out of sync if a player delays shroud updates and undoes a move. This should not be an onerous restriction, though, as clearing fog will block the ability to undo, regardless of what happens within an event. Secondly, it is currently possible for WML to kill a unit involved in a sighted event before that event fires. If that happens, filters on the killed unit will not match anything and the event may seem to have not fired. | ||
+ | |||
+ | === enter_hex === | ||
+ | |||
+ | Triggers for each hex entered during movement, with $x1,$y1 identifying the hex entered and $x2,$y2 identifying the previous hex (just exited). In Wesnoth 1.12, the movement will be interrupted, stopping the unit where it is; this behavior can be avoided by using the {{tag|DirectActionsWML|allow_undo}} tag or `NO_INTERRUPT_NO_UNDO` macro. {{DevFeature1.13|11}} movement is not interrupted unless the {{tag|DirectActionsWML|cancel_action}} tag is used. | ||
+ | |||
+ | '''Note:''' This event behaves a bit unusually if the hex is occupied (and the moving unit is simply passing through). When this happens, $x1,$y1 is still the hex where the event was triggered, but the moving unit (stored in $unit) will be located somewhere earlier in the route (the most recent unoccupied hex). That is, $x1,$y1 will not equal $unit.x,$unit.y (a condition that can be used to detect when the entered hex is occupied). The moving unit will have already spent its movement points to enter the event's hex even though it is has not actually moved from the most recent unoccupied hex. | ||
+ | |||
+ | '''Note:''' At the time of writing (7ca5a0df, just before 1.13.11), if the hex is occupied then $unit contains the occupying unit, not the moving unit. | ||
+ | |||
+ | '''Note:''' At the time of writing (1.16.2), if the hex is occupied then $unit does contain the moving unit. | ||
+ | |||
+ | === exit_hex === | ||
+ | |||
+ | Triggers for each hex exited during movement, with $x1,$y1 identifying the hex exited and $x2,$y2 identifying the next hex (to be entered). If this event is handled without using {{tag|DirectActionsWML|allow_undo}}, then movement is interrupted, stopping the unit where it is. {{DevFeature1.13|11}} movement is not interrupted unless the {{tag|DirectActionsWML|cancel_action}} tag is used. | ||
+ | |||
+ | '''Note:''' This event behaves a bit unusually if the hex is occupied (and the moving unit is simply passing through). When this happens, $x1,$y1 is still the hex where the event was triggered, but the moving unit (stored in $unit) will be located somewhere earlier in the route (the most recent unoccupied hex). That is, $x1,$y1 will not equal $unit.x,$unit.y (a condition that can be used to detect when the exited hex is occupied). The moving unit will have already spent its movement points to enter the event's hex even though it is has not actually moved from the most recent unoccupied hex. | ||
+ | |||
+ | === pre attack {{DevFeature1.17|7}}=== | ||
+ | |||
+ | Similar to '''attack''', but is triggered before calculating the number of attacks and the movement of the unit. Can be used for modifications, which affect these values. | ||
+ | |||
+ | === attack === | ||
+ | |||
+ | Triggers when the primary unit attacks the secondary unit. Variables $weapon and $second_weapon contain weapons used for this attack by primary and secondary units respectively for all attack-related events (attack_end, attacker_hits, attacker_misses, defender_hits, defender_misses, die and last_breath). | ||
+ | |||
+ | === attack end === | ||
+ | |||
+ | Similar to '''attack''', but is triggered ''after'' the fight instead of before. Note that if either unit is killed during the fight, this event triggers before any '''die''' events. | ||
+ | |||
+ | === attacker hits === | ||
+ | |||
+ | Triggers when the the primary unit (the attacker) hits the secondary unit (the defender). The value of the WML variable '''damage_inflicted''' is set to the number of hitpoints inflicted by the attacker. | ||
+ | |||
+ | === attacker misses === | ||
+ | |||
+ | Same as ''attacker hits'', but is triggered when the attacker misses. | ||
+ | |||
+ | === defender hits === | ||
+ | |||
+ | Triggers when the primary unit (the attacker) is hit in retaliation by the secondary unit (the defender). The value of the WML variable '''damage_inflicted''' is set to the number of hitpoints inflicted by the defender. | ||
+ | |||
+ | === defender misses === | ||
+ | |||
+ | Same as ''defender hits'', but is triggered when the defender misses. | ||
+ | |||
+ | === unit hits {{DevFeature1.19|2}} === | ||
+ | |||
+ | Triggers when the the primary unit (either attacker or defender) hits the secondary unit (the other). The value of the WML variable '''damage_inflicted''' is set to the number of hitpoints inflicted by the primary unit. | ||
+ | |||
+ | Compared to ''defender hits'', primary and secondary units are swapped. | ||
+ | |||
+ | === unit misses {{DevFeature1.19|2}} === | ||
+ | |||
+ | Same as ''unit hits'', but is triggered when the unit misses. | ||
+ | |||
+ | === petrified === | ||
+ | Triggers when the primary unit is hit by an attack with the 'petrifies' ability (See ''petrifies'', [[AbilitiesWML]]) by the secondary unit (the unit with the 'petrifies' ability). | ||
+ | |||
+ | === last breath === | ||
+ | |||
+ | Triggers when the primary unit is killed by the secondary unit, but before the death animation is triggered. Use this instead of name=die when you want the primary unit to make a final [message]. | ||
+ | |||
+ | === die === | ||
+ | |||
+ | Triggers when the primary unit is killed by the secondary unit. ''Note: The primary unit is not removed from the game until the end of this event. The primary unit can still be manipulated, will block other units from taking its hex, and will still be found by standard unit filters (except [have_unit]). To prevent this behavior, you can use [kill] to remove the unit immediately. However, this will stop any (still unfired) other events that also match the unit from firing afterwards, so use with caution.'' If you want to the primary unit to make a final [message], use name=last_breath, see above. | ||
+ | |||
+ | === capture === | ||
+ | |||
+ | Triggers when the primary unit captures a village. The village may have been previously neutral, or previously owned by another side; merely moving into your own villages does not constitute a capture. This event will be fired before the moveto event. Villages becoming neutral (via [capture_village]) do not fire capture events. The variable $owner_side contains the previous owner side of the village. 0 means neutral. | ||
+ | |||
+ | === recruit === | ||
+ | |||
+ | Triggers when the primary unit is recruited (by the secondary unit). (That is, when a unit is recruited it will trigger this event and this event's filter will filter that unit.). | ||
+ | |||
+ | === prerecruit === | ||
+ | |||
+ | Triggers when the primary unit is recruited (by the secondary unit) but before it is displayed. | ||
+ | |||
+ | === recall === | ||
+ | |||
+ | Triggers after the primary unit is recalled (by the secondary unit). | ||
+ | |||
+ | === prerecall === | ||
+ | |||
+ | Triggers when the primary unit is recalled (by the secondary unit) but before it is displayed. | ||
+ | |||
+ | === advance === | ||
+ | |||
+ | Triggers just before the primary unit is going to advance to another unit, or advance by AMLA. (This is after the player selects which advancement, if there is a choice). If this event removes the unit, changes the unit's type, or reduces the unit's experience below what it needs to advance, then the advancement is aborted. This also applies to advancement by AMLA. | ||
+ | |||
+ | === pre advance === | ||
+ | |||
+ | {{DevFeature1.13|0}} Triggers before the unit advancement dialog is shown. If this event removes the unit or reduces the unit's experience below what it needs to advance, then the advancement is aborted. | ||
+ | |||
+ | Care needs to be taken when tags that may trigger advancement themselves are used in this event. For example '''[transform_unit]''', '''[unstore_unit]''', '''[modify_unit]''' etc. | ||
+ | |||
+ | === post advance === | ||
+ | |||
+ | Triggers just after the primary unit has advanced to another unit, or advance by AMLA. | ||
+ | |||
+ | === select === | ||
+ | |||
+ | Triggers when the primary unit is selected. Prior to version 1.11, this also triggered when a move was interrupted, as the game keeps the moving unit selected by selecting it again at the end of movement. ''Note: in networked multiplayer, these events are only executed by the client on which the event is triggered, leading to out of sync errors if you modify the game state in the event.'' | ||
+ | |||
+ | === menu item ''X'' === | ||
+ | |||
+ | Triggers when a WML menu item with id=''X'' is selected. ''Note: if the menu item has a [command], this event may be executed before or after the command; there is no guarantee.'' | ||
+ | |||
+ | === unit placed {{DevFeature1.13|3}}=== | ||
+ | |||
+ | Triggers when the primary unit is placed on the map, regardless of method. This includes but might not be limited to: | ||
+ | * Leaders and units placed in side definitions (fired once for every unit right before prestart events) | ||
+ | * Recruited and recalled units | ||
+ | * Units placed on the map with the [unit] tag ('''not''' units created directly onto a recall list or variable) | ||
+ | * Units placed by the wesnoth.put_unit() Lua function | ||
+ | * Units placed by :to_map in Lua (which is a shortcut for the above) | ||
+ | * Units created via debug mode | ||
+ | * Units created by plague | ||
+ | * Every use of [unstore_unit], when ''fire_event'' is set to ''yes'' (default is ''no'') | ||
+ | * Units moved on map with [move_unit] before {{DevFeature1.15|8}} | ||
+ | * Units matching the filter of [petrify], [unpetrify] or [harm_unit] before {{DevFeature1.15|8}} | ||
+ | * Units who receive a bonus from the feeding ability every time except the first, before {{DevFeature1.15|8}} | ||
+ | This event is solely intended for special cases where no other event types suffice, for example if you must immediately apply a modification to every unit that ever appears. The event does '''not''' keep track of which units it has previously fired for, but can fire an unlimited number of times for the same unit as long the unit is "placed" several times and the event filter doesn't prevent it. | ||
== Miscellaneous Notes and Examples == | == Miscellaneous Notes and Examples == |
Revision as of 09:05, 7 July 2024
Contents
- 1 The [event] Tag
- 2 Multiplayer safety
- 3 A Trap for the Unwary
- 4 Predefined Events Without Filters
- 4.1 preload
- 4.2 prestart
- 4.3 start
- 4.4 new turn
- 4.5 turn end
- 4.6 turn X end
- 4.7 side turn
- 4.8 ai turn
- 4.9 turn refresh
- 4.10 turn X
- 4.11 side X turn Y
- 4.12 side X turn
- 4.13 side turn X
- 4.14 side X turn Y refresh
- 4.15 side X turn refresh
- 4.16 turn X refresh
- 4.17 side turn end
- 4.18 time over
- 4.19 enemies defeated
- 4.20 local_victory
- 4.21 local_defeat
- 4.22 victory
- 4.23 defeat
- 4.24 scenario_end
- 5 Predefined Events With Filters
- 5.1 moveto
- 5.2 sighted
- 5.3 enter_hex
- 5.4 exit_hex
- 5.5 pre attack (Version 1.17.7 and later only)
- 5.6 attack
- 5.7 attack end
- 5.8 attacker hits
- 5.9 attacker misses
- 5.10 defender hits
- 5.11 defender misses
- 5.12 unit hits (Version 1.19.2 and later only)
- 5.13 unit misses (Version 1.19.2 and later only)
- 5.14 petrified
- 5.15 last breath
- 5.16 die
- 5.17 capture
- 5.18 recruit
- 5.19 prerecruit
- 5.20 recall
- 5.21 prerecall
- 5.22 advance
- 5.23 pre advance
- 5.24 post advance
- 5.25 select
- 5.26 menu item X
- 5.27 unit placed (Version 1.13.3 and later only)
- 6 Miscellaneous Notes and Examples
- 7 See Also
The [event] Tag
This tag is a subtag of the [scenario], [unit_type] and [era] tags which is used to describe a set of actions which trigger at a certain point in a scenario. When used in a [scenario] tag (also includes [multiplayer] and [test]), the event only occurs in that scenario. When used in a [unit_type] tag, the event will occur in all scenarios in which a unit of that type appears in (only after such a unit appears during the scenario, however). When used in an [era], the event will occur in any scenario which is played using that era.
This tag has keys and child tags that control when and if the event actions will be triggered. Most important of these is the name key. Without it, no error will be raised but the event will never fire. Therefore, from a practical standpoint, it can be considered mandatory. All of the others can be used or not and the event actions will fire either way.
Lexicon side note: The word "event" in the [event] tag itself may be considered an abbreviation of the term "event handler" because it is technically not a game "event" but an event handler for the game events fired with the given 'name'. However, this distinction is usually unimportant in most discussions and the event handlers are therefore simply referred to as "events" in this documentation.
The 'name' Key (Mandatory)
Usage:
name=<value>
This key defines which game event or trigger your [event] tag will be handling. This 'name' key should not be confused with a descriptive comment; it is rather a precise value which must match the predefined game event's name to be valid.
The name key can accept a list of comma separated values describing when the event will be triggered.* These values may be either predefined event types or custom event names not matching any predefined type.
For example:
name=attacker misses,defender misses
* Note that unless you use first_time_only=no, the event will fire only once, not once for each listed type.
All predefined event types are listed below, along with a description of when this value will cause the event to be triggered, in the Predefined Events Without Filters and Predefined Events With Filters sections. Any value not listed there is a custom event name which can be triggered only by a [fire_event] tag somewhere else.
Spaces in event names can be interchanged with underscores (for example, name=new turn and name=new_turn are equivalent).
Variables in the name
If the name contains variables, they will be substituted each time the event is triggered. For example, name=turn $disaster_turn will only trigger if the turn number is currently equal to whatever number is stored in the variable $disaster_turn; updating the variable will adjust the turn that the event triggers on. However, if the variable contents contains a comma, it won't be parsed after substitution. Since an event name can't contain a comma, this means the event will never trigger.
(Version 1.17.6 and later only)
Commas resulting from variable substitution are now parsed. If you write name=$important_event and the variable $important_event contains the text "capture,die", the event will trigger on either a death or a village capture.
Custom events
An event with a custom name may be invoked using the [fire_event] tag. Normally you'll use such custom events as named subroutines to be called by events with predefined types. One common case of this, for example, is that more than one sighted events might fire the same custom event that changes the scenario objectives. Also, custom events come very handy in Wml_optimisation.
Example:
# The following is the definition of a custom event "unit recruited"
[event]
name=unit_recruited
first_time_only=no
[message]
speaker=unit
message=_ "Reporting for duty!"
[/message]
[/event]
# This is a standard recruit event that triggers whenever a unit is recruited by side 1
[event]
name=recruit
first_time_only=no
[filter]
[/filter]
[filter_second]
side=1
[/filter_second]
# And now a fire_event tag is used to trigger the previously defined event. To use
# "speaker=unit" in the fired event, it's also necessary to specify the [primary_unit].
[fire_event]
name=unit_recruited
[primary_unit]
id=$unit.id
[/primary_unit]
[/fire_event]
# As a result, every time side 1 recruits a unit, this unit says "Reporting for duty!"
[/event]
You can have more code after the [fire_event], which will run after the fired event has happened. Example:
# This is a standard recall event that triggers whenever a unit is recalled by side 1
[event]
name=recall
first_time_only=no
[filter]
[/filter]
[filter_second]
side=1
[/filter_second]
# Fire the custom event, exactly as the in recruit event
[fire_event]
name=unit_recruited
[primary_unit]
id=$unit.id
[/primary_unit]
[/fire_event]
# After that event has happened, the remaining code in this event is run
[message]
speaker=second_unit
message=_ "Glad to have you back"
[/message]
# As a result, every time side 1 recalls a unit, the recalled unit says
# "Reporting for duty!", and the leader replies "Glad to have you back"
[/event]
Optional Keys and Tags
These keys and tags are more complex ways to filter when an event should trigger:
first_time_only
- Whether the event should be removed from the scenario after it is triggered. This key takes a boolean; for example:
- first_time_only=yes
- Default behavior if key is omitted. The event will trigger the first time it can and never again.
- first_time_only=no
- The event will trigger every time the criteria are met instead of only the first time.
id
- If an id is specified, then the event will not be added if another event with the same id already exists. An id will also allow the event to be removed, see below. Supplying a non-empty id= is mandatory in case of a [unit_type][event].
remove
- Removes an event instead of adding a new one. This key takes a boolean; if yes, does the same as a [remove_event] with the same id= value, and the other attributes of this event tag are ignored.
(Version 1.13.0 and later only) May be a comma separated list.
(Version 1.15.7 and later only) Prints a deprecation warning recommending to use [remove_event] instead.
priority
- (Version 1.17.20 and later only) If several '[event]' tags have the same name, then any with a high priority value will be triggered before events with a lower priority value. Negative numbers are also supported, to run after events without a priority (as the attribute defaults to zero). For events with equal priority, the order is determined by the order in which the events were added.
[filter]
- The event will only trigger if the primary unit matches this filter.
- StandardUnitFilter: selection criteria
[filter_second]
- Like [filter], but for the secondary unit.
- StandardUnitFilter: selection criteria
[filter_attack]
- Can be used to set additional filtering criteria based on the weapon used by the primary unit. This is usable in the events attack, attacker hits, attacker misses, defender hits, defender misses, attack end, last breath, and die. For more information and filter keys, see Filtering Weapons. The most commonly used keys are the following.
- name: the name of the weapon used.
- range: the range of the weapon used.
- special_id: filter on the attack's weapon special id.
- special_type: filter on the attack's weapon special type.
- (Version 1.17.15 and later only) special_id_active: filter on the attack's weapon special id active(encoded in [specials] or [abilities] tags).
- (Version 1.17.15 and later only) special_type_active: filter on the attack's weapon special type active(encoded in [specials] or [abilities] tags).
[filter_second_attack]
- Like [filter_attack], but for the weapon used by the secondary unit.
[filter_condition]
- This tag makes sense inside any sort of event - even those that don't have units, or custom events,... The event will only trigger if this condition evaluates to true.
- note: This tag is meant to be used when the firing of an event shall be based on variables/conditions which cannot be retrieved from the filtered units.
[filter_side]
- The current side (usually the side $side_number) must match the passed StandardSideFilter for the event to fire.
- SSF tags and keys as arguments as described in StandardSideFilter.
- note: This tag makes most sense in side turn and turn refresh events. However, all wml events have a current side so one could also prevent e.g. a moveto event from firing if you put a [filter_side] tag there and the moving unit's side doesn't match.
[insert_tag]
- An [insert_tag] that expands to any of the above filter tags will result in the filter being loaded from the variable each time the game checks if the event should fire. This can result in the event's filter varying from turn to turn.
filter_formula
- (Version 1.17.6 and later only)
- Similar to [filter_condition], but the condition is expressed in Wesnoth Formula Language. The formula has access to the following keys:
- Event information:
- event - the event name
- event_id - the event's unique ID
- event_data - additional information specific to the event, such as owner_side or damage_inflicted, or anything passed in [fire_event][data].
- loc, unit - primary event location and unit
- second_loc, second_unit - secondary event location and unit
- weapon, second_weapon - primary and secondary weapon
- Gamestate information:
- turn_number
- time_of_day - the time of day ID
- side_number - currently active side
- sides - a list of all sides
- units - a list of all units on the map
- map - the entire game map as a two-dimensional array
- Event information:
delayed_variable_substitution
- This key is only relevant inside of a nested event and controls when variable substitution will occur in those special case actions.
Actions triggered by [event]
After the trigger conditions have been met, all action tags within the [event] tag are executed in the order they are written in.
There are 3 main types of actions:
- direct actions (DirectActionsWML) which have a direct effect on gameplay
- display actions (InterfaceActionsWML) which show something to the user
- internal actions (InternalActionsWML) which are used by WML internally
More details in ActionWML. Actions can also be dynamically inserted via [insert_tag].
Several actions use standard filters to find out which units to execute the command on. These are denoted by the phrases "standard unit filter" and "standard location filter".
Nested Events
There is one special type of action: event creation. By placing an [event] tag inside another [event] tag, the nested event is spawned (created) when the parent (outer) event is encountered (when executing the contents of the parent event).
Delayed Variable Substitution
Variable substitution for a nested event can happen either when it is spawned by the parent event or when it is triggered itself. This is controlled with the key delayed_variable_substitution which is used in the nested event.
If this key is set to yes, the variables in the nested event will contain values from the turn in which the nested event was triggered. This is the default behavior if the key is omitted. If set to no, the variables in the nested event are set at the time the parent event is triggered.
This behavior can be fine tuned with a special syntax when referencing variables. Instead of the normal $variable syntax, use $|variable to cause a variable to contain values relevant to the turn in which the nested event was triggered even when delayed_variable_substitution is set to no. In this way you can have a mix of variables relevant to the parent and nested event trigger times.
Multiplayer safety
In multiplayer it is only safe to use WML that might require synchronization with other players because of input or random numbers (like [message] with input or options or [unstore_unit] where a unit might advance) in the following events. This is because in these cases WML needs data from other players to work right and/or do the same thing for all players. This data is only available after a network synchronization.
List of synchronized events:
- moveto
- enter hex
- exit hex
- sighted
- last breath
- menu item X
- die
- capture
- recruit
- prerecruit
- recall
- prerecall
- advance
- pre advance
- post advance
- attack
- attack end
- attacker hits
- attacker misses
- defender hits
- defender misses
- unit hits
- unit misses
- start
- prestart (prestart are synced but [message][option] & [unstore_unit] advancement choices will do a random decision because UI things don't work during prestart events.)
- new turn
- side turn
- turn X
- side X turn
- side X turn Y
- turn refresh
- side turn end
- side X turn end
- side turn X end
- side X turn Y end
- turn end
- turn X end
- (Version 1.13.0 and later only) enemies defeated
- (Version 1.13.0 and later only) time over
- (Version 1.13.10 and later only) victory
- (Version 1.13.10 and later only) defeat
- (Version 1.13.0 and later only) scenario_end
The following are not synced:
- select
- preload
- victory (Version 1.13.10 and later only) local_victory
- defeat (Version 1.13.10 and later only) local_defeat
- ai turn
If an event is not listed here, ask someone to be sure.
There is also the possibility of events that are normally synchronized when fired by the engine but can be non-synchronized when fired by WML tags from non-synchronized event. So when you are using them you must be extra careful. For example [unstore_unit] may trigger a unit advancement that will fire advance and post advance events.
A Trap for the Unwary
You need to beware of using macros to generate events. If you include a macro expanding to an event definition twice, the event will be executed twice (not once) each time the trigger condition fires. Consider this code:
#define DOUBLE
[event]
name=multiply_by_2
{VARIABLE_OP 2_becomes_4 multiply 2}
[/event]
#enddef
{DOUBLE}
{DOUBLE}
{VARIABLE 2_becomes_4 2}
[fire_event]
name=multiply_by_2
[/fire_event]
{DEBUG_MSG "$2_becomes_4 should be 4"}
After it executes, the debug message will reveal that the variable has been set to 8, not 4.
Event IDs
This problem can be avoided by setting an id on the event, i.e.:
#define DOUBLE
[event]
name=multiply_by_2
id=doubler_event
{VARIABLE_OP 2_becomes_4 multiply 2}
[/event]
#enddef
Events with the same ID will only be accepted once by the engine no matter how many times they are included, and will only be saved once to the scenario's savefile. Events with an ID can also be removed by using the remove key, i.e.:
[event]
id=doubler_event
remove=yes
[/event]
After that WML is encountered (at toplevel or after created from another event), the event with this ID is removed from the scenario wml, thus firing it has no effect. After an event is removed, it can still be re-added later.
Predefined Events Without Filters
These events do not take filter parameters (except [filter_condition] which works for all events).
preload
Triggers before a scenario 'prestarts' and when loading a savegame -- before anything is shown on the screen at all. Can be used to set up the Lua environment: loading libraries, defining helper functions, etc.
Note: If a game is started, saved, and then reloaded, the preload event will fire two times while playing. However, it will only fire once when viewing the replay. If the preload event alters the gamestate the second time it fired while playing (when loading the saved game) then it can result in Out Of Sync errors.
Note: Unlike prestart and start, the preload event must be able to fire more than once! This is because it is triggered each time a savegame is loaded in addition to the initial time when it loads before the scenario 'prestart'. This means that it is effectively mandatory to have the first_time_only=no key value in a preload event.
prestart
Triggers before a scenario 'starts' -- before anything is shown on the screen at all. Can be used to set up things like village ownership. For things displayed on-screen such as character dialog, use start instead.
Note: This value makes the first_time_only key irrelevant since, by definition, it can only fire once.
start
Triggers after the map is shown but before the scenario begins -- before players can 'do' anything.
Note: This value makes the first_time_only key irrelevant since, by definition, it can only fire once.
new turn
Triggers at the start of every turn (not side turn). See also first_time_only=no. Before any events of this type trigger, the value of the WML variable turn_number is set to the number of the turn that is beginning.
turn end
Triggers at the end of every turn (not side turn). See also first_time_only=no. The WML variable side_number will contain the side that ended their turn.
turn X end
Triggers at the end of turn X.
side turn
Triggers when a side is about to start its turn. Before events of this type trigger, the value of the WML variable side_number is set to the number of the side of the player about to take their turn. This is before any healing takes place for that side, before calculating income, and before restoring unit movement and status.
ai turn
Triggered just before the AI is invoked for a side. This is called after side turn, and thus the WML variable side_number still holds the number of this side. Note that this event might be called several times per turn in case that fallbacks to human or droiding is involved. I.e. it happens at the middle of turn of human side 1 if the human player droids his side. It happens after the selection of ai to play the turn but before AI is told that new turn has come.
Note: This event can break replays if it is used improperly. The ai turn event does not fire during replays. The intention is only to guide the AI to make choices (movements, attacks) which are then saved to the replay.
turn refresh
Like side turn, triggers just before a side is taking control but after healing, calculating income, and restoring unit movement and status. WML variable side_number holds the number of this side.
Note that the turn refresh event does occur on turn 1, even though healing, income and unit refreshing do not.
turn X
Triggers at the start of turn X. It's the first side initialization event.
Side initialization events go in the order of:
- turn X
- new turn
- side turn
- side X turn
- side turn X
- side X turn Y
- turn refresh
- side X turn refresh
- turn X refresh
- side X turn Y refresh
side X turn Y
This event triggers at the start of turn Y of side X
side X turn
This event triggers at the start of any turn of side X
Note: Of course, first_time_only=no is needed for this event to be triggered more than once.
side turn X
This event triggers at the start of any side on turn X
Note: Of course, first_time_only=no is needed for this event to be triggered more than once.
side X turn Y refresh
This event triggers at the turn refresh for side X on turn Y
side X turn refresh
This event triggers at the turn refresh for side X
Note: Of course, first_time_only=no is needed for this event to be triggered more than once.
turn X refresh
This event triggers for any side at the refresh of turn X.
Note: Of course, first_time_only=no is needed for this event to be triggered more than once.
side turn end
Triggers after a side ends its turn. Like side turn, there are also some variations for specific combinations of side number and turn number. Here is the order in which the turn end events trigger:
- side turn end
- side X turn end
- side turn X end
- side X turn Y end
- turn end
- turn X end
time over
Triggers on turn turns. (turns is specified in [scenario])
enemies defeated
Triggers when all sides that are not defeated are allied and if there is at least one human (or human networked) side among them. Especially this event triggers in a situaltion that would normaly cause a victory due to enemies defeated. (regardless of whether this was disabled with victory_when_enemies_defeated=no).
local_victory
In Wesnoth 1.12 and earlier, the event described here is victory, (Version 1.13.10 and later only) in 1.14 the event described here is local_victory.
This event will be fired at the end of a scenario, if the player's side won. If it fires as a result of an [endlevel] tag, the event is processed before the line after the [endlevel]] tag. The event is not synchronized, as in networked mp it is possible to have different results for different players.
local_defeat
In Wesnoth 1.12 are earlier, the event described here is defeat, (Version 1.13.10 and later only) in 1.14 the event described here is local_defeat.
Functions identically to local_victory, except that the player's side lost.
victory
This section describes a new event Wesnoth 1.14. In 1.12 and earlier, the victory event is equivalent to 1.14's local_victory.
This event will be fired at the end of a scenario, if the game will proceed to the next scenario. In multiplayer, this means that it will fire on all players' clients, even for players who received a local_defeat, as long as the game continues to the next scenario. This event is synchronized.
It helps debugging if the victory event allows you to safely advance to any of the possible next maps after using the ":next_level" command. Scenarios where key units are picked up before the victory, or where some action chosen earlier determines which map to advance to, make it hard to quickly test scenarios in a campaign.
defeat
This section describes a new event Wesnoth 1.14. In 1.12 and earlier, the defeat event is equivalent to 1.14's local_defeat.
This event will be fired at the end of a scenario, if the game resulted in a game-over other than victoriously reaching the end of a campaign (including single-scenario campaigns). Synchronization (including bug #4667) is the same as victory.
scenario_end
(Version 1.13.10 and later only) This event fires immediately after victory or defeat; it is synchronized, but is also affected by bug #4667.
Note: in 1.13.0 - 1.13.9 this event was added as a synchronized alternative to the events that are, since 1.13.10, called local_victory or local_defeat.
Predefined Events With Filters
Filters (except [filter_condition] which is for all sorts of events) can be applied to the following event triggers (see FilterWML; see also below). The actions specified in the event tag will be executed only if the filter returns true. These event triggers are all actions by units (moveto, attack) or things that happen to units (recruit, advance). When one of these events is triggered, the position of the active unit (referred to as the primary unit) is stored in the variables x1 and y1 and the position of any unit that primary unit does something to is stored in the variables x2 and y2 (this unit is referred to as the secondary unit below). These units are also automatically stored in the variables unit and second_unit as if they had been stored using the [store_unit] tag. see SingleUnitWML. weapon and second_weapon variables are available inside attack, attacker_hits, defender_hits, unit_hits, die and last_breath events. See automatically stored variables for more information.
moveto
Triggers after the primary unit moves. Typically this is used when the primary unit gets to a particular location and a filter for the location of the primary unit is included; remember that this is the location that the primary unit lands on, not the location it started on or any location it travels on. If the unit moves to a village, the capture event will be fired before this event.
An [allow_undo] tag anywhere within a moveto event will cancel any lack of undo functionality the event would have caused. Note that undo functionality will only move the unit back to its former location; it will not undo other changes to the game caused by the event. Thus it is up to the scenario designer to use this tag correctly. $x2 and $y2 refer to the hex the unit came from.
sighted
A sighted event is triggered by a unit becoming visible to a side (other than the unit's own side). This is mostly useful when the side seeing the unit uses fog of war or shroud, but they still fire even when fog/shroud is not in use, and they do take into account the [hides] ability (for a moving unit and for ambushers). The primary unit is the unit that became visible, and the secondary unit belongs to the side that now sees the primary unit. In some cases, sighted events can be delayed from when they "should" occur. If that happens, the secondary unit will be filtered as if it was at the location where the event "should" have occurred, and x2,y2 will store that location (not the current position of the secondary unit). To understand when sighted events fire, it is helpful to distinguish the times the acting unit sights other units from the times when the acting unit is sighted.
An acting unit can sight other units when it is recruited, recalled, leveled, or moved, and when fog or shroud is cleared from occupied hexes as a result. In these cases, the acting unit is always the secondary unit. For the first three actions, there are two events associated with the action; clearing occurs between these events, but any sighted events are fired after the second event. (For example, when a unit is recruited, the prerecruit event fires, then fog is cleared, then the recruit event fires, then sighted events fire.) For movement, the sighted events fire between enter_hex and exit_hex events, but sometimes sighted events are postponed until the moving unit reaches a good place to stop (e.g. not in an occupied hex). As a major exception to the above, players have the option to delay shroud (and fog) updates. If the player delays shroud updates, sighted events are also delayed until the shroud is updated.
An acting unit can be sighted by other sides when it is recruited, recalled, leveled (in rare cases), or moved. In these cases, the acting unit is always the primary unit. These events fire after sightings by the acting unit (unless the player delayed shroud updates). For the first two, the sighted event fires for all sides that can see the unit, other than the unit's own side (even if those sides use neither fog nor shroud). For leveling units, sides that could see the unit before it leveled are excluded. (This is why these events are rare – the leveling unit must have lost a [hides] ability as a result of leveling in order to be seen after, but not before, leveling.) For movement, a sighted event is fired for each side that could see the unit after movement, but not before. In particular, only the starting and ending hexes are considered; a unit that moves through seen hexes but ends movement in a fogged hex does not trigger a sighted event for itself. In all cases where the acting unit is sighted, a (single) secondary unit is chosen from the sighting team. This choice should be considered arbitrary, but units within their sight range of the acting unit are chosen in preference to units further away. You may want to use [filter_second] in order to restrict a sighted event in a single player scenario to only being triggered by the player and not by other non-allied sides.
Sighted events are not triggered by a hides ability becoming inactive, unless it becomes inactive due to that unit's movement or to that unit ambushing another. (To detect a nightstalk ability becoming inactive due to time of day, use a new_turn event. Custom hides abilities might need similar handling.)
Sighted events have some special caveats for WML authors. First and foremost, [allow_undo] should generally be avoided in sighted events. It can be used if current unit positions have no bearing on the event, but otherwise it could cause a replay to go out of sync if a player delays shroud updates and undoes a move. This should not be an onerous restriction, though, as clearing fog will block the ability to undo, regardless of what happens within an event. Secondly, it is currently possible for WML to kill a unit involved in a sighted event before that event fires. If that happens, filters on the killed unit will not match anything and the event may seem to have not fired.
enter_hex
Triggers for each hex entered during movement, with $x1,$y1 identifying the hex entered and $x2,$y2 identifying the previous hex (just exited). In Wesnoth 1.12, the movement will be interrupted, stopping the unit where it is; this behavior can be avoided by using the [allow_undo] tag or `NO_INTERRUPT_NO_UNDO` macro. (Version 1.13.11 and later only) movement is not interrupted unless the [cancel_action] tag is used.
Note: This event behaves a bit unusually if the hex is occupied (and the moving unit is simply passing through). When this happens, $x1,$y1 is still the hex where the event was triggered, but the moving unit (stored in $unit) will be located somewhere earlier in the route (the most recent unoccupied hex). That is, $x1,$y1 will not equal $unit.x,$unit.y (a condition that can be used to detect when the entered hex is occupied). The moving unit will have already spent its movement points to enter the event's hex even though it is has not actually moved from the most recent unoccupied hex.
Note: At the time of writing (7ca5a0df, just before 1.13.11), if the hex is occupied then $unit contains the occupying unit, not the moving unit.
Note: At the time of writing (1.16.2), if the hex is occupied then $unit does contain the moving unit.
exit_hex
Triggers for each hex exited during movement, with $x1,$y1 identifying the hex exited and $x2,$y2 identifying the next hex (to be entered). If this event is handled without using [allow_undo], then movement is interrupted, stopping the unit where it is. (Version 1.13.11 and later only) movement is not interrupted unless the [cancel_action] tag is used.
Note: This event behaves a bit unusually if the hex is occupied (and the moving unit is simply passing through). When this happens, $x1,$y1 is still the hex where the event was triggered, but the moving unit (stored in $unit) will be located somewhere earlier in the route (the most recent unoccupied hex). That is, $x1,$y1 will not equal $unit.x,$unit.y (a condition that can be used to detect when the exited hex is occupied). The moving unit will have already spent its movement points to enter the event's hex even though it is has not actually moved from the most recent unoccupied hex.
pre attack (Version 1.17.7 and later only)
Similar to attack, but is triggered before calculating the number of attacks and the movement of the unit. Can be used for modifications, which affect these values.
attack
Triggers when the primary unit attacks the secondary unit. Variables $weapon and $second_weapon contain weapons used for this attack by primary and secondary units respectively for all attack-related events (attack_end, attacker_hits, attacker_misses, defender_hits, defender_misses, die and last_breath).
attack end
Similar to attack, but is triggered after the fight instead of before. Note that if either unit is killed during the fight, this event triggers before any die events.
attacker hits
Triggers when the the primary unit (the attacker) hits the secondary unit (the defender). The value of the WML variable damage_inflicted is set to the number of hitpoints inflicted by the attacker.
attacker misses
Same as attacker hits, but is triggered when the attacker misses.
defender hits
Triggers when the primary unit (the attacker) is hit in retaliation by the secondary unit (the defender). The value of the WML variable damage_inflicted is set to the number of hitpoints inflicted by the defender.
defender misses
Same as defender hits, but is triggered when the defender misses.
unit hits (Version 1.19.2 and later only)
Triggers when the the primary unit (either attacker or defender) hits the secondary unit (the other). The value of the WML variable damage_inflicted is set to the number of hitpoints inflicted by the primary unit.
Compared to defender hits, primary and secondary units are swapped.
unit misses (Version 1.19.2 and later only)
Same as unit hits, but is triggered when the unit misses.
petrified
Triggers when the primary unit is hit by an attack with the 'petrifies' ability (See petrifies, AbilitiesWML) by the secondary unit (the unit with the 'petrifies' ability).
last breath
Triggers when the primary unit is killed by the secondary unit, but before the death animation is triggered. Use this instead of name=die when you want the primary unit to make a final [message].
die
Triggers when the primary unit is killed by the secondary unit. Note: The primary unit is not removed from the game until the end of this event. The primary unit can still be manipulated, will block other units from taking its hex, and will still be found by standard unit filters (except [have_unit]). To prevent this behavior, you can use [kill] to remove the unit immediately. However, this will stop any (still unfired) other events that also match the unit from firing afterwards, so use with caution. If you want to the primary unit to make a final [message], use name=last_breath, see above.
capture
Triggers when the primary unit captures a village. The village may have been previously neutral, or previously owned by another side; merely moving into your own villages does not constitute a capture. This event will be fired before the moveto event. Villages becoming neutral (via [capture_village]) do not fire capture events. The variable $owner_side contains the previous owner side of the village. 0 means neutral.
recruit
Triggers when the primary unit is recruited (by the secondary unit). (That is, when a unit is recruited it will trigger this event and this event's filter will filter that unit.).
prerecruit
Triggers when the primary unit is recruited (by the secondary unit) but before it is displayed.
recall
Triggers after the primary unit is recalled (by the secondary unit).
prerecall
Triggers when the primary unit is recalled (by the secondary unit) but before it is displayed.
advance
Triggers just before the primary unit is going to advance to another unit, or advance by AMLA. (This is after the player selects which advancement, if there is a choice). If this event removes the unit, changes the unit's type, or reduces the unit's experience below what it needs to advance, then the advancement is aborted. This also applies to advancement by AMLA.
pre advance
(Version 1.13.0 and later only) Triggers before the unit advancement dialog is shown. If this event removes the unit or reduces the unit's experience below what it needs to advance, then the advancement is aborted.
Care needs to be taken when tags that may trigger advancement themselves are used in this event. For example [transform_unit], [unstore_unit], [modify_unit] etc.
post advance
Triggers just after the primary unit has advanced to another unit, or advance by AMLA.
select
Triggers when the primary unit is selected. Prior to version 1.11, this also triggered when a move was interrupted, as the game keeps the moving unit selected by selecting it again at the end of movement. Note: in networked multiplayer, these events are only executed by the client on which the event is triggered, leading to out of sync errors if you modify the game state in the event.
Triggers when a WML menu item with id=X is selected. Note: if the menu item has a [command], this event may be executed before or after the command; there is no guarantee.
unit placed (Version 1.13.3 and later only)
Triggers when the primary unit is placed on the map, regardless of method. This includes but might not be limited to:
- Leaders and units placed in side definitions (fired once for every unit right before prestart events)
- Recruited and recalled units
- Units placed on the map with the [unit] tag (not units created directly onto a recall list or variable)
- Units placed by the wesnoth.put_unit() Lua function
- Units placed by :to_map in Lua (which is a shortcut for the above)
- Units created via debug mode
- Units created by plague
- Every use of [unstore_unit], when fire_event is set to yes (default is no)
- Units moved on map with [move_unit] before (Version 1.15.8 and later only)
- Units matching the filter of [petrify], [unpetrify] or [harm_unit] before (Version 1.15.8 and later only)
- Units who receive a bonus from the feeding ability every time except the first, before (Version 1.15.8 and later only)
This event is solely intended for special cases where no other event types suffice, for example if you must immediately apply a modification to every unit that ever appears. The event does not keep track of which units it has previously fired for, but can fire an unlimited number of times for the same unit as long the unit is "placed" several times and the event filter doesn't prevent it.
Miscellaneous Notes and Examples
Primary/Secondary Unit Speaker Example
In events, the primary unit can be referred to as unit and the secondary unit can be referred to as second_unit in [message] tags using the speaker key. For example:
[event]
name=last breath
[message]
speaker=second_unit
message= _ "Hahaha! I finally killed you!"
[/message]
[message]
speaker=unit
message= _ "It's not over yet! I'll come back to haunt you!"
[/message]
[/event]
Nested Event Example
An event is created for a portal that opens on turn 10. The parent (or 'outer') event executes on turn 10 at which point the nested moveto event is created. This nested event executes when a player steps on a certain spot.
[event]
name=turn 10
[event]
name=moveto
[filter]
x,y=5,8
[/filter]
# moving to 5,8 will trigger this event only on turn 10 and after
[/event]
[/event]
An equivalent way of doing this would be to create a single moveto event with a [filter_condition] statement to check for turn number but using nested [event] tags is a convenient shortcut to accomplish this task without resorting to [filter_condition] statements. Using [if] tags is also an option especially if your event has first_time_only=yes.
Delayed Variable Substitution Example
This code will display a message showing the turn number on which the nested moveto event happens.
[event]
name=turn 10
[event]
name=moveto
delayed_variable_substitution=yes
[filter]
x,y=5,8
[/filter]
{DEBUG_MSG "Turn $turn_number"}
[/event]
[/event]
Since this is the default behavior for the delayed_variable_substitution key, the following example is identical.
[event]
name=turn 10
[event]
name=moveto
[filter]
x,y=5,8
[/filter]
{DEBUG_MSG "Turn $turn_number"}
[/event]
[/event]
The following code will always display "Turn 10" when the nested moveto event happens. This is because the variable substitution is done when the parent event is triggered and spawns the nested event, not when the nested event is triggered.
[event]
name=turn 10
[event]
name=moveto
delayed_variable_substitution=no
[filter]
x,y=5,8
[/filter]
{DEBUG_MSG "Turn $turn_number"}
[/event]
[/event]
Finally, the following example is identical to the first two in that it will display a message showing the turn number on which the nested moveto event happens, despite the fact that the delayed_variable_substitution key is set to no. This is because the special $|variable syntax is used.
[event]
name=turn 10
[event]
name=moveto
delayed_variable_substitution=no
[filter]
x,y=5,8
[/filter]
{DEBUG_MSG "Turn $|turn_number"}
[/event]
[/event]
Multiple Nested Events
Every delayed_variable_substitution=no causes a variable substitution run on the subevent where it occurs at the spawn time of this event and on all following subevents. For any specific event, variable substitution happens at least one time when the event is executed. For each delayed=no key appearing in itself or in an event of an "older" generation, which is not the toplevel event, an additional variable substitution run is made.
[event] # parent
name=turn 2
# delayed_variable_substitution=no # In the parent event, delayed= has no effect.
[event] # child
name=turn 3
delayed_variable_substitution=no # Causes variable substitution in the child, grandchild and great-grandchild event
# at execution time of the parent event = spawn time of the child event.
[event]# grandchild
name=turn 4
delayed_variable_substitution=yes # no variable substitution in the grandchild and great-grandchild event
# at execution time of the child event = spawn time of the grandchild event
[event] # great-grandchild
name=turn 5
{DEBUG_MSG $turn_number} # output: 2 - value from the variable substitution at execution time of the parent event,
# caused by delayed=no in the child event
{DEBUG_MSG $||turn_number}# output: "$turn_number"
# Each variable substitution transforms a "$|" to a "$" (except when no | left).
{DEBUG_MSG $|turn_number}# output: 5 - from the variable substitution at execution time
# of the great-grandchild event
[/event]
[/event]
[/event]
[/event]