Difference between revisions of "AnimationWML"

From The Battle for Wesnoth Wiki
(Remove DvFeture, highlight tags)
Line 1: Line 1:
 
{{WML Tags}}
 
{{WML Tags}}
  
== Animation and sound ==
 
  
Several key/tags of the '''[unit]''' and '''[attack]''' tags do not affect gameplay, but are available to control the way units and their attacks will be animated and heard.
+
== Introduction ==
  
All times (see '''begin''', '''end''', '''time''') are measured in milliseconds, or 1000ths of seconds. Unit movement is automatically animated based on these times; the attacking unit or missile begins in the center of the hex at the lowest '''begin''' time, then slides continuously to the center of the defender's hex, which it reaches at time=0. If the attack is a melee attack, the unit will then slide continuously back onto its own hex until the highest '''end''' time. Note that in accelerated mode or under a lot of stress the game engine can skip some frames (sounds included), and very short frames (less than 10ms?) may get skipped even in normal circumstances.  
+
This page covers unit animations. At any point in game, units are playing an animation. Even when the unit is standing, it is actually playing a single frame animation.
  
All unit animations use the same engine, so most tags and keys are common for all animations types.
+
This page will deal with the two problems of animations
 +
* How are animations Chosen
 +
* What exactly is drawn
  
=== [animation] blocks ===
 
  
All animations are enclosed in '''[animation]''' tags. The actual name of the tag changes depending on the type of animation (so for example healing animations are written inside '''[healing_anim]''' tags, death anims inside '''[death]''' tags, and so on).
 
  
Individual animation frames are described by '''[frame]''' tags.
+
== How animations are drawned ==
 +
=== Animations ===
 +
Any unit has a huge set of animations to choose from. Animations are WML blocks in the unit type, enclosed in either the generic type '''[animation]''' or some more specific tags such as '''[attack_anim]''' '''[idle_anim]''' and the like. An animation is what a unit displays when a given event is triggered, and a certain set of conditions are met such as
 +
* unit is attacking
 +
* unit is idling
 +
* unit is attacking (event) and uses a melee weapon (condition)
 +
* unit is attacking (event) and uses a melee weapon (condition) and opponent can't retaliate (condition)
  
* '''[animation]''': all animations are enclosed in '''[animation]''' tags. The actual name of the tag changes depending on the type of animation (so for example healing animations are written inside '''[healing_anim]''' tags, death anims inside '''[death]''': tags, and so on), but here we refer to all of them simply as '''[animation]''' tags, since they all work the same. Wherever you can put an '''[animation]''': tag, you can put multiple ones - you can use this to create variations on animations or to have some animations be used only in certain circumstances (like only on a certain terrain or only when delivering a killing blow in combat to name a few possibilities).
+
events and conditions are described entirely in the [animation] block, and will be discussed in the animation choice section.
** '''[frame]''': describes what an animation should display at a given time. Only one frame can be displayed at a time.
 
*** '''begin''': the time at which this frame should start (in milliseconds).
 
*** '''end''': the time at which the animation should end.
 
*** '''duration''': how long the frame should be displayed. Use instead of '''begin=''' and '''end='''.
 
*** '''image''': the image to display during the frame.
 
*** '''sound''': the sound to play when the frame begins. Can be a comma-separated list of sounds, in which case one of them is chosen randomly every time.
 
*** '''halo''': the halo to display at the time.
 
*** '''halo_x''': the position the halo is displayed in pixel relative to the unit's center.
 
*** '''halo_y''': the position the halo is displayed in pixel relative to the unit's center.
 
*** '''alpha''': transparency level to apply to the frame. This is a floating point progressive parameter ranging from 0.0 to 1.0.
 
*** '''offset''': the position of the image relative to the hex the unit is facing, 0.0 will display the unit in the center of the hex, 1.0 in the center of the faced hex, -1.0 at the center of the hex behind you. This is a progressive parameter.
 
*** '''blend_color''': a comma separated list of numbers representing a color in RGB (0-255) this color will be mixed to the frame to give it a tint.
 
*** '''blend_ratio''': this is a progressive parameter ranging from 0 to 1: 0 means no tint, 1 means target color only.
 
*** '''text''': if specified, floats a label with the given text above the unit (identical to the floating damage and healing numbers).
 
*** '''text_color''': the color of the above floating label.
 
** '''[missile_frame]''': can only be used for ranged attacks; describes a frame of animation for the projectile. Most commonly only one ''[missile_frame]'' is used and the missile isn't actually animated. Accepts the same keys as ''[frame]'' and also the following:
 
*** '''image_diagonal''': the image to display when the attack occurs diagonally (directions ne,se,sw,nw).
 
**'''[XXX_frame]''': you can have as many "sub animations" within an animation by defining them in their own type of frame blocks. note that XXX should not start with an underscore ("_") this is reserver for internal use by the engine
 
*** '''image_diagonal''': the image to display when the animation occurs diagonally (directions ne,se,sw,nw).
 
  
 +
=== Frames ===
 +
   
 +
An animation is cut in frames. Frames are WML blocks that are contained either in '''[frame]''' WML blocks or in generic '''[xxx_frame]''' block. (the xxx part can be any string not starting with an underscore) the xxx part in the frame name is called the frame prefix. frames of the type '''[frame]''' are said to have an empty prefix
 +
 +
A frame typically describes an image, where an how to render it. It can contain such things as
 +
* the image to display
 +
* how transparent should that image be
 +
* where to draw that image.
 +
 +
At any given time, an animation will display one frame for each frame prefix it can find. I.e if your animation has both '''[frame]''' and '''[missile_frame]''' blocks, both will be displayed at the same time
 +
 +
 +
The frame with the empty prefix is special in many way. It is assumed to contain the image representing the unit itself, and as such the engine will heavily temper with it in multiple ways, such as providing a default image if none is available, or forcing the image to be green when the unit is poisoned
 +
 +
=== Timing, Clock, Multiple animations ===
 +
When an animation is played it has an internal clock that is run. The step of this clock is the milisecond, and each frame is played for a given duration. Each animation also has a starting time which tells the animation engine at what value the animation clock should start
 +
 +
This starting time is very important when multiple animations from different units are played synchronously  Typically a fight involves a unit playing its defense animation while the opponent plays it's attack animation (and a third might play its leading animation, too). In that case all animations have a common clock, and are played concurrently.
 +
 +
The convention is that the "important time" (usually the time of the hit) is at time 0. everything before should be at negative time, everything after at positive time. This is a WML convention that is not enforced by the engine
 +
 +
 +
In that case, it is very important that these animations (which can have different lengths) be synchronized. Fight animations are synchronized around the point of impact, so they all reach time 0 when the attack lands (or misses).
 +
 +
 +
=== The content of a frame ===
 +
==== Syntax summary ====
 +
[frame]
 +
    duration=<integer>
 +
    begin=<deprecated,integer>
 +
    end=<deprecated,integer>
 +
    image=<string>
 +
    image_diagonal=<string>
 +
    sound=<string>
 +
    halo=<progressive string>
 +
    halo_x=<progressive int>
 +
    halo_y=<progressive int>
 +
    alpha=<progressive float>
 +
    offset=<progressive float>
 +
    blend_color=< red, green, blue >
 +
    blend_ratio=<progressive float>
 +
    text=<string>
 +
    text_color=< red, green, blue >
 +
[/frame]
 
==== Progressive parameters ====
 
==== Progressive parameters ====
  
You can make a value of a key smoothly slide from one starting value to another one during the duration of the '''[frame]'''. To make a frame fade from normal to completely transparent, you could use:
+
Some parameters above are marked as ''progressive'' This means that you can specify that during the time the frame is displayed, the parameter should smoothly slide from one value to an other.
 +
 
 +
A typical example would be a unit progressively fading out, becoming transparent
 +
 
 +
To do that, you could use:
  
 
  alpha=1~0
 
  alpha=1~0
Line 46: Line 80:
 
  alpha=1~0:300,0:300,0~1:300
 
  alpha=1~0:300,0:300,0~1:300
  
if you want to define this parameter for other sub animation, use the prefix of that animation. For instance, the default sliding of missile animations can be specified with
+
you could also specify it like that
 +
 
 +
alpha=1~0,0,0~1
 +
 
 +
when a timing is missing, the engine will do its best to fill in in a fair way.  
 +
 
 +
a progressive string has a similar syntax
  
  missile_offset=0~0.8
+
  halo=halo1.png:300,halo2.png:300,halo2.png:300
  
When defining an animation for use in a specific situation, you have a variety of keys with which you can define when the animation is to be used. The filters go directly inside the '''[animation]''' tag. Different types of animations have slightly different set of filters available. See further below for a detailed explanation on how more complex filtering works.
+
==== Field Description ====
  
'''Generic animation filters available for all animations'''
+
** '''begin''': (deprecated) will be replaced by '''duration= <end - begin >'''
* '''terrain''': a list of comma separated terrain letters, the animation will only be used on these terrains. See [[FilterWML]].
+
** '''end''': (deprecated) see '''begin'''
* '''direction''': a list of directions (n,ne,se,s,sw,nw), the animation will only be used when acting or moving in this direction (the attack direction for attack animations, moving direction for movement animations, direction of lead unit for leading animations, and so on).
+
** '''duration''': how long the frame should be displayed. Use instead of '''begin=''' and '''end='''.
* '''frequency''': this integer value allows to easily tweak the matching frequency of animations. The filter will fail n-1 times out of n, randomly. Note that unlike every other filter, matching this filter won't give an extra point.
+
** '''image''': the image to display during the frame.
* '''[unit_filter]''': this will filter using a standard unit filter on the animated unit. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[unit_filter]''' blocks in an animation.
+
** '''image_diagonal''': the image to display when the attack occurs diagonally (directions ne,se,sw,nw).
* '''[secondary_unit_filter]''': this will filter using a standard unit filter on the unit in the hex faced. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[secondary_unit_filter]''' blocks in an animation. Also note that if the faced hex is empty, the whole filter will fail
+
** '''sound''': the sound to play when the frame begins. Can be a comma-separated list of sounds, in which case one of them is chosen randomly every time.
* '''[neighbour_unit_filter]''': this will filter using a standard unit filter on allunits in adjacent hexes. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[neighbour_unit_filter]''' blocks in an animation. This filter will earn you one point for each matching neighbouring unit, and will fail if no unit matches the criteria (i.e no neighbour or no matching neighbour) .
+
** '''halo''': the halo to display at the time.
 +
