• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • 💡 We're thrilled to announce that our upcoming texturing contest is in the works, and we're eager to hear your suggestions! Please take this opportunity to share your ideas in this theme discussion thread for the Texturing Contest #34!
  • 🏆 Hive's 7th HD Modeling Contest: Icecrown Creature is now open! The frozen wastes of Icecrown are home to some of Azeroth’s most terrifying and resilient creatures. For this contest, your challenge is to design and model a HD 3D monster that embodies the cold, undead, and sinister essence of Icecrown! 📅 Submissions close on April 13, 2025. Don't miss this opportunity to let your creativity shine! Enter now and show us your frozen masterpiece! 🔗 Click here to enter!

Advanced Ability Animations

A simple system that enables you to give any ability a unique Art - Animation - Cast Point as well as any Animation of your choosing.

Cast Point is the value that determines how long it takes to cast a spell. Normally, you define this value once on your Unit and it applies to ALL of their abilities. With this system, you can bypass that limitation and assign this value on a per ability basis. You can also choose to play a specific Animation by relying on the SetUnitAnimationByIndex() function which uses Integers instead of Strings to give you exact control. This is useful since the Art - Animation Names field that Abilities use is limited in what it can play. Furthermore, the system will adjust your casting Unit's timescale (Animation speed) in order to play the entire Animation within the given time frame.

However, do note that it comes with some requirements:
1) Your Unit needs to have it's Art - Animation - Cast Point set to 0.00 for it to work smoothly.
2) Your Ability needs to have it's Casting Time set to it's new Cast Point value. This may not work with every single ability (Shadow Strike and Flame Strike come to mind).
3) Your Ability needs to have it's Art - Animation Names set to stand for it to work smoothly.
(Technically you could tweak #1 and #3 and it'd still work, just with different results than what I was going for here)
4) You need to copy and paste the AAA_Has_Alternate_Tag ability from the demo map into your own map. Then set it's rawcode to AAAT, or if that's already taken you can use your own rawcode and modify this system variable to match it:
vJASS:
private constant integer ALTERNATE_ABILITY_ID = 'AAAT'

Also, you should note some other caveats:
1) You cannot interrupt the cast with a standard "Move" order like you're used to. Instead, you have to issue a "Stop" order then a "Move" order. I'm trying to fix this...
2) The mana cost will not be spent until the ability fully executes, which is intended. I say this because those who have used Flame Strike or an ability like it may be confused by the mechanics.
3) If all of the Units using this system have their Art - Animation - Cast Backswing set to 0.00 then you can set this variable to false to improve performance slightly:
vJASS:
private constant boolean DOES_USE_CAST_BACKSWING = true
Keep this set to true (default) if you're confused, it's not that important.


HOW TO USE THE SYSTEM:
This system is both GUI and JASS friendly. For GUI users, you need to register new abilities to the system like so:
  • AAA Demo Register Abilities
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • -------- How to use the system: --------
      • -------- --------
      • -------- 1) Set your casting unit's Art - Animation - Cast Point to 0.00. --------
      • -------- 2) Set your abilities Casting Time to whatever you want it's new Cast Point to be. This is how long it takes to cast! --------
      • -------- 3) Set your abilities Art - Animation Names to stand. The system will play your desired animation automatically! --------
      • -------- 4) Set the AAA__ variables below. --------
      • -------- Abil_Type is the ability that you want to register to the system. --------
      • -------- Anim_Index is the Integer id of the animation you want to play. You can find this value in a Model Editor or on Hiveworkshop's 3D Model Viewer. --------
      • -------- Anim_String can be used instead of Anim_Index to work with the standard "attack", "move", "spell" animation names. --------
      • -------- Anim_Duration is the duration in seconds of your animation, you can see this in the unit preview on your left. (Tweak this to make the animation play faster/slower) --------
      • -------- 5) Call the AAA_Register_Ability() function to add this ability to the system. --------
      • -------- --------
      • -------- --------
      • -------- In this example I am changing the Paladin's Holy Light to use the "stand victory" animation and take 1.0 second to cast: --------
      • Set VariableSet AAA__Abil_Type = Holy Light (Paladin)
      • Set VariableSet AAA__Anim_Index = 7
      • Set VariableSet AAA__Anim_Duration = 2.66
      • Custom script: call AAA_Register_Ability()
      • -------- --------
      • -------- --------
      • -------- In this example I am changing the DH's Holy Light to use the "spell" animation and take 1.0 second to cast: --------
      • Set VariableSet AAA__Abil_Type = Holy Light (Demon Hunter)
      • Set VariableSet AAA__Anim_Index = 11
      • Set VariableSet AAA__Anim_Duration = 0.76
      • -------- Optional: You can use these alt settings for when your model uses a "alternate" animation tag (Metamorphosis, Defend, etc): --------
      • Set VariableSet AAA__Anim_Index_Alt = 16
      • Set VariableSet AAA__Anim_Duration_Alt = 0.93
      • Custom script: call AAA_Register_Ability()
      • -------- --------
      • -------- --------
      • -------- In this example I am changing the Mountain King's Holy Light to use the "death" animation and take 1.0 second to cast: --------
      • Set VariableSet AAA__Abil_Type = Holy Light (Mountain King)
      • Set VariableSet AAA__Anim_String = death
      • Set VariableSet AAA__Anim_Duration = 2.50
      • Custom script: call AAA_Register_Ability()

