• 🏆 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] Want input on how to do a stacking spell

Status
Not open for further replies.
Level 8
Joined
Mar 17, 2016
Messages
133
Hi, I'm trying to make a spell that essentially will add +1 to a stack every time the unit is attacked by the Hero. What I'm looking to make is almost like Shadow Demon's shadow poison spell from Dota, though it will not be added through a spell but rather an auto attack. It will be able to be detonated by the hero at any given time to damage the units that have been hit by it. My plan was to use an array of unit variables and set the units individually as they are attacked, then add them to a unit group if not already in it. My issue is that I'll need a way to call upon these units at any given time when they are attacked in order to add another stack to what they already have. I would like input before I start doing things that could be a waste of time. Any thoughts on how to accomplish this? Thanks!
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,537
It can be rather simple depending on whether or not it's MUI.

How many units do you plan on giving this stacking attack to?

Edit: Example
  • Stack Attack
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (Unit-type of DamageEventSource) Equal to YourHero
    • Actions
      • Set VariableSet CV = (Custom value of DamageEventTarget)
      • -------- --------
      • -------- Increase Stack Count --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Or - Any (Conditions) are true
            • Conditions
              • Stack_Count[CV] Less than Stack_Limit
              • Stack_Limit Equal to 0
        • Then - Actions
          • Set VariableSet Stack_Count[CV] = (Stack_Count[CV] + 1)
        • Else - Actions
      • -------- --------
      • -------- Duration is reduced by 1 every 0.10 seconds (50 = 5.00 seconds) --------
      • Set VariableSet Stack_Duration[CV] = 50
      • -------- --------
      • -------- Add to Stack Unit Group --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (DamageEventTarget is in Stack_UG.) Equal to False
        • Then - Actions
          • Unit Group - Add DamageEventTarget to Stack_UG
        • Else - Actions
      • -------- --------
      • -------- Turn On Stack Loop --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Stack Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Stack Loop <gen>
        • Else - Actions
  • Stack Loop
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Stack_UG and do (Actions)
        • Loop - Actions
          • Set VariableSet CV = (Custom value of (Picked unit))
          • Set VariableSet Stack_Duration[CV] = (Stack_Duration[CV] - 1)
          • -------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • Stack_Duration[CV] Equal to 0
                  • ((Picked unit) is alive) Equal to False
            • Then - Actions
              • Unit Group - Remove (Picked unit) from Stack_UG.
            • Else - Actions
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in Stack_UG) Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
 
Last edited:
Level 8
Joined
Mar 17, 2016
Messages
133
Oh, good point. I didn't think to mention that, It will be unique to 1 hero that will only be selectable by 1 player so no need to be MUI. I'm assuming this is the non-MUI method? Also, I was wondering about this when thinking of a way to accomplish this; I see you've used "Set Custom Value" here and I am using a respawn trigger that uses the custom value of each unit. Is that going to get in the way of the respawn? (I've never used it before but saw the respawn trigger uses it and was worried that it might conflict.)
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,537
Ah, I left out a lot of information, I'm using a Unit Indexer and Bribe's Damage Engine.

GUI Unit Indexer 1.4.0.0
Damage Engine 5.7.1.1

The Unit Indexer essentially opens up the possibility to use custom value for as many things as you want.

So yes, it would conflict with your respawn trigger, but you could also adjust your respawn trigger to use the Unit Indexer instead.

Basically, you'd replace all cases of Custom Value with an Integer (Array) that uses the respawning unit's custom value as the Index.

I don't know how your respawn triggers work, but here's an example:
A unit dies -> Set RespawnTime[custom value of dying unit] = 10.00 seconds

If you post your Respawn trigger(s) I can show you how to easily modify them to work with the Unit Indexer. It's a great tool to have that will make your life much easier, so it's well worth it.
 
Level 8
Joined
Mar 17, 2016
Messages
133
Oh wow, this unit indexer seems very powerful. Probably would've been useful to know about a long time ago. :p too bad I guess
The respawn triggers are:
  • RespawnInitialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet Respawn_Timer_Creep = 600.00
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area) owned by Neutral Hostile) and do (Actions)
        • Loop - Actions
          • Set VariableSet Temp_Integer_Creep = (Temp_Integer_Creep + 1)
          • Unit - Set the custom value of (Picked unit) to Temp_Integer_Creep
          • Set VariableSet Creep_Point[Temp_Integer_Creep] = (Position of (Picked unit))
  • The Respawn
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Triggering unit)) Equal to Neutral Hostile
      • (Custom value of (Triggering unit)) Greater than 0
    • Actions
      • Wait Respawn_Timer_Creep game-time seconds
      • Unit - Create 1 (Unit-type of (Triggering unit)) for Neutral Hostile at Creep_Point[(Custom value of (Triggering unit))] facing (Random point in (Playable map area))
      • Unit - Set the custom value of (Last created unit) to (Custom value of (Triggering unit))
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,537
Oh wow, this unit indexer seems very powerful. Probably would've been useful to know about a long time ago. :p too bad I guess
The respawn triggers are:
  • RespawnInitialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet Respawn_Timer_Creep = 600.00
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area) owned by Neutral Hostile) and do (Actions)
        • Loop - Actions
          • Set VariableSet Temp_Integer_Creep = (Temp_Integer_Creep + 1)
          • Unit - Set the custom value of (Picked unit) to Temp_Integer_Creep
          • Set VariableSet Creep_Point[Temp_Integer_Creep] = (Position of (Picked unit))
  • The Respawn
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Triggering unit)) Equal to Neutral Hostile
      • (Custom value of (Triggering unit)) Greater than 0
    • Actions
      • Wait Respawn_Timer_Creep game-time seconds
      • Unit - Create 1 (Unit-type of (Triggering unit)) for Neutral Hostile at Creep_Point[(Custom value of (Triggering unit))] facing (Random point in (Playable map area))
      • Unit - Set the custom value of (Last created unit) to (Custom value of (Triggering unit))