** '''halo_x''': the position the halo is displayed in pixel relative to the unit's center.
 +
** '''halo_y''': the position the halo is displayed in pixel relative to the unit's center.
 +
** '''alpha''': transparency level to apply to the frame. This is a floating point progressive parameter ranging from 0.0 to 1.0.
 +
** '''offset''': the position of the image relative to the hex the unit is facing, 0.0 will display the unit in the center of the hex, 1.0 in the center of the faced hex, -1.0 at the center of the hex behind you. This is a progressive parameter.
 +
** '''blend_color''': a comma separated list of numbers representing a color in RGB (0-255) this color will be mixed to the frame to give it a tint.
 +
** '''blend_ratio''': this is a progressive parameter ranging from 0 to 1: 0 means no tint, 1 means target color only.
 +
** '''text''': if specified, floats a label with the given text above the unit (identical to the floating damage and healing numbers).
 +
** '''text_color''': the color of the above floating label.
  
 +
=== Drawing related animation content ===
 +
==== Syntax summary ====
 +
[animation]
 +
  <animation choice related content>
 +
  [frame]
 +
    <frame content>
 +
  [/frame]
 +
  [frame]
 +
    <frame content>
 +
  [/frame]
 +
  start_time=<integer>
 +
  offset=<progressive float>
 +
  blend_with=<r,g,b>
 +
  blend_ratio=<progressive float>
 +
  halo=<progressive_string>
 +
  halo_x=<progressive int>
 +
  halo_y=<progressive int>
 +
 
 +
  [xxx_frame]
 +
    <frame content>
 +
  [/xxx_frame]
 +
  xxx_start_time=<integer>
 +
  xxx_offset=<progressive float>
 +
  xxx_blend_with=<r,g,b>
 +
  xxx_blend_ratio=<progressive float>
 +
  xxx_halo=<progressive_string>
 +
  xxx_halo_x=<progressive int>
 +
  xxx_halo_y=<progressive int>
  
