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

Respawn system like League of Legends

Status
Not open for further replies.
Level 12
Joined
May 16, 2020
Messages
660
Hi all,

I searched for a good creep respawn system like in league of legends (LoL), but didn't find one similarly.

In LoL, Creeps respawn only when the entire creep camp is dead. This means if you have 3 creeps in a spot and you kill 2 of the 3, the 2 will not revive until the last one is also dead. Also, the respawned creeps don't just respawn in a random spot within a region, but at their original location with original facing angle. And, also important, they should ideally not be pre-placed in the map, to reduce loading times.

The respawn systems here are very good, but they unfortunately don't include this "grouping" aspect of the revive:
Can someone please help create such a system/adjust the ones above?

If there are any benefits of JASS compared to GUI, then JASS is fine (I don't really know how to adjust JASS though, so please ideally make it so that I can adjust it)

Cheers!
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
Contain the camp in a unit group, then when one of the creeps dies remove them from the group and check if the group is empty. If the group is empty then you can begin the respawning process.

Example:
Step 1: Wait 60 seconds -> Create X units at X points facing the desired angle(s) -> Add them to UnitGroup[X]
Step 2: A unit dies -> If Unit is in UnitGroup[X] -> Remove unit from UnitGroup[X] -> If UnitGroup[X] is empty -> Run step 1
 
Level 12
Joined
May 16, 2020
Messages
660
So I starting with using Simple Spawning and Reviving System 1.2f [GUI] as base. In the below I want to first of test if the concept works, but not sure how efficient this is:

(everything here is set up for 1 camp only as of now to keep it simple)

  • Creep Setup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- CAMP 1: The KOBOLD gang --------
      • Set VariableSet Creep_SpawnUnit[1] = Kobold Taskmaster
      • Set VariableSet Creep_SpawnUnit[2] = Kobold Tunneler
      • Set VariableSet Creep_SpawnUnit[3] = Kobold
      • Set VariableSet Creep_SpawnUnit[4] = Kobold
      • Set VariableSet Creep_SpawnUnit[5] = Kobold
      • Set VariableSet Creep_SpawnRegion[1] = Creep Unit 1 Kobolt <gen>
      • Set VariableSet Creep_SpawnRegion[2] = Creep Unit 2 Kobolt <gen>
      • Set VariableSet Creep_SpawnRegion[3] = Creep Unit 3 Kobolt <gen>
      • Set VariableSet Creep_SpawnRegion[4] = Creep Unit 4 Kobolt <gen>
      • Set VariableSet Creep_SpawnRegion[5] = Creep Unit 5 Kobolt <gen>
      • -------- Not sure if this works: --------
      • Set VariableSet Creep_Group_CampUnit[1] = Creep_Group_Camp[1]
      • Set VariableSet Creep_Group_CampUnit[2] = Creep_Group_Camp[1]
      • Set VariableSet Creep_Group_CampUnit[3] = Creep_Group_Camp[1]
      • Set VariableSet Creep_Group_CampUnit[4] = Creep_Group_Camp[1]
      • Set VariableSet Creep_Group_CampUnit[5] = Creep_Group_Camp[1]
      • -------- IDEALLY COMBINE THESE ENTRIES --------
      • Set VariableSet Creep_SpawnAngle[1] = 285.00
      • Set VariableSet Creep_SpawnAngle[2] = 285.00
      • Set VariableSet Creep_SpawnAngle[3] = 285.00
      • Set VariableSet Creep_SpawnAngle[4] = 285.00
      • Set VariableSet Creep_SpawnAngle[5] = 285.00
      • Set VariableSet Creep_RespawnDuration[1] = 5.00
      • Set VariableSet Creep_RespawnDuration[2] = 5.00
      • Set VariableSet Creep_RespawnDuration[3] = 5.00
      • Set VariableSet Creep_RespawnDuration[4] = 5.00
      • Set VariableSet Creep_RespawnDuration[5] = 5.00
      • -------- --------
      • -------- --------
      • -------- This should match the amount of Creeps in the map --------
      • Set VariableSet Creep_MaxSpawnUnits = 5
      • -------- --------
      • -------- --------
      • -------- CREATE CREEPS --------
      • For each (Integer Creep_Integer) from 1 to Creep_MaxSpawnUnits, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Creep_SpawnUnit[Creep_Integer] for Neutral Hostile at (Center of Creep_SpawnRegion[Creep_Integer]) facing Creep_SpawnAngle[Creep_Integer] degrees
          • -------- Not sure if this works: --------
          • Unit Group - Add (Last created unit) to Creep_Group_CampUnit[Creep_Integer]
      • -------- --------
      • -------- --------
      • -------- ADD THEM TO GROUPS AND DEFINE RESPAWN TIME --------
      • Set VariableSet Creep_Group_Camp[1] = (Units in Creep Group 1 Kobolt <gen> owned by Neutral Hostile)
      • -------- --------
      • -------- --------
      • -------- DO NOT TOUCH IF YOU DON'T UNDERSTAND --------
      • -------- The creations of these units is optional, it's up to you how the units enter the map --------
      • -------- Hashtable creating for future saving data --------
      • Custom script: set udg_Creep_Hashtable = InitHashtable()
      • -------- How often your timer moves per interval (to be realistic, the lower the value, the realistic it is) --------
      • Set VariableSet Creep_Check_Interval = 0.03
      • Trigger - Add to Creep Respawn Time <gen> the event (Time - Every Creep_Check_Interval seconds of game time)
  • Creep Death
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Triggering unit)) Equal to Neutral Hostile
    • Actions
      • -------- What about units who were charmed? --------
      • Set VariableSet Creep_UnitTemp = (Triggering unit)
      • For each (Integer Creep_Integer) from 1 to Creep_MaxSpawnUnits, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of Creep_UnitTemp) Equal to Creep_SpawnUnit[Creep_Integer]
              • (Creep_UnitTemp is in Creep_Group_Camp[Creep_Integer].) Equal to True
            • Then - Actions
              • -------- BUG IN GROUP DEFINITION --------
              • Unit Group - Remove Creep_UnitTemp from Creep_Group_Camp[Creep_Integer].
              • Unit Group - Add Creep_UnitTemp to Creep_Group_Dead
              • Custom script: set udg_Creep_Key = GetHandleId(udg_Creep_UnitTemp)
              • Trigger - Turn on Creep Respawn Time <gen>
              • Hashtable - Save Creep_RespawnDuration[Creep_Integer] as 0 of Creep_Key in Creep_Hashtable.
              • Hashtable - Save Creep_Integer as 1 of Creep_Key in Creep_Hashtable.
              • Skip remaining actions
            • Else - Actions
  • Creep Respawn Time
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Creep_Group_Dead is empty) Equal to True
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
          • Unit Group - Pick every unit in Creep_Group_Dead and do (Actions)
            • Loop - Actions
              • Set VariableSet Creep_UnitTemp = (Picked unit)
              • Custom script: set udg_Creep_Key = GetHandleId(udg_Creep_UnitTemp)
              • Set VariableSet Creep_RespawnDuration[(Creep_MaxSpawnUnits + 1)] = (Load 0 of Creep_Key from Creep_Hashtable.)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Creep_RespawnDuration[(Creep_MaxSpawnUnits + 1)] Greater than 0.00
                • Then - Actions
                  • -------- Here the game reduces the timer --------
                  • Hashtable - Save (Creep_RespawnDuration[(Creep_MaxSpawnUnits + 1)] - Creep_Check_Interval) as 0 of Creep_Key in Creep_Hashtable.
                • Else - Actions
                  • Set VariableSet Creep_PointTemp = (Center of Creep_SpawnRegion[(Load 1 of Creep_Key from Creep_Hashtable.)])
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Creep_UnitTemp is A Hero) Equal to True
                    • Then - Actions
                      • Hero - Instantly revive Creep_UnitTemp at Creep_PointTemp, Show revival graphics
                    • Else - Actions
                      • -------- Will need to add angle --------
                      • Unit - Create 1 (Unit-type of Creep_UnitTemp) for (Owner of Creep_UnitTemp) at Creep_PointTemp facing Creep_SpawnAngle[1] degrees
                  • Custom script: call RemoveLocation(udg_Creep_PointTemp)
                  • Hashtable - Clear all child hashtables of child Creep_Key in Creep_Hashtable.
                  • Unit Group - Remove Creep_UnitTemp from Creep_Group_Dead.