Okay, this is easy, so all you have to do is delete these two lines:
  • Set VariableSet Temp_Integer_Creep = (Temp_Integer_Creep + 1)
  • Unit - Set the custom value of (Picked unit) to Temp_Integer_Creep
And set Creep_Point using the unit's custom value instead of Temp_Integer:
  • Creep_Point[Custom value of (Picked unit)] = (Position of (Picked unit))
Also delete this line from the second trigger:
  • Unit - Set the custom value of (Last created unit) to (Custom value of (Triggering unit))
The Unit Indexer will manage the Custom Values for you, so never adjust them yourself.

Note that you're leaking a point with this line in your Create Unit function: (Random point in (Playable map area))
You'd want to set (Random point in (Playable map area)) as a Point variable first, then reference it, and remove it when you're done.

Like:
Set TempPoint = Random point in playable map area
Create 1 Unit at Creep_Point facing TempPoint
Custom script: call RemoveLocation (udg_TempPoint)
 
Last edited:
Level 8
Joined
Mar 17, 2016
Messages
133
I've noticed something odd happening since implementing the respawn changes. The units will only respawn once, rather than before where it would be indefinitely, as well as respawning units are taking the points of previously killed units. Eg. I have bandits in a forest and clockwerk goblins on an island, after killing the clockwerk goblins and then the bandits I noticed there were bandits on the island, as well as the bandits stopped spawning in the forest. Any idea what could cause this? Here is what I did to the respawn trigger:

  • RespawnInitialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet Respawn_Timer_Creep = 5.00
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area) owned by Neutral Hostile) and do (Actions)
        • Loop - Actions
          • Set VariableSet Creep_Point[(Custom value of (Picked unit))] = (Position of (Picked unit))
      • Unit Group - Pick every unit in (Units in (Playable map area) owned by Player 8 (Pink)) and do (Actions)
        • Loop - Actions
          • Set VariableSet Creep_Point[(Custom value of (Picked unit))] = (Position of (Picked unit))
  • The Respawn
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Dying unit)) Equal to Neutral Hostile
      • ((Dying unit) is An Ancient) Equal to False
      • ((Dying unit) is Summoned) Equal to False
    • Actions
      • Wait Respawn_Timer_Creep game-time seconds
      • Unit - Create 1 (Unit-type of (Dying unit)) for Neutral Hostile at Creep_Point[(Custom value of (Dying unit))] facing (Random point in (Playable map area))
The reason I have checks for Is unit ancient is because I'm making a boss system where the bosses do not respawn, and are set to ancient. And the reason I have pink selected is to basically use it as a secondary Neutral Hostile that will fight the regular neutral hostile units. The units that were taking eachother's respawn points are regular Neutral Hostile units.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,537
Ah, you need to re-set Creep_Point after they're created. This is because you're creating a new unit, so it'll be assigned a new custom value. The system does recycle unused custom values, but it's unlikely that a newly created unit would end up with the same value that it had before.
 
Level 8
Joined
Mar 17, 2016
Messages
133
Hey, Im actually just getting around to doing the stacking spell now and I have a question about it:

Would it be easier on the system to fire every 1 second flat and set the variable to 5 instead of firing every .1 seconds? Or perhaps even every .5 seconds?

I'm curious because I want to make sure I don't introduce too much lag to my game which im predicting will be played to upwards of 1.5 hours. Im trying to do everything right to keep it running smoothly but I've never really done anything of this scope before and surely have at least a few things that could cause lag
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,537
Hey, Im actually just getting around to doing the stacking spell now and I have a question about it:

Would it be easier on the system to fire every 1 second flat and set the variable to 5 instead of firing every .1 seconds? Or perhaps even every .5 seconds?

I'm curious because I want to make sure I don't introduce too much lag to my game which im predicting will be played to upwards of 1.5 hours. Im trying to do everything right to keep it running smoothly but I've never really done anything of this scope before and surely have at least a few things that could cause lag
It would be easier on the system, but not really necessary.

Remember, the trigger will only be turned on when a unit has a stack. That and there probably won't be many units affected at once just by the nature of the ability.

Plus, if you increase the interval to every 1 second you'll lose precision which would result in the stacks potentially lasting ~1 second shorter than they should have.

Some of the big performance killers:
-Creating multiple special effects, multiple times per second.
-Creating multiple units, multiple times per second.
-Picking through multiple units, multiple times per second. This one can change greatly depending on what you're doing after picking these units and how many units you're looping through. In the case of the Stack trigger, I imagine you'd have to go out of your way to get 5+ units inside the Unit Group at once. Because of this, and because it's only dealing with simple arithmetic (Reducing an Integer by 1) it's very lightweight.
 
Last edited:
Status
Not open for further replies.
Top