[Solved] Forcefully stop Defend ability

Level 3
Joined
Jul 5, 2022
Messages
15
Hi everyone!

TL;DR: is there an option to forcefully stop Defend ability except "Unit - Order (Triggering unit) to Human Footman - Stop Defend" (aka 'undefend')?

The long version goes below :)

I have a custom Channel-based spell ("Repair") that is perfect in every way I need it to be but one little annoying thing: I need it to stop any other active "defensive" abilities of a unit (and also remove all protective buffs). Currently my unit has Wind Walk and custom Defend-like ability. I can disable Wind Walk by removing buff from unit, I can disable Invulnerability of any kind by also removing buff and so on, but I can't force the unit out of this "Defend-like" ability.

What I have already tried and it did not work:
  • Events
    • Unit - A unit Begins channeling an ability
  • Conditions
    • (Ability being cast) Equal to Repair
  • Actions
    • Unit - Order (Triggering unit) to Human Footman - Stop Defend.
It hangs my Channel-based spell for eternity.

Tried to remove ability itself, to "unresearch" the requirement for the ability, to disable ability for the player — none of these works. It disables the ability itself, but the unit still remains in "Defend-on"-state.

Are there any other options I missed?
Or should i just remake my Defend-based ability from scratch, using something else instead? If so, what options do I have?

Currently my Defend-based ability works like default Defend with 50% chance to reflect, but there's also a trigger that adds custom Spiked Carapace-based ability to unit on 'defend' and removes when 'undefend' and adds some ManaShield-like effect for the duration of the Defend. How can I remake that?
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Detect when your Unit issues the Order to cast the Repair ability, cancel the issued Order, Issue orders to cancel Defend and others, Re-issue the Repair Order.

Likely need to use BlzPauseUnitEx() to interrupt the Order and Issue news ones within the same frame.
 
Last edited:
Level 3
Joined
Jul 5, 2022
Messages
15
Detect when your Unit issues the Order to cast the Repair ability, cancel the issued Order, Issue orders to cancel Defend and others, Re-issue the Repair Order.

Likely need to use BlzPauseUnitEx() to interrupt the Order and Issue news ones within the same frame.
If I understood you correctly, you're suggesting something like this:
  • RepairTrigger
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
      • (Issued order) Equal to (Order(channel))
    • Actions
      • Trigger - Turn off (This trigger) // to avoid trigger launch itself
      • Unit - Remove Wind Walk buff from my_unit
      • Unit - Remove Divine Shield buff from my_unit
      • Unit - Order my_unit to Human Footman - Stop Defend.
      • Custom script: call BlzPauseUnitEx(udg_my_unit, true)
      • Custom script: call BlzPauseUnitEx(udg_my_unit, false)
      • Wait 0.10 seconds
      • Unit - Order my_unit to Special - Channel.
      • Trigger - Turn on (This trigger)
is that correct?
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Yes, but you shouldn't need the Wait, so something like this:
  • RepairTrigger
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
      • (Issued order) Equal to (Order(channel))
    • Actions
      • Trigger - Turn off (This trigger) // to avoid trigger launch itself
      • Set Variable my_unit = (Triggering unit)
      • Unit - Remove Wind Walk buff from my_unit
      • Unit - Remove Divine Shield buff from my_unit
      • Custom script: call BlzPauseUnitEx(udg_my_unit, true)
      • Unit - Order my_unit to Stop
      • Unit - Order my_unit to Human Footman - Stop Defend.
      • Custom script: call BlzPauseUnitEx(udg_my_unit, false)
      • Unit - Order my_unit to Special - Channel.
      • Trigger - Turn on (This trigger)
Play around with the order of the Actions.
 
Level 3
Joined
Jul 5, 2022
Messages
15
Yes, but you shouldn't need the Wait, so something like this:
  • RepairTrigger
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
      • (Issued order) Equal to (Order(channel))
    • Actions
      • Trigger - Turn off (This trigger) // to avoid trigger launch itself
      • Set Variable my_unit = (Triggering unit)
      • Unit - Remove Wind Walk buff from my_unit
      • Unit - Remove Divine Shield buff from my_unit
      • Custom script: call BlzPauseUnitEx(udg_my_unit, true)
      • Unit - Order my_unit to Stop
      • Unit - Order my_unit to Human Footman - Stop Defend.
      • Custom script: call BlzPauseUnitEx(udg_my_unit, false)
      • Unit - Order my_unit to Special - Channel.
      • Trigger - Turn on (This trigger)