For JASS users, simply use these two functions to register your abilities:
vJASS:
// Note: A value of -1 or a "" string ignores those animation options!
function AAA_Register takes integer abilId, integer animIndex, string animString, real abilDuration returns nothing
function AAA_Register_Alt takes integer abilId, integer animIndex, string animString, real abilDuration returns nothing

The "Alt" variables and functions are there to allow you to have an alternate animation setup for when your caster's animations have changed. This could occur during something like Metamorphosis or the Defend ability. I've created a custom ability called AAA_Has_Alternate_Tag which you're meant to Add/Remove to your Units as a way to signal to the system that you want to use your registered alternate settings. Here's an example:
  • AAA Demo Add Tag To Demon Hunter
    • Events
      • Time - Elapsed game time is 0.01 seconds
    • Conditions
    • Actions
      • Animation - Add the alternate animation tag to Demon Hunter 0006 <gen>
      • Unit - Add AAA__Alt_Ability to Demon Hunter 0006 <gen>
Now when the Demon Hunter casts a registered ability it will attempt to use that abilities alternate settings instead, IF they exist.


THE CODE:
vJASS:
library AdvancedAbilityAnimations initializer Init
    // Created by Uncle
    globals
        private constant integer ALTERNATE_ABILITY_ID = 'AAAT'
        // Define the ALTERNATE_ABILITY_ID to match the rawcode
        // of the AAA_Has_Alternate_Tag ability, which you should have
        // imported from the demo map. This is necessary if you plan
        // on taking advantage of alternate animations.

        private constant boolean DOES_USE_CAST_BACKSWING = true
        // Define the DOES_USE_CAST_BACKSWING boolean.
        // If any unit has an Art - Cast Backswing > 0.00 then
        // keep this set to true. Otherwise, set it to false to
        // make the system slightly more efficient.



        ////////////////////////////////////////////////////////
        // STOP - Do NOT modify anything else below this line //
        private hashtable hash = InitHashtable()
        private unit caster
        private integer abilityId
        private integer timerHandle
        private timer abilityTimer

        // References to your AAA_ variables
        private integer castAnim  // animation index
        private real castDuration // animation standard duration
        private real castTime     // animation desired duration

        // KEYS in the Hashtable
        private constant integer KEY_UNIT = 0
        private constant integer KEY_ABIL = 1

        private constant integer KEY_ANIM = 0
        private constant integer KEY_DURATION = 1
        private constant integer KEY_ANIM_ALT = 2
        private constant integer KEY_DURATION_ALT = 3
        private constant integer KEY_REGISTERED = 4
    endglobals

    private function StopCasting takes nothing returns nothing
        set abilityId = GetSpellAbilityId()
        // Return if this ability is not registered
        if LoadBoolean(hash, abilityId, KEY_REGISTERED) == false then
            return
        endif
        set caster = GetTriggerUnit()
        call SetUnitTimeScale(caster, 1.0)
        set abilityTimer = LoadTimerHandle(hash, GetHandleId(caster), 0)
        if abilityTimer != null then
            call FlushChildHashtable(hash, GetHandleId(abilityTimer))
            call FlushChildHashtable(hash, GetHandleId(caster))
            call DestroyTimer(abilityTimer)
        endif
    endfunction
 
    private function BeginCastingCallback takes nothing returns nothing
        set abilityTimer = GetExpiredTimer()
        set timerHandle = GetHandleId(abilityTimer)
        set caster = LoadUnitHandle(hash, timerHandle, KEY_UNIT)
        if IsUnitType(caster, UNIT_TYPE_DEAD) or GetUnitTypeId(caster) == 0 then
            return
        endif
        set abilityId = LoadInteger(hash, timerHandle, KEY_ABIL)
        set castTime = BlzGetAbilityRealLevelField(BlzGetUnitAbility(caster, abilityId), ABILITY_RLF_CASTING_TIME, GetUnitAbilityLevel(caster, abilityId) - 1)
 
        // Variables used to play the special cast animation
        if GetUnitAbilityLevel(caster, udg_AAA__Alt_Ability) > 0 then
            // It has the alternate animation tag
            set castAnim = LoadInteger(hash, abilityId, KEY_ANIM_ALT)
            if castAnim == 0 then
                // It must have registered a string
                call SetUnitAnimation(caster, LoadStr(hash, abilityId, KEY_ANIM_ALT))
            else
                call SetUnitAnimationByIndex(caster, castAnim)
            endif
            set castDuration = LoadReal(hash, abilityId, KEY_DURATION_ALT)
        else
            // It does not have an alternate animation tag
            set castAnim = LoadInteger(hash, abilityId, KEY_ANIM)
                    call DisplayTextToPlayer(Player(0), 0, 0, "castAnim: " + I2S(castAnim))
            if castAnim == 0 then
                // It must have registered a string
                call SetUnitAnimation(caster, LoadStr(hash, abilityId, KEY_ANIM))
            else
                call SetUnitAnimationByIndex(caster, castAnim)
            endif
            set castDuration = LoadReal(hash, abilityId, KEY_DURATION)
        endif
        // Avoid dividing by zero (castDuration should always be > 0 at this stage)
        if castTime <= 0 then
            set castTime = 0.01
        endif
        call SetUnitTimeScale(caster, castDuration / castTime)
        call FlushChildHashtable(hash, timerHandle)
        call FlushChildHashtable(hash, GetHandleId(caster))
        call DestroyTimer(abilityTimer)
    endfunction

    private function BeginCasting takes nothing returns nothing
        set abilityId = GetSpellAbilityId()
        // Return if this ability is not registered
        if LoadBoolean(hash, abilityId, KEY_REGISTERED) == false then
            return
        endif
        set caster = GetTriggerUnit()
        set abilityTimer = CreateTimer()
        set timerHandle = GetHandleId(abilityTimer)
        call SaveUnitHandle(hash, timerHandle, KEY_UNIT, caster)
        call SaveInteger(hash, timerHandle, KEY_ABIL, abilityId)
        call SaveTimerHandle(hash, GetHandleId(caster), 0, abilityTimer)
        call TimerStart(abilityTimer, 0, false, function BeginCastingCallback)
    endfunction

    ////////////
    // [JASS] //
    ////////////
    // Note: A value of -1 or a "" string ignores those animation options!
    function AAA_Register takes integer abilId, integer animIndex, string animString, real abilDuration returns nothing
        if abilDuration <= 0 then
            call DisplayTextToPlayer(Player(0), 0, 0, "[AAA Error] Ability " + GetAbilityName(abilId) + " was not registered! abilDuration must be > 0.")
            return
        endif
        if animString != "" then
            call SaveStr(hash, abilId, KEY_ANIM, animString)
            call SaveReal(hash, abilId, KEY_DURATION, abilDuration)
        elseif animIndex > -1 then
            call SaveInteger(hash, abilId, KEY_ANIM, animIndex)
            call SaveReal(hash, abilId, KEY_DURATION, abilDuration)
        endif
        // Mark this ability as registered
        call SaveBoolean(hash, abilId, KEY_REGISTERED, true)
    endfunction

    function AAA_Register_Alt takes integer abilId, integer animIndex, string animString, real abilDuration returns nothing
        if abilDuration <= 0 then
            call DisplayTextToPlayer(Player(0), 0, 0, "[AAA Error] Ability " + GetAbilityName(abilId) + " was not registered! abilDuration must be > 0.")
            return
        endif
        if animString != "" then
            call SaveStr(hash, abilId, KEY_ANIM_ALT, animString)
            call SaveReal(hash, abilId, KEY_DURATION_ALT, abilDuration)
        elseif animIndex > -1 then
            call SaveInteger(hash, abilId, KEY_ANIM_ALT, animIndex)
            call SaveReal(hash, abilId, KEY_DURATION_ALT, abilDuration)
        endif
        // Mark this ability as registered
        call SaveBoolean(hash, abilId, KEY_REGISTERED, true)
    endfunction

    ///////////
    // [GUI] //
    ///////////
    function AAA_Register_Ability takes nothing returns nothing
        local integer id = udg_AAA__Abil_Type
        if udg_AAA__Anim_Duration <= 0 then
            call DisplayTextToPlayer(Player(0), 0, 0, "[AAA Error] Ability " + GetAbilityName(id) + " was not registered! Anim_Duration must be > 0.")
            return
        endif
        if udg_AAA__Anim_Index > -1 then
            call SaveInteger(hash, id, KEY_ANIM, udg_AAA__Anim_Index)
            call SaveReal(hash, id, KEY_DURATION, udg_AAA__Anim_Duration)
        elseif udg_AAA__Anim_String != "" then
            call SaveStr(hash, id, KEY_ANIM, udg_AAA__Anim_String)
            call SaveReal(hash, id, KEY_DURATION, udg_AAA__Anim_Duration)
        endif
        // A value of -1 represents unused
        if udg_AAA__Anim_Index_Alt > -1 then
            call SaveInteger(hash, id, KEY_ANIM_ALT, udg_AAA__Anim_Index_Alt)
            call SaveReal(hash, id, KEY_DURATION_ALT, udg_AAA__Anim_Duration_Alt)
        elseif udg_AAA__Anim_String_Alt != "" then
            call SaveStr(hash, id, KEY_ANIM_ALT, udg_AAA__Anim_String_Alt)
            call SaveReal(hash, id, KEY_DURATION_ALT, udg_AAA__Anim_Duration_Alt)
        endif
        // Mark this ability as registered
        call SaveBoolean(hash, id, KEY_REGISTERED, true)
        // Reset variables to unused state
        set udg_AAA__Anim_Index = -1
        set udg_AAA__Anim_Index_Alt = -1
        set udg_AAA__Anim_String = ""
        set udg_AAA__Anim_String_Alt = ""
    endfunction
 
    private function Init takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        // The ability used to determine alternate animations
        set udg_AAA__Alt_Ability = ALTERNATE_ABILITY_ID
        // A value of -1 represents unused
        set udg_AAA__Anim_Index = -1
        set udg_AAA__Anim_Index_Alt = -1
        set udg_AAA__Anim_String = ""
        set udg_AAA__Anim_String_Alt = ""
        call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
        call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        // Art - Cast Backswing may need to be accounted for (if > 0.00)
        if DOES_USE_CAST_BACKSWING then
            call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        endif
        call TriggerAddAction(t1, function BeginCasting)
        call TriggerAddAction(t2, function StopCasting)
        set t1 = null
        set t2 = null
    endfunction
 
