• Check out the results of the Techtree Contest #19!
  • 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.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

[Solved] Unit Animation not playing after Issued Order

Level 5
Joined
Aug 9, 2005
Messages
97
I have a set of Villagers that are suppose to wander in a specific region. To wander, every 10 to 50 seconds a timer ticks and issues an order for them to move to a random point in that region and play the "Stand Work" animation. The animation plays if no order is issued beforehand, But I simply can't get them to play it after they move.

  • CheckWander
    • Events
      • Unit - A unit Is issued an order targeting a point
    • Conditions
      • ((Ordered unit) is in Farmhands.) Equal to True
      • (Distance between (Position of (Ordered unit)) and (Target point of issued order)) Equal to 0.00
    • Actions
      • Animation - Play (Ordered unit)'s stand work animation
  • Wander
    • Events
      • Time - Every (Random real number between 10.00 and 50.00) seconds of game time
    • Conditions
    • Actions
      • Unit - Order Villager <gen> to Move To (Random point in WanderRegion <gen>)
 
"(Distance between (Position of (Ordered unit)) and (Target point of issued order)) Equal to 0.00" will most likely never be true.
  • The event fires when you select a point with your mouse, not when unit reaches the point, so distance is most likely > 0.00 when order is being issued
  • Even when unit reaches the point, there is usually some distance between the unit and the target point... around ~10 range, but that may be affected by unit's pathing size, not sure.
So unless you are issuing the point order via trigger and you issue it directly to the point on which unit is already standing, then I don't think the range check will ever be true.

Also, for this event:
  • Time - Every (Random real number between 10.00 and 50.00) seconds of game time
This will randomly pick a number between 10 and 50 only once at the start of the game and then use that picked number every time. So the delay will be constant for the entire duration of a playthrough.
To truly run that trigger randomly between 10 and 50 second, use countdown timer:
  • Wander
    • Events
      • Time - WanderTimer expires
    • Conditions
    • Actions
      • -------- do some stuff with villager --------
      • Countdown Timer - Start WanderTimer as a One-shot timer that will expire in (Random real number between 10.00 and 50.00) seconds
 
"(Distance between (Position of (Ordered unit)) and (Target point of issued order)) Equal to 0.00" will most likely never be true.
  • The event fires when you select a point with your mouse, not when unit reaches the point, so distance is most likely > 0.00 when order is being issued
  • Even when unit reaches the point, there is usually some distance between the unit and the target point... around ~10 range, but that may be affected by unit's pathing size, not sure.
So unless you are issuing the point order via trigger and you issue it directly to the point on which unit is already standing, then I don't think the range check will ever be true.

Also, for this event:
  • Time - Every (Random real number between 10.00 and 50.00) seconds of game time
This will randomly pick a number between 10 and 50 only once at the start of the game and then use that picked number every time. So the delay will be constant for the entire duration of a playthrough.
To truly run that trigger randomly between 10 and 50 second, use countdown timer:
  • Wander
    • Events
      • Time - WanderTimer expires
    • Conditions
    • Actions
      • -------- do some stuff with villager --------
      • Countdown Timer - Start WanderTimer as a One-shot timer that will expire in (Random real number between 10.00 and 50.00) seconds
This means I'll need a new Timer for each Villager right? Also I still can't get them to play the animation. Does it only work if I issue the order?
 
Also I still can't get them to play the animation. Does it only work if I issue the order?
The animation may be working, but will most likely be immediately overridden by Walking animation if the unit is moving.

This means I'll need a new Timer for each Villager right?
Yes, or you can have a single "Time - Every 1.00 seconds of game time" event and an integer variable array and unit variable array, where each index in the array corresponds to different Villager (basically, villager stored in unit array under index X will have his remaining time set in integer array under same index X).
At map initialization assign random integer number between 10 and 50 to each index in the array.
In a trigger with the "Time - Every 1.00 seconds of game time" event iterate over each item in the array (from 1 up to how many villagers you have), decrease value of each item in the integer array by 1 and if that value is 0, then order the villager to move randomly and set new random number between 10 and 50 to the array under given index (this way you reset the timer for a villager).

Something like this pseudo-code:
Code:
Variables:
   Villagers: unit array
   RemainingTimes: integer array
   TotalVillagers: integer

// At map initialization
Actions
   Set Villagers[1] = Bob<0001>
   Set Villagers[2] = John<0047>
   Set Villagers[3] = Patrick<0925>
   Set TotalVillagers = 3
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
         

// In trigger running with event "Time - Every 1.00 seconds of game time"
Actions
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = RemainingTimes[(Integer A)] - 1
         If All conditions are true:
             RemainingTimes[(Integer A)] is equal to 0
         Then actions:
             Unit - Order Villagers[(Integer A)] to Move To (Random point in WanderRegion <gen>)
             Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
 
