EventWML

From The Battle for Wesnoth Wiki
Revision as of 21:17, 26 August 2010 by Gambit (talk | contribs) (Predefined 'name' Key Values: more reordering)

[edit]WML Tags

A:

abilities, about, achievement, achievement_group, add_ai_behavior, advanced_preference, advancefrom, advancement, advances, affect_adjacent, ai, allied_with, allow_end_turn, allow_extra_recruit, allow_recruit, allow_undo, and, animate, animate_unit, animation, aspect, attack (replay, weapon), attack_anim, attacks (special, stats), avoid;

B:

base_unit, background_layer, berserk, binary_path, break, brush;

C:

campaign, cancel_action, candidate_action, capture_village, case, chance_to_hit, change_theme, chat, checkbox, choice, choose, clear_global_variable, clear_menu_item, clear_variable, color_adjust, color_palette, color_range, command (action, replay), continue, credits_group, criteria;

D:

damage, death, deaths, default, defend, defends, defense, delay, deprecated_message, destination, difficulty, disable, disallow_end_turn, disallow_extra_recruit, disallow_recruit, do, do_command, drains, draw_weapon_anim;

E:

editor_group, editor_music, editor_times, effect, else (action, animation), elseif, endlevel, end_turn (action, replay), enemy_of, engine, entry (credits, options), era, event, experimental_filter_ability, experimental_filter_ability_active, experimental_filter_specials, extra_anim;

F:

facet, facing, fake_unit, false, feedback, female, filter (concept, event), filter_adjacent, filter_adjacent_location, filter_attack, filter_attacker, filter_base_value, filter_condition, filter_defender, filter_enemy, filter_location, filter_opponent, filter_own, filter_owner, filter_radius, filter_recall, filter_second, filter_second_attack, filter_self, filter_side, filter_student, filter_vision, filter_weapon, filter_wml, find_path, fire_event, firststrike, floating_text, found_item, for, foreach, frame;

G:

game_config, get_global_variable, goal, gold, gold_carryover;

H:

harm_unit, has_ally, has_attack, has_unit, has_achievement, have_location, have_unit, heal_on_hit, heal_unit, healed_anim, healing_anim, heals, hide_help, hide_unit, hides;

I:

idle_anim, if (action, animation, intro), illuminates, image (intro, terrain), init_side, insert_tag, inspect, item, item_group;

J:

jamming_costs, join;

K:

kill, killed;

L:

label, language, leader, leader_goal, leadership, leading_anim, levelin_anim, levelout_anim, lift_fog, limit, literal, load_resource, locale, lock_view, lua;

M:

male, menu_item, message, micro_ai, missile_frame, modification, modifications, modify_ai, modify_side, modify_turns, modify_unit, modify_unit_type, move, move_unit, move_unit_fake, move_units_fake, movement_anim, movement costs, movetype, multiplayer, multiplayer_side, music;

N:

not, note;

O:

object, objective, objectives, on_undo, open_help, option, options, or;

P:

part, petrifies, petrify, place_shroud, plague, poison, post_movement_anim, pre_movement_anim, primary_attack, primary_unit, print, progress_achievement, put_to_recall_list;

R:

race, random_placement, recall (action, replay), recalls, recruit, recruit_anim, recruiting_anim, recruits, redraw, regenerate, remove_event, remove_item, remove_object, remove_shroud, remove_sound_source, remove_time_area, remove_trait, remove_unit_overlay, repeat, replace_map, replace_schedule, replay, replay_start, reset_fog, resistance (ability, unit), resistance_defaults, resource, return, role, rule;

S:

save, scenario, screen_fade, scroll, scroll_to, scroll_to_unit, secondary_attack, secondary_unit, section, select_unit, sequence, set_achievement, set_extra_recruit, set_global_variable, set_menu_item, set_recruit, set_specials, set_variable, set_variables, sheath_weapon_anim, show_if (message, objective, set_menu_item), show_objectives, side, skirmisher, slider, slow, snapshot, sound, sound_source, source (replay, teleport), special_note, specials, split, stage, standing_anim, statistics, status, store_gold, store_items, store_locations, store_map_dimensions, store_reachable_locations, store_relative_direction, store_side, store_starting_location, store_time_of_day, store_turns, store_unit, store_unit_defense, store_unit_defense_on, store_unit_type, store_unit_type_ids, store_villages, story, swarm, sub_achievement, switch, sync_variable;