Progressive parameters can be set both in the '''[frame]''' or in the '''[animation]''' the general rule is that frame level specification overrides animation level specifications, which overrides engine provided defaults. The following parameters can be specified both at animation and at frame level
+
[/animation]
* '''alpha'''
+
==== Parameter handling ====
* '''halo'''
+
All drawing related parameters in '''[animation]''' can be matched with a corresponding parameter in a '''[frame]''' block (or a '''[xxx_frame]''' block) The value provided in the animation will be used if no value is provided in the frame.  
* '''halo_x'''
 
* '''halo_y'''
 
* '''offset'''
 
* '''blend_color'''
 
* '''blend_ratio'''
 
  
Note that these can be set as animation-level parameters also for sub-animations (see [XXX_frame] above) by using keys XXX_offset, XXX_alpha, etc.
+
The point of these two level of parameters is to easily be able to specify a parameter at the animation level and override it for a special case of frame.
  
  
'''Fighting animation filters'''
+
== How animations are chosen ==
** '''hits''': filters attack animations based on whether the attack hits, misses or kills. Accepts a list of the following:
+
Within a unit decription block there are multiple animations. Each animation is meant to be played in a very special set of circumstances. We will discuss here how to tell the animation engine when a given animation should be played.  
*** '''hit''': the attack hits, defender survives.
 
*** '''no''' or '''miss''': the attack misses.
 
*** '''kill''': the attack hits, defender dies.
 
*** '''yes''': is an alias of '''hit,kill'''.
 
** '''range''': a list of ranges that the attack must match for this animation to be used.
 
** '''damage_type''': a list of damage types that the animation should be used with (damage type of the attack).
 
** '''attack_special''': a list of special abilities the attack should have.
 
** '''swing''': a list of numbers representing the swing numbers this animation should match (numbered from 1).
 
** '''damage''': a comma separated list of values of the damage the defender will take (note that damage is 0 if the attack misses).
 
** '''[attack_filter]''': a standard attack filter to match on the attacker's attack. See  [[FilterWML]].
 
** '''[secondary_attack_filter]''': a standard attack filter to match on the defender's attack. See [[FilterWML]]. Also note that if the defender doesn't have any weapon to retaliate with, this filter will always fail.
 
  
==== Attack animation: ''[attack_anim]'' ====
+
Let's take an example. Suppose we have a unit which has the skirmisher ability. We have the folowing movement animations :
 +
* a normal walking animation
 +
* a swimming animation when the unit is in water
 +
* a tiptioeing animation when moving next to an ennemy unit
  
This animation is played when a unit attempts a blow on another unit. The attacking unit is always facing the defending unit.
+
Ok. most of the time it's easy to guess what animation should be. However if you are both in water and next to an ennemy unit, the animation to play is not obvious.
  
This animation can contain some [missile_frame] blocks, see below...
+
To solve that question, each animation has a number of filtering criterias. The engine follow the following rules to select an animation
 +
* Start with all animations
 +
* Drop all animations with a criteria that fails on the current situation
 +
* Take the animations that have the most maching criterias
 +
* If there are more than one animation remaining, take an animation randomly
 +
* If all animations have been droped, the engine will provide a smart default.
 +
   
 +
here is a pseudo-code explaination of this algorithm
  
==== Defensive animation: ''[defend]'' ====
+
foreach animation
 +
    animation_score = 0
 +
    foreach filter-criteria
 +
      if <criteria-fails>
 +
  animation_score = -1;
 +
  break;
 +
      elsif <criteria-matches>
 +
  animation_score++
 +
    endfor
 +
    if animation_score > max_score
 +
<empty animation list>
 +
max_score = animation_score;
 +
push(animation,animation_list);
 +
    elsif animation_score = max_score
 +
push(animation,animation_list);
 +
endfor
 +
<choose an animation randomly from animation_list>
  
This animation is used when facing a blow in a fight. The defending unit is always facing the attacking unit.
+
 +
Note that all animations don't have all the filters...
  
==== Death animation: ''[death]'' ====
+
so, if we have a unit with
 +
# an animation for water terrain
 +
# an animation for SE on grassland
 +
# an animation with no criteria
 +
# an animation for N,NE,NW,S,SW,SE
 +
# an animation for NW
 +
 
 +
* 3. will never be taken, because 4. will always trump it
 +
* on water going NW, it can be 1. 4. 5.
 +
* on water, any direction but NW, it will be 1. or 4.
 +
* on SE grassland it will be 2.
 +
* on other grasslands, it will be 4. (4. or 5. if NW)
  
This animation is used when the unit dies, before it is removed from display. It is called after the fight is finished and the hits criteria is always set to kill.
+
=== Generic animation filters available for all animations ===
 +
* '''apply_to''': a list of comma separated keywords describing what event should trigger the animation (movement, attack...) the complete list is given below
 +
* '''value''': a list of comma separated integer, the meaning depends on the triggering event. the meaning is given with the list of event
 +
* '''terrain''': a list of comma separated terrain letters, the animation will only be used on these terrains.  See [[FilterWML]].
 +
* '''[unit_filter]''': this will filter using a standard unit filter on the animated unit. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[unit_filter]''' blocks in an animation.
 +
* '''[secondary_unit_filter]''': this will filter using a standard unit filter on the unit in the hex faced. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[secondary_unit_filter]''' blocks in an animation. Also note that if the faced hex is empty, the whole filter will fail
 +
* '''direction''': a list of directions (n,ne,se,s,sw,nw), the animation will only be used when acting or moving in this direction (the attack direction for attack animations, moving direction for movement animations, direction of lead unit for leading animations, and so on).
 +
* '''frequency''': this integer value allows to easily tweak the matching frequency of animations. The filter will fail n-1 times out of n, randomly. Note that unlike every other filter, matching this filter won't give an extra point.
 +
