Difference between revisions of "AnimationWML"

From The Battle for Wesnoth Wiki
(Merging the animation WML pages a bit.)
(134 intermediate revisions by 23 users not shown)
Line 1: Line 1:
 
{{WML Tags}}
 
{{WML Tags}}
  
'''The page is getting a bigger overhaul, so things are a bit messy right now.'''
+
== Introduction ==
  
== Animation and sound ==
+
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.
  
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.
+
This page will deal with the two problems of animations
 +
* How are animations chosen
 +
* What exactly is drawn
  
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.
 
  
All unit animations use the same engine, so most tags and keys are common for all animations types.
 
  
=== [animation] blocks ===
+
== How animations are drawn ==
 +
=== 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)
  
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).
+
events and conditions are described entirely in the [animation] block, and will be discussed in the animation choice section.
  
Individual animation frames are described by ''[frame]'' tags.
+
=== 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
  
* '''[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).
+
A frame typically describes an image, where an how to render it. It can contain such things as
** '''[frame]''' describes what an animation should display at a given time. Several frames cannot be displayed at the same time.
+
* the image to display
*** ''begin'' the time at which this frame should start (in milliseconds).
+
* how transparent should that image be
*** ''end'' the time at which the animation should end.
+
* where to draw that image.
*** ''duration'' {{DevFeature}} how long the frame should be displayed. Use instead of ''begin='' and ''end=''.
+
 
*** ''image'' the image to display during the frame.
+
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
*** ''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.
+
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
*** ''halo_y'' the position the halo is displayed in pixel relative to the unit's center.
+
 
*** ''alpha'' {{DevFeature}} transparency level to apply to the frame. This is a floating point progressive parameter ranging from 0.0 to 1.0.
+
=== Timing, Clock, Multiple animations ===
*** ''offset'' {{DevFeature}} 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.
+
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
*** ''blend_color'' {{DevFeature}} 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'' {{DevFeature}} this is a progressive parameter ranging from 0 to 1: 0 means no tint, 1 means target color only.
+
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 its attack animation (and a third might play its leading animation, too). In that case all animations have a common clock, and are played concurrently.
** '''[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).
+
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). This is accomplished through the use of the '''start_time''' key of the '''[animation]''' tag.
 +
 
 +
Just like the '''[frame]''' tag can have a prefix, so can the '''start_time''' key. A '''start_time''' key without prefix will affect a '''[frame]''' tag without prefix, while a '''start_time''' key with a prefix will affect a '''[frame]''' tag with the same prefix.
 +
 
 +
==== Example Syntax ====
 +
<syntaxhighlight lang=wml highlight=5,11,29>
 +
[attack_anim]
 +
    [filter_attack]
 +
        name=bow
 +
    [/filter_attack]
 +
    missile_start_time=-150
 +
    [missile_frame]
 +
        duration=150
 +
        image="projectiles/missile-n.png"
 +
        image_diagonal="projectiles/missile-ne.png"
 +
    [/missile_frame]
 +
    start_time=-200
 +
    [frame]
 +
        image=units/bowshooter.png:25  #because defense animations could possibly
 +
                                      #be longer and if so this image will display
 +
                                      #Also gives a bit of a pause before attacking
 +
    [/frame]
 +
    [frame]
 +
        image=units/bowshooter-prepare-bow.png:25
 +
    [/frame]
 +
    #now the time is synchronized with the missile frame for the arrow
 +
    [frame]
 +
        image=units/bowshooter-fire-bow[1~3].png:50
 +
    [/frame]
 +
    [frame]
 +
        image=units/bowshooter.png:25  #because defense animations could possibly
 +
                                      #be longer and if so this image will display
 +
                                      #Also gives a bit of a pause after attacking
 +
    [/frame]
 +
    sound_start_time=-150
 +
    [if]
 +
        hits=yes
 +
        [sound_frame]
 +
            sound=bow.ogg
 +
        [/sound_frame]
 +
    [/if]
 +
    [else]
 +
        hits=no
 +
        [sound_frame]
 +
            sound=bow-miss.ogg
 +
        [/sound_frame]
 +
    [/else]
 +
[/attack_anim]
 +
</syntaxhighlight>
 +
Note: that the arrow hits the target at time=0. Defense hit sounds are typically played at time=-25, slightly before the arrow hits the centre of the hex (the unit would feel it slightly before). It is the same idea for sword swishes and such, that 'hit' the outside of the unit before they hit the centre of the hex.
 +
 
 +
=== The content of a frame ===
 +
==== Syntax summary ====
 +
[frame]
 +
    duration=<integer>
 +
    begin=<deprecated,integer>
 +
    end=<deprecated,integer>
 +
    image=<string, dev feature 1.11.2 - progressive string>
 +
    image_diagonal=<string, dev feature 1.11.2 - progressive string>
 +
    image_mod=<string>
 +
    sound=<string>
 +
    halo=<progressive string>
 +
    halo_x=<progressive int>
 +
    halo_y=<progressive int>
 +
    halo_mod=<string>
 +
    alpha=<progressive float>
 +
    offset=<progressive float>
 +
    blend_color=<red, green, blue>
 +
    blend_ratio=<progressive float>
 +
    text=<string>
 +
    text_color=< red, green, blue >
 +
    submerge=<progressive float>
 +
    x=<progressive int>
 +
    y=<progressive int>
 +
    directional_x=<progressive int>
 +
    directional_y=<progressive int>
 +
    layer=<progressive int>
 +
    auto_hflip=<boolean>
 +
    auto_vflip=<boolean>
 +
    primary=<boolean>
 +
