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

Monkey King Spell Pack

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
Monkey King:
Always in search of a good fight, Monkey King travels atop the trees aiming to spring from leafy cover and surprise his enemies. Calling upon an army of monkey soldiers to overwhelm opponents, this agile trickster revels in the chaos of battle, ready to slam his legendary staff down on any hopes of escape.
Spell Pack for model of Monkey King from hive.

Instructions:
1 Go into file => preferences => check "Automatically create unknown variables while pasting trigger data".
2.1 Copy part of VariableIntialization with variables from spell that you want to copy(if you want all spells, then just copy whole trigger).
2.2 You can change most variables(in VariableIntialization) however you wish, outside of hashtable and few variables specified to not be changed.
3 Run VariableIntialization at the initialization of your map.
4 Copy Folder with spell you want to use.
5 Follow Instructions in Read Trigger Comment for copied spell.
6 Abilitiies Jingu Mastery and Mischief require Damage Engine(you can use alternative, but then of course you need to change part of triggers to fit your need) so just copy whole folder(Damage Engine) to your map if you want use either of these two abilities.

Boundless Strike:
Monkey King enlarges his staff and slams it against the ground, stunning enemies in a line and damaging them with a critical hit based on his attack. Has True Strike.
Level 1
- 2.2 times normal damage, 1.4 second stun.
Level 2 - 2.6 times normal damage, 1.6 second stun.
Level 3 - 3 times normal damage, 1.8 second stun.

Statue:
Monkey King uses his secret energy to create statue of himself. Statue is invulnerable, uncontrollable, slowed, deals 100% damage of Monkey King and attacks random targets.
Level 1 - Lasts 15 seconds, cost 80 mana, coldown 30seconds.
Level 2 - Lasts 20 seconds, costs 65 mana, cooldown 25seconds.
Level 3 - Lasts 25 seconds, cost 50 mana, cooldown 20seconds.

Jingu Mastery:
Monkey King's attacks awaken the Jingu Bang's power. Upon the fourth hit, Monkey King earns four charged attacks that have bonus damage and lifesteal.
Level 1 - 20 damage bonus, 30% lifesteal.
Level 2 - 35 damage bonus, 50% lifesteal.
Level 3 - 50 damage bonus, 70% lifesteal.

Wukong's Command:
Monkey King creates a circular formation, in which enemy units will be damaged every 1 second by Monkey King base damage, If Monkey King leaves the circle his formation disperse.

Wukong's Command v2.0:
Monkey King creates a circular formation with his statue around. If Monkey King leaves the circle his formation disperse.

NOTE: it is alternative to Wukong's Command it is not better or worse, it is just a little bit diffrent

Tree Dance:
Monkey King jumps to a tree and perches atop it. While perched, he gains the Primal Spring ability-a channeled leap attack. Primal Spring will deal damage and slow in area based off channeling time.
Level 1 - Primal spring damage 50-125, slow 10%-40%.
Level 2 - Primal spring damage 75-195, slow 15%-60%.
Level 3 - Primal spring damage 100-265, slow 20%-80%.

Primal Spring:
Monkey King springs out from his tree perch, damaging and slowing enemies based of his lvl of Tree Dance in the area where he lands.

Mischief:
Changes Monkey King's shape to deceive opponents. Taking damage, or dealing damage breaks Monkey King's disguise. Also reduce damage taken to 0.


18 June - release date
22 June - fixed Mischief ability, added instructions how to import abilities(both there and in map), fixed few types typos, added new bugs


CREDITS:
Jab1z

BLazeKraze
Darky29
Sun gate
Bribe
JollyD
Alexen
Kimbo
alfredx_sotn
Bill Millsap(Sounds from Dota 2)

Contents

Monkey King Spell Pack (Map)

Reviews
MyPad
Neat. If I recall, Monkey King was the first Dota 2 exclusive Hero to be introduced. It would be poetic justice to see that it is one of the first Dota 2 exclusive Heroes to be properly (re)introduced back into Warcraft 3. Anyway, here's the...
Level 3
Joined
May 7, 2020
Messages
15
Could you be more specific? Perhaps there is a solution.
I done this ability by creating two abilities based on chaos and created one unit that is exactly same as Monkey King. And then add one chaos ability that changes unit into they morphed or unmorphed version and remove second ability. Only bug that i found is that unit will have day vision during night. But since it is pretty hacky way to do that, i suspect there are some others bugs that could occure in some weird scenario, I left this ability in pack just because it shouldn't cause problems if used for boss unit for example. Also there is probably no other way around to change model of unit via trigger.
 