* '''[attack_filter]''': a standard attack filter to match on the attacker's attack. See  [[FilterWML]].
 +
* '''[secondary_attack_filter]''': a standard attack filter to match on the defender's attack. See [[FilterWML]]. Also note that if the defender doesn't have any weapon to retaliate with, this filter will always fail.
 +
* '''hits''': filters attack animations based on whether the attack hits, misses or kills. Accepts a list of the following:
 +
** '''hit''': the attack hits, defender survives.
 +
** '''no''' or '''miss''': the attack misses.
 +
** '''kill''': the attack hits, defender dies.
 +
** '''yes''': is an alias of '''hit,kill'''.
 +
* '''swing''': a list of numbers representing the swing numbers this animation should match (numbered from 1).
  
==== Movement animation: ''[movement_anim]'' ====
+
=== Events trigerring animations and default animations ===
 +
==== standing ====
 +
This animation is triggered whenever any other animation is finished, and is played in loop until another animation is triggered
  
This animation is used when a unit is moving. The moving unit is always facing the hex it's moving into. The animation will be truncated if the unit reaches its destination before the end of the movement. The animation will also be ended if the unit enters a hex where the current animation has a negative score, but not if its still valid (but not the best score).
+
this is the default "standing image" for the unit
  
==== Standing animation: ''[standing_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when a unit is standing and doing nothing.
+
if no standing animation is set a single frame animation based on the enclosing unit's '''image=''' field is used
 +
==== selected ====
 +
This animation is triggered whenever the unit is selected
  
==== Idle animation: ''[idle_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is called randomly every now and then when the unit is idle.
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="0.0~0.3:100,0.3~0.0:200" blend_color=255,255,255''
 +
==== recruited ====
 +
This animation is triggered whenever the unit is recruited or recalled
  
==== Leading animation: ''[leading_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when a unit is using it's leadership ability on another unit. The leading unit is always facing the unit it leads.
+
if no animation is available, the default uses the standing animation(s) with ''highlight=0~1:600''
 +
==== levelin ====
 +
This animation is triggered whenever the unit levels, before the unit is replaced by the new unit
  
==== Healing animation: ''[healing_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when a unit has a healing ability and is using it on another unit. The healing unit is always facing the unit it heals.
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="1~0:600" blend_color=255,255,255''
* '''damage''': a comma separated list of values: the damage healed.
+
==== levelout ====
 +
This animation is triggered whenever the unit levels, after the unit is replaced by the new unit
  
==== Teleport animation: ''[teleport_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when a unit teleports by using the teleport ability ('''not''' when the unit is moved by using the ''[teleport]'' tag). The part of the animation before time 0 is displayed at the starting point, and the rest displayed when arriving at the destination.
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="0~1:600" blend_color=255,255,255''
 +
==== movement ====
 +
This animation is used whenever a unit moves. There are multiple things to consider when dealing with movement animation
 +
* unit stay ''exactly'' 150ms in each hex. so you typically want to have an offset of ''0~1:150,0~1:150,0~1:150,0~1:150,0~1:150'' or something similar
 +
* when a unit enters a hex, the current anim is tested again.
 +
** if the current animation is still valid (i.e it passes all its filter) it is kept, whatever the final score is
 +
** if it fails, a new movement anim is searched
  
==== Victory animation: ''[victory_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when the unit kills another unit, during the other unit's death animation. It is called after the fight is finished and the hits criteria is always set to kill.
+
if no animation is available, the default uses the standing animation(s) with ''offset="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150"''
 +
==== pre_teleport ====
 +
This animation is triggered whenever the unit teleports, but before it has moved to the target hex
  
==== Poison animation: ''[poison_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when the unit suffers poison damage (at the beginning of turn).
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="1~0:150" blend_color=255,255,255''
* ''damage'': a comma separated list of values: the damage suffered.
+
==== post_teleport ====
 +
This animation is triggered whenever the unit teleports, but after it has moved to the target hex
  
==== Healed animation: ''[healed_anim]'' ====
+
''value='' is not used, and always contains 0
  
This animation is used when the unit is healed (by a healer or a village).
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="0~1:150" blend_color=255,255,255''
* ''healing'': a comma separated list of values: the HP healed.
+
==== healing ====
 +
This animation is triggered when the unit has healing powers and uses them
  
==== Recruit animation: ''[recruit_anim]'' ====
+
''value='' is the number of points healed
  
This animation is used when a unit is recruited (or created via the plague special ability).
+
No default is provided by the engine
 +
==== healed ====
 +
This animation is triggered whenever the unit is healed for any reason
  
==== Level-in animation: ''[levelin_anim]'' ====
+
''value='' is the number of points healed
  
This animation is used when a unit has leveled. The new unit is displayed, and this animation is played immediately.
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30" blend_color=255,255,255''
 +
and plays the sound ''heal.wav''
 +
==== poisoned ====
 +
This animation is triggered whenever the unit suffers poison dammage
  
==== Level-out animation: ''[levelout_anim]'' ====
+
''value='' is the number of points lost
  
This animation is used when a unit has leveled. The old unit is still displayed, and this animation is played just before changing it to the new unit.
+
if no animation is available, the default uses the standing animation(s) with ''blend_with="0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30" blend_color=0,255,0''
 +
and plays the sound 'poison.ogg''
 +
==== defend ====
 +
This animation is triggered during a strike, of the unit receiving the blow
  
==== Custom animations: ''[extra_anim]'' ====
+
''value='' is the number of point lost, if any
  
This animation defines a custom animation that can be called in WML events (via the ''[animate_unit]'' tag), to make a unit display arbitrary animations at arbitrary times.
+
No default is provided by the engine
* '''flag''': this identifies the animation, and will be used to choose the correct animation to play.
+
==== attack ====
 +
This animation is triggered during a strike, of the unit giving the blow
  
== How animations are chosen ==
+
''value='' is the number of damage dealt, if any
Wherever you can put an animation block, you can put multiple ones. So an interesting question is which one of them will the engine choose when the animation should be displayed? Simply put, the engine always chooses the one that matches the given filtering best. If several match equally well, one of them is picked randomly every time. Below is a more detailed and technical explanation of the choosing process.
 
  
The animation engine always uses the same rules to choose an animation. I will take the example from movement animations. Movement animations can take two filters (via special flags in the animation block) to filter on movement direction and on the terrain the unit is currently on. So, the engine takes all movement animations and assigns them scores with the following algorithm:
+
if no animation is available, the default uses the standing animation(s) with ''offset="0~0.6:150,0.6~0:150"'' for melee attacks
 +
No default is provided for range attacks
 +
==== leading ====
 +
This animation is triggered for units with the leading special ability, when the unit they are leading is attacking
  
the animation starts with a score of 0
+
''value='' is not used, and always contains 0
for each criteria,
 
* if filter is not there, the score is unchanged
 
* if filter is not matched the animation is given a score of -1 and the algorithm ends (disqualified)
 
* if filter is matched, the score is increased by one
 
  
After that, the engine takes all top score animations and chooses a random one.
+
No default is provided by the engine
 +
==== death ====
 +
This animation is triggered when a unit die.
  
so, if we have a unit with
+
''value='' is not used, and always contains 0
# an animation for water terrain
 
# an animation for SE on grassland
 
# an animation with no criteria
 
# an animation for N,NE,NW,S,SW,SE
 
# an animatio for NW
 
  
* 3. will never be taken, because 4. will always trump it
+
if no animation is available, the default uses the standing animation(s) with ''highlight=1~0:600'' and plays the sound in ''die_sound='' of the enclosing unit
* on water going NW, it can be 1. 4. 5.
+
==== victory ====
* on water, any direction but NW, it will be 1. or 4.
+
This animation is triggered when a unit finishes a fight by killing the other unit
* on SE grassland it will be 2.
 
* on other grasslands, it will be 4. (4. or 5. if NW)
 
  
 +
''value='' is not used, and always contains 0
  
== How animations are synchronized ==
+
No default is provided by the engine
 +
==== idling ====
 +
This animation is called when the unit has been using its standing animation for a random duration.
  
Some events require multiple units playing different animations simultaneously. Typically a fight involves a unit playing its defense animation while the opponent plays it's attack animation (and a third might play its leading animation, too).
+
''value='' is not used, and always contains 0
  
In that case, it is very important that these animations (which can have different lengths) be synchronized. Fight animations are synchronized around the point of impact, so they all reach time 0 when the attack lands (or misses).
+
No default is provided by the engine
 +
==== extra animations ====
 +
Other values are never called by the engine. However they can be triggered by WML events allowing custom animations.
  
When you use '''duration=''' to time '''[frame]'''s instead of the '''begin=''' and '''end=''' keys (which is recommended), animation blocks can specify a '''start_time=''' key. This is a virtual time at which the animation should be launched. Suppose the attack animation has '''start_time=-150''' and the defense animation has '''start_time=-100''': for 50ms, the attack animation will play alone, then the defense animation will start, they will both reach their virtual 0 at the same time (which is the time of impact) and then continue. If no '''start_time''' is available, it is defaulted to zero.
+
Note that WML events can also trigger standard animations.
 +
''value='' is set from the WML event
  
 +
== Shortcuts, tricks and quirks ==
  
== ''[if]'' and ''[else]'' ==
+
=== ''[if]'' and ''[else]'' ===
  
If you need to do very slight variations in an animation (like a different sound depending on whether the unit hits or misses its attack), the '''[if]''' and '''[else]''' tags are useful. Using these in an animation is equivalent to having multiple animations, one with the '''[if]''' block and one with each of the ''[else]'' blocks. Any filtering flags in these blocks will replace the toplevel filters. You can have multiple '''[if]''' blocks in an animation, but you can't nest an '''[if]''' inside another. These should be written directly inside the '''[animation]''' block. The following example would make the '''[frame]''' inside the '''[if]''' be played when the attack misses, and the '''[frame]''' inside the '''[else]''' be played when the attack hits (producing a different sound):
+
Often, you need to do very slight variations in an animation (like a different sound depending on whether the unit hits or misses its attack), the '''[if]''' and '''[else]''' tags are meant to help you do that.  
 +
   
 +
Using these in an animation is equivalent to having multiple animations, one with the '''[if]''' block and one with each of the ''[else]'' blocks. Any filtering flags in these blocks will replace the toplevel filters. You can have multiple '''[if]''' blocks in an animation, but you can't nest an '''[if]''' inside another. These should be written directly inside the '''[animation]''' block. The following example would make the '''[frame]''' inside the '''[if]''' be played when the attack misses, and the '''[frame]''' inside the '''[else]''' be played when the attack hits (producing a different sound):
  
 
     [if]
 
     [if]
Line 216: Line 359:
 
     [/else]
 
     [/else]
  
 +
note that this is very close to preprocessing and should be considered as such, especially with regard to scoring and animation selection
 +
 +
=== Simplified animation blocks ===
 +
To simplify the most common animation cases, you can use different blocks instead of the generic '''[animation]''' block. These are also here for backward compatibility, but are not deprecated and fully supported
 +
 +
some of these use extra tags which are translated in the normal ''value='' tag
 +
 +
some of these define '''[xxx_frame]''' blocks where the frame prefix starts with an underscore. This is not allowed in normal WML (prefix starting with underscore is reserved for the engine internal use). It is here for clarity purpose
 +
 +
* '''[leading_anim]''' is an animation with the following parameters automatically set
 +
apply_to=leading
 +
* '''[recruit_anim]''' is an animation with the following parameters automatically set
 +
apply_to=recruited
 +
* '''[standing_anim]''' is an animation with the following parameters automatically set
 +
apply_to=standing,_default_
 +
* '''[idle_anim]''' is an animation with the following parameters automatically set
 +
apply_to=idling
 +
* '''[levelin_anim]''' is an animation with the following parameters automatically set
 +
apply_to=levelin
 +
* '''[levelout_anim]''' is an animation with the following parameters automatically set
 +
apply_to=levelout
 +
* '''[healing_anim]''' is an animation with the following parameters automatically set
 +
apply_to=healing
 +
value=<damage= value>
 +
* '''[healed_anim]''' is an animation with the following parameters automatically set
 +
apply_to=healed
 +
value=<healing= value>
 +
[_healed_sound_frame]
 +
    sound=heal.wav
 +
[/_healed_sound_frame]
 +
* '''[poison_anim]''' is an animation with the following parameters automatically set
 +
apply_to=poisoned
 +
value=<damage= value>
 +
[_poison_sound_frame]
 +
    sound=poison.ogg
 +
[/_poison_sound_frame]
 +
* '''[movement_anim]''' is an animation with the following parameters automatically set
 +
apply_to=movement
 +
offset="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150"
 +
* '''[defend]''' is an animation with the following parameters automatically set
 +
apply_to=defend
 +
value=<damage= value>
 +
<WML content>
 +
[frame]
 +
    blend_with=255,0,0
 +
    blend_ratio="0.5:50,0.0:50"
 +
[/frame]
 +
 +
there are some subtil change compared to what is described above to avoid the red flash when value=0, but it should work as expected as far as WML author are concerned
 +
 +
* '''[attack_anim]''' is an animation with the following parameters automatically set
 +
if the animation contains a missile frame
 +
 +
apply_to=attack
 +
missile_offset="0~0.8"
 +
 +
else
 +
 +
apply_to=attack
 +
offset="0~0.6,0.6~0"
 +
 +
* '''[death]''' is an animation with the following parameters automatically set
 +
apply_to=death
 +
[_death_sound_frame]
 +
    sound=<die_sound= of the enclosing [unit] tag>
 +
[/_death_sound_frame]
 +
* '''[victory_anim]''' is an animation with the following parameters automatically set
 +
apply_to=victory
 +
* '''[extra_anim]''' is an animation with the following parameters automatically set
 +
apply_to=<flag= value of the anim>
 +
* '''[teleport_anim]''' will be cut into two at the clock-time 0
 +
everything before zero becomes an animation with the following parameters automatically set
 +
apply_to=pre_teleport
 +
everything after zero becomes an animation with the following parameters automatically set
 +
apply_to=post_teleport
  
 
== See Also ==
 
== See Also ==

Revision as of 17:45, 20 March 2008

[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;


Introduction

This page covers unit animations. At any point in game, units are playing an animation. Even when the unit is standing, it is actually playing a single frame animation.

This page will deal with the two problems of animations

  • How are animations Chosen
  • What exactly is drawn


How animations are drawned

Animations

Any unit has a huge set of animations to choose from. Animations are WML blocks in the unit type, enclosed in either the generic type [animation] or some more specific tags such as [attack_anim] [idle_anim] and the like. An animation is what a unit displays when a given event is triggered, and a certain set of conditions are met such as

  • unit is attacking
  • unit is idling
  • unit is attacking (event) and uses a melee weapon (condition)
  • unit is attacking (event) and uses a melee weapon (condition) and opponent can't retaliate (condition)

events and conditions are described entirely in the [animation] block, and will be discussed in the animation choice section.

Frames

An animation is cut in frames. Frames are WML blocks that are contained either in [frame] WML blocks or in generic [xxx_frame] block. (the xxx part can be any string not starting with an underscore) the xxx part in the frame name is called the frame prefix. frames of the type [frame] are said to have an empty prefix

A frame typically describes an image, where an how to render it. It can contain such things as

  • the image to display
  • how transparent should that image be
  • where to draw that image.

At any given time, an animation will display one frame for each frame prefix it can find. I.e if your animation has both [frame] and [missile_frame] blocks, both will be displayed at the same time


The frame with the empty prefix is special in many way. It is assumed to contain the image representing the unit itself, and as such the engine will heavily temper with it in multiple ways, such as providing a default image if none is available, or forcing the image to be green when the unit is poisoned

Timing, Clock, Multiple animations

When an animation is played it has an internal clock that is run. The step of this clock is the milisecond, and each frame is played for a given duration. Each animation also has a starting time which tells the animation engine at what value the animation clock should start

This starting time is very important when multiple animations from different units are played synchronously Typically a fight involves a unit playing its defense animation while the opponent plays it's attack animation (and a third might play its leading animation, too). In that case all animations have a common clock, and are played concurrently.

The convention is that the "important time" (usually the time of the hit) is at time 0. everything before should be at negative time, everything after at positive time. This is a WML convention that is not enforced by the engine


In that case, it is very important that these animations (which can have different lengths) be synchronized. Fight animations are synchronized around the point of impact, so they all reach time 0 when the attack lands (or misses).


The content of a frame

Syntax summary

[frame]
   duration=<integer>
   begin=<deprecated,integer>
   end=<deprecated,integer>
   image=<string>
   image_diagonal=<string>
   sound=<string>
   halo=<progressive string>
   halo_x=<progressive int>
   halo_y=<progressive int>
   alpha=<progressive float>
   offset=<progressive float>
   blend_color=< red, green, blue >
   blend_ratio=<progressive float>
   text=<string>
   text_color=< red, green, blue >
[/frame]

Progressive parameters

Some parameters above are marked as progressive This means that you can specify that during the time the frame is displayed, the parameter should smoothly slide from one value to an other.

A typical example would be a unit progressively fading out, becoming transparent

To do that, you could use:

alpha=1~0

To make a frame, which is 900ms long, slide to transparent for 300ms, stay transparent for another 300ms and finally fade back to normal for 300ms, use:

alpha=1~0:300,0:300,0~1:300

you could also specify it like that

alpha=1~0,0,0~1

when a timing is missing, the engine will do its best to fill in in a fair way.

a progressive string has a similar syntax

halo=halo1.png:300,halo2.png:300,halo2.png:300

Field Description

    • begin: (deprecated) will be replaced by duration= <end - begin >
    • end: (deprecated) see begin
    • duration: how long the frame should be displayed. Use instead of begin= and end=.
    • image: the image to display during the frame.
    • image_diagonal: the image to display when the attack occurs diagonally (directions ne,se,sw,nw).
    • sound: the sound to play when the frame begins. Can be a comma-separated list of sounds, in which case one of them is chosen randomly every time.
    • halo: the halo to display at the time.
    • halo_x: the position the halo is displayed in pixel relative to the unit's center.
    • halo_y: the position the halo is displayed in pixel relative to the unit's center.
    • alpha: transparency level to apply to the frame. This is a floating point progressive parameter ranging from 0.0 to 1.0.
    • offset: the position of the image relative to the hex the unit is facing, 0.0 will display the unit in the center of the hex, 1.0 in the center of the faced hex, -1.0 at the center of the hex behind you. This is a progressive parameter.
    • blend_color: a comma separated list of numbers representing a color in RGB (0-255) this color will be mixed to the frame to give it a tint.
    • blend_ratio: this is a progressive parameter ranging from 0 to 1: 0 means no tint, 1 means target color only.
    • text: if specified, floats a label with the given text above the unit (identical to the floating damage and healing numbers).
    • text_color: the color of the above floating label.

Drawing related animation content

Syntax summary

[animation]
  <animation choice related content>
  [frame]
    <frame content>
  [/frame]
  [frame]
    <frame content>
  [/frame]
  start_time=<integer>
  offset=<progressive float>
  blend_with=<r,g,b>
  blend_ratio=<progressive float>
  halo=<progressive_string>
  halo_x=<progressive int>
  halo_y=<progressive int>
  
  [xxx_frame]
    <frame content>
  [/xxx_frame]
  xxx_start_time=<integer>
  xxx_offset=<progressive float>
  xxx_blend_with=<r,g,b>
  xxx_blend_ratio=<progressive float>
  xxx_halo=<progressive_string>
  xxx_halo_x=<progressive int>
  xxx_halo_y=<progressive int>
[/animation]

Parameter handling

All drawing related parameters in [animation] can be matched with a corresponding parameter in a [frame] block (or a [xxx_frame] block) The value provided in the animation will be used if no value is provided in the frame.

The point of these two level of parameters is to easily be able to specify a parameter at the animation level and override it for a special case of frame.


How animations are chosen

Within a unit decription block there are multiple animations. Each animation is meant to be played in a very special set of circumstances. We will discuss here how to tell the animation engine when a given animation should be played.

Let's take an example. Suppose we have a unit which has the skirmisher ability. We have the folowing movement animations :

  • a normal walking animation
  • a swimming animation when the unit is in water
  • a tiptioeing animation when moving next to an ennemy unit

Ok. most of the time it's easy to guess what animation should be. However if you are both in water and next to an ennemy unit, the animation to play is not obvious.

To solve that question, each animation has a number of filtering criterias. The engine follow the following rules to select an animation

  • Start with all animations
  • Drop all animations with a criteria that fails on the current situation
  • Take the animations that have the most maching criterias
  • If there are more than one animation remaining, take an animation randomly
  • If all animations have been droped, the engine will provide a smart default.

here is a pseudo-code explaination of this algorithm

foreach animation
   animation_score = 0
   foreach filter-criteria
     if <criteria-fails> 

animation_score = -1; break;

     elsif <criteria-matches> 

animation_score++

   endfor
   if animation_score > max_score

<empty animation list> max_score = animation_score; push(animation,animation_list);

   elsif animation_score = max_score

push(animation,animation_list);

endfor
<choose an animation randomly from animation_list>


Note that all animations don't have all the filters...

so, if we have a unit with

  1. an animation for water terrain
  2. an animation for SE on grassland
  3. an animation with no criteria
  4. an animation for N,NE,NW,S,SW,SE
  5. an animation for NW
  • 3. will never be taken, because 4. will always trump it
  • on water going NW, it can be 1. 4. 5.
  • on water, any direction but NW, it will be 1. or 4.
  • on SE grassland it will be 2.
  • on other grasslands, it will be 4. (4. or 5. if NW)

Generic animation filters available for all animations

  • apply_to: a list of comma separated keywords describing what event should trigger the animation (movement, attack...) the complete list is given below
  • value: a list of comma separated integer, the meaning depends on the triggering event. the meaning is given with the list of event
  • terrain: a list of comma separated terrain letters, the animation will only be used on these terrains. See FilterWML.
  • [unit_filter]: this will filter using a standard unit filter on the animated unit. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple [unit_filter] blocks in an animation.
  • [secondary_unit_filter]: this will filter using a standard unit filter on the unit in the hex faced. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple [secondary_unit_filter] blocks in an animation. Also note that if the faced hex is empty, the whole filter will fail
  • direction: a list of directions (n,ne,se,s,sw,nw), the animation will only be used when acting or moving in this direction (the attack direction for attack animations, moving direction for movement animations, direction of lead unit for leading animations, and so on).
  • frequency: this integer value allows to easily tweak the matching frequency of animations. The filter will fail n-1 times out of n, randomly. Note that unlike every other filter, matching this filter won't give an extra point.
  • [attack_filter]: a standard attack filter to match on the attacker's attack. See FilterWML.
  • [secondary_attack_filter]: a standard attack filter to match on the defender's attack. See FilterWML. Also note that if the defender doesn't have any weapon to retaliate with, this filter will always fail.
  • hits: filters attack animations based on whether the attack hits, misses or kills. Accepts a list of the following:
    • hit: the attack hits, defender survives.
    • no or miss: the attack misses.
    • kill: the attack hits, defender dies.
    • yes: is an alias of hit,kill.
  • swing: a list of numbers representing the swing numbers this animation should match (numbered from 1).

Events trigerring animations and default animations

standing

This animation is triggered whenever any other animation is finished, and is played in loop until another animation is triggered

this is the default "standing image" for the unit

value= is not used, and always contains 0

if no standing animation is set a single frame animation based on the enclosing unit's image= field is used

selected

This animation is triggered whenever the unit is selected

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_with="0.0~0.3:100,0.3~0.0:200" blend_color=255,255,255

recruited

This animation is triggered whenever the unit is recruited or recalled

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with highlight=0~1:600

levelin

This animation is triggered whenever the unit levels, before the unit is replaced by the new unit

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_with="1~0:600" blend_color=255,255,255

levelout

This animation is triggered whenever the unit levels, after the unit is replaced by the new unit

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_with="0~1:600" blend_color=255,255,255

movement

This animation is used whenever a unit moves. There are multiple things to consider when dealing with movement animation

  • unit stay exactly 150ms in each hex. so you typically want to have an offset of 0~1:150,0~1:150,0~1:150,0~1:150,0~1:150 or something similar
  • when a unit enters a hex, the current anim is tested again.
    • if the current animation is still valid (i.e it passes all its filter) it is kept, whatever the final score is
    • if it fails, a new movement anim is searched

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with offset="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150"

pre_teleport

This animation is triggered whenever the unit teleports, but before it has moved to the target hex

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_with="1~0:150" blend_color=255,255,255

post_teleport

This animation is triggered whenever the unit teleports, but after it has moved to the target hex

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_with="0~1:150" blend_color=255,255,255

healing

This animation is triggered when the unit has healing powers and uses them

value= is the number of points healed

No default is provided by the engine

healed

This animation is triggered whenever the unit is healed for any reason

value= is the number of points healed

if no animation is available, the default uses the standing animation(s) with blend_with="0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30" blend_color=255,255,255 and plays the sound heal.wav

poisoned

This animation is triggered whenever the unit suffers poison dammage

value= is the number of points lost

if no animation is available, the default uses the standing animation(s) with blend_with="0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30" blend_color=0,255,0 and plays the sound 'poison.ogg

defend

This animation is triggered during a strike, of the unit receiving the blow

value= is the number of point lost, if any

No default is provided by the engine

attack

This animation is triggered during a strike, of the unit giving the blow

value= is the number of damage dealt, if any

if no animation is available, the default uses the standing animation(s) with offset="0~0.6:150,0.6~0:150" for melee attacks No default is provided for range attacks

leading

This animation is triggered for units with the leading special ability, when the unit they are leading is attacking

value= is not used, and always contains 0

No default is provided by the engine

death

This animation is triggered when a unit die.

value= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with highlight=1~0:600 and plays the sound in die_sound= of the enclosing unit

victory

This animation is triggered when a unit finishes a fight by killing the other unit

value= is not used, and always contains 0

No default is provided by the engine

idling

This animation is called when the unit has been using its standing animation for a random duration.

value= is not used, and always contains 0

No default is provided by the engine

extra animations

Other values are never called by the engine. However they can be triggered by WML events allowing custom animations.

Note that WML events can also trigger standard animations. value= is set from the WML event

Shortcuts, tricks and quirks

[if] and [else]

Often, you need to do very slight variations in an animation (like a different sound depending on whether the unit hits or misses its attack), the [if] and [else] tags are meant to help you do that.

Using these in an animation is equivalent to having multiple animations, one with the [if] block and one with each of the [else] blocks. Any filtering flags in these blocks will replace the toplevel filters. You can have multiple [if] blocks in an animation, but you can't nest an [if] inside another. These should be written directly inside the [animation] block. The following example would make the [frame] inside the [if] be played when the attack misses, and the [frame] inside the [else] be played when the attack hits (producing a different sound):

   [if]
       hits=no
       [frame]
           begin=-100
           end=100
           image="units/dwarves/lord-attack.png"
           sound={SOUND_LIST:MISS}
       [/frame]
   [/if]
   [else]
       hits=yes
       [frame]
           begin=-100
           end=100
           image="units/dwarves/lord-attack.png"
           sound=axe.ogg
       [/frame]
   [/else]

note that this is very close to preprocessing and should be considered as such, especially with regard to scoring and animation selection

Simplified animation blocks

To simplify the most common animation cases, you can use different blocks instead of the generic [animation] block. These are also here for backward compatibility, but are not deprecated and fully supported

some of these use extra tags which are translated in the normal value= tag

some of these define [xxx_frame] blocks where the frame prefix starts with an underscore. This is not allowed in normal WML (prefix starting with underscore is reserved for the engine internal use). It is here for clarity purpose

  • [leading_anim] is an animation with the following parameters automatically set
apply_to=leading
  • [recruit_anim] is an animation with the following parameters automatically set
apply_to=recruited
  • [standing_anim] is an animation with the following parameters automatically set
apply_to=standing,_default_
  • [idle_anim] is an animation with the following parameters automatically set
apply_to=idling
  • [levelin_anim] is an animation with the following parameters automatically set
apply_to=levelin
  • [levelout_anim] is an animation with the following parameters automatically set
apply_to=levelout
  • [healing_anim] is an animation with the following parameters automatically set
apply_to=healing
value=<damage= value>
  • [healed_anim] is an animation with the following parameters automatically set
apply_to=healed
value=<healing= value>
[_healed_sound_frame]
   sound=heal.wav
[/_healed_sound_frame]
  • [poison_anim] is an animation with the following parameters automatically set
apply_to=poisoned
value=<damage= value>
[_poison_sound_frame]
   sound=poison.ogg
[/_poison_sound_frame]
  • [movement_anim] is an animation with the following parameters automatically set
apply_to=movement
offset="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150"
  • [defend] is an animation with the following parameters automatically set
apply_to=defend
value=<damage= value>
<WML content>
[frame]
   blend_with=255,0,0
   blend_ratio="0.5:50,0.0:50"
[/frame]

there are some subtil change compared to what is described above to avoid the red flash when value=0, but it should work as expected as far as WML author are concerned

  • [attack_anim] is an animation with the following parameters automatically set

if the animation contains a missile frame

apply_to=attack
missile_offset="0~0.8"

else

apply_to=attack
offset="0~0.6,0.6~0"
  • [death] is an animation with the following parameters automatically set
apply_to=death
[_death_sound_frame]
   sound=<die_sound= of the enclosing [unit] tag>
[/_death_sound_frame]
  • [victory_anim] is an animation with the following parameters automatically set
apply_to=victory
  • [extra_anim] is an animation with the following parameters automatically set
apply_to=<flag= value of the anim>
  • [teleport_anim] will be cut into two at the clock-time 0

everything before zero becomes an animation with the following parameters automatically set

apply_to=pre_teleport

everything after zero becomes an animation with the following parameters automatically set

apply_to=post_teleport

See Also