Difference between revisions of "AnimationWML"

From The Battle for Wesnoth Wiki
(= default {{DevFeature}})
(111 intermediate revisions by 22 users not shown)
Line 1: Line 1:
 
{{WML Tags}}
 
{{WML Tags}}
 
  
 
== Introduction ==
 
== Introduction ==
Line 7: Line 6:
  
 
This page will deal with the two problems of animations
 
This page will deal with the two problems of animations
* How are animations Chosen
+
* How are animations chosen
 
* What exactly is drawn
 
* What exactly is drawn
  
  
  
== How animations are drawned ==
+
== How animations are drawn ==
 
=== Animations ===
 
=== 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
 
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
Line 39: Line 38:
 
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
 
When an animation is played it has an internal clock that is run. The step of this clock is the milisecond, and each frame is played for a given duration. Each animation also has a starting time which tells the animation engine at what value the animation clock should start
  
This starting time is very important when multiple animations from different units are played synchronously  Typically a fight involves a unit playing its defense animation while the opponent plays it's attack animation (and a third might play its leading animation, too). In that case all animations have a common clock, and are played concurrently.
+
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
+
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.
  
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).
+
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 ===
 
=== The content of a frame ===
Line 53: Line 99:
 
     begin=<deprecated,integer>
 
     begin=<deprecated,integer>
 
     end=<deprecated,integer>
 
     end=<deprecated,integer>
     image=<string>
+
     image=<string, dev feature 1.11.2 - progressive string>
     image_diagonal=<string>
+
     image_diagonal=<string, dev feature 1.11.2 - progressive string>
 +
    image_mod=<string>
 
     sound=<string>
 
     sound=<string>
 
     halo=<progressive string>
 
     halo=<progressive string>
 
     halo_x=<progressive int>
 
     halo_x=<progressive int>
 
     halo_y=<progressive int>
 
     halo_y=<progressive int>
 +
    halo_mod=<string>
 
     alpha=<progressive float>
 
     alpha=<progressive float>
 
     offset=<progressive float>
 
     offset=<progressive float>
     blend_color=< red, green, blue >
+
     blend_color=<red, green, blue>
 
     blend_ratio=<progressive float>
 
     blend_ratio=<progressive float>
 
     text=<string>
 
     text=<string>
 
     text_color=< red, green, blue >
 
     text_color=< red, green, blue >
     submerge=<dev:progressige float>
+
     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]
 
  [/frame]
 
 
dev denotes a {{DevFeature}}
 
  
 
==== Progressive parameters ====
 
==== Progressive parameters ====
Line 91: Line 144:
 
when a timing is missing, the engine will do its best to fill in in a fair way.  
 
when a timing is missing, the engine will do its best to fill in in a fair way.  
  
a progressive string has a similar syntax
+
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
  
  halo=halo1.png:300,halo2.png:300,halo2.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:
 +
 
 +
* 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''' ''<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”.
 +
 
 +
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”.
 +
 
 +
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”.
 +
 
 +
 
 +
If both endpoints are padded with leading zeros, they should both be padded with the same quantity of leading zeros.
 +
 
 +
===== Repetition expansion =====
 +
 
 +
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”.
 +
 
 +
===== 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 <var>L</var> 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 <var>L</var> elements.
 +
 
 +
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).
 +
 
 +
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 ====
 
==== Field Description ====
  
** '''begin''': (deprecated) will be replaced by '''duration= <end - begin >'''
+
* '''begin''': (deprecated) will be replaced by '''duration= <end - begin >'''
** '''end''': (deprecated) see '''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='''.
+
* '''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 to display during the frame.
+
* '''image''': the image, or sequence of images, to display during the frame.
** '''image_diagonal''': the image to display when the attack occurs diagonally (directions ne,se,sw,nw).
+
* '''image_diagonal''': the image, or sequence of images, to display when the attack occurs diagonally (directions ne,se,sw,nw).
** '''sound''': the sound to play when the frame begins. Can be a comma-separated list of sounds, in which case one of them is chosen randomly every time.
+
* '''image_mod''': a string modifications (see [[ImagePathFunctions]] ) that will be applied to all images
** '''halo''': the halo to display at the 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_x''': the position the halo is displayed in pixel relative to the unit's center.
+
* '''halo''': the halo to display at the time.
** '''halo_y''': the position the halo is displayed in pixel relative to the unit's center.
+
* '''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.
** '''alpha''': transparency level to apply to the frame. This is a floating point progressive parameter ranging from 0.0 to 1.0.
+
* '''halo_mod''': a string modifications (see [[ImagePathFunctions]] ) that will be applied to all haloes
** '''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.
+
* '''alpha''': transparency level to apply to the frame. This is a floating point progressive parameter ranging from 0.0 to 1.0.
** '''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.
+
* '''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_ratio''': this is a progressive parameter ranging from 0 to 1: 0 means no tint, 1 means target color only.
+
* '''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.
** '''text''': if specified, floats a label with the given text above the unit (identical to the floating damage and healing numbers).
+
* '''blend_ratio''': this is a progressive parameter ranging from 0 to 1: 0 means no tint, 1 means target color only.
** '''text_color''': the color of the above floating label.
+
* '''text''': if specified, floats a label with the given text above the unit (identical to the floating damage and healing numbers).
** '''submerge''': the part of the unit that should drawn with 50% opacity (for units in water)
+
* '''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 ===
 