Play around with the order of the Actions.
For some reason without 'Wait' the Channel action do not start at all — more than that, nothing happens at all, not even 'undefend' happens. Tried both my version from above and your exact version.

Currently my working solution looks like this:
  • RepairTrigger
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
      • (Issued order) Equal to (Order(channel))
    • Actions
      • Trigger - Turn off (This trigger) // to avoid trigger launch itself
      • Unit - Remove Wind Walk buff from my_unit
      • Unit - Remove Divine Shield buff from my_unit
      • Unit - Order my_unit to Human Footman - Stop Defend.
      • Player - Disable Defend for (Owner of my_unit) // to avoid hotkey spamming in 0.1 sec gap
      • Wait 0.10 seconds
      • Unit - Order my_unit to Special - Channel.
      • Player - Enable Defend for (Owner of my_unit)
      • Trigger - Turn on (This trigger)
It works without BlzPauseUnitEx() and I can't get it how exactly it should help me in this context... :peasant-thinking:

But still thanks a lot for your advice to capture Order and not 'Begins channeling' — it helped me a lot!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
BlzPauseUnitEx(), and originally Pause, can be used to "replace" an issued Order without needing a Wait. But since you're doing so much stuff here it might not work properly, although I bet with enough tinkering it could. Normally, if you try to Issue a new Order in response to an Issued Order the unit simply ignores the new Order, I imagine because the engine is already in the middle of processing one and can't handle such a request.

Anyway, if you use a Wait make sure that you reference (Triggering unit) or a global variable that never changes. Also, if other units use this trigger then you'll run into issues because the trigger is off for a period of time. To fix that, you can introduce a Boolean variable tied to the Unit which is checked in the Conditions. Toggle it to True/False instead of turning the Trigger Off/On. Unit Indexing would make this very simple.
 
Level 3
Joined
Jul 5, 2022
Messages
15
It works without BlzPauseUnitEx() and I can't get it how exactly it should help me in this context... :peasant-thinking:
Found out that without BlzPauseUnitEx() animation can go out of sync and Channel effect (Art - Caster) won't play sometimes for some reason. Adding this soft 'pause/unpause'-like mechanic fixes this issue.
Also figured out that Wait could be as little as possible (i.e. 0.01 sec), but should be at it's place, otherwise, as mentioned above, trigger and ability won't work at all.

Final (for now) solution looks like this:
  • RepairTrigger
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
      • (Issued order) Equal to (Order(channel))
    • Actions
      • Set VariableSet my_unit = (Triggering unit)
      • Trigger - Turn off (This trigger) // to avoid trigger launch itself
      • Unit - Order my_unit to Human Footman - Stop Defend.
      • Player - Disable Defend for (Owner of my_unit) // to avoid hotkey spamming in 0.01 sec gap
      • Custom script: call BlzPauseUnitEx(udg_my_unit, true)
      • Custom script: call BlzPauseUnitEx(udg_my_unit, false)
      • Wait 0.01 seconds
      • Unit - Order my_unit to Special - Channel.
      • Unit - Remove Divine Shield buff from my_unit // moved lower to be sure
      • Unit - Remove Wind Walk buff from my_unit
      • Player - Enable Defend for (Owner of my_unit)
      • Trigger - Turn on (This trigger)
@Uncle thanks a lot again for your effort and helpful tips! Solved!
 