Some comment on my thoughts / what I noticed:
  • I create 1 region for every creep, because I want to control exactly where a creep should spawn and in which angle. So no single "Camp 1" region, because then I wouldn't be able to tell the game where exactly in this region (and which angle) a creep should spawn
  • Somehow I need to be able to add a unit with array [5] to a Group with array [1], which Is why I did this. But I think this won't work (?):
    • Set VariableSet Creep_Group_CampUnit[1] = Creep_Group_Camp[1]
  • Respawn duration: Is the same across group, not units. So similar issue to the previous point.
  • What if units are charmed? I want charmed units to be considered "dead"
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
So a camp is ALWAYS the same, right? Meaning if you kill the Kobold camp that's located in the center of the map (for example) then the same exact Kobolds will respawn there? And this will be true throughout the game? Just like how it works in League of Legends.
 
Level 12
Joined
May 16, 2020
Messages
660
Yes to all of your points:
  • A camp location will not change in any way, throughout the game.
  • The unit composition of these camps will also not change.
  • The respawn timers are fix per camp.
  • Units should (re-)spawn at their designated location only after the defined respawn timer, but ONLY after the entire camp has been killed / charmed. So for example: Respawn timer of Camp A is 60 seconds. if you kill 2/3 units at minute 1, and kill the remaing 3rd unit at minute 3, only at minute 4 will all 3 units respawn.