endlibrary
CHANGELOG:
v1.0: Released.

v1.1: Added DOES_USE_CAST_BACKSWING boolean to improve performance when Art - Animation - Cast Backswing is set to 0.00 for your Units that use this system. Added more If condition checks to prevent unnecessary code from running. Fixed unit handle memory leak.

v1.2: Adjusted code syntax and added an error message for when an ability fails to register. Renamed map to have spaces in title.

v.1.3: Added _Alt variables for Index, Duration, and Cast Time which can be registered along with the standard variables. These will be used instead if the caster has the new AAA__Alt_Ability ability - which must now be imported into your map with the rawcode 'AAAT'. If this rawcode is already taken then you'll need to go into the code and modify the line that assigns this variable. This ability is meant to be paired with the "alternate" animation tag or any kind of tag that would change the unit's animations.

v.1.4: Added standard animation Strings as an option instead of using Animation Index. Removed Cast_Time variables, Casting Time is now automatically detected for any ability level.
Previews
Contents

Advanced Ability Animations v.1.4 (Map)

Reviews
Antares
An option to pass the animation type either by string or by index would be great. While index gives you more control, it is also more cumbersome in a case where a string would suffice. I expected the mana to get deducted when the cast sequence...
This would probably make more sense as something that inserts into Spell System, to avoid having to configure two separate things for spells. If you want, I could add some //! runtextmacro optional statements inside of Spell System, like I did with Damage Engine, to allow your system to be optionally supported and integrated.
 