T:

target, team, teleport (ability, action), teleport_anim, terrain, terrain_defaults, terrain_graphics, terrain_mask, terrain_type, test, test_condition, test_do_attack_by_id, text_input, textdomain, theme, then, tile, time, time_area, topic, toplevel, trait, transform_unit, traveler, true, tunnel;

U:

unhide_unit, unit, unit_overlay, unit_type, unit_worth, units, unlock_view, unpetrify, unstore_unit, unsynced;

V:

value, variable, variables, variant, variation, victory_anim, village, vision_costs, volume;

W:

while, wml_message, wml_schema;

Z:

zoom;

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], [tutorial] 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 word "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.

Lexicon side note: It is not uncommon to refer to these values as the 'trigger' for an event and, furthermore, to call an event by its 'trigger' name. For example, in an event containing name=moveto, a person might refer to the event as a 'moveto event' and/or refer to the 'moveto trigger' in the event or even talk about the 'event trigger' when referring to the moveto value of the 'name' key in that event. Some or all of this usage can, in fact, be found throughout this page.

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.

Predefined 'name' Key Values

All predefined event types are listed here along with a description of when this value will cause the event to be triggered. Any value not listed here 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).

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: 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.
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.
Side initialization events go in the order of:
1) turn X
2) new turn
3) side turn
4) side X turn
5) side turn X
6) side X turn Y
7) turn refresh
8) side X turn refresh
9) turn X refresh
10) side X turn Y refresh
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 currently breaks replays since it is not explicitly saved in a replay and there is no AI involved in replays...
turn refresh
Like side turn, triggers just before a side is taking control but after healing, calculating income, and restoring unit movement and status.
turn X
Triggers at the start of turn X. It's the first side initialization event.
turn end Template:DevFeature1.9
Triggers at the end of every turn (not side turn end). The WML variable side_number will contain the side that ended their turn. It is the last event in the group of end turn events.
turn X end Template:DevFeature1.9
Triggers at the end of turn X. It's the second to last event in the group of end turn events.
side X turn Y
This event triggers at the start of turn Y of side X Template:DevFeature
side X turn
This event triggers at the start of any turn of side X Template:DevFeature
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 Template:DevFeature1.9
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 Template:DevFeature1.9
side X turn refresh
This event triggers at the turn refresh for side X Template:DevFeature1.9
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. Template:DevFeature1.9
Note: Of course, first_time_only=no is needed for this event to be triggered more than once.
side turn end Template:DevFeature1.9
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:
1) side turn end
2) side X turn end
3) side turn X end
4) side X turn Y end
5) turn end
6) turn X end

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.

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.

[filter]

The event will only trigger if the primary unit matches this filter.

[filter_second]

Like [filter], but for the secondary unit.

[filter_attack]

Can be used to set additional filtering criteria for the primary unit and the secondary unit that are not generally available in a standard unit filter. Can be used in events attack, attacker hits, attacker misses, defender hits, defender misses and attack end. For more information and other filter keys, see FilterWML.
  • name: the name of the weapon used.
  • range: the range of the weapon used.
  • special: filter on the attack's special power.

[filter_second_attack]

Like [filter_attack], but for the secondary unit.
  • name: the name of the weapon used.
  • range: the range of the weapon used.
  • special: filter on the attack's special power.

[event]

A special case 'action', the [event] tag may be used to create a nested event.

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:

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).

(See Examples)

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.

(See Examples)

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
  • sighted
  • attack
  • attack_end
  • attacker hits
  • attacker misses
  • defender hits
  • defender misses
  • stone
  • last breath
  • menu item X
  • die
  • capture
  • recruit
  • prerecruit
  • recall
  • prerecall
  • advance
  • post_advance

getting message options (etc) from the following events is not synchronized, except in the development version (1.9+svn):

  • new turn
  • side turn
  • turn X
  • side X turn
  • side X turn Y
  • turn refresh

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

It is perfectly possible (and, in fact, useful) to have multiple events with the same predefined name and thus the same trigger condition. However, it is not defined what order such events will fire in, so you need to code so the order will not matter.

Because of the above, 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.

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=die
    [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 an [if] statement to check for turn number but using nested [event] tags is a convenient shortcut to accomplish this task without resorting to [if] statements.

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]

See Also