If you are familiar with League of Legends, YES, the system should work exactly like there (and not Dota, where units respawn if their camp region is empty at specific timers).
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
Here's a simple system that should do exactly what you need.
  • Creep Camp Setup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Set these to the Creep trigger associated with your camp --------
      • Set VariableSet Creep_Trigger[1] = Spawn Kobolds 1 <gen>
      • Set VariableSet Creep_Trigger[2] = Spawn Golems 2 <gen>
      • -------- --------
      • -------- Set these to the Creep Camp's respawn time --------
      • Set VariableSet Creep_Respawn[1] = 5.00
      • Set VariableSet Creep_Respawn[2] = 5.00
      • -------- --------
      • -------- Set this to the number of Creep Camps --------
      • Set VariableSet Creep_Total_Camps = 2
      • -------- --------
      • -------- Run Creep Spawn Triggers --------
      • For each (Integer Creep_Loop) from 1 to Creep_Total_Camps, do (Actions)
        • Loop - Actions
          • -------- Create the Unit Groups --------
          • Custom script: set udg_Creep_Group[udg_Creep_Loop] = CreateGroup()
          • -------- Create the Creep Camps --------
          • Trigger - Run Creep_Trigger[Creep_Loop] (ignoring conditions)
  • Creep Camp Respawn
    • Events
      • Unit - A unit Dies
      • Unit - A unit Changes owner
    • Conditions
      • (Level of Creep Classification for (Triggering unit)) Not equal to 0
    • Actions
      • For each (Integer Creep_Loop) from 1 to Creep_Total_Camps, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Triggering unit) is in Creep_Group[Creep_Loop].) Equal to True
            • Then - Actions
              • Unit Group - Remove (Triggering unit) from Creep_Group[Creep_Loop].
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in Creep_Group[Creep_Loop]) Equal to 0
                • Then - Actions
                  • -------- Run Creep Spawn Trigger --------
                  • Set VariableSet Creep_Wait = Creep_Respawn[Creep_Loop]
                  • Trigger - Run Creep_Trigger[Creep_Loop] (ignoring conditions)
                • Else - Actions
            • Else - Actions
  • Spawn Kobolds 1
    • Events
    • Conditions
    • Actions
      • -------- Customize this trigger to suit your needs --------
      • Wait Creep_Wait seconds
      • Set VariableSet TempPoint[0] = (Center of Camp1 <gen>)
      • Set VariableSet TempPoint[1] = (TempPoint[0] offset by (100.00, -100.00))
      • Set VariableSet TempPoint[2] = (TempPoint[0] offset by (-100.00, -100.00))
      • Set VariableSet TempPoint[3] = (TempPoint[0] offset by (100.00, -200.00))
      • Set VariableSet TempPoint[4] = (TempPoint[0] offset by (-100.00, -200.00))
      • -------- --------
      • Unit - Create 1 Kobold Taskmaster for Neutral Hostile at TempPoint[0] facing 270.00 degrees
      • Unit Group - Add (Last created unit) to Creep_Group[1]
      • Unit - Add Creep Classification to (Last created unit)
      • Custom script: call RemoveLocation (udg_TempPoint[0])
      • -------- --------
      • For each (Integer Creep_Loop) from 1 to 4, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Kobold for Neutral Hostile at TempPoint[Creep_Loop] facing 270.00 degrees
          • Unit Group - Add (Last created unit) to Creep_Group[1]
          • Unit - Add Creep Classification to (Last created unit)
          • Custom script: call RemoveLocation (udg_TempPoint[udg_Creep_Loop])
  • Spawn Golems 2
    • Events
    • Conditions
    • Actions
      • -------- Customize this trigger to suit your needs --------
      • Wait Creep_Wait seconds
      • Set VariableSet TempPoint[0] = (Center of Camp2 <gen>)
      • Set VariableSet TempPoint[1] = (TempPoint[0] offset by (-100.00, 100.00))
      • Set VariableSet TempPoint[2] = (TempPoint[0] offset by (-100.00, -100.00))
      • -------- --------
      • Unit - Create 1 Granite Golem for Neutral Hostile at TempPoint[0] facing 180.00 degrees
      • Unit Group - Add (Last created unit) to Creep_Group[2]
      • Unit - Add Creep Classification to (Last created unit)
      • Custom script: call RemoveLocation (udg_TempPoint[0])
      • -------- --------
      • Unit - Create 1 Mud Golem for Neutral Hostile at TempPoint[1] facing 180.00 degrees
      • Unit Group - Add (Last created unit) to Creep_Group[2]
      • Unit - Add Creep Classification to (Last created unit)
      • Custom script: call RemoveLocation (udg_TempPoint[1])
      • -------- --------
      • Unit - Create 1 Rock Golem for Neutral Hostile at TempPoint[2] facing 180.00 degrees
      • Unit Group - Add (Last created unit) to Creep_Group[2]
      • Unit - Add Creep Classification to (Last created unit)
      • Custom script: call RemoveLocation (udg_TempPoint[2])
