• 🏆 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!

[Spell] Triggered Spell Bug help

Level 6
Joined
May 13, 2023
Messages
44
Hello, I have this simple spell that gives the caster bonus attack damage based on the caster's lost hitpoints. The trigger works fine but the problem starts when more than 1 unit uses the ability simultaneously. The unit that casts first get's their damage reverted back but the following units don't. Would appreciate any help.
  • Berserk Init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Berserk
    • Actions
      • Set BerserkCaster = (Triggering unit)
      • Set BerserkInitDamage = (Base Damage of BerserkCaster for weapon index 1)
      • Set BerserkBonusDamage = (((Max life of BerserkCaster) - (Life of BerserkCaster)) x 0.08)
      • Countdown Timer - Start BerserkTimer as a One-shot timer that will expire in 15.00 seconds
      • Unit - Set Base Damage of BerserkCaster to ((Base Damage of BerserkCaster for weapon index 1) + (Integer(BerserkBonusDamage))) for weapon index: 1
      • Trigger - Turn on Berserk End <gen>
  • Berserk End
    • Events
      • Time - BerserkTimer expires
    • Conditions
    • Actions
      • Unit - Set Base Damage of BerserkCaster to BerserkInitDamage for weapon index: 1
      • Trigger - Turn off (This trigger)
 
Level 6
Joined
May 13, 2023
Messages
44
Thank you Nichilus for the reply, well I did try to do dynimac indexing but i just can't get it work with Timers, I used waits and it worked fine but i was told multiple times to not use waits.

Here is my attemp
  • Berserk Init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Berserk
    • Actions
      • Set BerserkIndex = (BerserkIndex + 1)
      • Set BerserkCaster[BerserkIndex] = (Triggering unit)
      • Set BerserkDamageInit[BerserkIndex] = (Base Damage of BerserkCaster[BerserkIndex] for weapon index 1)
      • Set BerserkDamageBns[BerserkIndex] = (((Max life of BerserkCaster[BerserkIndex]) - (Life of BerserkCaster[BerserkIndex])) x 0.08)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • BerserkIndex Greater than or equal to 1
        • Then - Actions
          • Unit - Set Base Damage of BerserkCaster[BerserkIndex] to (BerserkDamageInit[BerserkIndex] + (Integer(BerserkDamageBns[BerserkIndex]))) for weapon index: 1
          • Trigger - Turn on Berserk End <gen>
          • Countdown Timer - Start BerserkTimer as a One-shot timer that will expire in 15.00 seconds
        • Else - Actions
  • Berserk End
    • Events
      • Time - BerserkTimer expires
    • Conditions
    • Actions
      • Unit - Set Base Damage of BerserkCaster[BerserkIndex] to BerserkDamageInit[BerserkIndex] for weapon index: 1
      • Set BerserkIndex = (BerserkIndex - 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • BerserkIndex Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
I wouldn't use Dynamic Indexing for an ability that should never stack. Use Unit Indexing and simply track the buff, when the buff is gone, reset the damage.

Here's an example:
 
Last edited:
Level 25
Joined
Sep 26, 2009
Messages
2,378
irrespective of whether you use dynamic or unit indexing, the issue why your modified trigger does not work is because you are using a single instance of Timer. The 'Berserk End' will also end the effect for incorrect unit.

You can see the issue if you run those triggers 2 times 'on paper':
First cast:
  • Index = Index + 1 => 0 + 1 = 1
  • Caster[Index] = Unit_A => Caster[1] = Unit_A
  • Start timer 'T' with 15.0 seconds remaining
Second cast (6 seconds after first cast):
  • Index = Index + 1 => 1 + 1 = 2
  • Caster[Index] = Unit_B => Caster[2] = Unit_B
  • (Re)start timer 'T' with 15.0 seconds remaining
Wait 15 seconds since second cast for the timer to expire and start Berserk End:
  • Update damage of Caster[Index] => Update damage of Caster[2] => Update damage of Unit_B
  • Index = Index - 1 => 2 - 1 = 1
So you can see here, that the you actually remove the effect from Caster[2]. Also, both first and second cast share same timer, so the second cast actually restarted the timer which affected the duration of the spell of the first cast.

The solution here is to not use timers but periodic events like in the thread that Uncle posted and keep track of the remaining time in an integer array
 
Level 12
Joined
Feb 5, 2018
Messages
521
There are many ways to approach this. We can use a hashtable with periodic loop, local unit or simply set the buff duration to 15 seconds in object editor and use a damage detection event and set the damage to damage amount + your damage formula. I use lots of hashtables to track time and also variabless triggers with local units.

With the hashtables you have too keep in mind that the hashtable must be created in Map initialization trigger.

Method 1:

  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set VariableSet Berserk_Hash = (Last created hashtable)
  • Bersker With Hashtables
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Berserk
    • Actions
      • Unit Group - Add (Triggering unit) to Berserk_Group
      • Set VariableSet Bersker_Time = 15.00
      • Hashtable - Save Bersker_Time as 0 of (Key (Triggering unit).) in Berserk_Hash.
      • Trigger - Turn on Bersker Hashtabe Loop <gen>
  • Bersker Hashtabe Loop
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Berserk_Group and do (Actions)
        • Loop - Actions
          • Set VariableSet Bersker_Time = (Load 0 of (Key (Picked unit).) from Berserk_Hash.)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Bersker_Time Greater than 0.00
            • Then - Actions
              • Hashtable - Save (Bersker_Time - 0.10) as 0 of (Key (Picked unit).) in Berserk_Hash.
            • Else - Actions
              • Hashtable - Clear all child hashtables of child (Key (Picked unit).) in Berserk_Hash.
              • Unit - Remove Berserk buff from (Picked unit)
              • Unit Group - Remove (Picked unit) from Berserk_Group.
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in Berserk_Group) Less than or equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions

Method 2:

  • Berserk No Variables
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Berserk
    • Actions
      • Custom script: local unit Caster =(GetTriggerUnit())
      • Custom script: local real Wait = 15.00
      • Custom script: call PolledWait(Wait)
      • -------- Set the 'Bbsk' to your custom buff code and we are good to go! --------
      • Custom script: call UnitRemoveBuffBJ( 'Bbsk', (Caster) )

Method 3: Requires Damage Engine 5.A.0.0

  • Berserk on Damage
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (DamageEventSource has buff Berserk) Equal to True
    • Actions
      • Set VariableSet Bersker_Caster = DamageEventSource
      • Set VariableSet DamageEventAmount = (DamageEventAmount + ((Max life of Bersker_Caster) - ((Life of Bersker_Caster) x 0.08)))
 
Top