Level 3
Joined
May 7, 2020
Messages
15
I think Hero Passive Transformation is somewhat-dated, since now you can set a unit's skin/attack point/damage point.
Using skin/s solved problem, I thought that skins in warcraft are the same as in other games, where you buy hats and then you have cowboy hat on paladin model, but they replace unit with diffrent unit, while keeping stats and abilities. And luckily have gui method for changing skin when you just have to input "string" integer, but you cant, making it pretty much worthless in a sense(since you can save "string" integer using Jass and then pass is it).
 
Neat. If I recall, Monkey King was the first Dota 2 exclusive Hero to be introduced. It would be poetic justice to see that it is one of the first Dota 2 exclusive Heroes to be properly (re)introduced back into Warcraft 3. Anyway, here's the code/trigger review:

  • In the trigger BoundleStrike (Boundle):
    • BoundleAngle appears to be causing a memory leak by referring to an unstored generated location handle in (Position of BoundleStrikeUnit). You could fix that by making it refer to BoundleStartingPosition, moving the initialization of BoundleStartingPosition before it.

    • In the same vein, BoundleEndingPoint should refer to BoundleStartingPosition.

      • For each (Integer A) from 1 to 3 , do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (X of BoundleCorners[(Integer A)]) Greater than BoundleMaxX
            • Then - Actions
              • Set Variable Set BoundleMaxX = (X of BoundleCorners[(Integer A)])
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (X of BoundleCorners[(Integer A)]) Less than BoundleMinX
                • Then - Actions
                  • Set Variable Set BoundleMinX = (X of BoundleCorners[(Integer A)])
                • Else - Actions
      From the looks of things, there's no need to nest the conditions within the else block. Just move the inner if-then block out of the outer if-then-else block.

      • -------- Picking Unit Affecte by Boundle --------
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Region(BoundleMinX, BoundleMinY, BoundleMaxX, BoundleMaxY)) matching ((((Matching unit) belongs to an enemy of (Owner of BoundleStrikeUnit).) Equal to True) and ((((Matching unit) is A flying unit) Equal to False) and ((((Matching unit) is Magic Immune) Equal to False) and (((Matching unit) is Mechanical) Equal to False))))) and do (Actions)
        • Loop - Actions
          • -------- Finding point of center of unit in rotated env --------
          • Set Variable Set RotatedPositionOfUnit = ((Point(BoundleCenterX, BoundleCenterY)) offset by (Distance between (Position of (Picked unit)) and (Point(BoundleCenterX, BoundleCenterY))) towards ((Angle from (Position of (Picked unit)) to (Point(BoundleCenterX, BoundleCenterY))) - (BoundleAngle - 90.00)) degrees.)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • And - All (Conditions) are true
                • Conditions
                  • (X of RotatedPositionOfUnit) Less than or equal to (X of BotRightCornerInRotatedBoundle)
                  • (X of RotatedPositionOfUnit) Greater than or equal to (X of BotLeftCornerInRotatedBoundle)
                  • (Y of RotatedPositionOfUnit) Greater than or equal to (Y of BotLeftCornerInRotatedBoundle)
                  • (Y of RotatedPositionOfUnit) Less than or equal to (Y of TopLeftCornerInRotatedBoundle)
            • Then - Actions
              • Unit Group - Add (Picked unit) to UnitsAffectedByBoundle
              • -------- Continue would be nice there istead of else if to have less indentation --------
            • Else - Actions
              • -------- Finding closest Y to rotated position of unit --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Y of RotatedPositionOfUnit) Greater than (Y of TopLeftCornerInRotatedBoundle)
                • Then - Actions
                  • Set Variable Set ClosestYToRotatedPoint = (Y of TopLeftCornerInRotatedBoundle)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Y of RotatedPositionOfUnit) Less than (Y of BotLeftCornerInRotatedBoundle)
                    • Then - Actions
                      • Set Variable Set ClosestXToRotatedPoint = (X of BotRightCornerInRotatedBoundle)
                      • Set Variable Set ClosestYToRotatedPoint = (Y of BotLeftCornerInRotatedBoundle)
                    • Else - Actions
                      • Set Variable Set ClosestYToRotatedPoint = (Y of RotatedPositionOfUnit)
              • -------- Finding closest X to rotated position of unit --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (X of RotatedPositionOfUnit) Less than (X of BotLeftCornerInRotatedBoundle)
                • Then - Actions
                  • Set Variable Set ClosestXToRotatedPoint = (X of BotLeftCornerInRotatedBoundle)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (X of RotatedPositionOfUnit) Greater than (X of BotRightCornerInRotatedBoundle)
                    • Then - Actions
                      • Set Variable Set ClosestXToRotatedPoint = (X of BotRightCornerInRotatedBoundle)
                    • Else - Actions
                      • Set Variable Set ClosestXToRotatedPoint = (X of RotatedPositionOfUnit)
              • Set Variable Set BoundleDistanceToEdge = (Square root(((Power((Abs(((X of RotatedPositionOfUnit) - ClosestXToRotatedPoint))), 2.00)) + (Power((Abs(((Y of RotatedPositionOfUnit) - ClosestYToRotatedPoint))), 2.00)))))
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Collision Size of (Picked unit)) Greater than or equal to BoundleDistanceToEdge
                • Then - Actions
                  • Unit Group - Add (Picked unit) to UnitsAffectedByBoundle
                • Else - Actions
      1.) It looks like a JASS rect (GUI region) handle is being created without being referenced and subsequently cleaned up. You can clean this up using the following function: native RemoveRect takes rect whichRect returns nothing.

      2.) The inner filter function in the nested matching condition statement can look quite ugly really fast with a lot of conditions. Try filtering them out within the Actions block instead. Check out this tutorial for more info: Convenient Unit Group Filtering in GUI

      3.) The liberal use of (Position of (Picked unit)) translates to more memory leaks.

      4.) You can use Skip Remaining Actions in the Then - Actions block on the first If-then-else block as a quasi-continue statement, since the function (Pick all units in n group) generates a new thread for each picked unit. (Memory leaks that have been created before that point will have to be cleaned up, though).

      5.) (Picked unit) is called an awful lot within this block. Perhaps you might want to store that in a temp variable?

    • The floating text should only show the integer value of the amount of damage dealt, not the real value. (250 instead of 250.16, for example).

  • In the trigger Jingu Lifesteal:
    • You can directly call FlushChildHashtable instead of the wrapper.
      • API difference between the two functions:
        JASS:
        native FlushChildHashtable takes hashtable whichHashtable, integer parentKey
        function FlushChildHashtableBJ takes integer parentKey, hashtable whichHashtable

  • In the trigger Jingu Check for Buff:
    • Don't be shy with the interval period. Even when not enabled and disabled properly, this trigger should not be too costly. I'd recommend a 0.50 second interval.

  • In the trigger ArenaCreate:
    • The (A unit starts the effect of an ability) event would be more suitable here.

  • In the trigger Arena Damage (may also apply in ArenaSoldiersV2):
    • (Position of MonkeyArena) and (Position of MonkeyArenaCreator) is not stored.

      • Set Variable Set MonkeyArenaToDamageLeft = ((Load 2 of (Key (Picked unit).) from MonkeyArenaHastable.) - 0.04)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MonkeyArenaToDamageLeft Less than or equal to 0.00
        • Then - Actions
          • Set Variable Set MonkeyArenaToDamageLeft = MonkeyArenaDamageInterval
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within MonkeyArenaSize of (Position of MonkeyArena) matching (((Matching unit) belongs to an ally of (Owner of MonkeyArenaCreator).) Equal to False).) and do (Actions)
            • Loop - Actions
              • Unit - Cause MonkeyArenaCreator to damage (Picked unit) , dealing ((Real((Base Damage of MonkeyArenaCreator for weapon index 1))) x MonkeyArenaDamageMult) damage of attack type Hero and damage type Normal
        • Else - Actions
      Readability of the filter function can be improved. Also, another location handle (Position of MonkeyArena) has been generated and not cleaned up.

      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((MonkeyArenaDuration - MonkeyArenaDurationLeft) mod 12.00) Equal to 0.00
        • Then - Actions
          • -------- Model of arena will disapear around12 seconds, so we swap arena for new, it is looks a little weird since dragon will change positiom, but it is better than nothing --------
          • Unit - Replace MonkeyArena with a Monkey Arena using The old unit's relative life and mana
          • Animation - Change (Last replaced unit) 's size to ( (100.00 x MonkeyArenaScale) %, (100.00 x MonkeyArenaScale) %, 100.00 %) of its original size
          • Set Variable Set MonkeyArena = (Last replaced unit)
          • Hashtable - Save Handle Of MonkeyArena as 0 of (Key (Picked unit).) in MonkeyArenaHastable .
        • Else - Actions
      I suggest resetting the MonkeyArena unit's animation instead of replacing the MonkeyArena unit (model) every 12 seconds.

  • In the triggers Statue Cast and Mischief:
    • (A unit finishes casting an ability) -> (A unit starts the effect of an ability).

  • In the Tree Dance Folder:
    • In trigger IncreaseLvl:
      • In the if-then conditional block, (Picked unit) is used over (Learning Hero). Given the event, (Picked unit) will always return null, leading to the condition never evaluating as true (Level Equal to 1?).
    • There may be a lot more things I'd like to point out here, but I will leave it for another day.