It might not be as clean as you wanted since you'll need to create a new Spawn trigger for each Creep Camp, but that also makes it very flexible in customizing your camps.

Note that I created a hidden custom ability that I use as a Creep Classification. I add this ability to all of the Creep Camp units and use it to determine when a Camp unit dies/changes owner.
 

Attachments

  • Creep Camp System 1.w3m
    20.2 KB · Views: 47
Level 12
Joined
May 16, 2020
Messages
660
Ah, I wrote that I will test it (didn’t have the chance yet) - and I think this solution of having creeps splitted up is good, since it allows me to give them individual items.

will let you know how it went - thanks!

Edit: Just tested it, seems to work perfectly. Thanks a lot.
 
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
Sorry need to open this again.

For some reason the camp color does not match the corresponding creep level(s). The camp marked below consists of 1 creep which is lvl 40 (just for testing purposes). If I put this creep in the editor, it shows deep red. But if I create it via the system, it is green...


11.png
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
Well, it doesn't have anything to do with the system, it's just the Create unit function having problems. Apparently this bug has been around since 1.29.

I don't think there's an easy solution yet.
 
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
Hey Uncle, I want to expand the system a bit by making monster getting more HP / attack / bounty as the game progresses.

I did it the following way, but I think this leaks a group..?
And I cannot delete the group, as this would destroy the system. Will I be forced to add the 8 adjustment triggers individually to each unit section? It's just not the nicest solution...

  • Spawn Bandits 2
    • Events
    • Conditions
    • Actions
      • Wait Creep_Wait seconds
      • Set VariableSet TempPoint[0] = (Center of Creeps 2 Sentinel Bandits <gen>)
      • Set VariableSet TempPoint[1] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (-60.00, -120.00))
      • Set VariableSet TempPoint[2] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (120.00, 0.00))
      • Set VariableSet TempPoint[3] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (60.00, 120.00))
      • Set VariableSet TempPoint[4] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (-120.00, 0.00))
      • -------- --------
      • Unit - Create 1 Enforcer for Neutral Hostile at TempPoint[0] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[0])
      • -------- --------
      • Unit - Create 1 Assassin for Neutral Hostile at TempPoint[1] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[1])
      • -------- --------
      • Unit - Create 1 Assassin for Neutral Hostile at TempPoint[2] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[2])
      • -------- --------
      • Unit - Create 1 Rogue for Neutral Hostile at TempPoint[3] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[3])
      • -------- --------
      • Unit - Create 1 Rogue for Neutral Hostile at TempPoint[4] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[4])
      • -------- ADJUST STATS AS GAME PROGRESSES --------
      • Unit Group - Pick every unit in Creep_Group[2] and do (Actions)
        • Loop - Actions
          • Set VariableSet Creep_UnitTemp = (Picked unit)
          • Unit - Set Max HP of Creep_UnitTemp to (Integer(((Max life of Creep_UnitTemp) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Real Field: Hit Points ('uhpc') to Value: (Max life of Creep_UnitTemp)
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Base ('ua1b')at Index:0 to Value: (Integer(((Real((Base Damage of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Number Of Dice ('ua1d')at Index:0 to Value: (Integer(((Real((Dice Number of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Sides Per Die ('ua1s')at Index:0 to Value: (Integer(((Real((Dice Sides of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Base ('ubba') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Base ('ubba')))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Number of Dice ('ubdi') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Number of Dice ('ubdi')))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Sides per Die ('ubsi') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Sides per Die ('ubsi')))) x Creep_Multiplier)))
 
Level 4
Joined
May 26, 2020
Messages
67
Actually, isn't it like 90% easier if you put 3 events when they die, and 3 conditions so it confirms that they are dead, and 3 actions to create units at the locations.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
Hey Uncle, I want to expand the system a bit by making monster getting more HP / attack / bounty as the game progresses.

I did it the following way, but I think this leaks a group..?
And I cannot delete the group, as this would destroy the system. Will I be forced to add the 8 adjustment triggers individually to each unit section? It's just not the nicest solution...

  • Spawn Bandits 2
    • Events
    • Conditions
    • Actions
      • Wait Creep_Wait seconds
      • Set VariableSet TempPoint[0] = (Center of Creeps 2 Sentinel Bandits <gen>)
      • Set VariableSet TempPoint[1] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (-60.00, -120.00))
      • Set VariableSet TempPoint[2] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (120.00, 0.00))
      • Set VariableSet TempPoint[3] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (60.00, 120.00))
      • Set VariableSet TempPoint[4] = ((Center of Creeps 2 Sentinel Bandits <gen>) offset by (-120.00, 0.00))
      • -------- --------
      • Unit - Create 1 Enforcer for Neutral Hostile at TempPoint[0] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[0])
      • -------- --------
      • Unit - Create 1 Assassin for Neutral Hostile at TempPoint[1] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[1])
      • -------- --------
      • Unit - Create 1 Assassin for Neutral Hostile at TempPoint[2] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[2])
      • -------- --------
      • Unit - Create 1 Rogue for Neutral Hostile at TempPoint[3] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[3])
      • -------- --------
      • Unit - Create 1 Rogue for Neutral Hostile at TempPoint[4] facing 140.00 degrees
      • Set VariableSet Creep_UnitTemp = (Last created unit)
      • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
      • Unit - Add Creep Classification to Creep_UnitTemp
      • Custom script: call RemoveLocation (udg_TempPoint[4])
      • -------- ADJUST STATS AS GAME PROGRESSES --------
      • Unit Group - Pick every unit in Creep_Group[2] and do (Actions)
        • Loop - Actions
          • Set VariableSet Creep_UnitTemp = (Picked unit)
          • Unit - Set Max HP of Creep_UnitTemp to (Integer(((Max life of Creep_UnitTemp) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Real Field: Hit Points ('uhpc') to Value: (Max life of Creep_UnitTemp)
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Base ('ua1b')at Index:0 to Value: (Integer(((Real((Base Damage of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Number Of Dice ('ua1d')at Index:0 to Value: (Integer(((Real((Dice Number of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Sides Per Die ('ua1s')at Index:0 to Value: (Integer(((Real((Dice Sides of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Base ('ubba') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Base ('ubba')))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Number of Dice ('ubdi') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Number of Dice ('ubdi')))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Sides per Die ('ubsi') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Sides per Die ('ubsi')))) x Creep_Multiplier)))
That won't leak a group, you only leak groups when you use "Pick every unit..." and then create a new Unit Group on the fly, like "Units within range of point", "Units in playable map area", "Units in region", etc...

Since you're referencing Creep_Group[2], there's nothing new being created that you won't have access to. That's all a leak really is, something you no longer have access to and thus cannot remove. If you always have access to something due it to being saved as a variable, it's not a leak, at least not yet. It becomes a leak once you set that variable to something else without getting rid of whatever was stored there first. Keep in mind this only holds true for variable types that actually leak, it's safe to overwrite most variable types like Integer, Real, Boolean, etc....

That aside, I imagine it will take 1 minute to copy and paste that Pick every Unit function and adjust it for all 8 triggers, which is hardly a pain.

Though, and I should've done this from the start, you can save some editing by replacing all instances of [2] with Creep_Loop since that'll be equal to 2. That variable will always be equal to whatever Creep Camp # you're currently working on.

EDIT:
You are leaking points though. Your TempPoints from 1 to 4 should be referencing TempPoint[0] offset by X,Y, not the Region. Doing it your way creates 2 Points. One Point at the center of the region (leaks), and the other Point offset from the first Point (doesn't leak). The 1st Point cannot be accessed/removed so it leaks, and the 2nd Point will be stored under TempPoint[X] so we can safely remove it and avoid a leak.
 
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
@Lone_Wolf_2021 : Sorry can you elaborate? Don't quite get what you mean.

@Uncle : Thanks, this explanation actually helped a lot. But two points:

Though, and I should've done this from the start, you can save some editing by replacing all instances of [2] with Creep_Loop since that'll be equal to 2. That variable will always be equal to whatever Creep Camp # you're currently working on.

I'd need to create a variable for unit type and angle though, since these values change per loop, right?

This looks clean at least, but not sure how well it's done:

  • Spawn 2 Bandits
    • Events
    • Conditions
    • Actions
      • Wait Creep_Wait seconds
      • Set VariableSet TempPoint[0] = (Center of Creeps 2 Sentinel Bandits <gen>)
      • Set VariableSet TempPoint[1] = TempPoint[0]
      • Set VariableSet TempPoint[2] = (TempPoint[0] offset by (-60.00, -120.00))
      • Set VariableSet TempPoint[3] = (TempPoint[0] offset by (120.00, 0.00))
      • Set VariableSet TempPoint[4] = (TempPoint[0] offset by (60.00, 120.00))
      • Set VariableSet TempPoint[5] = (TempPoint[0] offset by (-120.00, 0.00))
      • Set VariableSet Creep_UnitType[1] = Enforcer
      • Set VariableSet Creep_UnitType[2] = Assassin
      • Set VariableSet Creep_UnitType[3] = Assassin
      • Set VariableSet Creep_UnitType[4] = Rogue
      • Set VariableSet Creep_UnitType[5] = Rogue
      • Set VariableSet Creep_Angle[1] = 140.00
      • Set VariableSet Creep_Angle[2] = 140.00
      • Set VariableSet Creep_Angle[3] = 140.00
      • Set VariableSet Creep_Angle[4] = 140.00
      • Set VariableSet Creep_Angle[5] = 140.00
      • -------- --------
      • For each (Integer Creep_Loop) from 1 to 5, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Creep_UnitType[Creep_Loop] for Neutral Hostile at TempPoint[Creep_Loop] facing Creep_Angle[Creep_Loop] degrees
          • Set VariableSet Creep_UnitTemp = (Last created unit)
          • Unit Group - Add Creep_UnitTemp to Creep_Group[2]
          • Unit - Add Creep Classification to Creep_UnitTemp
          • Custom script: call RemoveLocation (udg_TempPoint[udg_Creep_Loop])
          • -------- ADJUST STATS AS GAME PROGRESSES --------
          • Unit - Set Max HP of Creep_UnitTemp to (Integer(((Max life of Creep_UnitTemp) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Real Field: Hit Points ('uhpc') to Value: (Max life of Creep_UnitTemp)
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Base ('ua1b')at Index:0 to Value: (Integer(((Real((Base Damage of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Number Of Dice ('ua1d')at Index:0 to Value: (Integer(((Real((Dice Number of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Weapon Integer Field: Attack Damage Sides Per Die ('ua1s')at Index:0 to Value: (Integer(((Real((Dice Sides of Creep_UnitTemp for weapon index 0))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Base ('ubba') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Base ('ubba')))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Number of Dice ('ubdi') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Number of Dice ('ubdi')))) x Creep_Multiplier)))
          • Unit - Set Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Sides per Die ('ubsi') to Value: (Integer(((Real((Unit: Creep_UnitTemp's Integer Field: Gold Bounty Awarded - Sides per Die ('ubsi')))) x Creep_Multiplier)))
      • Custom script: call RemoveLocation (udg_TempPoint[0])

EDIT: Had to adjust the trigger a bit. I had TempPoint[0] as part of the loop, but when removing [0], the latter points had nothing to refer to. Looks a bit ugly but seems to work. Your verdict on this? :p

You are leaking points though. Your TempPoints from 1 to 4 should be referencing TempPoint[0] offset by X,Y, not the Region. Doing it your way creates 2 Points. One Point at the center of the region (leaks), and the other Point offset from the first Point (doesn't leak). The 1st Point cannot be accessed/removed so it leaks, and the 2nd Point will be stored under TempPoint[X] so we can safely remove it and avoid a leak.

Does "Center of X" leak even though this region is pre-placed? I always read that this shouldn't leak if you remove the point. See for example here: Complete list of things that leak

But if it Center of the Region does leak, is there no way to prevent this? Maybe in JASS?
I'm using the "center of region" quite often to spawn lane minions for example...
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,509
Center of region only leaks if you don't remove the point. The way you're using TempPoint[0] is how it should be done.

Also, your TempPoint[1] = TempPoint[0] seems redundant. Just delete TempPoint[0] and instead set TempPoint[1] to the center of the Region. Then reference TempPoint[1] in your other four Points. If it causes problems then I guess it's not a big deal, just a minor optimization.

When it comes to Point leaks, there's really no safe alternative. If you see the word "Position", "Center" "Point", you'll need to create a Point variable referencing it and clean it up afterwards. The way Blizzard coded it, anytime some place in the world is being referenced, they create a Point in their code. A Point is just the X/Y coordinates of whatever place you're referencing. The problem is that Blizz never removes these Points, so we need to remove them ourselves.
vJASS:
local point BlizzardPoint = Location(0, 0)
CreateUnitAtLoc(Player(1), "Hfoo", BlizzardPoint , 270)
^ An example of it in Jass, if you don't create your own Point variable then Blizzard will do it for you, and they won't clean theirs up. Jerks.

I know it can be confusing because something like "Pick every player in All Players" doesn't leak, but that's a special exception. Same goes for "A unit enters playable map area", it doesn't leak because Blizzard has essentially saved these as Variables or "Constants" for you to use throughout the game.
 
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
Hi Uncle,

I think this is a WC3 bug, but maybe you have more insights what is going on here.

The problem is as follows:
If I add 1 line into the code, the system fails to add a cooldown to the hero ability once he has 0 stacks. The problematic line is (see full trigger below, it's under "ADD SLOW"):

  • Unit - Order LD_Dummy to Human Sorceress - Slow LD_Target[LD_Index]

  • Life Drain Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Life Drain
    • Actions
      • Set VariableSet LifeDrain_Caster = (Triggering unit)
      • Set VariableSet LifeDrain_CV = (Custom value of LifeDrain_Caster)
      • Set VariableSet LifeDrain_Level = (Level of Life Drain for LifeDrain_Caster)
      • -------- --------
      • -------- --------
      • Set VariableSet LD_Index = (LD_Index + 1)
      • Set VariableSet LD_Caster[LD_Index] = (Triggering unit)
      • Set VariableSet LD_Target[LD_Index] = (Target unit of ability being cast)
      • Set VariableSet LD_Caster_CV = (Custom value of LD_Caster[LD_Index])
      • Set VariableSet LD_Counter[LD_Index] = 0.00
      • Set VariableSet LD_Drained_HP[LD_Index] = ((14.00 + ((Max life of LD_Target[LD_Index]) x ((-0.50 + (1.50 x (Real((Level of Life Drain for LD_Caster[LD_Index]))))) / 100.00))) / 4.00)
      • Set VariableSet LD_Point[1] = (Position of LD_Caster[LD_Index])
      • Set VariableSet LD_Point[2] = (Position of LD_Target[LD_Index])
      • Special Effect - Create a special effect attached to the chest of LD_Caster[LD_Index] using Abilities\Spells\Other\Drain\DrainCaster.mdl
      • Set VariableSet LD_SpecialeffectA[LD_Index] = (Last created special effect)
      • Special Effect - Create a special effect attached to the chest of LD_Target[LD_Index] using Abilities\Spells\Other\Drain\DrainTarget.mdl
      • Set VariableSet LD_SpecialeffectB[LD_Index] = (Last created special effect)
      • Custom script: set udg_LD_L[udg_LD_Index] = AddLightningEx("DRAB", true, GetLocationX(udg_LD_Point[1]), GetLocationY(udg_LD_Point[1]), GetLocationZ(udg_LD_Point[1]) + 70, GetLocationX(udg_LD_Point[2]), GetLocationY(udg_LD_Point[2]), GetLocationZ(udg_LD_Point[2]) + 70)
      • -------- --------
      • -------- ADD SLOW --------
      • Set VariableSet LD_Drained_Slow[LD_Index] = (0.02 + (0.02 x (Real((Level of Life Drain for LD_Caster[LD_Index])))))
      • Unit - Create 1 Dummy (Ground/Speed 0) for (Owner of LD_Caster[LD_Index]) at LD_Point[1] facing Default building facing degrees
      • Set VariableSet LD_Dummy = (Last created unit)
      • Unit - Add Life Drain (Slow) to LD_Dummy
      • Ability - Set Ability: (Unit: LD_Dummy's Ability with Ability Code: Life Drain (Slow))'s Real Level Field: Movement Speed Factor ('Slo1') of Level: 0 to LD_Drained_Slow[LD_Index]
      • Unit - Order LD_Dummy to Human Sorceress - Slow LD_Target[LD_Index]
      • Unit - Add a 0.50 second Generic expiration timer to LD_Dummy
      • -------- --------
      • -------- ADD SPEED --------
      • Set VariableSet LD_CounterSpeed[LD_Caster_CV] = (LD_CounterSpeed[LD_Caster_CV] + 1)
      • Set VariableSet LD_Drained_Speed[LD_Caster_CV] = ((0.02 + (0.02 x (Real((Level of Life Drain for LD_Caster[LD_Index]))))) x (Real(LD_CounterSpeed[LD_Caster_CV])))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (LD_Caster[LD_Index] is in LD_Group.) Equal to False
        • Then - Actions
          • Unit Group - Add LD_Caster[LD_Index] to LD_Group
          • Unit - Add Life Drain (Speed - Aura) to LD_Caster[LD_Index]
          • Unit - Remove Life Drain (Speed) buff from LD_Caster[LD_Index]
          • Ability - Set Ability: (Unit: LD_Caster[LD_Index]'s Ability with Ability Code: Life Drain (Speed - Aura))'s Real Level Field: Movement Speed Increase (%) ('Oae1') of Level: 0 to LD_Drained_Speed[LD_Caster_CV]
          • Unit - For LD_Caster[LD_Index], Ability Life Drain (Speed - Aura), Disable ability: True, Hide UI: False
          • Unit - For LD_Caster[LD_Index], Ability Life Drain (Speed - Aura), Disable ability: False, Hide UI: False
        • Else - Actions
          • Unit - Remove Life Drain (Speed) buff from LD_Caster[LD_Index]
          • Ability - Set Ability: (Unit: LD_Caster[LD_Index]'s Ability with Ability Code: Life Drain (Speed - Aura))'s Real Level Field: Movement Speed Increase (%) ('Oae1') of Level: 0 to LD_Drained_Speed[LD_Caster_CV]
          • Unit - For LD_Caster[LD_Index], Ability Life Drain (Speed - Aura), Disable ability: True, Hide UI: False
          • Unit - For LD_Caster[LD_Index], Ability Life Drain (Speed - Aura), Disable ability: False, Hide UI: False
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • LD_Index Equal to 1
        • Then - Actions
          • Countdown Timer - Start LD_Timer as a Repeating timer that will expire in 0.25 seconds
          • Trigger - Turn on Life Drain Cast Loop <gen>
        • Else - Actions
      • Custom script: call RemoveLocation(udg_LD_Point[1])
      • Custom script: call RemoveLocation(udg_LD_Point[2])
      • -------- --------
      • -------- --------
      • -------- Remove Charge --------
      • Unit - Remove LifeDrain_Ability[LifeDrain_Charges[LifeDrain_CV]] from LifeDrain_Caster
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • LifeDrain_Charges[LifeDrain_CV] Equal to 1
        • Then - Actions
          • -------- 0 charges --------
          • Set VariableSet LifeDrain_Charges[LifeDrain_CV] = (LifeDrain_Charges[LifeDrain_CV] - 1)
          • Unit - Remove LifeDrain_Buff[1] buff from LifeDrain_Caster
          • Unit - Add LifeDrain_Ability[0] to LifeDrain_Caster
          • Unit - For LifeDrain_Caster, Ability LifeDrain_Ability[0], Disable ability: True, Hide UI: False
          • Unit - For LifeDrain_Caster, Ability LifeDrain_Ability[0], Disable ability: False, Hide UI: False
          • -------- --------
          • -------- Set Cooldown --------
          • Unit - For Unit LifeDrain_Caster, Set cooldown of ability (Ability being cast), Level: (LifeDrain_Level - 1) to LifeDrain_Duration[LifeDrain_CV]
        • Else - Actions
          • -------- 1 to 2 charges --------
          • Unit - Remove LifeDrain_Buff[LifeDrain_Charges[LifeDrain_CV]] buff from LifeDrain_Caster
          • Set VariableSet LifeDrain_Charges[LifeDrain_CV] = (LifeDrain_Charges[LifeDrain_CV] - 1)
          • Unit - Add LifeDrain_Ability[LifeDrain_Charges[LifeDrain_CV]] to LifeDrain_Caster
          • Unit - For LifeDrain_Caster, Ability LifeDrain_Ability[LifeDrain_Charges[LifeDrain_CV]], Disable ability: True, Hide UI: False
          • Unit - For LifeDrain_Caster, Ability LifeDrain_Ability[LifeDrain_Charges[LifeDrain_CV]], Disable ability: False, Hide UI: False
      • -------- --------
      • Set VariableSet LifeDrain_Index[LifeDrain_CV] = (LifeDrain_Index[LifeDrain_CV] + 1)
      • -------- --------
      • -------- Turn on Loop --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (LifeDrain_Caster is in LifeDrain_Group.) Equal to False
        • Then - Actions
          • Set VariableSet LifeDrain_Duration[LifeDrain_CV] = LifeDrain_Cooldown[LifeDrain_Level]
          • Unit Group - Add LifeDrain_Caster to LifeDrain_Group
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Life Drain Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Life Drain Loop <gen>
        • Else - Actions

I deleted line by line until coming to the conclusion that this line is the problem... once I delete it, the cooldown is added properly again once no stacks remain. Makes no sense to me why this would interfere with the cooldown. Do you know why though and how I could fix this?

FYI: The same problem appeared when I use the "Move" command on the hero. But I could fix this by using X and Y point (set unit X to point X etc).
 
Status
Not open for further replies.
Top