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

[Solved] Need help with custom poison cloud ability

Status
Not open for further replies.
Level 8
Joined
Mar 17, 2016
Messages
133
So I have been trying to get this ability to work for a couple of days now. I cannot figure out a few things and it's possible that I'm going at it the wrong way.

The goal of the ability is to have a cloud of poisonous smoke. While units are within the radius they have a chance to miss and take stacking poison damage every second. It's important to the ability that the damage of the poison stacks the longer you are in it, so I need multiple dummy units to spawn to re-apply the poison through another instance.

Right now, as you can see below, I'm trying to get it to work through a unit group: to make the dummy with the poison to attack every unit in the radius once and then, 1 second later, another will spawn and do the same. I have tried simply giving the dummy unit multishot but as far as I know barrage does not apply orb effects (such as poison). I could imagine that this unit group method might work, but I am running into problems that I don't understand.

If you look below at the trigger, you see I'm printing the amount of units in the unit group. What happens is the 1st instance of the loop the correct amount of units will show up, but on the 2nd to 6th loop it will always return 0 units in UnitGroupB - even when every check or "remove unit from" function is not there. Something I'm missing perhaps?
Also, no matter what the poison will only be applied to one unit. The whole idea of the "Integer B loop" is to try to get the dummy unit to attack each unit that has been put into the group, aka units in range. But only 1 unit is ever affected, even during the first loop when it prints the correct amount of units within the unit group. I don't understand this, especially because the dummy unit itself has the right amount of range on it (375) as well as target acquisition range - AND it's attack speed is set to 0.01, so it should not be a problem of cooldown time.



  • TR PoisonCloud
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Toxic Cloud (TR)
    • Actions
      • Set VariableSet AbilityPointTargeting[14] = (Target point of ability being cast)
      • Unit - Create 1 DummyUnit 24 (TR Poison Cloud) for (Owner of (Triggering unit)) at AbilityPointTargeting[14] facing Default building facing degrees
      • Unit - Add a 6.50 second Generic expiration timer to (Last created unit)
      • Unit - Set level of Toxic Cloud Dummy for (Last created unit) to (Level of Toxic Cloud (TR) for (Triggering unit))
      • Unit - Order (Last created unit) to Human Dragonhawk Rider - Cloud AbilityPointTargeting[14]
      • Custom script: call GameTimeWait(0.5)
      • -------- ---- --------
      • For each (Integer A) from 1 to 6, do (Actions)
        • Loop - Actions
          • Unit - Create 1 DummyUnit 24 (TR Poison Cloud) for (Owner of (Triggering unit)) at AbilityPointTargeting[14] facing Default building facing degrees
          • Set VariableSet DummyTracker[17] = (Last created unit)
          • Unit - Add a 0.60 second Generic expiration timer to DummyTracker[17]
          • Unit - Set level of TR Toxic DMG Dummy (TR) for DummyTracker[17] to (Level of Toxic Cloud (TR) for (Triggering unit))
          • -------- ---- --------
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 350.00 of AbilityPointTargeting[14].) and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Picked unit) is alive) Equal to True
                  • ((Picked unit) belongs to an enemy of (Owner of (Triggering unit)).) Equal to True
                  • ((Picked unit) is Magic Immune) Equal to False
                  • ((Picked unit) is in UnitGroupB[0].) Equal to False
                • Then - Actions
                  • Unit Group - Add (Picked unit) to UnitGroupB[0]
                • Else - Actions
          • -------- ---- --------
          • Game - Display to (All players) the text: GROUP _______
          • Game - Display to (All players) the text: (String((Number of units in UnitGroupB[0])))
          • Set VariableSet PulsesInteger[9] = (Number of units in UnitGroupB[0])
          • Game - Display to (All players) the text: PulseInteger _____...
          • Game - Display to (All players) the text: (String(PulsesInteger[9]))
          • For each (Integer B) from 1 to PulsesInteger[9], do (Actions)
            • Loop - Actions
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Random 1 units from UnitGroupB[0]) and do (Actions)
                • Loop - Actions
                  • Unit - Order DummyTracker[17] to Attack Once (Picked unit)
                  • Unit - Cause DummyTracker[17] to damage (Picked unit), dealing 1.00 damage of attack type Normal and damage type Normal
                  • Unit Group - Remove (Picked unit) from UnitGroupB[0].
          • Unit Group - Remove all units from UnitGroupB[0].
          • Custom script: call GameTimeWait(1)
          • Game - Display to (All players) the text: waiting 1 second
      • Custom script: call RemoveLocation (udg_AbilityPointTargeting[14])

Is there someone that could help me with this? Am I missing something with the dummy unit, is the code wrong, is there flat out a better way?

Worst case scenario I make the damage not ramp and just use something like blizzard to damage, but that's absolutely not what I'm going for with this and is last resort only.

Thanks in advance.
 
Level 14
Joined
Feb 7, 2020
Messages
386
I think there's some specific use cases of the "issue order" function that are limited by number of calls per frame. Also, not certain here, but your attack once might not obey the queued command rule (so they're all happening within less than a .01 sec window and failing).

I think this could be simplified with a custom damage event or by installing a damage engine, and a unit indexer. You would then have direct control over the damage multiplier or scaling effects and could do away with requiring a dummy unit and all of this convoluted "engine hackery". I used to do this and going to a damage engine has been, simply put, the best dev pipeline change ever.

This is a decent pair: GUI Unit Indexer 1.4.0.0 and Damage Engine 5.5.0.0 (I think the damage engine comes with the former mentioned indexer by default). I have more information about this damage engine's basics here.

Here is a rudimentary sample using these two packages to give you an idea (didn't test it):

- Create a spell dummy that casts rain of fire or another AoE over time effect, with damage set to 1, then make a trigger like this that listens for that damage and alters it.
- This could also be a timer that runs, but I did this to keep my example simple; it also limits the amount of conditions you add to the GUI code (they get handled by the spell i.e. only enemies, etc.) and prevents the GUI 'only runs once' bug that occasionally occurs with GUI periodic timers. Can tackle it however you wish.

  • Poison Cloud
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • DamageEventSource Equal to tempunit (this is your spell dummy; to convert to MUI could probably check for unit type instead and then check for unit index of DamageEventSource in actions)
      • IsDamageSpell Equal to True
    • Actions
      • -------- Unit index value --------
      • Set VariableSet ID = (Custom value of DamageEventTarget)
      • -------- Increment the damage by your multiplier or scaling value for specific unit (based on unit indexer) --------
      • Set VariableSet stackingDamageAmount[ID] = (stackingDamageAmount[ID] + 1.00)
      • Unit - Cause tempunit to damage DamageEventTarget, dealing (DamageEventAmount + stackingDamageAmount[ID]) damage of attack type Spells and damage type Normal
Add all of your other effects as desired on spell cast, etc., with on-use trigger(s) etc. You would also need to clear/reset the stackingDamageAmount[] array to 0 after the effect ends, which you could probably do by storing the IDs that get used in hashtable or something. I am spoiled by writing in Lua so not sure if there's a better way in GUI or JASS.
 
Last edited:
Status
Not open for further replies.
Top