Uncle

Warcraft Moderator
Level 72
Joined
Aug 10, 2018
Messages
7,682
This would probably make more sense as something that inserts into Spell System, to avoid having to configure two separate things for spells. If you want, I could add some //! runtextmacro optional statements inside of Spell System, like I did with Damage Engine, to allow your system to be optionally supported and integrated.
Sounds good to me, I don't really have much attachment to this, it's quite simple after all.
 
An option to pass the animation type either by string or by index would be great. While index gives you more control, it is also more cumbersome in a case where a string would suffice.

I expected the mana to get deducted when the cast sequence starts, since that's the case with Flamestrike. Adding back the mana cost to the Holy Light in the test map would clarify that. It might also be worth noting in the documentation that a spell cast this way cannot be aborted with a movement command until it is finished.

Since the AAA__Cast_Time variable should match the Casting Time field of the ability, you should be able to remove it and retrieve the casting time with BlzGetAbilityRealLevelField(abi, ABILITY_RLF_CASTING_TIME, GetUnitAbilityLevel(caster, abilityId) - 1).

A pure JASS register function would be nice to have.


A nice light-weight system to give more control over spell animations and cast duration.

Approved.
 
Level 36
Joined
Aug 6, 2015
Messages
768
Noticed a little bug.
- If adding an "Alternate" tag to the unit. Then casting a spell tied to the system -> it will move the unit in his non-alternate form after the cast.