Phew, that was a lot to write. Interesting and functional as it currently is, there are a too many instances of memory leaks that need to be removed for me to approve of this right now, so I'll have to put it in Awaiting Update.

Version Reviewed:

  • v.1.0.1 (?) - Released 22nd of June, 2022.

Status:

  • Awaiting Update
 
Level 3
Joined
May 7, 2020
Messages
15
Neat. If I recall, Monkey King was the first Dota 2 exclusive Hero to be introduced. It would be poetic justice to see that it is one of the first Dota 2 exclusive Heroes to be properly (re)introduced back into Warcraft 3. Anyway, here's the code/trigger review:

  • In the trigger BoundleStrike (Boundle):
    • BoundleAngle appears to be causing a memory leak by referring to an unstored generated location handle in (Position of BoundleStrikeUnit). You could fix that by making it refer to BoundleStartingPosition, moving the initialization of BoundleStartingPosition before it.

    • In the same vein, BoundleEndingPoint should refer to BoundleStartingPosition.

      • For each (Integer A) from 1 to 3 , do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (X of BoundleCorners[(Integer A)]) Greater than BoundleMaxX
            • Then - Actions
              • Set Variable Set BoundleMaxX = (X of BoundleCorners[(Integer A)])
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (X of BoundleCorners[(Integer A)]) Less than BoundleMinX
                • Then - Actions
                  • Set Variable Set BoundleMinX = (X of BoundleCorners[(Integer A)])
                • Else - Actions
      From the looks of things, there's no need to nest the conditions within the else block. Just move the inner if-then block out of the outer if-then-else block.

      • -------- Picking Unit Affecte by Boundle --------
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Region(BoundleMinX, BoundleMinY, BoundleMaxX, BoundleMaxY)) matching ((((Matching unit) belongs to an enemy of (Owner of BoundleStrikeUnit).) Equal to True) and ((((Matching unit) is A flying unit) Equal to False) and ((((Matching unit) is Magic Immune) Equal to False) and (((Matching unit) is Mechanical) Equal to False))))) and do (Actions)
        • Loop - Actions
          • -------- Finding point of center of unit in rotated env --------
          • Set Variable Set RotatedPositionOfUnit = ((Point(BoundleCenterX, BoundleCenterY)) offset by (Distance between (Position of (Picked unit)) and (Point(BoundleCenterX, BoundleCenterY))) towards ((Angle from (Position of (Picked unit)) to (Point(BoundleCenterX, BoundleCenterY))) - (BoundleAngle - 90.00)) degrees.)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • And - All (Conditions) are true
                • Conditions
                  • (X of RotatedPositionOfUnit) Less than or equal to (X of BotRightCornerInRotatedBoundle)
                  • (X of RotatedPositionOfUnit) Greater than or equal to (X of BotLeftCornerInRotatedBoundle)
                  • (Y of RotatedPositionOfUnit) Greater than or equal to (Y of BotLeftCornerInRotatedBoundle)
                  • (Y of RotatedPositionOfUnit) Less than or equal to (Y of TopLeftCornerInRotatedBoundle)
            • Then - Actions
              • Unit Group - Add (Picked unit) to UnitsAffectedByBoundle
              • -------- Continue would be nice there istead of else if to have less indentation --------
            • Else - Actions
              • -------- Finding closest Y to rotated position of unit --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Y of RotatedPositionOfUnit) Greater than (Y of TopLeftCornerInRotatedBoundle)
                • Then - Actions
                  • Set Variable Set ClosestYToRotatedPoint = (Y of TopLeftCornerInRotatedBoundle)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Y of RotatedPositionOfUnit) Less than (Y of BotLeftCornerInRotatedBoundle)
                    • Then - Actions
                      • Set Variable Set ClosestXToRotatedPoint = (X of BotRightCornerInRotatedBoundle)
                      • Set Variable Set ClosestYToRotatedPoint = (Y of BotLeftCornerInRotatedBoundle)
                    • Else - Actions
                      • Set Variable Set ClosestYToRotatedPoint = (Y of RotatedPositionOfUnit)
              • -------- Finding closest X to rotated position of unit --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (X of RotatedPositionOfUnit) Less than (X of BotLeftCornerInRotatedBoundle)
                • Then - Actions
                  • Set Variable Set ClosestXToRotatedPoint = (X of BotLeftCornerInRotatedBoundle)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (X of RotatedPositionOfUnit) Greater than (X of BotRightCornerInRotatedBoundle)
                    • Then - Actions
                      • Set Variable Set ClosestXToRotatedPoint = (X of BotRightCornerInRotatedBoundle)
                    • Else - Actions
                      • Set Variable Set ClosestXToRotatedPoint = (X of RotatedPositionOfUnit)
              • Set Variable Set BoundleDistanceToEdge = (Square root(((Power((Abs(((X of RotatedPositionOfUnit) - ClosestXToRotatedPoint))), 2.00)) + (Power((Abs(((Y of RotatedPositionOfUnit) - ClosestYToRotatedPoint))), 2.00)))))
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Collision Size of (Picked unit)) Greater than or equal to BoundleDistanceToEdge
                • Then - Actions
                  • Unit Group - Add (Picked unit) to UnitsAffectedByBoundle
                • Else - Actions
      1.) It looks like a JASS rect (GUI region) handle is being created without being referenced and subsequently cleaned up. You can clean this up using the following function: native RemoveRect takes rect whichRect returns nothing.

      2.) The inner filter function in the nested matching condition statement can look quite ugly really fast with a lot of conditions. Try filtering them out within the Actions block instead. Check out this tutorial for more info: Convenient Unit Group Filtering in GUI

      3.) The liberal use of (Position of (Picked unit)) translates to more memory leaks.

      4.) You can use Skip Remaining Actions in the Then - Actions block on the first If-then-else block as a quasi-continue statement, since the function (Pick all units in n group) generates a new thread for each picked unit. (Memory leaks that have been created before that point will have to be cleaned up, though).

      5.) (Picked unit) is called an awful lot within this block. Perhaps you might want to store that in a temp variable?

    • The floating text should only show the integer value of the amount of damage dealt, not the real value. (250 instead of 250.16, for example).
  • In the trigger Jingu Lifesteal:
    • You can directly call FlushChildHashtable instead of the wrapper.
      • API difference between the two functions:
        JASS:
        native FlushChildHashtable takes hashtable whichHashtable, integer parentKey
        function FlushChildHashtableBJ takes integer parentKey, hashtable whichHashtable
  • In the trigger Jingu Check for Buff:
    • Don't be shy with the interval period. Even when not enabled and disabled properly, this trigger should not be too costly. I'd recommend a 0.50 second interval.
  • In the trigger ArenaCreate:
    • The (A unit starts the effect of an ability) event would be more suitable here.
  • In the trigger Arena Damage (may also apply in ArenaSoldiersV2):
    • (Position of MonkeyArena) and (Position of MonkeyArenaCreator) is not stored.

      • Set Variable Set MonkeyArenaToDamageLeft = ((Load 2 of (Key (Picked unit).) from MonkeyArenaHastable.) - 0.04)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MonkeyArenaToDamageLeft Less than or equal to 0.00
        • Then - Actions
          • Set Variable Set MonkeyArenaToDamageLeft = MonkeyArenaDamageInterval
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within MonkeyArenaSize of (Position of MonkeyArena) matching (((Matching unit) belongs to an ally of (Owner of MonkeyArenaCreator).) Equal to False).) and do (Actions)
            • Loop - Actions
              • Unit - Cause MonkeyArenaCreator to damage (Picked unit) , dealing ((Real((Base Damage of MonkeyArenaCreator for weapon index 1))) x MonkeyArenaDamageMult) damage of attack type Hero and damage type Normal
        • Else - Actions
      Readability of the filter function can be improved. Also, another location handle (Position of MonkeyArena) has been generated and not cleaned up.

      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((MonkeyArenaDuration - MonkeyArenaDurationLeft) mod 12.00) Equal to 0.00
        • Then - Actions
          • -------- Model of arena will disapear around12 seconds, so we swap arena for new, it is looks a little weird since dragon will change positiom, but it is better than nothing --------
          • Unit - Replace MonkeyArena with a Monkey Arena using The old unit's relative life and mana
          • Animation - Change (Last replaced unit) 's size to ( (100.00 x MonkeyArenaScale) %, (100.00 x MonkeyArenaScale) %, 100.00 %) of its original size
          • Set Variable Set MonkeyArena = (Last replaced unit)
          • Hashtable - Save Handle Of MonkeyArena as 0 of (Key (Picked unit).) in MonkeyArenaHastable .
        • Else - Actions
      I suggest resetting the MonkeyArena unit's animation instead of replacing the MonkeyArena unit (model) every 12 seconds.
  • In the triggers Statue Cast and Mischief:
    • (A unit finishes casting an ability) -> (A unit starts the effect of an ability).
  • In the Tree Dance Folder:
    • In trigger IncreaseLvl:
      • In the if-then conditional block, (Picked unit) is used over (Learning Hero). Given the event, (Picked unit) will always return null, leading to the condition never evaluating as true (Level Equal to 1?).
    • There may be a lot more things I'd like to point out here, but I will leave it for another day.