=== Drawing related animation content ===
Line 126: Line 265:
 
   start_time=<integer>
 
   start_time=<integer>
 
   offset=<progressive float>
 
   offset=<progressive float>
   blend_with=<r,g,b>
+
   image_mod=<string>
 +
  blend_color=<r,g,b>
 
   blend_ratio=<progressive float>
 
   blend_ratio=<progressive float>
 
   halo=<progressive_string>
 
   halo=<progressive_string>
 
   halo_x=<progressive int>
 
   halo_x=<progressive int>
 
   halo_y=<progressive int>
 
   halo_y=<progressive int>
   submerge=<dev:progressive float>
+
  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]
 
   [xxx_frame]
Line 137: Line 284:
 
   [/xxx_frame]
 
   [/xxx_frame]
 
   xxx_start_time=<integer>
 
   xxx_start_time=<integer>
 +
  xxx_image_mod=<string>
 
   xxx_offset=<progressive float>
 
   xxx_offset=<progressive float>
   xxx_blend_with=<r,g,b>
+
   xxx_blend_color=<r,g,b>
 
   xxx_blend_ratio=<progressive float>
 
   xxx_blend_ratio=<progressive float>
 
   xxx_halo=<progressive_string>
 
   xxx_halo=<progressive_string>
 
   xxx_halo_x=<progressive int>
 
   xxx_halo_x=<progressive int>
 
   xxx_halo_y=<progressive int>
 
   xxx_halo_y=<progressive int>
   xxx_submerge=<dev:progressive float>
+
  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]
 
  [/animation]
 
dev denotes a {{DevFeature}}
 
  
 
==== Parameter handling ====
 
==== Parameter handling ====
Line 154: Line 307:
 
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.
 
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 ==
 
== How animations are chosen ==
Within a unit decription block there are multiple animations. Each animation is meant to be played in a very special set of circumstances. We will discuss here how to tell the animation engine when a given animation should be played.  
+
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 folowing movement animations :
+
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 normal walking animation
 
* a swimming animation when the unit is in water
 
* a swimming animation when the unit is in water
* a tiptioeing animation when moving next to an ennemy unit
+
* 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 ennemy unit, the animation to play is not obvious.
+
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 criterias. The engine follow the following rules to select an animation
+
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
 
* Start with all animations
* Drop all animations with a criteria that fails on the current situation
+
* Drop all animations with a criterion that fails on the current situation
* Take the animations that have the most maching criterias
+
* Take the animations that have the most matching criteria
 
* If there are more than one animation remaining, take an animation randomly
 
* If there are more than one animation remaining, take an animation randomly
* If all animations have been droped, the engine will provide a smart default.
+
* If all animations have been dropped, the engine will provide a smart default.
 
      
 
      
here is a pseudo-code explaination of this algorithm
+
here is a pseudo-code explanation of this algorithm:
  
 
  foreach animation
 
  foreach animation
Line 178: Line 332:
 
     foreach filter-criteria
 
     foreach filter-criteria
 
       if <criteria-fails>  
 
       if <criteria-fails>  
  animation_score = -1;
+
          animation_score = -1;
  break;
+
          break;
 
       elsif <criteria-matches>  
 
       elsif <criteria-matches>  
  animation_score++
+
          animation_score++
 
     endfor
 
     endfor
 
     if animation_score > max_score
 
     if animation_score > max_score
<empty animation list>
+
        <empty animation list>
max_score = animation_score;
+
        max_score = animation_score;
push(animation,animation_list);
+
        push(animation,animation_list);
 
     elsif animation_score = max_score
 
     elsif animation_score = max_score
push(animation,animation_list);
+
        push(animation,animation_list);
 
  endfor
 
  endfor
 
  <choose an animation randomly from animation_list>
 
  <choose an animation randomly from animation_list>