The animation may be working, but will most likely be immediately overridden by Walking animation if the unit is moving.


Yes, or you can have a single "Time - Every 1.00 seconds of game time" event and an integer variable array and unit variable array, where each index in the array corresponds to different Villager (basically, villager stored in unit array under index X will have his remaining time set in integer array under same index X).
At map initialization assign random integer number between 10 and 50 to each index in the array.
In a trigger with the "Time - Every 1.00 seconds of game time" event iterate over each item in the array (from 1 up to how many villagers you have), decrease value of each item in the integer array by 1 and if that value is 0, then order the villager to move randomly and set new random number between 10 and 50 to the array under given index (this way you reset the timer for a villager).

Something like this pseudo-code:
Code:
Variables:
   Villagers: unit array
   RemainingTimes: integer array
   TotalVillagers: integer

// At map initialization
Actions
   Set Villagers[1] = Bob<0001>
   Set Villagers[2] = John<0047>
   Set Villagers[3] = Patrick<0925>
   Set TotalVillagers = 3
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
        

// In trigger running with event "Time - Every 1.00 seconds of game time"
Actions
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = RemainingTimes[(Integer A)] - 1
         If All conditions are true:
             RemainingTimes[(Integer A)] is equal to 0
         Then actions:
             Unit - Order Villagers[(Integer A)] to Move To (Random point in WanderRegion <gen>)
             Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
Thanks for replying again. I did figure out why I wasn't get the animation playing. Using "Ordered unit" would simply not trigger it, I either had to call the unit directly or use a variable for whatever reason. Anyway, this code seems to be what I'm looking for, even if it's with arrays and For Loops that I'm hopeless at, but this is easy to follow. One last thing is that I have a Region for each unit to wander in and this only applies to one. How would it work with multiple?
 
I did figure out why I wasn't get the animation playing. Using "Ordered unit" would simply not trigger it, I either had to call the unit directly or use a variable for whatever reason.
That's strange. (Ordered unit) should work as it was added exactly for "Unit is issued an order..."-like events... unless you have a wait action in your trigger before referencing (Ordered unit) or you issue an order to a unit inside the trigger. Anyway, try (Triggering unit), that should give you the unit that was issued an order, but it should be better than (Ordered unit).

One last thing is that I have a Region for each unit to wander in and this only applies to one. How would it work with multiple?
You will need to use a region variable array and assign Villagers' regions into it during map initialization, e.g.
Code:
Variables:
   Villagers: unit array
   VillagerRegions: region array

// At map initialization
Actions
   Set Villagers[1] = Bob<0001>
   Set VillagerRegions[1] = Region<0035>
   Set Villagers[2] = John<0047>
   Set VillagerRegions[2] = Region<0217>
   ...


// When ordering villager to move randomly:
Unit - Order Villagers[(Integer A)] to Move To (Random point in VillagerRegions[(Integer A)])

But if you want villagers to move randomly around the location they are placed in map editor and the region dimensions are +-same for each villager, then you could use Points instead of regions:
  • Create Point variable array
  • During map initialization store position of each villager into the array
  • When ordering villager to move randomly, use the villager's spawn point stored in the point array variable and the function 'Point with polar offset' to pick a point in random direction and random distance from the spawn point, like this:
Code:
Variables:
   Villagers: unit array
   RemainingTimes: integer array
   TotalVillagers: integer
   SpawnPoints: point array

// At map initialization
Actions
   Set Villagers[1] = Bob<0001>
   Set Villagers[2] = John<0047>
   Set Villagers[3] = Patrick<0925>
   Set TotalVillagers = 3
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
         Set SpawnPoints[(Integer A)] = (Position of Villagers[(Integer A)])


// In trigger running with event "Time - Every 1.00 seconds of game time"
Actions
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = RemainingTimes[(Integer A)] - 1
         If All conditions are true:
             RemainingTimes[(Integer A)] is equal to 0
         Then actions:
             Unit - Order Villagers[(Integer A)] to Move To (SpawnPoints[(Integer A)] offset by (Random real number between 30.00 and 400.00) towards (Random angle) degrees.)
             Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
The advantage is that you don't need to create regions and then manually set them up into the region array variable during map initialization, but you lose variance, as in the example above, all villagers will move to a random location within 30 to 400 range of their spawn point and towards a random angle.
 
That's strange. (Ordered unit) should work as it was added exactly for "Unit is issued an order..."-like events... unless you have a wait action in your trigger before referencing (Ordered unit) or you issue an order to a unit inside the trigger. Anyway, try (Triggering unit), that should give you the unit that was issued an order, but it should be better than (Ordered unit).