Phew, that was a lot to write. Interesting and functional as it currently is, there are a too many instances of memory leaks that need to be removed for me to approve of this right now, so I'll have to put it in Awaiting Update.

Version Reviewed:

  • v.1.0.1 (?) - Released 22nd of June, 2022.

Status:

  • Awaiting Update
Thanks for feedback, may I ask Why do you suggest using "A unit starts the effect of an ability" instead of "unit finishes casting an ability", is it because of perfomence or some gameplay diffrence in fringe scenarios.
You said that position of picked/casting unit leaks in every time? I thought it's only leaks when you order unit some action(moving) to that point or creating unit at that point.
Also i wonder how did Increase Lvl trigger worked correctly when i tested it, even though there is no way it should work with this check, maybe i changed it accidentally.
Nice suggestion with resetting arena animation.
Are there any other memory leaks that you didn't mention here?
 
Spells usually implement their effects at the event (A unit starts the effect of an ability), the moment when the manacost and cooldown has been applied. It's the norm for most spells here to use this event instead of (A unit finishes casting an ability).

Whenever (Position of unit) is called, a new location handle pointing to the current coordinates of the unit is generated.

As for Increase Level trigger working despite the logical error, I found that the Hero learning the ability already has the Spring Tree (or Spring Dance?) sub-ability at the moment when the event runs.

I'm not fully certain yet about the presence of more memory leaks (specifically within the Tree Dance folder). I will have to check that out in more detail and update my review accordingly.

For now, memory leaks can be spotted when functions that return a new handle (enclosed in opening-closing parentheses) are not stored in variables for subsequent clean-up. Such handle types to look out for are points (locations), Unit Groups, Special Effects (not used here), which are most commonly generated.

I did not bring this up in the review, but you can also use (Trigger unit) for all of these unit events, in place of their event-appropriate counterparts.
 
Top