• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Destructable animation tag

Status
Not open for further replies.
So, I have destructables that have these models Concrete Cliff
In some cases, I'd like to add the "alternate"-tag (if they would've been units), but I cannot find a good way of doing that...
Is there a known way of adding animation-tags to destructables?

Or do I need a bigger "if-tree" to manually play various animations depending on if it's dead or alive, possibly even handle the birth/death animations?
Maybe use string-array to keep track of current animation to enable tracking of birth/death animations.
Note. Birth/Deahs are controlled by centralized triggers, so I can easily ensure that this animation-array is tracked...

Currently I do not handle "dead" destructables, making their visuals not match what it should.
All walls and doors have exactly 200 occlusion height, so I can do this.
  • UpdateNearbyDestructiblesTick
    • Events
      • Time - Every 0.20 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in heroes_alive and do (Actions)
        • Loop - Actions
          • Set t_loc1 = (Position of (Picked unit))
          • Destructible - Pick every destructible within 550.00 of t_loc1 and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Occlusion height of (Picked destructible)) Equal to 200.00
                • Then - Actions
                  • Set t_loc2 = (Position of (Picked destructible))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Distance between t_loc1 and t_loc2) Less than 375.00
                      • (Y of t_loc2) Less than (Y of t_loc1)
                    • Then - Actions
                      • Animation - Play (Picked destructible)'s stand alternate animation
                    • Else - Actions
                      • Animation - Play (Picked destructible)'s stand animation
                  • Custom script: call RemoveLocation(udg_t_loc2)
                • Else - Actions
          • Custom script: call RemoveLocation(udg_t_loc1)
Edit: I now noticed that Destructible - Pick every destructible within seems leaks rects... I'll need to change way of picking destructables I guess...
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,549
You could make an Array of Destructibles, Loop over those, and make a distance check to see if they're within 550.00 range of t_loc1. It's not a big deal to leak here and there but every 0.20 seconds is obviously not ideal.

This would also remove the need for the Occlusion Height check since your Array could contain only Destructibles of that height already.

I'm not sure about the Animation Tag for Destructibles but I don't think that exists outside of the Object Editor. You may need to edit the model itself to use an Animation name that can be referenced properly using the GUI action:
  • Animation - Play (Picked destructible)'s birth animation
 
Last edited:
You could make an Array of Destructibles, Loop over those, and make a distance check to see if they're within 550.00 range of t_loc1. It's not a big deal to leak here and there but every 0.20 seconds is obviously not ideal.