Line 211: Line 365:
 
* '''apply_to''': a list of comma separated keywords describing what event should trigger the animation (movement, attack...) the complete list is given below
 
* '''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''': a list of comma separated integer, the meaning depends on the triggering event. the meaning is given with the list of event
* '''terrain''': a list of comma separated terrain letters, the animation will only be used on these terrains.  See [[FilterWML]].
+
* '''value_second''': a list of comma separated integer, the meaning depends on the triggering event. the meaning is given with the list of event
* '''[unit_filter]''': this will filter using a standard unit filter on the animated unit. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[unit_filter]''' blocks in an animation.
+
* '''terrain_type''': a list of comma separated terrain codes, the animation will only be used on matching terrains.  See [[FilterWML#Filtering Terrains|Filtering Terrains]].
* '''[secondary_unit_filter]''': this will filter using a standard unit filter on the unit in the hex faced. Note that matching all criterias in the filter will only earn you one point for animation selection, but that you can have multiple '''[secondary_unit_filter]''' blocks in an animation. Also note that if the faced hex is empty, the whole filter will fail
+
* '''[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).
 
* '''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.
 
* '''frequency''': this integer value allows to easily tweak the matching frequency of animations. The filter will fail n-1 times out of n, randomly. Note that unlike every other filter, matching this filter won't give an extra point.
* '''[attack_filter]''': a standard attack filter to match on the attacker's attack. See  [[FilterWML]].
+
* '''[filter_attack]''': a standard attack filter to match on the attacker's attack. See  [[FilterWML#Filtering Weapons|Filtering Weapons]].  
* '''[secondary_attack_filter]''': a standard attack filter to match on the defender's attack. See [[FilterWML]]. Also note that if the defender doesn't have any weapon to retaliate with, this filter will always fail.
+
* '''[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:
 
* '''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.
 
** '''hit''': the attack hits, defender survives.
Line 223: Line 378:
 
** '''kill''': the attack hits, defender dies.
 
** '''kill''': the attack hits, defender dies.
 
** '''yes''': is an alias of '''hit,kill'''.
 
** '''yes''': is an alias of '''hit,kill'''.
* '''swing''': a list of numbers representing the swing numbers this animation should match (numbered from 1).
+
* '''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 trigerring animations and default animations ===
+
=== Events triggering animations and default animations ===
 
==== standing ====
 
==== standing ====
 
This animation is triggered whenever any other animation is finished, and is played in loop until another animation is triggered
 
This animation is triggered whenever any other animation is finished, and is played in loop until another animation is triggered
Line 232: Line 388:
  
 
''value='' is not used, and always contains 0
 
''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
 
if no standing animation is set a single frame animation based on the enclosing unit's '''image=''' field is used
Line 239: Line 397:
 
''value='' is not used, and always contains 0
 
''value='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="0.0~0.3:100,0.3~0.0:200" blend_color=255,255,255''
+
''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 ====
 
==== recruited ====
 
This animation is triggered whenever the unit is recruited or recalled
 
This animation is triggered whenever the unit is recruited or recalled
Line 245: Line 405:
 
''value='' is not used, and always contains 0
 
''value='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''highlight=0~1:600''
+
''value_second='' is not used, and always contains 0
==== levelin ====
+
 
This animation is triggered whenever the unit levels, before the unit is replaced by the new unit
+
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='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="1~0:600" blend_color=255,255,255''
+
''value_second='' is not used, and always contains 0
 +
 
 +
no default animation is needed
 +
 
 +
note that is not triggered for WML triggered animations
 +
 
 
==== levelout ====
 
==== levelout ====
This animation is triggered whenever the unit levels, after the unit is replaced by the new unit
+
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='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="0~1:600" blend_color=255,255,255''
+
''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 ====
 
==== movement ====
 
This animation is used whenever a unit moves. There are multiple things to consider when dealing with movement animation
 
This animation is used whenever a unit moves. There are multiple things to consider when dealing with movement animation
* unit stay ''exactly'' 150ms in each hex. so you typically want to have an offset of ''0~1:150,0~1:150,0~1:150,0~1:150,0~1:150'' or something similar
+
* 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.
 
* 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 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
 
** if it fails, a new movement anim is searched
  
''value='' is not used, and always contains 0
+
''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
  
if no animation is available, the default uses the standing animation(s) with ''offset="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150"''
 
 
==== pre_teleport ====
 
==== pre_teleport ====
 
This animation is triggered whenever the unit teleports, but before it has moved to the target hex
 
This animation is triggered whenever the unit teleports, but before it has moved to the target hex
Line 273: Line 471:
 
''value='' is not used, and always contains 0
 
''value='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="1~0:150" blend_color=255,255,255''
+
''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 ====
 
==== post_teleport ====
 
This animation is triggered whenever the unit teleports, but after it has moved to the target hex
 
This animation is triggered whenever the unit teleports, but after it has moved to the target hex
Line 279: Line 479:
 
''value='' is not used, and always contains 0
 
''value='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="0~1:150" blend_color=255,255,255''
+
''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 ====
 
==== healing ====
 
This animation is triggered when the unit has healing powers and uses them
 
This animation is triggered when the unit has healing powers and uses them
  
 
''value='' is the number of points healed
 
''value='' is the number of points healed
 +
 +
''value_second='' is not used, and always contains 0
  
 
No default is provided by the engine
 
No default is provided by the engine
Line 291: Line 495:
 
''value='' is the number of points healed
 
''value='' is the number of points healed
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30" blend_color=255,255,255''
+
''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''
 
and plays the sound ''heal.wav''
 
==== poisoned ====
 
==== poisoned ====
This animation is triggered whenever the unit suffers poison dammage
+
This animation is triggered whenever the unit suffers poison damage
  
 
''value='' is the number of points lost
 
''value='' is the number of points lost
  
if no animation is available, the default uses the standing animation(s) with ''blend_with="0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30" blend_color=0,255,0''
+
''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''
 
and plays the sound 'poison.ogg''
 +
 
==== defend ====
 
==== defend ====
 
This animation is triggered during a strike, of the unit receiving the blow
 
This animation is triggered during a strike, of the unit receiving the blow
  
 
''value='' is the number of point lost, if any
 
''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
 
No default is provided by the engine
Line 311: Line 522:
 
''value='' is the number of damage dealt, if any
 
''value='' is the number of damage dealt, if any
  
if no animation is available, the default uses the standing animation(s) with ''offset="0~0.6:150,0.6~0:150"'' for melee attacks
+
''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
 
No default is provided for range attacks
 
==== leading ====
 
==== leading ====
Line 317: Line 530:
  
 
''value='' is not used, and always contains 0
 
''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
 
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 ====
 
==== death ====
 
This animation is triggered when a unit die.
 
This animation is triggered when a unit die.
Line 324: Line 550:
 
''value='' is not used, and always contains 0
 
''value='' is not used, and always contains 0
  
if no animation is available, the default uses the standing animation(s) with ''highlight=1~0:600'' and plays the sound in ''die_sound='' of the enclosing unit
+
''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 ====
 
==== victory ====
 
This animation is triggered when a unit finishes a fight by killing the other unit
 
This animation is triggered when a unit finishes a fight by killing the other unit
  
 
''value='' is not used, and always contains 0
 
''value='' is not used, and always contains 0
 +
 +
''value_second='' is not used, and always contains 0
  
 
No default is provided by the engine
 
No default is provided by the engine
Line 335: Line 565:
  
 
''value='' is not used, and always contains 0
 
''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
 
No default is provided by the engine
  
==== default {{DevFeature}} ====
+
==== 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
 
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='' 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
 
A single animation made of the base frame is provided by the engine if no default animation is available
Line 351: Line 597:
 
Note that WML events can also trigger standard animations.
 
Note that WML events can also trigger standard animations.
 
''value='' is set from the WML event
 
''value='' is set from the WML event
 +
 +
''value_second='' is set from the WML event
  
 
== Shortcuts, tricks and quirks ==
 
== Shortcuts, tricks and quirks ==
Line 356: Line 604:
 
=== ''[if]'' and ''[else]'' ===
 
=== ''[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.  
+
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, 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):
+
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 372: 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
 
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 ===
 
=== Simplified animation blocks ===
Line 389: Line 650:
  
 
* '''[leading_anim]''' is an animation with the following parameters automatically set
 
* '''[leading_anim]''' is an animation with the following parameters automatically set
apply_to=leading
+
<syntaxhighlight lang=wml>
 +
apply_to=leading
 +
</syntaxhighlight>
 
* '''[recruit_anim]''' is an animation with the following parameters automatically set
 
* '''[recruit_anim]''' is an animation with the following parameters automatically set
apply_to=recruited
+
<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
 
* '''[standing_anim]''' is an animation with the following parameters automatically set
apply_to=standing,_default_
+
<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
 
* '''[idle_anim]''' is an animation with the following parameters automatically set
apply_to=idling
+
<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
 
* '''[levelin_anim]''' is an animation with the following parameters automatically set
apply_to=levelin
+
<syntaxhighlight lang=wml>
* '''[levelout_anim]''' is an animation with the following parameters automatically set
+
apply_to=levelin
apply_to=levelout
+
</syntaxhighlight>
 
* '''[healing_anim]''' is an animation with the following parameters automatically set
 
* '''[healing_anim]''' is an animation with the following parameters automatically set
apply_to=healing
+
<syntaxhighlight lang=wml>
value=<damage= value>
+
apply_to=healing
 +
value=<damage= value>
 +
</syntaxhighlight>
 
* '''[healed_anim]''' is an animation with the following parameters automatically set
 
* '''[healed_anim]''' is an animation with the following parameters automatically set
apply_to=healed
+
<syntaxhighlight lang=wml>
value=<healing= value>
+
apply_to=healed
[_healed_sound_frame]
+
value=<healing= value>
    sound=heal.wav
+
[_healed_sound_frame]
[/_healed_sound_frame]
+
  sound=heal.wav
 +
[/_healed_sound_frame]
 +
</syntaxhighlight>
 
* '''[poison_anim]''' is an animation with the following parameters automatically set
 
* '''[poison_anim]''' is an animation with the following parameters automatically set
apply_to=poisoned
+
<syntaxhighlight lang=wml>
value=<damage= value>
+
apply_to=poisoned
[_poison_sound_frame]
+
value=<damage= value>
    sound=poison.ogg
+
[_poison_sound_frame]
[/_poison_sound_frame]
+
  sound=poison.ogg
 +
[/_poison_sound_frame]
 +
</syntaxhighlight>
 
* '''[movement_anim]''' is an animation with the following parameters automatically set
 
* '''[movement_anim]''' is an animation with the following parameters automatically set
apply_to=movement
+
<syntaxhighlight lang=wml>
offset="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150"
+
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
 
* '''[defend]''' is an animation with the following parameters automatically set
apply_to=defend
+
<syntaxhighlight lang=wml>
value=<damage= value>
+
apply_to=defend
<WML content>
+
value=<damage= value>
[frame]
+
{WML content}
    blend_with=255,0,0
+
[frame]
    blend_ratio="0.5:50,0.0:50"
+
  blend_color=255,0,0
[/frame]
+
  blend_ratio="0.5:50,0.0:50"
 +
[/frame]
 +
</syntaxhighlight>
  
there are some subtil change compared to what is described above to avoid the red flash when value=0, but it should work as expected as far as WML author are concerned
+
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
 
* '''[attack_anim]''' is an animation with the following parameters automatically set
 
if the animation contains a missile frame
 
if the animation contains a missile frame
  
apply_to=attack
+
<syntaxhighlight lang=wml>
missile_offset="0~0.8"
+
apply_to=attack
 +
missile_offset="0~0.8"
 +
</syntaxhighlight>
  
 
else
 
else
  
apply_to=attack
+
<syntaxhighlight lang=wml>
offset="0~0.6,0.6~0"
+
apply_to=attack
 +
offset="0~0.6,0.6~0"
 +
</syntaxhighlight>
  
 
* '''[death]''' is an animation with the following parameters automatically set
 
* '''[death]''' is an animation with the following parameters automatically set
apply_to=death
+
<syntaxhighlight lang=wml>
[_death_sound_frame]
+
apply_to=death
    sound=<die_sound= of the enclosing [unit] tag>
+
[_death_sound_frame]
[/_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
 
* '''[victory_anim]''' is an animation with the following parameters automatically set
apply_to=victory
+
<syntaxhighlight lang=wml>
 +
apply_to=victory
 +
</syntaxhighlight>
 
* '''[extra_anim]''' is an animation with the following parameters automatically set
 
* '''[extra_anim]''' is an animation with the following parameters automatically set
apply_to=<flag= value of the anim>
+
<syntaxhighlight lang=wml>
 +
apply_to=<flag= value of the anim>
 +
</syntaxhighlight>
 
* '''[teleport_anim]''' will be cut into two at the clock-time 0
 
* '''[teleport_anim]''' will be cut into two at the clock-time 0
 
everything before zero becomes an animation with the following parameters automatically set
 
everything before zero becomes an animation with the following parameters automatically set
apply_to=pre_teleport
+
<syntaxhighlight lang=wml>
 +
apply_to=pre_teleport
 +
</syntaxhighlight>
 
everything after zero becomes an animation with the following parameters automatically set
 
everything after zero becomes an animation with the following parameters automatically set
apply_to=post_teleport
+
<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)
 +
 
 +
* ''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 ==
 
== 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