You will need to use a region variable array and assign Villagers' regions into it during map initialization, e.g.
Code:
Variables:
   Villagers: unit array
   VillagerRegions: region array

// At map initialization
Actions
   Set Villagers[1] = Bob<0001>
   Set VillagerRegions[1] = Region<0035>
   Set Villagers[2] = John<0047>
   Set VillagerRegions[2] = Region<0217>
   ...


// When ordering villager to move randomly:
Unit - Order Villagers[(Integer A)] to Move To (Random point in VillagerRegions[(Integer A)])

But if you want villagers to move randomly around the location they are placed in map editor and the region dimensions are +-same for each villager, then you could use Points instead of regions:
  • Create Point variable array
  • During map initialization store position of each villager into the array
  • When ordering villager to move randomly, use the villager's spawn point stored in the point array variable and the function 'Point with polar offset' to pick a point in random direction and random distance from the spawn point, like this:
Code:
Variables:
   Villagers: unit array
   RemainingTimes: integer array
   TotalVillagers: integer
   SpawnPoints: point array

// At map initialization
Actions
   Set Villagers[1] = Bob<0001>
   Set Villagers[2] = John<0047>
   Set Villagers[3] = Patrick<0925>
   Set TotalVillagers = 3
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
         Set SpawnPoints[(Integer A)] = (Position of Villagers[(Integer A)])


// In trigger running with event "Time - Every 1.00 seconds of game time"
Actions
   For each (Integer A) from 1 to TotalVillagers
      Loop
         Set RemainingTimes[(Integer A)] = RemainingTimes[(Integer A)] - 1
         If All conditions are true:
             RemainingTimes[(Integer A)] is equal to 0
         Then actions:
             Unit - Order Villagers[(Integer A)] to Move To (SpawnPoints[(Integer A)] offset by (Random real number between 30.00 and 400.00) towards (Random angle) degrees.)
             Set RemainingTimes[(Integer A)] = Random integer number between 10 and 50
The advantage is that you don't need to create regions and then manually set them up into the region array variable during map initialization, but you lose variance, as in the example above, all villagers will move to a random location within 30 to 400 range of their spawn point and towards a random angle.
Must have done something wrong. Only one Villager is moving and he's not obeying the integer interval.
  • FarmhandsSet
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet Farmhands[1] = Villager (Male) 0020 <gen>
      • Set VariableSet FarmhandsRegion[1] = WorkerRegion3 <gen>
      • Set VariableSet Farmhands[2] = Villager (Male 2) 0021 <gen>
      • Set VariableSet FarmhandsRegion[2] = WorkerRegion2 <gen>
      • Set VariableSet Farmhands[3] = Villager (Male) 0018 <gen>
      • Set VariableSet FarmhandsRegion[3] = WorkerRegion1 <gen>
      • Set VariableSet Farmhands[4] = Villager (Male) 0019 <gen>
      • Set VariableSet FarmhandsRegion[4] = WorkerRegion4 <gen>
      • Set VariableSet Farmhands[5] = Villager (Male 2) 0017 <gen>
      • Set VariableSet FarmhandsRegion[5] = WorkerRegion5 <gen>
      • Set VariableSet Farmhands[6] = Villager (Male) 0022 <gen>
      • Set VariableSet FarmhandsRegion[6] = WorkerRegion6 <gen>
      • Set VariableSet TotalFarmhands = 6
      • For each (Integer A) from 1 to TotalFarmhands, do (Actions)
        • Loop - Actions
          • Set VariableSet RemainingTimes[(Integer A)] = (Random integer number between 10 and 50)
  • FarmhandsWander
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer A) from 1 to TotalFarmhands, do (Actions)
        • Loop - Actions
          • Set VariableSet RemainingTimes[(Integer A)] = RemainingTimes[((Integer A) - 1)]
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • RemainingTimes[(Integer A)] Equal to 0
            • Then - Actions
              • Unit - Order Farmhands[(Integer A)] to Move To (Random point in FarmhandsRegion[(Integer A)])
              • Set VariableSet RemainingTimes[(Integer A)] = (Random integer number between 10 and 50)
            • Else - Actions
 
the -1 should be outside the square brackets. Like this:
  • Set VariableSet RemainingTimes[(Integer A)] = (RemainingTimes[(Integer A)] - 1)
Yup that was it. Took me a while to find the exact path to get there. Then I added the following trigger and they all play the animation after moving. Thanks so much!
  • FarmhandsCheck
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 6, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Current order of Farmhands[(Integer A)]) Equal to (Order(stand down))
            • Then - Actions
              • Animation - Play Farmhands[(Integer A)]'s stand work animation
            • Else - Actions
 
Back
Top