Can be fixed by ordering the unit to move to his own position after finishing the cast (this way the alternate animation will re-cast itself after the spell is finished - maybe something like this could be implemented into the system where you can give the creator an option to set a variable is the spell is using alternate animations - to order the unit to move to his own position after cast - or something in this lines.

I also don't understand how to make use of the spell efficiently in my case.
So i have a heal - it is casted instantly by default - but i want to play a custom animation when casting it - and i don't really understand how to do it.
 

Attachments

  • Advanced Ability Animations v.1.2.w3m
    22.8 KB · Views: 6
Last edited:

Uncle

Warcraft Moderator
Level 72
Joined
Aug 10, 2018
Messages
7,682
Noticed a little bug.
- If adding an "Alternate" tag to the unit. Then casting a spell tied to the system -> it will move the unit in his non-alternate form after the cast.

Can be fixed by ordering the unit to move to his own position after finishing the cast (this way the alternate animation will re-cast itself after the spell is finished - maybe something like this could be implemented into the system where you can give the creator an option to set a variable is the spell is using alternate animations - to order the unit to move to his own position after cast - or something in this lines.

I also don't understand how to make use of the spell efficiently in my case.
So i have a heal - it is casted instantly by default - but i want to play a custom animation when casting it - and i don't really understand how to do it.
Thanks for pointing this out, I just fixed it in the latest update (1.3). I've added 4 new variables which are meant to address the problem.

The first 3 variables are alternate versions of the animation index, duration, and cast time variables:
AAA__Anim_Index_Alt
AAA__Anim_Duration_Alt
AAA__Cast_Time_Alt


These are optional and can be registered along with the original variables. When your unit has the "alternate" tag it will use the values provided by these instead, allowing you to have two sets of animations per Ability (standard and alternate).

The last variable is an Ability Code called AAA__Alt_Ability which must be added/removed along with the "alternate" animation tag. For example:
  • AAA Demo Add Tag To Demon Hunter
    • Events
      • Player - Player 1 (Red) types a chat message containing add as An exact match
    • Conditions
    • Actions
      • -------- Tell the AAA system that this Unit has the "alternate" tag: --------
      • Animation - Add the alternate animation tag to Demon Hunter 0006 <gen>
      • Unit - Add AAA__Alt_Ability to Demon Hunter 0006 <gen>
  • AAA Demo Remove Tag From Demon Hunter
    • Events
      • Player - Player 1 (Red) types a chat message containing remove as An exact match
    • Conditions
    • Actions
      • -------- Tell the AAA system that this Unit no longer has the "alternate" tag: --------
      • Animation - Remove the alternate animation tag to Demon Hunter 0006 <gen>
      • Unit - Remove AAA__Alt_Ability from Demon Hunter 0006 <gen>
I rely on this custom ability to detect that the unit has the "alternate" tag. Unfortunately, there's no native way to do this or I would have simply done something like this in my code: If unit has "alternate" tag Equal to True.

Although, I suppose this approach is more flexible since the "alternate" tag isn't even necessary to get access to the alternate animation.
 
Last edited:

Uncle

Warcraft Moderator
Level 72
Joined
Aug 10, 2018
Messages
7,682
I meant to do this sooner and completely forgot... Part of the reason why I avoid uploading resources.
Anyway, I updated the map to v1.4 which should cover just about everything.
An option to pass the animation type either by string or by index would be great. While index gives you more control, it is also more cumbersome in a case where a string would suffice.
Makes sense, I added the AAA__Anim_String and AAA__Anim_String_Alt variables which allow this behavior. They will be used if an integer Index is not provided.

I expected the mana to get deducted when the cast sequence starts, since that's the case with Flamestrike. Adding back the mana cost to the Holy Light in the test map would clarify that. It might also be worth noting in the documentation that a spell cast this way cannot be aborted with a movement command until it is finished.
The mana cost being paid during the "Starts the effect of an ability" stage is the default behavior that I think a user would expect. That's the case for 99% of abilities. I'll add a note though. I'll also add a note about the cancelling issue - which I can't seem to fix. The caster won't even fire a Point order during the "Begins channeling" phase so I can't detect and override the behavior. The user can still issue a Stop order to interrupt the cast, which may actually be preferred, I just wish I could allow both methods for cancelling.

Since the AAA__Cast_Time variable should match the Casting Time field of the ability, you should be able to remove it and retrieve the casting time with BlzGetAbilityRealLevelField(abi, ABILITY_RLF_CASTING_TIME, GetUnitAbilityLevel(caster, abilityId) - 1).
Yeah, I was originally going to do this but decided against it for whatever reason. I deleted the Cast_Time variables and added this functionality.

A pure JASS register function would be nice to have.
I added two new functions, AAA_Register() and AAA_Register_Alt(). These avoid the need for the GUI variables. A pure Jass user could get rid of all of the GUI related stuff if they modified the code and deleted the variables in the Trigger Editor.
 
Last edited:

Uncle

Warcraft Moderator
Level 72
Joined
Aug 10, 2018
Messages
7,682
I also don't understand how to make use of the spell efficiently in my case.
So i have a heal - it is casted instantly by default - but i want to play a custom animation when casting it - and i don't really understand how to do it.
Apologies for glossing over this and responding so late. Are you by any chance still struggling with the system? I go into great detail in the description above (see requirements, HOW TO USE THE SYSTEM, and the preview image). If you provide more details then I could probably come up with a solution.

Note that a truly "instant" ability like Berserk will NOT work with this system nor should it. If you wanted something like Berserk to play an animation then you can accomplish that pretty easily:
  • Berserk Animation
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Berserk
    • Actions
      • Animation - Play (Triggering unit)'s death animation
Note that this animation will be interrupted if your unit takes any action or is already in the middle of an action like moving/attacking.

I don't think this is what you're talking about, though.
 
Last edited:
Top