This would also remove the need for the Occlusion Height check since your Array could contain only Destructibles of that height already.
That's a "side note" that I noticed while asking the question, but thank you, I'll consider it when making the solution.
The "main question" is still "animation-tag" (if they'd be units).
 
You could do whatever trees do to exist at 0/max hp in their chopped state. Make the alt version of the walls what they look like with 0 health in their death animation?
The problem is doors, where they're opened while dead, closed while alive, meaning that I can have occlusion built-in (cannot see through closed doors, but opened) if I set them up similar to trees.

My current soulution idea is to have an array or strings that I index with GetHandleId (unsure of ranges, need to search) or use a hashmap or a Bribe Table or something. Basically, I can "flag" "alternate"-suffix in my "storage" and also have a "flag" when playing an animation so I don't cancel it when moving out-side range for the "alternate"-flag.

Edit: Destructables are pretty annoying to work with, but I don't want a ton of units are walls. It'd be impossible unless it's a tiny map. Doodads are completely impossible to do anything dynamic with, so destructible it is!
 
I ended up writing a system for it.
I don't think anyone else would be interested, but here it is anyways.

Because I'll probably have over 3000 "wall"-destructables I prefer not looping over every one of them every 0.2 seconds and checking distance, so I do something fairly similar to what I had.

For some reason, the BlzGroupAddGroupFast caused a ton of lagg in my update-loop when I tried to move heroes_alive -> temp group in order to FirstOfGroup-loop through the temp-group, so I had to use ForGroup instead. No idea why the lagg, because I haven't had issues with it before...

JASS:
library DestructableUpdates requires Table, TimerUtils, Respawn
    globals
        constant integer SPAWN_POINT_DEST = 'B016'
        constant real WALL_CHECK_RANGE = 550.
        constant real WALL_LOW_RANGE = 350.
        constant real WALL_LOW_RANGE_SQR = WALL_LOW_RANGE * WALL_LOW_RANGE
        constant integer NO_FLAG = 0
        constant integer DEAD_FLAG = 1
        constant integer LOW_FLAG = 2
        constant integer ANIMATING_FLAG = 4
        constant string ANIM_HIGH_ALIVE = "stand"
        constant string ANIM_LOW_ALIVE = "stand alternate"
        constant string ANIM_HIGH_DEAD = "decay" //TODO Change models anims
        constant string ANIM_LOW_DEAD = "death alternate"
    endglobals
    struct DestructableUpdater
        readonly static Table table
        private static rect enumRect
        private static unit u
        private static real ux
        private static real uy
        private static method setHigh takes destructable d returns nothing
            local integer id = GetHandleId(d)
            if table[id] == LOW_FLAG then
                //LOW and NOT DEAD and not playing animation
                call table.integer.remove(id)
                call SetDestructableAnimation(d, ANIM_HIGH_ALIVE)
            endif
        endmethod
        private static method setLow takes destructable d returns nothing
            local integer id = GetHandleId(d)
            if table[id] == NO_FLAG then
                set table[id] = LOW_FLAG
                call SetDestructableAnimation(d, ANIM_LOW_ALIVE)
            endif
        endmethod
        private static method updateLowerableDestructable takes destructable d returns nothing
            local real dx = GetDestructableX(d) - ux
            local real y = GetDestructableY(d)
            local real dy = y - uy
            if y < uy and (dx * dx + dy * dy) < WALL_LOW_RANGE_SQR then
                call setLow(d)
            else
                call setHigh(d)
            endif
        endmethod
        private static method updateDestructable takes nothing returns nothing
            local destructable d = GetEnumDestructable()
            if GetDestructableOccluderHeight(d) == 200.00 then
                call updateLowerableDestructable(d)
            elseif GetDestructableTypeId(d) == SPAWN_POINT_DEST then
                call heroRespawnUpdateSpawnPointWithDistanceCheck(u, d)
            endif
        endmethod
        private static method foreachUnit takes nothing returns nothing
            set u = GetEnumUnit()
            set ux = GetUnitX(u)
            set uy = GetUnitY(u)
            call SetRect(enumRect, ux - WALL_CHECK_RANGE, uy - WALL_CHECK_RANGE, ux + WALL_CHECK_RANGE, uy + WALL_CHECK_RANGE)
            call EnumDestructablesInRect(enumRect, null, function thistype.updateDestructable)
        endmethod
        private static method updateLoop takes nothing returns nothing
            call ForGroup(udg_heroes_alive, function thistype.foreachUnit)
            //For some reason did BlzGroupAddGroupFast lagg my game, so I cannot FirstOfGroup-loop here
        endmethod
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), 0.2, true, function thistype.updateLoop)
            set table = Table.create()
            set enumRect = Rect(0., 0., 0., 0.)
        endmethod
        static method resetAnimatingFlag takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local integer id = GetTimerData(t)
            call ReleaseTimer(t)
            set table[id] = BlzBitAnd(table[id], BlzBitXor(ANIMATING_FLAG, -1))
            set t = null
        endmethod
    endstruct
endlibrary
// ------------ Public functions --------------
function OpenDoor takes destructable d returns nothing
    local integer id = GetHandleId(d)
    call KillDestructable(d)
    set DestructableUpdater.table[id] = BlzBitOr(DestructableUpdater.table[id], BlzBitOr(DEAD_FLAG, ANIMATING_FLAG))
    call TimerStart(NewTimerEx(id), 1.0, false, function DestructableUpdater.resetAnimatingFlag)
endfunction
function CloseDoor takes destructable d returns nothing
    local integer id = GetHandleId(d)
    call DestructableRestoreLife(d, GetDestructableMaxLife(d), true)
    set DestructableUpdater.table[id] = BlzBitOr(BlzBitAnd(DestructableUpdater.table[id], BlzBitXor(DEAD_FLAG, -1)), ANIMATING_FLAG)
    call TimerStart(NewTimerEx(id), 1.0, false, function DestructableUpdater.resetAnimatingFlag)
endfunction
Note: I still need to change the model and add a "permamently open with high walls" animation (probably "decay") and add it to this, but I've tought about it when I wrote this.
 
Status
Not open for further replies.
Top