[/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 44: Line 138:
 
  alpha=1~0:300,0:300,0~1:300
 
  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 an expanded syntax:
 +
 +
image=image1.png:100,image2.png:100,image3.png:100
 +
halo=halo1.png:100,halo2.png:200,halo3.png:300
 +
 +
or (from Wesnoth 1.11.2+) equivalently,
 +
image=image[1~3]:100
 +
halo=halo[1~3]:[100,200,300]
 +
see below for more information.
 +
 +
==== Progressive string square bracket expansion syntax ====
 +
 +
The square bracket syntax for progressive strings is a syntactic shortcut that, for convenience, works like so:
 +
 +
{|class=wikitable valign=top
 +
! This expression… !! …is equivalent to this…
 +
|-
 +
| <tt>halo=halo[3,5,7].png</tt> || <tt>halo=halo3.png,halo5.png,halo7.png</tt>
 +
|-
 +
| <tt>halo=halo[07~10].png</tt> || <tt>halo=halo07.png,halo08.png,halo09.png,halo10.png</tt><sup>*</sup>
 +
|-
 +
| <tt>halo=halo[001~100].png</tt> || <tt>halo=halo001.png,halo002.png,...,halo099.png,halo100.png</tt>
 +
|-
 +
| <tt>halo=halo[5~3,1].png</tt> || <tt>halo=halo5.png,halo4.png,halo3.png,halo1.png</tt>
 +
|-
 +
| <tt>image=image[1~2]-ex[4~5].png:[100,200]</tt> || <tt>image=image1-ex4.png:100,image2-ex5:200.png</tt>
 +
|-
 +
| <tt>image=image[1~4].png:[10,20*3]</tt> || <tt>image1.png:10,image2.png:20,image3.png:20,image4.png:20</tt>
 +
|-
 +
| <tt>image=image[1~3].png:50,other.png:40</tt> || <tt>image1.png:50,image2.png:50,image3.png:50,other.png:40</tt>
 +
|}
 +
<sup>*</sup><small>(if you include leading zeros, the digits will be padded throughout that square bracket expansion to match)</small>
  
 +
Each set of square brackets (‘[’ and ‘]’) contains a comma-separated list — an '''''expansion list''''' — of which each element can be:
  
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.
+
* a '''plain string''' — e.g., “abc” or “123”;
 +
* a '''range''', expressed as two radix-10 integers, separated by a tilde — e.g., “1~5”; or
 +
* a '''repetition''', notated as a string and a radix-10 integer, separated by an asterisk — e.g., “a*3”.
  
'''Generic animation filters available for all animations'''
+
Ranges can not only be from a lesser number to a greater number (e.g., “1~5”), but can also be '''backward''' — from a greater number to a lesser number (e.g., “5~1”).
** ''terrain'' a list of comma separated terrain letters, the animation will only be used on these terrains.
 
** ''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).
 
  
'''Fighting animation filters'''
+
===== Range expansion =====
** ''hits'' filters attack animations based on whether the attack hits, misses or kills. Accepts a list of the following:
 
*** ''yes'' or ''hit'' the attack hits, defender survives.
 
*** ''no'' or ''miss'' the attack misses.
 
*** ''kill'' the attack hits, defender dies.
 
** ''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.
 
  
 +
Each '''range''' ''<var>x</var>~<var>y</var>'' is expanded within its expansion list to a comma-separated list of radix-10 integers (which are plain strings), starting from the first endpoint <var>x</var> and ending at the second endpoint <var>y</var>.
  
 +
If '''<var>x</var> < <var>y</var>''', then the numbers in this list increase by increments of 1; if '''<var>x</var> > <var>y</var>''', then the numbers in this list decrease by decrements of 1. E.g., “1~3” would become “1,2,3”, and “3~1” would become “3,2,1”.
  
==== Standing animation: ''[standing_anim]'' ====
+
If '''<var>x</var> = <var>y</var>''', then this list has only one element, which is <var>x</var> (and is also <var>y</var>, of course). E.g., “2~2” would becomes “2”.
  
This animation is used when a unit is standing and doing nothing.
+
If either <var>x</var> or <var>y</var> (or both) are padded with '''leading zeros''', then each number in the resultant list will be padded with leading zeros such that it is expressed in at least <var>z</var>+1 digits, where <var>z</var> is the quantity of leading zeros with which one or both endpoints are padded. E.g.,
 +
* “07~11” would become “07,08,09,10,11”,
 +
* “098~100” would become “98,99,100”,
 +
* “003~1” (or “3~001”) would become “003,002,001”, and
 +
* “0098~100” would become “098,099,100” (although poor form), and
 +
* “01~100” would become “01,02,...,10,11,...,99,100”.
  
==== Leading animation: ''[leading_anim]'' ====
 
  
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 both endpoints are padded with leading zeros, they should both be padded with the same quantity of leading zeros.
  
==== Healing animation: ''[healing_anim]'' ====
+
===== Repetition expansion =====
  
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.
+
Each '''repetition''' ''<var>s</var>*<var>n</var>'' is expanded within its expansion list to a comma-separated list with <var>n</var> elements, each of which is the string <var>s</var>. E.g., “abc*3” would become “abc,abc,abc”.
  
==== Recruited animation: ''[recruit_anim]'' ====
+
===== Square bracket expansion =====
  
This animation is used when a unit is recruited or created via a plague special ability.
+
A single '''progressive string value''' may contain multiple '''square-bracketed expansion lists''', which must all be of the same length in elements (after range and repetition expansion). This length shall be referred to as <var>L</var> for the remainder of this section.
  
==== Movement animation: ''[movement_anim]'' ====
+
When a progressive string that contains expansion lists is processed to expand its expansion lists, it is transformed into a comma-separated list with <var>L</var> elements.
  
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).
+
For each integer <var>n</var> from 1 to <var>L</var>, the <var>n</var>-th element of this list shall be a copy of the progressive string, with each expansion list it contains replaced with that expansion list’s <var>n</var>-th element (after range and repetition expansion).
  
==== Death animation: ''[death]'' ====
+
When a progressive string that contains expansion lists is processed it is transformed at each bracket pair into a comma-separated list, which is generated as follows (in pseudo code):
 +
for each comma separated string entry
 +
for all square brackets entries at once
 +
expand outwards such that S[A~B]T expands to SAT, ..., SBT preserving any leading zeros
 +
expand outwards such that S[A,B]T expands to SAT, SBT
 +
expand outwards such that S[A*N]T expands to SAT, ..., SAT (n times)
 +
and any combination of above separated by commas executed sequentially
 +
next
 +
next
  
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.
+
==== Field Description ====
  
==== Defensive animation: ''[defend]'' ====
+
* '''begin''': (deprecated) will be replaced by '''duration= <end - begin >'''
 +