Level 3
Joined
Jul 5, 2022
Messages
15
Also, if other units use this trigger then you'll run into issues because the trigger is off for a period of time. To fix that, you can introduce a Boolean variable tied to the Unit which is checked in the Conditions. Toggle it to True/False instead of turning the Trigger Off/On. Unit Indexing would make this very simple.
Great advice, thank you! I'll have it in mind, but currently it's only one unit and the "Repair" trigger would actually be turned on and provided with Event from another trigger (hero choice) like this:
  • HeroWarGolem
    • Events
      • Unit - A unit enters WarGolem <gen>
    • Conditions
    • Actions
      • Unit - Create 1 War Golem for (Owner of (Entering unit)) at (Center of Start2 <gen>) facing Default building facing degrees
      • Set VariableSet PlayerHero = (Last created unit)
      • Hero - Create Ankh of Reincarnation and give it to PlayerHero
      • Unit - Remove (Entering unit) from the game
      • <lots of other stuff>
      • Trigger - Add to WarGolemAbils <gen> the event (Unit - PlayerHero Is issued an order with no target) // multiple orders are monitored there
      • Trigger - Turn on WarGolemAbils <gen>
      • Trigger - Add to WarGolemIntZero <gen> the event (Unit - PlayerHero's mana becomes Greater than 0.00) // always set hero's maxMana and Int to 0
      • Trigger - Turn on WarGolemIntZero <gen>
      • Trigger - Turn off (This trigger)
 
Level 24
Joined
Feb 27, 2019
Messages
833
Whenever a wait is needed to delay something just a smudge its almost always just required to wait a single frame. Probably the best way to delay something a single frame is by starting a timer at 0.00 seconds and executing the required actions when the timer expires.

Example:
  • Untitled Trigger 001
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Unit Group - Add Footman 0000 <gen> to g
      • Unit - Remove Defend from Footman 0000 <gen>
      • Countdown Timer - Start t as a One-shot timer that will expire in 0.00 seconds
  • Untitled Trigger 002
    • Events
      • Time - t expires
    • Conditions
    • Actions
      • Unit Group - Pick every unit in g and do (Actions)
        • Loop - Actions
          • Unit - Add Defend to (Picked unit)
          • Unit Group - Remove (Picked unit) from g
By the way, this works to make the unit undefend.
  • Untitled Trigger 001
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Unit - Remove Defend from Footman 0000 <gen>
      • Unit - Add Defend to Footman 0000 <gen>
 
Last edited:
Level 3
Joined
Jul 5, 2022
Messages
15
By the way, this works to make the unit undefend.
  • base.gif
    Untitled Trigger 001
    • joinminus.gif
      events.gif
      Events
      • line.gif
        joinbottom.gif
        player.gif
        Player - Player 1 (Red) skips a cinematic sequence
    • join.gif
      cond.gif
      Conditions
    • joinbottomminus.gif
      actions.gif
      Actions
      • empty.gif
        join.gif
        unit.gif
        Unit - Remove Defend from Footman 0000 <gen>
      • empty.gif
        joinbottom.gif
        unit.gif
        Unit - Add Defend to Footman 0000 <gen>
That was unexpected! 😲 Just removing the ability will just remove the icon, but unit will still be in 'defend' position. But adding it back not only 'releases' defend, but also triggers the 'undefend' order. Just tested with two triggers and it worked greatly:
  • def
    • Events
      • Player - Player 1 (Red) types a chat message containing def as An exact match
    • Conditions
    • Actions
      • Unit - Remove Defend from Footman 0002 <gen>
      • Unit - Add Defend to Footman 0002 <gen>
  • orderdef
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Issued order) Equal to (Order(defend))
        • Then - Actions
          • Unit - Add Spiked Shell (2,2 Button Pos) to (Triggering unit)
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Issued order) Equal to (Order(undefend))
        • Then - Actions
          • Unit - Remove Spiked Shell (2,2 Button Pos) from (Triggering unit)
        • Else - Actions
Now if I use Defend, my footy gets Spikes and when I type 'def' — he 'undefends' and spikes are gone too.
Very much thank you for not so obvious but so much straightforward solution 👍

Will continue to experiment with my initial plan — looks like there will be more than one "final" working solution after all 😁

UPD: it also works if Defend is a hero ability. If removed from unit the ability is placed to available skills to learn (without releasing ability point though), and adding it back simply learns it again (without consuming ability point). Looks fantastic, continuing experiments!
 
Last edited:
Level 24
Joined
Feb 27, 2019
Messages
833
That was unexpected! 😲 Just removing the ability will just remove the icon, but unit will still be in 'defend' position. But adding it back not only 'releases' defend, but also triggers the 'undefend' order. Just tested with two triggers and it worked greatly:
  • def
    • Events
      • Player - Player 1 (Red) types a chat message containing def as An exact match
    • Conditions
    • Actions
      • Unit - Remove Defend from Footman 0002 <gen>
      • Unit - Add Defend to Footman 0002 <gen>
  • orderdef
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Issued order) Equal to (Order(defend))
        • Then - Actions
          • Unit - Add Spiked Shell (2,2 Button Pos) to (Triggering unit)
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Issued order) Equal to (Order(undefend))
        • Then - Actions
          • Unit - Remove Spiked Shell (2,2 Button Pos) from (Triggering unit)
        • Else - Actions
Now if I use Defend, my footy gets Spikes and when I type 'def' — he 'undefends' and spikes are gone too.
Very much thank you for not so obvious but so much straightforward solution 👍

Will continue to experiment with my initial plan — looks like there will be more than one "final" working solution after all 😁
You got me thinking a bit more. It doesnt even have to be the same defend ability that is removed/added but can be a dummy defend ability that is added/removed. That should remove potential problems caused by adding/removing the original one.
 
Top