* '''end''': (deprecated) see '''begin''' and also [[AnimationWML#Timing.2C_Clock.2C_Multiple_animations|Timing, Clock, Multiple animations]] section for coverage of '''start_time''' which combines with '''duration''' to replace '''begin=''' '''end='''.
 +
* '''duration''': how long the frame should be displayed. Use instead of '''begin=''' and '''end='''. If specified by timing in a progressive string, such as a halo, this can be left out and will be automatically calculated.
 +
* '''image''': the image, or sequence of images, to display during the frame.
 +
* '''image_diagonal''': the image, or sequence of images, to display when the attack occurs diagonally (directions ne,se,sw,nw).
 +
* '''image_mod''': a string modifications (see [[ImagePathFunctions]] ) that will be applied to all images
 +
* '''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''', '''halo_y''': the position the halo is displayed in pixel relative to the unit's center. These are directional, taking into account the direction the unit is facing.
 +
* '''halo_mod''': a string modifications (see [[ImagePathFunctions]] ) that will be applied to all haloes
 +
* '''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.
 +
* '''submerge''': the part of the unit that should drawn with 50% opacity (for units in water)
 +
* '''x''': x offset applied to the frame
 +
* '''y''': y offset applied to the frame
 +
* '''directional_x''': the x offset, in pixels, applied to the frame in the direction the unit is facing
 +
* '''directional_y''': the y offset, in pixels, applied to the frame in the direction the unit is facing
 +
* '''layer''': layer used to draw the frame, see discussion bellow
 +
* '''auto_hflip''': should the image flip horizontally depending on sprite orientation
 +
* '''auto_vflip''': should the image flip vertically depending on sprite orientation
 +
* '''primary''': should the engine consider that frame as a primary frame (affected by visual effects like stone and poison)
  
This animation is used when facing a blow in a fight. The defending unit is always facing the attacking unit.
+
=== 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>
 +
  image_mod=<string>
 +
  blend_color=<r,g,b>
 +
  blend_ratio=<progressive float>
 +
  halo=<progressive_string>
 +
  halo_x=<progressive int>
 +
  halo_y=<progressive int>
 +
  halo_mod=<string>
 +
  alpha=<progressive float>
 +
  submerge=<progressive float>
 +
  x=<progressive int>
 +
  y=<progressive int>
 +
  directional_x=<progressive int>
 +
  directional_y=<progressive int>
 +
  layer=<progressive int>
 +
 
 +
  [xxx_frame]
 +
    <frame content>
 +
  [/xxx_frame]
 +
  xxx_start_time=<integer>
 +
  xxx_image_mod=<string>
 +
  xxx_offset=<progressive float>
 +
  xxx_blend_color=<r,g,b>
 +
  xxx_blend_ratio=<progressive float>
 +
  xxx_halo=<progressive_string>
 +
  xxx_halo_x=<progressive int>
 +
  xxx_halo_y=<progressive int>
 +
  xxx_halo_mod=<string>
 +
  xxx_alpha=<progressive float>
 +
  xxx_submerge=<progressive float>
 +
  xxx_x=<progressive int>
 +
  xxx_y=<progressive int>
 +
  xxx_directional_x=<progressive int>
 +
  xxx_directional_y=<progressive int>
 +
  xxx_layer=<progressive int>
 +
 +
[/animation]
  
==== Attack animation: ''[animation]'' within an ''[attack]'' block ====
+
==== 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.
  
This animation is played when a unit attempts a blow on another unit. The attacking unit is always facing the defending unit.
+
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.
  
Also note that unlike all other animations, this one is in the ''[attack]'' block, not directly in the ''[unit]'' block. Please see the special case of the ''[missile_frame]'' below.
+
Note that xxx_ parameters (e.g. missile_offset) are shortcuts to access parameters from outside of their corresponding frame and have no effect inside of them.
  
 
== How animations are chosen ==
 
== How animations are chosen ==
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?
+
Within a unit description 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.
  
The animation engine always uses the same rules to choose an animation.
+
Let's take an example. Suppose we have a unit which has the skirmisher ability. We have the following movement animations :
I will take the example from movement animations.
+
* a normal walking animation
 +
* a swimming animation when the unit is in water
 +
* a tiptoeing animation when moving next to an enemy unit
  
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.
+
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 enemy unit, the animation to play is not obvious.
  
So, the engine takes all movement animations and assign it a score with the following algorithm:
+
To solve that question, each animation has a number of filtering criteria. The engine follow the following rules to select an animation
 +
* Start with all animations
 +
* Drop all animations with a criterion that fails on the current situation
 +
* Take the animations that have the most matching criteria
 +
* If there are more than one animation remaining, take an animation randomly
 +
* If all animations have been dropped, the engine will provide a smart default.
 +
   
 +
here is a pseudo-code explanation of this algorithm:
  
the animation starts with a score of 0
+
foreach animation
for each criteria,
+
    animation_score = 0
* if filter is not there, the score is unchanged
+
    foreach filter-criteria
* if filter is not matched the animation is given a score of -1 and the algorithm ends (disqualified)
+
      if <criteria-fails>
* if filter is matched, the score is increased by one
+
          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>
  
After that, the engine takes all top score animations and chooses a random one.
+
 +
Note that all animations don't have all the filters...
  
 
so, if we have a unit with
 
so, if we have a unit with
Line 120: Line 354:
 
# an animation with no criteria
 
# an animation with no criteria
 
# an animation for N,NE,NW,S,SW,SE
 
# an animation for N,NE,NW,S,SW,SE
# an animatio for NW
+
# an animation for NW
  
 
* 3. will never be taken, because 4. will always trump it
 
* 3. will never be taken, because 4. will always trump it
Line 128: Line 362:
 
* on other grasslands, it will be 4. (4. or 5. if NW)
 
* on other grasslands, it will be 4. (4. or 5. if NW)
  
== ''[if]'' and ''[else]'' ==
+
=== 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
 +
* '''value_second''': a list of comma separated integer, the meaning depends on the triggering event. the meaning is given with the list of event
 +
* '''terrain_type''': a list of comma separated terrain codes, the animation will only be used on matching terrains.  See [[FilterWML#Filtering Terrains|Filtering Terrains]].
 +
* '''[filter]''': this will filter using a [[StandardUnitFilter|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 '''[filter]''' blocks in an animation.
 +
* '''[filter_second]''': this will filter using a [[StandardUnitFilter|standard unit filter]] on the unit in the hex faced. Note that matching all criteria in the filter will only earn you one point for animation selection, but that you can have multiple '''[filter_second]''' 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.
 +
* '''[filter_attack]''': a standard attack filter to match on the attacker's attack. See  [[FilterWML#Filtering Weapons|Filtering Weapons]].
 +
* '''[filter_second_attack]''': a standard attack filter to match on the defender's attack. See [[FilterWML#Filtering Weapons|Filtering Weapons]]. 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). this has been replaced by value_second
 +
* '''base_score''': a number that will always be added to the score. Use with caution
 +
 
 +
=== Events triggering 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
 +
 
 +
''value_second='' 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
 +
 
 +
''value_second='' is not used, and always contains 0
 +
 
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="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
  
If you need to do very slight variations in an anim (like a different sound depending on whether the unit hits or misses it's 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):
+
''value='' is not used, and always contains 0
  
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''alpha=0~1:600''
 +
 +
==== recruiting ====
 +
 +
This animation is triggered for the leader when a unit is recruited or recalled
 +
 +
''value='' is not used, and always contains 0
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
no default animation is needed
 +
 +
note that is not triggered for WML triggered animations
 +
 +
==== levelout ====
 +
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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="0~1:600" blend_color=255,255,255''
 +
 +
==== levelin ====
 +
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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="1~0: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'' 200ms in each hex. so you typically want to have an offset of ''0~1:200,0~1:200,0~1:200,0~1:200,0~1:200'' 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='' contains the number of steps already taken
 +
 +
''value_second='' contains the number of steps left
 +
 +
if no animation is available, the default uses the standing animation(s) with ''offset="0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200"''
 +
 +
==== pre_movement ====
 +
This animation is used before any unit movement
 +
 +
''value='' is not used, and always contains 0
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
==== post_movement ====
 +
This animation is used after any unit movement
 +
 +
''value='' is not used, and always contains 0
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
==== 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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="1~0:200" 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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="0~1:200" 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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="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 damage
 +
 +
''value='' is the number of points lost
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''blend_ratio="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
 +
 +
''value_second='' is the number of the swing, starting from 1
 +
 +
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
 +
 +
''value_second='' is the number of the swing, starting from 1
 +
 +
if no animation is available, the default uses the standing animation(s) with ''offset="0~0.6:200,0.6~0:200"'' 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
 +
 +
''value_second='' is the number of the swing, starting from 1
 +
 +
No default is provided by the engine
 +
 +
 +
==== resistance ====
 +
This animation is triggered for units with the resistance special ability affecting neighbouring fights, when the unit they are helping is defending
 +
 +
''value='' is not used, and always contains 0
 +
 +
''value_second='' is the number of the swing, starting from 1
 +
 +
No default is provided by the engine
 +
 +
==== death ====
 +
This animation is triggered when a unit die.
 +
 +
''value='' is not used, and always contains 0
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
if no animation is available, the default uses the standing animation(s) with ''alpha=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
 +
 +
''value_second='' 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
 +
 +
''value_second='' is not used, and always contains 0
 +
 +
No default is provided by the engine
 +
 +
==== draw_weapon ====
 +
This animation is played before a fight
 +
 +
''hit='' is set to HIT for the attacker and MISS for the defender
 +
 +
No default is provided by the engine
 +
 +
==== sheath_weapon ====
 +
This animation is played after a fight simultaneously for all surviving units
 +
 +
No default is provided by the engine
 +
 +
==== default ====
 +
 +
This animation is never triggered, but is used as a base to create new animations
 +
 +
''value='' is used depending of the type of animation it replaces
 +
 +
''value_second='' is used depending of the type of animation it replaces
 +
 +
A single animation made of the base frame is provided by the engine if no default animation is available
 +
 +
==== 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
 +
 +
''value_second='' 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.  ('''Attention:''' These do not have the same syntax as the action tag [if] and its subtag [else] in [[ConditionalActionsWML]].)
 +
   
 +
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, and from 1.11.7+ you can 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):
 +
 +
<syntaxhighlight lang=wml>
 +
[animation]
 +
    start_time=-100
 
     [if]
 
     [if]
 
         hits=no
 
         hits=no
 
         [frame]
 
         [frame]
            begin=-100
+
             image="units/dwarves/lord-attack.png:200"
            end=100
 
             image="units/dwarves/lord-attack.png"
 
 
             sound={SOUND_LIST:MISS}
 
             sound={SOUND_LIST:MISS}
 
         [/frame]
 
         [/frame]
Line 144: Line 621:
 
         hits=yes
 
         hits=yes
 
         [frame]
 
         [frame]
            begin=-100
+
             image="units/dwarves/lord-attack.png:200"
            end=100
 
             image="units/dwarves/lord-attack.png"
 
 
             sound=axe.ogg
 
             sound=axe.ogg
 
         [/frame]
 
         [/frame]
 
     [/else]
 
     [/else]
 +
[/animation]
 +
</syntaxhighlight>
 +
 +
note that this is very close to preprocessing and should be considered as such, especially with regard to scoring and animation selection
 +
 +
A macro exists under macros/sound-util.cfg called SOUND:HIT_AND_MISS to simplify this type of animation, which is equivalent to:
 +
 +
<syntaxhighlight lang=wml>
 +
[animation]
 +
    start_time=-100
 +
    [frame]
 +
        image="units/dwarves/lord-attack.png:200"
 +
    [/frame]
 +
    {SOUND:HIT_AND_MISS axe.ogg {SOUND_LIST:MISS} -100}
 +
[/animation]
 +
</syntaxhighlight>
 +
 +
=== 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
 +
<syntaxhighlight lang=wml>
 +
apply_to=leading
 +
</syntaxhighlight>
 +
* '''[recruit_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=recruited
 +
</syntaxhighlight>
 +
* '''[recruiting_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=recruiting
 +
</syntaxhighlight>
 +
* '''[standing_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=standing,default
 +
</syntaxhighlight>
 +
 +
i.e: the animation will be used to build default animations
 +
* '''[idle_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=idling
 +
</syntaxhighlight>
 +
* '''[levelout_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=levelout
 +
</syntaxhighlight>
 +
* '''[levelin_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=levelin
 +
</syntaxhighlight>
 +
* '''[healing_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=healing
 +
value=<damage= value>
 +
</syntaxhighlight>
 +
* '''[healed_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=healed
 +
value=<healing= value>
 +
[_healed_sound_frame]
 +
  sound=heal.wav
 +
[/_healed_sound_frame]
 +
</syntaxhighlight>
 +
* '''[poison_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=poisoned
 +
value=<damage= value>
 +
[_poison_sound_frame]
 +
  sound=poison.ogg
 +
[/_poison_sound_frame]
 +
</syntaxhighlight>
 +
* '''[movement_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=movement
 +
offset="0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200"
 +
</syntaxhighlight>
 +
* '''[pre_movement_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=pre_movement
 +
</syntaxhighlight>
 +
* '''[post_movement_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=post_movement
 +
</syntaxhighlight>
 +
* '''[draw_weapon_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=draw_weapon
 +
</syntaxhighlight>
 +
* '''[sheath_weapon_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=sheath_weapon_movement
 +
</syntaxhighlight>
 +
* '''[defend]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=defend
 +
value=<damage= value>
 +
{WML content}
 +
[frame]
 +
  blend_color=255,0,0
 +
  blend_ratio="0.5:50,0.0:50"
 +
[/frame]
 +
</syntaxhighlight>
 +
 +
there are some subtle changes 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
 +
 +
<syntaxhighlight lang=wml>
 +
apply_to=attack
 +
missile_offset="0~0.8"
 +
</syntaxhighlight>
 +
 +
else
 +
 +
<syntaxhighlight lang=wml>
 +
apply_to=attack
 +
offset="0~0.6,0.6~0"
 +
</syntaxhighlight>
 +
 +
* '''[death]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=death
 +
[_death_sound_frame]
 +
  sound=<die_sound= of the enclosing [unit] tag>
 +
[/_death_sound_frame]
 +
</syntaxhighlight>
 +
* '''[victory_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=victory
 +
</syntaxhighlight>
 +
* '''[extra_anim]''' is an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=<flag= value of the anim>
 +
</syntaxhighlight>
 +
* '''[teleport_anim]''' will be cut into two at the clock-time 0
 +
everything before zero becomes an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=pre_teleport
 +
</syntaxhighlight>
 +
everything after zero becomes an animation with the following parameters automatically set
 +
<syntaxhighlight lang=wml>
 +
apply_to=post_teleport
 +
</syntaxhighlight>
 +
 +
== Layering ==
 +
The ''layer'' progressive parameter allows the animation writer to choose in what order the animation should be drawn.
  
 +
this value must be between 0 and 100
  
 +
* the back of haloes is drawn with a value of 10
 +
* when unspecified, a animation is drawn with a value of 40
 +
* terrain elements that are supposed to go in front of units (castles) are drawn with a value of 50
 +
* orbs and status bars are drawn on layer 80
 +
* when unspecified missile frames are drawn on layer 90
  
 +
by changing these values, it is easy to have the unit display the way you want
  
 +
== Optimization ==
  
 +
there is a special flag that goes into the animation block (not the frame)
  
* '''[frame]''' In WML, animations are made using the '''[frame]''' tag. It describes one frame of an animation. The following keys are recognized for '''[frame]''':
+
* ''offscreen'' a boolean saying if the unit's animation should be played when the unit is offscreen. You want the animation to play offscreen if the animation contains some usefull sound effects.This attribute defaults to true (play offscreen) except for standing and idle animations where it defaults to false
** ''begin'' when to start displaying this frame
 
** ''end'' when to stop displaying this frame
 
** ''image'' the image to display during this frame to represent the unit
 
** ''halo'' comma separated list of halo images to be displayed around the unit. The duration of images can be given with colons after the image name - else these images will be given equal amounts of time, based on the time between ''begin'' and ''end''. It is recommended that you allow for at least 50 time units per image; i.e. ''end'' - ''beginning'' > 50 * number of halos. ''halo'' is generally used only for long-range attack animations (both [frame] and [missile_frame]). Example: <pre>halo = "img1:10,img2:20,img3:10"</pre>
 
** ''halo_x'',''halo_y'' pixel offset between the center of the ''halo'' images and the center of the unit.
 
** ''sound'' {{DevFeature}} the sound to play (at the begining) when this frame is displayed: if a comma-separated list, one is chosen randomly. If a list is used, then the same sound won't be picked from it two times in a row. The list can contain the same sound several times, which can be used for example to avoid an alternating pattern in a list of just two sounds, by changing ''sound=sound1.ogg,sound2.ogg'' to ''sound=sound1.ogg,sound2.ogg,sound1.ogg,sound2.ogg''.
 
  
The following display key/tags are recognized for '''[unit]''':
+
== Cycling ==
* ''image'' the unit image displayed on the main map when the unit is resting, and on the status table when the unit is selected. Also the default for all other unit images.
 
* ''profile'' the image displayed when the unit is talking. See [message], [[InterfaceActionsWML]].
 
* ''image_moving'' the image displayed while the unit is moving, this is deprecated in 1.1.x, see '''[movement_animation]''' below.
 
* ''image_long'' the image displayed while the unit is using a long-range (ranged) attack (can be overloaded; see '''[frame]''', '''[attack]''').
 
* ''image_short'' the image displayed while the unit is using a short-range (melee) attack (can be overloaded; see '''[frame]''', '''[attack]''').
 
* ''image_leading'',''image_healing'' the images displayed for this unit while using the 'leadership', 'heals', or 'cures' ability, if present. See also [[AbilitiesWML]].
 
* ''image_halo_healing'' a halo (see above) used together with image_healing
 
* '''[teleport_anim]''' describes an animation for when this unit teleports.
 
** '''[frame]''' see '''[frame]''' above. The frames before time 0 are displayed at the original location; the ones after are displayed at the new location.
 
* ''image_defensive'' default for ''image_defensive_long'' and ''image_defensive_short'' this is deprecated in 1.1.x see '''[defend]'''.
 
* ''image_defensive_long'' default image when the unit is defending against a long-range attack. This is deprecated in 1.1.x see '''[defend]'''.
 
* ''image_defensive_short'' default image when the unit is defending against a short-range attack. This is depecated in 1.1.x see '''[defend]'''.
 
* '''[defend]''' describes an animation for when this unit defends. Multiple [defend]s tags can be used.
 
** ''range'' if this key is present, the attack must be at this range in order for the animation to trigger. Values 'short', 'long'. {{DevFeature}}: this is a comma separated list of ranges to filter the defensive animation, values must be the same than the one in the ''range'' flag of the corresponding attack (melee and ranged for standard wesnoth)
 
** ''hits'' if this key is present, the attack must either hit('yes') or miss('no') in order for this animation to trigger.
 
** '''[frame]''' defense animation. See '''[frame]''' above.
 
* ''get_hit_sound'' the sound played (at time=0) when this unit is hit.  {{DevFeature}} If a comma-separated list, one is chosen at random.
 
* ''die_sound'' the sound played (at time=0) when the unit dies.  {{DevFeature}} If a comma-separated list, one is chosen at random.
 
* '''[death]''' describes an animation for when this unit is killed. Times before 0 are not allowed for this animation; the first frame's begin time will be displayed immediately following the unit's defense animation, regardless of whether it is before or after 0.
 
** '''[frame]''' death animation. See '''[frame]''' above.
 
* '''[extra_anim]''' {{DevFeature}} describes a unit animation that will be displayed on a '''[animate_unit]''' wml action
 
** ''flag'' this tag will be used to choose the animation to play. If a unit has more than one animaiton with a given tag, a random one will be choosen
 
** '''[frame]''' the animation itself, see '''[frame]''' above
 
* '''[movement_anim]''' describe an animation to use when the unit is moving. multiple animations are allowed
 
** ''terrain'' a comma separated list of letters, this animation will only be used on these terrains (Note this code has some bugs the fix is '''''[[User:SkeletonCrew#Branch_terrain|(SVN terrain only)]]''''').
 
** ''direction'' a comma separated list of directions, the animations will only be used when moving in these directions
 
  
The following display tags are recognized for '''[attack]''' (deprecated in 1.1.x, use the '''[animation]''' tag described in [[unitWML]] which has the same syntax):
+
there is a special boolean parameter that can be put in an animation block (not the frame)
* ''hits'' {{DevFeature}} if this key is present, the attack must either hit('yes') or miss('no') in order for this animation to trigger.
 
* ''direction'' (only in an [animation] tag ) a comma separated list of directions, the animations will only be used when moving in these directions
 
  
* '''[frame]''' unit's attack animation. For melee attacks ('''range=short'''), this animation is moved toward the enemy; otherwise it is stationary. See '''[frame]''' above for syntax.
+
* ''cycles'' a boolean value. if set to true the animation will cycles forever until it is replaced. That animation will not influence the end time of all related animations (for example a cycling defense animation will play normally but the overall duration of the fight animation will be only decided by the attack animation)
* '''[missile_frame]''' missile's animation during the attack. Only valid for ranged attacks ('''range=long''').
 
** ''begin'',''end'',''halo'',''halo_x'',''halo_y'' same as in '''[frame]''' above.
 
** ''image'' the image to display when the unit is attacking orthogonally.
 
** ''image_diagonal'' the image to display if the unit is attacking diagonally.
 
* '''[sound]''' describes a sound to play during the attack (deprecated in 1.1.x, please use the sound= line in frames instead)
 
** ''sound'' the sound to play if the attack hits.  {{DevFeature}} If a comma-separated list, one is chosen at random.
 
** ''sound_miss'' the sound to play if the attack misses.  {{DevFeature}} If a comma-separated list, one is chosen at random.
 
** ''time'' when to start playing the sound
 
  
 
== See Also ==
 
== See Also ==
  
* [[UnitWML]]
+
* [[UnitTypeWML]]
 
* [[ReferenceWML]]
 
* [[ReferenceWML]]
  
  
 
[[Category: WML Reference]]
 
[[Category: WML Reference]]

Revision as of 18:43, 12 March 2020

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

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 its 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). This is accomplished through the use of the start_time key of the [animation] tag.

Just like the [frame] tag can have a prefix, so can the start_time key. A start_time key without prefix will affect a [frame] tag without prefix, while a start_time key with a prefix will affect a [frame] tag with the same prefix.

Example Syntax

[attack_anim]
    [filter_attack]
        name=bow
    [/filter_attack]
    missile_start_time=-150
    [missile_frame]
        duration=150
        image="projectiles/missile-n.png"
        image_diagonal="projectiles/missile-ne.png"
    [/missile_frame]
    start_time=-200
    [frame]
        image=units/bowshooter.png:25  #because defense animations could possibly
                                       #be longer and if so this image will display
                                       #Also gives a bit of a pause before attacking
    [/frame]
    [frame]
        image=units/bowshooter-prepare-bow.png:25
    [/frame]
    #now the time is synchronized with the missile frame for the arrow
    [frame]
        image=units/bowshooter-fire-bow[1~3].png:50
    [/frame]
    [frame]
        image=units/bowshooter.png:25  #because defense animations could possibly
                                       #be longer and if so this image will display
                                       #Also gives a bit of a pause after attacking
    [/frame]
    sound_start_time=-150
    [if]
        hits=yes
        [sound_frame]
            sound=bow.ogg
        [/sound_frame]
    [/if]
    [else]
        hits=no
        [sound_frame]
            sound=bow-miss.ogg
        [/sound_frame]
    [/else]
[/attack_anim]

Note: that the arrow hits the target at time=0. Defense hit sounds are typically played at time=-25, slightly before the arrow hits the centre of the hex (the unit would feel it slightly before). It is the same idea for sword swishes and such, that 'hit' the outside of the unit before they hit the centre of the hex.

The content of a frame

Syntax summary

[frame]
   duration=<integer>
   begin=<deprecated,integer>
   end=<deprecated,integer>
   image=<string, dev feature 1.11.2 - progressive string>
   image_diagonal=<string, dev feature 1.11.2 - progressive string>
   image_mod=<string>
   sound=<string>
   halo=<progressive string>
   halo_x=<progressive int>
   halo_y=<progressive int>
   halo_mod=<string>
   alpha=<progressive float>
   offset=<progressive float>
   blend_color=<red, green, blue>
   blend_ratio=<progressive float>
   text=<string>
   text_color=< red, green, blue >
   submerge=<progressive float>
   x=<progressive int>
   y=<progressive int>
   directional_x=<progressive int>
   directional_y=<progressive int>
   layer=<progressive int>
   auto_hflip=<boolean>
   auto_vflip=<boolean>
   primary=<boolean>
[/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 an expanded syntax:

image=image1.png:100,image2.png:100,image3.png:100
halo=halo1.png:100,halo2.png:200,halo3.png:300

or (from Wesnoth 1.11.2+) equivalently,

image=image[1~3]:100
halo=halo[1~3]:[100,200,300]

see below for more information.

Progressive string square bracket expansion syntax

The square bracket syntax for progressive strings is a syntactic shortcut that, for convenience, works like so:

This expression… …is equivalent to this…
halo=halo[3,5,7].png halo=halo3.png,halo5.png,halo7.png
halo=halo[07~10].png halo=halo07.png,halo08.png,halo09.png,halo10.png*
halo=halo[001~100].png halo=halo001.png,halo002.png,...,halo099.png,halo100.png
halo=halo[5~3,1].png halo=halo5.png,halo4.png,halo3.png,halo1.png
image=image[1~2]-ex[4~5].png:[100,200] image=image1-ex4.png:100,image2-ex5:200.png
image=image[1~4].png:[10,20*3] image1.png:10,image2.png:20,image3.png:20,image4.png:20
image=image[1~3].png:50,other.png:40 image1.png:50,image2.png:50,image3.png:50,other.png:40

*(if you include leading zeros, the digits will be padded throughout that square bracket expansion to match)

Each set of square brackets (‘[’ and ‘]’) contains a comma-separated list — an expansion list — of which each element can be:

  • a plain string — e.g., “abc” or “123”;
  • a range, expressed as two radix-10 integers, separated by a tilde — e.g., “1~5”; or
  • a repetition, notated as a string and a radix-10 integer, separated by an asterisk — e.g., “a*3”.

Ranges can not only be from a lesser number to a greater number (e.g., “1~5”), but can also be backward — from a greater number to a lesser number (e.g., “5~1”).

Range expansion

Each range x~y is expanded within its expansion list to a comma-separated list of radix-10 integers (which are plain strings), starting from the first endpoint x and ending at the second endpoint y.

If x < y, then the numbers in this list increase by increments of 1; if x > y, then the numbers in this list decrease by decrements of 1. E.g., “1~3” would become “1,2,3”, and “3~1” would become “3,2,1”.

If x = y, then this list has only one element, which is x (and is also y, of course). E.g., “2~2” would becomes “2”.

If either x or y (or both) are padded with leading zeros, then each number in the resultant list will be padded with leading zeros such that it is expressed in at least z+1 digits, where z is the quantity of leading zeros with which one or both endpoints are padded. E.g.,

  • “07~11” would become “07,08,09,10,11”,
  • “098~100” would become “98,99,100”,
  • “003~1” (or “3~001”) would become “003,002,001”, and
  • “0098~100” would become “098,099,100” (although poor form), and
  • “01~100” would become “01,02,...,10,11,...,99,100”.


If both endpoints are padded with leading zeros, they should both be padded with the same quantity of leading zeros.

Repetition expansion

Each repetition s*n is expanded within its expansion list to a comma-separated list with n elements, each of which is the string s. E.g., “abc*3” would become “abc,abc,abc”.

Square bracket expansion

A single progressive string value may contain multiple square-bracketed expansion lists, which must all be of the same length in elements (after range and repetition expansion). This length shall be referred to as L for the remainder of this section.

When a progressive string that contains expansion lists is processed to expand its expansion lists, it is transformed into a comma-separated list with L elements.

For each integer n from 1 to L, the n-th element of this list shall be a copy of the progressive string, with each expansion list it contains replaced with that expansion list’s n-th element (after range and repetition expansion).

When a progressive string that contains expansion lists is processed it is transformed at each bracket pair into a comma-separated list, which is generated as follows (in pseudo code):

for each comma separated string entry
	for all square brackets entries at once
		expand outwards such that S[A~B]T expands to SAT, ..., SBT preserving any leading zeros
		expand outwards such that S[A,B]T expands to SAT, SBT
		expand outwards such that S[A*N]T expands to SAT, ..., SAT (n times)
		and any combination of above separated by commas executed sequentially
	next
next

Field Description

  • begin: (deprecated) will be replaced by duration= <end - begin >
  • end: (deprecated) see begin and also Timing, Clock, Multiple animations section for coverage of start_time which combines with duration to replace begin= end=.
  • duration: how long the frame should be displayed. Use instead of begin= and end=. If specified by timing in a progressive string, such as a halo, this can be left out and will be automatically calculated.
  • image: the image, or sequence of images, to display during the frame.
  • image_diagonal: the image, or sequence of images, to display when the attack occurs diagonally (directions ne,se,sw,nw).
  • image_mod: a string modifications (see ImagePathFunctions ) that will be applied to all images
  • 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, halo_y: the position the halo is displayed in pixel relative to the unit's center. These are directional, taking into account the direction the unit is facing.
  • halo_mod: a string modifications (see ImagePathFunctions ) that will be applied to all haloes
  • 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.
  • submerge: the part of the unit that should drawn with 50% opacity (for units in water)
  • x: x offset applied to the frame
  • y: y offset applied to the frame
  • directional_x: the x offset, in pixels, applied to the frame in the direction the unit is facing
  • directional_y: the y offset, in pixels, applied to the frame in the direction the unit is facing
  • layer: layer used to draw the frame, see discussion bellow
  • auto_hflip: should the image flip horizontally depending on sprite orientation
  • auto_vflip: should the image flip vertically depending on sprite orientation
  • primary: should the engine consider that frame as a primary frame (affected by visual effects like stone and poison)

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>
  image_mod=<string>
  blend_color=<r,g,b>
  blend_ratio=<progressive float>
  halo=<progressive_string>
  halo_x=<progressive int>
  halo_y=<progressive int>
  halo_mod=<string>
  alpha=<progressive float>
  submerge=<progressive float>
  x=<progressive int>
  y=<progressive int>
  directional_x=<progressive int>
  directional_y=<progressive int>
  layer=<progressive int>
  
  [xxx_frame]
    <frame content>
  [/xxx_frame]
  xxx_start_time=<integer>
  xxx_image_mod=<string>
  xxx_offset=<progressive float>
  xxx_blend_color=<r,g,b>
  xxx_blend_ratio=<progressive float>
  xxx_halo=<progressive_string>
  xxx_halo_x=<progressive int>
  xxx_halo_y=<progressive int>
  xxx_halo_mod=<string>
  xxx_alpha=<progressive float>
  xxx_submerge=<progressive float>
  xxx_x=<progressive int>
  xxx_y=<progressive int>
  xxx_directional_x=<progressive int>
  xxx_directional_y=<progressive int>
  xxx_layer=<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.

Note that xxx_ parameters (e.g. missile_offset) are shortcuts to access parameters from outside of their corresponding frame and have no effect inside of them.

How animations are chosen

Within a unit description 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 following movement animations :

  • a normal walking animation
  • a swimming animation when the unit is in water
  • a tiptoeing animation when moving next to an enemy 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 enemy unit, the animation to play is not obvious.

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

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

here is a pseudo-code explanation 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
  • value_second: a list of comma separated integer, the meaning depends on the triggering event. the meaning is given with the list of event
  • terrain_type: a list of comma separated terrain codes, the animation will only be used on matching terrains. See Filtering Terrains.
  • [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 [filter] blocks in an animation.
  • [filter_second]: this will filter using a standard unit filter on the unit in the hex faced. Note that matching all criteria in the filter will only earn you one point for animation selection, but that you can have multiple [filter_second] 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.
  • [filter_attack]: a standard attack filter to match on the attacker's attack. See Filtering Weapons.
  • [filter_second_attack]: a standard attack filter to match on the defender's attack. See Filtering Weapons. 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). this has been replaced by value_second
  • base_score: a number that will always be added to the score. Use with caution

Events triggering 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

value_second= 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

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_ratio="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

value_second= is not used, and always contains 0

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

recruiting

This animation is triggered for the leader when a unit is recruited or recalled

value= is not used, and always contains 0

value_second= is not used, and always contains 0

no default animation is needed

note that is not triggered for WML triggered animations

levelout

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

value_second= is not used, and always contains 0

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

levelin

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

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_ratio="1~0: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 200ms in each hex. so you typically want to have an offset of 0~1:200,0~1:200,0~1:200,0~1:200,0~1:200 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= contains the number of steps already taken

value_second= contains the number of steps left

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

pre_movement

This animation is used before any unit movement

value= is not used, and always contains 0

value_second= is not used, and always contains 0

post_movement

This animation is used after any unit movement

value= is not used, and always contains 0

value_second= is not used, and always contains 0

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

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_ratio="1~0:200" 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

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_ratio="0~1:200" 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

value_second= is not used, and always contains 0

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

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_ratio="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 damage

value= is the number of points lost

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with blend_ratio="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

value_second= is the number of the swing, starting from 1

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

value_second= is the number of the swing, starting from 1

if no animation is available, the default uses the standing animation(s) with offset="0~0.6:200,0.6~0:200" 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

value_second= is the number of the swing, starting from 1

No default is provided by the engine


resistance

This animation is triggered for units with the resistance special ability affecting neighbouring fights, when the unit they are helping is defending

value= is not used, and always contains 0

value_second= is the number of the swing, starting from 1

No default is provided by the engine

death

This animation is triggered when a unit die.

value= is not used, and always contains 0

value_second= is not used, and always contains 0

if no animation is available, the default uses the standing animation(s) with alpha=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

value_second= 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

value_second= is not used, and always contains 0

No default is provided by the engine

draw_weapon

This animation is played before a fight

hit= is set to HIT for the attacker and MISS for the defender

No default is provided by the engine

sheath_weapon

This animation is played after a fight simultaneously for all surviving units

No default is provided by the engine

default

This animation is never triggered, but is used as a base to create new animations

value= is used depending of the type of animation it replaces

value_second= is used depending of the type of animation it replaces

A single animation made of the base frame is provided by the engine if no default animation is available

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

value_second= 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. (Attention: These do not have the same syntax as the action tag [if] and its subtag [else] in ConditionalActionsWML.)

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, and from 1.11.7+ you can 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):

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

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

A macro exists under macros/sound-util.cfg called SOUND:HIT_AND_MISS to simplify this type of animation, which is equivalent to:

[animation]
    start_time=-100
    [frame]
        image="units/dwarves/lord-attack.png:200"
    [/frame]
    {SOUND:HIT_AND_MISS axe.ogg {SOUND_LIST:MISS} -100}
[/animation]

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
  • [recruiting_anim] is an animation with the following parameters automatically set
apply_to=recruiting
  • [standing_anim] is an animation with the following parameters automatically set
apply_to=standing,default

i.e: the animation will be used to build default animations

  • [idle_anim] is an animation with the following parameters automatically set
apply_to=idling
  • [levelout_anim] is an animation with the following parameters automatically set
apply_to=levelout
  • [levelin_anim] is an animation with the following parameters automatically set
apply_to=levelin
  • [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:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200"
  • [pre_movement_anim] is an animation with the following parameters automatically set
apply_to=pre_movement
  • [post_movement_anim] is an animation with the following parameters automatically set
apply_to=post_movement
  • [draw_weapon_anim] is an animation with the following parameters automatically set
apply_to=draw_weapon
  • [sheath_weapon_anim] is an animation with the following parameters automatically set
apply_to=sheath_weapon_movement
  • [defend] is an animation with the following parameters automatically set
apply_to=defend
value=<damage= value>
{WML content}
[frame]
   blend_color=255,0,0
   blend_ratio="0.5:50,0.0:50"
[/frame]

there are some subtle changes 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

Layering

The layer progressive parameter allows the animation writer to choose in what order the animation should be drawn.

this value must be between 0 and 100

  • the back of haloes is drawn with a value of 10
  • when unspecified, a animation is drawn with a value of 40
  • terrain elements that are supposed to go in front of units (castles) are drawn with a value of 50
  • orbs and status bars are drawn on layer 80
  • when unspecified missile frames are drawn on layer 90

by changing these values, it is easy to have the unit display the way you want

Optimization

there is a special flag that goes into the animation block (not the frame)

  • offscreen a boolean saying if the unit's animation should be played when the unit is offscreen. You want the animation to play offscreen if the animation contains some usefull sound effects.This attribute defaults to true (play offscreen) except for standing and idle animations where it defaults to false

Cycling

there is a special boolean parameter that can be put in an animation block (not the frame)

  • cycles a boolean value. if set to true the animation will cycles forever until it is replaced. That animation will not influence the end time of all related animations (for example a cycling defense animation will play normally but the overall duration of the fight animation will be only decided by the attack animation)

See Also