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

Meat Hook System [GUI] v4.2

This system basically allows a caster to launch a head towards a target point with a chain attach to it. It has many features that allows you to create a meathook, grapple or similar spell very easily.


  • Meathook ini
    • Events
    • Conditions
    • Actions
      • Set MeatHCount = (MeatHCount + 1)
      • Set Temp_Unit = (Triggering unit)
      • Set Temp_Point = (Position of Temp_Unit)
      • Set MeatHNewPoint = (Temp_Point offset by Config_MeatHStartOffset towards Config_MeatHAngle degrees)
      • Unit - Create 1 dummy for Neutral Passive at MeatHNewPoint facing Config_MeatHAngle degrees
      • Set MeatHRef = (Custom value of (Last created unit))
      • Set MeatHSpell[MeatHRef] = Config_MeatHSpell
      • Animation - Change UDexUnits[MeatHRef]'s size to (Config_MeatHHeadScale%, Config_MeatHHeadScale%, Config_MeatHHeadScale%) of its original size
      • Unit Group - Add UDexUnits[MeatHRef] to MeatHHeads
      • Set MeatHChainModel[MeatHRef] = Config_MeatHChainModel
      • Set MeatHChainX[MeatHRef] = (X of MeatHNewPoint)
      • Set MeatHChainY[MeatHRef] = (Y of MeatHNewPoint)
      • Custom script: call RemoveLocation(udg_MeatHNewPoint)
      • Set MeatHDeg[MeatHRef] = Config_MeatHAngle
      • Set MeatHC[MeatHRef] = Temp_Unit
      • Set MeatHTraveled[MeatHRef] = 0.00
      • Set MeatHT[MeatHRef] = No unit
      • Custom script: set udg_MeatHRow[udg_MeatHRef] = CreateGroup()
      • Special Effect - Create a special effect attached to the orign of UDexUnits[MeatHRef] using Config_MeatHHeadModel
      • Set MeatHEffect[MeatHRef] = (Last created special effect)
      • Set MeatHChainScale[MeatHRef] = Config_MeatHChainScale
      • Set MeatHGrapple[MeatHRef] = Config_MeatHGrapple
      • Set MeatHRecicle[MeatHRef] = Config_MeatHRecicle
      • Set MeatHLockOn[MeatHRef] = Config_MeatHLockOn
      • Set MeatHIgnore[MeatHRef] = Config_MeatHIgnore
      • Set MeatHDestroyTrees[MeatHRef] = Config_MeatHDestroyTrees
      • Set MeatHDist[MeatHRef] = ((Config_MeatHDistance + ((Real(Config_MeatHlvl)) x Config_MeatHlvlDistnace)) - Config_MeatHStartOffset)
      • Set MeatHSpeed[MeatHRef] = (Config_MeatHSpeed + ((Real(Config_MeatHlvl)) x Config_MeatHlvlSpeed))
      • Set MeatHDamage[MeatHRef] = (Config_MeatHDamage + ((Real(Config_MeatHlvl)) x Config_MeatHlvlDamage))
      • Set MeatHDamageLoop[MeatHRef] = (Config_MeatHDamageLoop + ((Real(Config_MeatHlvl)) x Config_MeatHlvlDamageLoop))
      • Set MeatHDamageType[MeatHRef] = Config_MeatHDamageType
      • Set MeatHAoE[MeatHRef] = Config_MeatHAoE
      • Set MeatHDamageAoE[MeatHRef] = (Config_MeatHDamageAoE + ((Real(Config_MeatHlvl)) x Config_MeatHlvlDamageAoE))
      • Set MeatHAoEDamage[MeatHRef] = (Config_MeatHAoEDamage + ((Real(Config_MeatHlvl)) x Config_MeatHlvlAoEDamage))
      • Set MeatHAoESFX[MeatHRef] = Config_MeatHAoESFX
      • Set MeatHChainRate[MeatHRef] = Config_MeatHChainRate
      • Set MeatHSFX[MeatHRef] = Config_MeatHSFX
      • Set MeatHDamageLoop[MeatHRef] = ((Config_MeatHDamageLoop + ((Real(Config_MeatHlvl)) x MeatHlvlDamageLoop)) / 33.33)
      • Set MeatHAoE[MeatHRef] = (Config_MeatHAoE + ((Real(Config_MeatHlvl)) x Config_MeatHlvlAoE))
      • Set MeatHOffset[MeatHRef] = Config_MeatHOffset
      • Set MeatHFull[MeatHRef] = False
      • Set MeatHLaunch[MeatHRef] = True
      • Set MeatHSize[MeatHRef] = 1
      • Custom script: call RemoveLocation(udg_Temp_Point)
      • Unit Group - Add UDexUnits[MeatHRef] to MeatHRow[MeatHRef]
      • -------- > custom properties here < --------
      • -------- ----------------------- --------
      • Set MeatHLst[MeatHRef] = 1
      • Custom script: if udg_MeatHCount == 1 then
      • Custom script: call EnableTrigger( gg_trg_Meathook_loop )
      • Custom script: endif
  • Meathook loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in MeatHHeads and do (Actions)
        • Loop - Actions
          • Set MeatHHead = (Picked unit)
          • Set MeatHRef = (Custom value of MeatHHead)
          • Custom script: set udg_MeatHCX = GetUnitX(udg_MeatHC[udg_MeatHRef])
          • Custom script: set udg_MeatHCY = GetUnitY(udg_MeatHC[udg_MeatHRef])
          • -------- --------------------------------------------- --------
          • -------- Index row group into array --------
          • -------- --------------------------------------------- --------
          • Unit Group - Pick every unit in MeatHRow[MeatHRef] and do (Actions)
            • Loop - Actions
              • Set Temp_Int = (Custom value of (Picked unit))
              • -------- stores unit ID - used to access related data in other arrays --------
              • Set MeatHChainRef[MeatHLst[Temp_Int]] = Temp_Int
              • -------- stores unit in array for this spell instance --------
              • Set MeatHChain[MeatHLst[Temp_Int]] = UDexUnits[Temp_Int]
          • -------- --------------------------------------------- --------
          • -------- Move the chain --------
          • -------- --------------------------------------------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MeatHLaunch[MeatHRef] Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHLockOn[MeatHRef] Not equal to No unit
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MeatHC[MeatHRef] Equal to MeatHLockOn[MeatHRef]
                    • Then - Actions
                      • Set MeatHDeg[MeatHRef] = (Facing of MeatHC[MeatHRef])
                    • Else - Actions
                      • Custom script: set udg_tempX = GetUnitX(udg_MeatHLockOn[udg_MeatHRef])
                      • Custom script: set udg_tempY = GetUnitY(udg_MeatHLockOn[udg_MeatHRef])
                      • Custom script: set udg_MeatHDeg[udg_MeatHRef] = bj_RADTODEG * Atan2(udg_tempY - udg_MeatHChainY[udg_MeatHRef], udg_tempX - udg_MeatHChainX[udg_MeatHRef])
                • Else - Actions
              • Set tempX = (MeatHChainX[MeatHRef] + (MeatHSpeed[MeatHRef] x (Cos(MeatHDeg[MeatHRef]))))
              • Set tempY = (MeatHChainY[MeatHRef] + (MeatHSpeed[MeatHRef] x (Sin(MeatHDeg[MeatHRef]))))
              • -------- --------------------------------------------- --------
              • -------- If hook hit map boundary, return the hook. Else move it forward --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • tempX Less than minX
                      • tempY Less than minY
                      • tempX Greater than maxX
                      • tempY Greater than maxY
                • Then - Actions
                  • Set UDex = MeatHRef
                  • Set MeatHEvent = 5.00
                  • Set MeatHEvent = 0.00
                  • Set MeatHLaunch[MeatHRef] = False
                • Else - Actions
                  • Custom script: call SetUnitX(udg_MeatHHead, udg_tempX)
                  • Custom script: call SetUnitY(udg_MeatHHead, udg_tempY)
                  • Set MeatHChainX[MeatHRef] = tempX
                  • Set MeatHChainY[MeatHRef] = tempY
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MeatHLaunch[MeatHRef] Equal to True
            • Then - Actions
              • -------- --------------------------------------------- --------
              • -------- If Launch = true, move the chain forward --------
              • -------- --------------------------------------------- --------
              • For each (Integer Temp_IntB) from 2 to MeatHSize[MeatHRef], do (Actions)
                • Loop - Actions
                  • -------- move chain towards head --------
                  • Set Temp_IntC = (Temp_IntB - 1)
                  • Custom script: set udg_Temp_Real = bj_RADTODEG * Atan2(udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB]] - udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntC]], udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB]] - udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntC]])
                  • Set MeatHChainX[MeatHChainRef[Temp_IntB]] = (MeatHChainX[MeatHChainRef[Temp_IntC]] + (MeatHChainRate[MeatHRef] x (Cos(Temp_Real))))
                  • Set MeatHChainY[MeatHChainRef[Temp_IntB]] = (MeatHChainY[MeatHChainRef[Temp_IntC]] + (MeatHChainRate[MeatHRef] x (Sin(Temp_Real))))
                  • Custom script: call SetUnitX(udg_MeatHChain[udg_Temp_IntB], udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB]])
                  • Custom script: call SetUnitY(udg_MeatHChain[udg_Temp_IntB], udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB]])
                  • Custom script: call SetUnitFacing(udg_MeatHChain[udg_Temp_IntB], udg_Temp_Real)
              • Set MeatHTraveled[MeatHRef] = (MeatHTraveled[MeatHRef] + MeatHSpeed[MeatHRef])
              • -------- Set Launce to fasle when the maximum distance is reached --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHTraveled[MeatHRef] Greater than or equal to MeatHDist[MeatHRef]
                • Then - Actions
                  • Set UDex = MeatHRef
                  • Set MeatHEvent = 5.00
                  • Set MeatHEvent = 0.00
                  • Set MeatHLaunch[MeatHRef] = False
                • Else - Actions
            • Else - Actions
              • -------- --------------------------------------------- --------
              • -------- If Launch = false, check if grapple is true --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHGrapple[MeatHRef] Equal to True
                  • MeatHT[MeatHRef] Not equal to No unit
                • Then - Actions
                  • -------- --------------------------------------------- --------
                  • -------- If grapple is true and a target is in the hook... --------
                  • -------- --------------------------------------------- --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (MeatHT[MeatHRef] is alive) Equal to True
                    • Then - Actions
                      • -------- --------------------------------------------- --------
                      • -------- If target is alive, move grapple head to target --------
                      • -------- --------------------------------------------- --------
                      • Set MeatHNewPoint = (Position of MeatHT[MeatHRef])
                      • Set MeatHChainX[MeatHRef] = (X of MeatHNewPoint)
                      • Set MeatHChainY[MeatHRef] = (Y of MeatHNewPoint)
                      • Custom script: call RemoveLocation(udg_MeatHNewPoint)
                      • Custom script: call SetUnitX(udg_MeatHHead, udg_MeatHChainX[udg_MeatHRef])
                      • Custom script: call SetUnitY(udg_MeatHHead, udg_MeatHChainY[udg_MeatHRef])
                      • For each (Integer Temp_IntB) from 2 to MeatHSize[MeatHRef], do (Actions)
                        • Loop - Actions
                          • Custom script: set udg_Temp_Real = bj_RADTODEG * Atan2(udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB]] - udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB - 1]], udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB]] - udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB - 1]])
                          • Set MeatHChainX[MeatHChainRef[Temp_IntB]] = (MeatHChainX[MeatHChainRef[(Temp_IntB - 1)]] + (MeatHChainRate[MeatHRef] x (Cos(Temp_Real))))
                          • Set MeatHChainY[MeatHChainRef[Temp_IntB]] = (MeatHChainY[MeatHChainRef[(Temp_IntB - 1)]] + (MeatHChainRate[MeatHRef] x (Sin(Temp_Real))))
                          • Custom script: call SetUnitX(udg_MeatHChain[udg_Temp_IntB], udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB]])
                          • Custom script: call SetUnitY(udg_MeatHChain[udg_Temp_IntB], udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB]])
                          • Custom script: call SetUnitFacing(udg_MeatHChain[udg_Temp_IntB], udg_Temp_Real)
                    • Else - Actions
                      • Set MeatHT[MeatHRef] = No unit
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MeatHHooked[(Custom value of MeatHC[MeatHRef])] Equal to 0
                    • Then - Actions
                      • -------- --------------------------------------------- --------
                      • -------- If the caster is not hooked by someone else, move caster along the chain --------
                      • -------- --------------------------------------------- --------
                      • Custom script: set udg_Temp_Real = bj_RADTODEG * Atan2(udg_MeatHChainY[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]] - udg_MeatHCY, udg_MeatHChainX[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]] - udg_MeatHCX)
                      • Set MeatHCX = (MeatHCX + (MeatHSpeed[MeatHRef] x (Cos(Temp_Real))))
                      • Set MeatHCY = (MeatHCY + (MeatHSpeed[MeatHRef] x (Sin(Temp_Real))))
                      • Custom script: call SetUnitX(udg_MeatHC[udg_MeatHRef], udg_MeatHCX)
                      • Custom script: call SetUnitY(udg_MeatHC[udg_MeatHRef], udg_MeatHCY)
                    • Else - Actions
                • Else - Actions
                  • -------- --------------------------------------------- --------
                  • -------- If grapple is false, return the chain to the caster --------
                  • -------- --------------------------------------------- --------
                  • For each (Integer Temp_IntB) from 1 to (MeatHSize[MeatHRef] - 1), do (Actions)
                    • Loop - Actions
                      • -------- move chain, starting at the head --------
                      • Custom script: set udg_Temp_Real = bj_RADTODEG * Atan2(udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB + 1]] - udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB]], udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB + 1]] - udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB]])
                      • Set MeatHChainX[MeatHChainRef[Temp_IntB]] = (MeatHChainX[MeatHChainRef[Temp_IntB]] + (MeatHSpeed[MeatHRef] x (Cos(Temp_Real))))
                      • Set MeatHChainY[MeatHChainRef[Temp_IntB]] = (MeatHChainY[MeatHChainRef[Temp_IntB]] + (MeatHSpeed[MeatHRef] x (Sin(Temp_Real))))
                      • Custom script: call SetUnitX(udg_MeatHChain[udg_Temp_IntB], udg_MeatHChainX[udg_MeatHChainRef[udg_Temp_IntB]])
                      • Custom script: call SetUnitY(udg_MeatHChain[udg_Temp_IntB], udg_MeatHChainY[udg_MeatHChainRef[udg_Temp_IntB]])
                      • Custom script: call SetUnitFacing(udg_MeatHChain[udg_Temp_IntB], udg_Temp_Real)
                  • Custom script: set udg_Temp_Real = bj_RADTODEG * Atan2(udg_MeatHCY - udg_MeatHChainY[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]], udg_MeatHCX - udg_MeatHChainX[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]])
                  • Set MeatHChainX[MeatHChainRef[MeatHSize[MeatHRef]]] = (MeatHChainX[MeatHChainRef[MeatHSize[MeatHRef]]] + (MeatHSpeed[MeatHRef] x (Cos(Temp_Real))))
                  • Set MeatHChainY[MeatHChainRef[MeatHSize[MeatHRef]]] = (MeatHChainY[MeatHChainRef[MeatHSize[MeatHRef]]] + (MeatHSpeed[MeatHRef] x (Sin(Temp_Real))))
                  • Custom script: call SetUnitX(udg_MeatHChain[udg_MeatHSize[udg_MeatHRef]], udg_MeatHChainX[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]])
                  • Custom script: call SetUnitY(udg_MeatHChain[udg_MeatHSize[udg_MeatHRef]], udg_MeatHChainY[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]])
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MeatHT[MeatHRef] Not equal to No unit
                    • Then - Actions
                      • -------- --------------------------------------------- --------
                      • -------- Move target to the head --------
                      • -------- --------------------------------------------- --------
                      • Custom script: call SetUnitX(udg_MeatHT[udg_MeatHRef], udg_MeatHChainX[udg_MeatHRef])
                      • Custom script: call SetUnitY(udg_MeatHT[udg_MeatHRef], udg_MeatHChainY[udg_MeatHRef])
                    • Else - Actions
          • -------- --------------------------------------------- --------
          • -------- Add / Remove chains --------
          • -------- --------------------------------------------- --------
          • Custom script: set udg_Temp_Real = distance(udg_MeatHCX, udg_MeatHChainX[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]], udg_MeatHCY, udg_MeatHChainY[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]]) - udg_MeatHOffset[udg_MeatHRef]
          • If (MeatHLaunch[MeatHRef] Equal to False) then do (Set Temp_Real = (Temp_Real - MeatHSpeed[MeatHRef])) else do (-------- ... --------)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MeatHChainRate[MeatHRef] Greater than 0.00
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Temp_Real Greater than MeatHChainRate[MeatHRef]
                • Then - Actions
                  • Custom script: loop
                  • Custom script: exitwhen udg_Temp_Real < udg_MeatHChainRate[udg_MeatHRef]
                  • Custom script: set udg_MeatHAngle = bj_RADTODEG * Atan2(udg_MeatHCY - udg_MeatHChainY[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]], udg_MeatHCX - udg_MeatHChainX[udg_MeatHChainRef[udg_MeatHSize[udg_MeatHRef]]])
                  • Set MeatHTempX = (MeatHChainX[MeatHChainRef[MeatHSize[MeatHRef]]] + (MeatHChainRate[MeatHRef] x (Cos(MeatHAngle))))
                  • Set MeatHTempY = (MeatHChainY[MeatHChainRef[MeatHSize[MeatHRef]]] + (MeatHChainRate[MeatHRef] x (Sin(MeatHAngle))))
                  • Custom script: set udg_Temp_Int = GetUnitUserData(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), udg_dummy, udg_MeatHTempX, udg_MeatHTempY, udg_MeatHAngle ))
                  • Unit - Pause UDexUnits[Temp_Int]
                  • Unit Group - Add UDexUnits[Temp_Int] to MeatHRow[MeatHRef]
                  • Set MeatHSize[MeatHRef] = (MeatHSize[MeatHRef] + 1)
                  • Set MeatHLst[Temp_Int] = MeatHSize[MeatHRef]
                  • Set MeatHChainRef[MeatHSize[MeatHRef]] = Temp_Int
                  • Set MeatHChainX[Temp_Int] = MeatHTempX
                  • Set MeatHChainY[Temp_Int] = MeatHTempY
                  • Animation - Change UDexUnits[Temp_Int]'s size to (MeatHChainScale[MeatHRef]%, MeatHChainScale[MeatHRef]%, MeatHChainScale[MeatHRef]%) of its original size
                  • Special Effect - Create a special effect attached to the orign of UDexUnits[Temp_Int] using MeatHChainModel[MeatHRef]
                  • Set MeatHEffect[Temp_Int] = (Last created special effect)
                  • Set MeatHChain[MeatHSize[MeatHRef]] = UDexUnits[Temp_Int]
                  • Set MeatHChainRate[MeatHRef] = (MeatHChainRate[MeatHRef] + 0.10)
                  • Set Temp_Real = (Temp_Real - MeatHChainRate[MeatHRef])
                  • Custom script: endloop
                • Else - Actions
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Temp_Real Less than (1.50 x MeatHSpeed[MeatHRef])
            • Then - Actions
              • Custom script: loop
              • Custom script: exitwhen udg_Temp_Real > udg_MeatHSpeed[udg_MeatHRef]
              • -------- --------------------------------------------- --------
              • -------- If only the head is left and is returning to the caster, end spell --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHSize[MeatHRef] Equal to 1
                  • MeatHLaunch[MeatHRef] Equal to False
                • Then - Actions
                  • Set UDex = MeatHRef
                  • Set MeatHEvent = 3.00
                  • Set MeatHEvent = 0.00
                  • Trigger - Run Meathook end <gen> (ignoring conditions)
                  • Set Temp_Real = (MeatHSpeed[MeatHRef] + 1.00)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MeatHSize[MeatHRef] Not equal to 1
                    • Then - Actions
                      • Special Effect - Destroy MeatHEffect[MeatHChainRef[MeatHSize[MeatHRef]]]
                      • Unit - Remove MeatHChain[MeatHSize[MeatHRef]] from the game
                      • Set MeatHSize[MeatHRef] = (MeatHSize[MeatHRef] - 1)
                      • Set Temp_Real = (Temp_Real + MeatHChainRate[MeatHRef])
                      • Set MeatHChainRate[MeatHRef] = (MeatHChainRate[MeatHRef] - 0.10)
                    • Else - Actions
              • Custom script: endloop
            • Else - Actions
          • Set UDex = MeatHRef
          • Set MeatHEvent = 1.00
          • Set MeatHEvent = 0.00
          • -------- --------------------------------------------- --------
          • -------- if spell still exists... --------
          • -------- --------------------------------------------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (MeatHHead is dead) Equal to False
            • Then - Actions
              • -------- --------------------------------------------- --------
              • -------- Search for a target to hook --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHFull[MeatHRef] Equal to False
                  • MeatHAoE[MeatHRef] Greater than 0.00
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • Config_MeatHIgnore Equal to True
                    • Then - Actions
                      • Custom script: call GroupEnumUnitsInRange(udg_Temp_Targets, udg_MeatHChainX[udg_MeatHRef], udg_MeatHChainY[udg_MeatHRef], udg_MeatHAoE[udg_MeatHRef], function FilterLockedUnit)
                    • Else - Actions
                      • Custom script: call GroupEnumUnitsInRange(udg_Temp_Targets, udg_MeatHChainX[udg_MeatHRef], udg_MeatHChainY[udg_MeatHRef], udg_MeatHAoE[udg_MeatHRef], null)
                  • Unit Group - Pick every unit in Temp_Targets and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • MeatHT[MeatHRef] Equal to No unit
                        • Then - Actions
                          • Set Temp_Unit = (Picked unit)
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • Temp_Unit Not equal to MeatHC[MeatHRef]
                              • (Temp_Unit is A flying unit) Equal to False
                              • (Temp_Unit is dead) Equal to False
                            • Then - Actions
                              • Set MeatHT[MeatHRef] = Temp_Unit
                              • Set UDex = MeatHRef
                              • Set MeatHEvent = 2.00
                              • Set MeatHEvent = 0.00
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • ((Owner of MeatHT[MeatHRef]) is an enemy of (Owner of MeatHC[MeatHRef])) Equal to True
                                • Then - Actions
                                  • Unit - Cause MeatHC[MeatHRef] to damage MeatHT[MeatHRef], dealing MeatHDamage[MeatHRef] damage of attack type MeatHDamageType[MeatHRef] and damage type Normal
                                • Else - Actions
                              • Set MeatHLaunch[MeatHRef] = False
                              • Set MeatHFull[MeatHRef] = True
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • MeatHGrapple[MeatHRef] Equal to False
                                • Then - Actions
                                  • Unit - Turn collision for MeatHT[MeatHRef] Off
                                  • Set MeatHT[MeatHHooked[(Custom value of MeatHT[MeatHRef])]] = No unit
                                  • Set MeatHHooked[(Custom value of MeatHT[MeatHRef])] = MeatHRef
                                  • Set MeatHLockOn[MeatHRef] = No unit
                                • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • MeatHGrapling[(Custom value of MeatHC[MeatHRef])] Not equal to 0
                                    • Then - Actions
                                      • Set UDex = MeatHGrapling[(Custom value of MeatHC[MeatHRef])]
                                      • Trigger - Run Meathook end <gen> (ignoring conditions)
                                    • Else - Actions
                                  • Set MeatHGrapling[(Custom value of MeatHC[MeatHRef])] = MeatHRef
                                  • Unit - Turn collision for MeatHC[MeatHRef] Off
                            • Else - Actions
                        • Else - Actions
                  • Custom script: call GroupClear(udg_Temp_Targets)
                • Else - Actions
              • -------- --------------------------------------------- --------
              • -------- Deal damage --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Owner of MeatHC[MeatHRef]) is an enemy of (Owner of MeatHT[MeatHRef])) Equal to True
                • Then - Actions
                  • Unit - Cause MeatHC[MeatHRef] to damage MeatHT[MeatHRef], dealing MeatHDamageLoop[MeatHRef] damage of attack type MeatHDamageType[MeatHRef] and damage type Normal
                  • Custom script: call DestroyEffect(AddSpecialEffectTarget( udg_MeatHSFX[udg_MeatHRef], udg_MeatHT[udg_MeatHRef], "chest" ))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (MeatHT[MeatHRef] is dead) Equal to True
                    • Then - Actions
                      • Set UDex = MeatHRef
                      • Set MeatHEvent = 4.00
                      • Set MeatHEvent = 0.00
                      • Set MeatHT[MeatHRef] = No unit
                      • If (MeatHRecicle[MeatHRef] Equal to True) then do (Set MeatHFull[MeatHRef] = False) else do (-------- ... --------)
                    • Else - Actions
                • Else - Actions
              • -------- --------------------------------------------- --------
              • -------- Deal AoE damage --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHAoEDamage[MeatHRef] Greater than 0.00
                • Then - Actions
                  • Custom script: call GroupEnumUnitsInRange(udg_Temp_Targets, udg_MeatHChainX[udg_MeatHRef], udg_MeatHChainY[udg_MeatHRef], udg_MeatHDamageAoE[udg_MeatHRef], null)
                  • Unit Group - Pick every unit in Temp_Targets and do (Actions)
                    • Loop - Actions
                      • Set Temp_Unit = (Picked unit)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • Temp_Unit Not equal to MeatHC[MeatHRef]
                          • Temp_Unit Not equal to MeatHT[MeatHRef]
                          • (Temp_Unit is A flying unit) Equal to False
                          • ((Owner of Temp_Unit) is an enemy of (Owner of MeatHC[MeatHRef])) Equal to True
                        • Then - Actions
                          • Unit - Cause MeatHC[MeatHRef] to damage Temp_Unit, dealing MeatHAoEDamage[MeatHRef] damage of attack type MeatHDamageType[MeatHRef] and damage type Normal
                          • Custom script: call DestroyEffect(AddSpecialEffectTarget( udg_MeatHAoESFX[udg_MeatHRef], udg_Temp_Unit, "chest" ))
                        • Else - Actions
                • Else - Actions
              • -------- --------------------------------------------- --------
              • -------- Destroy destructables --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MeatHDestroyTrees[MeatHRef] Equal to True
                • Then - Actions
                  • Set Temp_Rect = (Region((MeatHChainX[MeatHRef] - MeatHDamageAoE[MeatHRef]), (MeatHChainY[MeatHRef] - MeatHDamageAoE[MeatHRef]), (MeatHChainX[MeatHRef] + MeatHDamageAoE[MeatHRef]), (MeatHChainY[MeatHRef] + MeatHDamageAoE[MeatHRef])))
                  • Destructible - Pick every destructible in Temp_Rect and do (Actions)
                    • Loop - Actions
                      • Unit - Order harvester to Harvest (Picked destructible)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Current order of harvester) Equal to (Order(harvest))
                        • Then - Actions
                          • Unit - Order harvester to Stop
                          • Destructible - Kill (Picked destructible)
                        • Else - Actions
                  • Custom script: call RemoveRect(udg_Temp_Rect)
                • Else - Actions
              • -------- --------------------------------------------- --------
              • -------- If Locked on target is dead, remove target --------
              • -------- --------------------------------------------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (MeatHLockOn[MeatHRef] is dead) Equal to True
                • Then - Actions
                  • Set MeatHLockOn[MeatHRef] = No unit
                • Else - Actions
            • Else - Actions
  • Meathook end
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (UDexUnits[UDex] is in MeatHHeads) Equal to True
        • Then - Actions
          • Unit - Turn collision for MeatHC[UDex] On
          • Unit - Turn collision for MeatHT[UDex] On
          • Set MeatHHooked[(Custom value of MeatHT[UDex])] = 0
          • Set MeatHGrapling[(Custom value of MeatHC[UDex])] = 0
          • Custom script: set udg_MeatHSpell[udg_UDex] = 0
          • Set MeatHT[UDex] = No unit
          • Set MeatHLockOn[UDex] = No unit
          • Set MeatHGrapple[UDex] = False
          • Set MeatHRecicle[UDex] = False
          • Set MeatHDestroyTrees[UDex] = False
          • Set MeatHOffset[UDex] = 0.00
          • Set MeatHChainScale[UDex] = 0.00
          • Set MeatHDist[UDex] = 0.00
          • Set MeatHTraveled[UDex] = 0.00
          • Set MeatHSpeed[UDex] = 0.00
          • Set MeatHDamage[UDex] = 0.00
          • Set MeatHDamageLoop[UDex] = 0.00
          • Set MeatHAoEDamage[UDex] = 0.00
          • Set MeatHAoE[UDex] = 0.00
          • Set MeatHChainRate[UDex] = 0.00
          • Custom script: set udg_MeatHDamageType[udg_UDex] = null
          • Custom script: set udg_MeatHChainModel[udg_UDex] = null
          • Set MeatHAngle = 0.00
          • Unit Group - Pick every unit in MeatHRow[UDex] and do (Actions)
            • Loop - Actions
              • Set Temp_Int = (Custom value of (Picked unit))
              • Special Effect - Destroy MeatHEffect[Temp_Int]
              • Unit - Kill UDexUnits[Temp_Int]
          • Unit Group - Remove UDexUnits[UDex] from MeatHHeads
          • Custom script: call DestroyGroup(udg_MeatHRow[udg_UDex])
          • Set MeatHCount = (MeatHCount - 1)
          • Custom script: if udg_MeatHCount == 0 then
          • Trigger - Turn off Meathook loop <gen>
          • Custom script: endif
        • Else - Actions
          • Game - Display to (All players) the text: (ERROR: Attempted to remove an invalid meathook with ID + (String(UDex)))




Launces a hook towards a target point or unit that grabs the first target it encounters, dealing 150/200/250/300 damage to enemies plus 75/100/125/150 DPS. The target will be dragged back to the Warden.
Range: 2250/2500/2750/3000
  • Meathook
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Meat Hook
    • Actions
      • Set Config_MeatHSpell = Meat Hook
      • Set Config_MeatHlvl = (Level of Meat Hook for (Triggering unit))
      • -------- set the angle --------
      • Set Temp_Point = (Position of (Triggering unit))
      • Set Temp_Point2 = (Target point of ability being cast)
      • Set Config_MeatHAngle = (Angle from Temp_Point to Temp_Point2)
      • Custom script: call RemoveLocation(udg_Temp_Point)
      • Custom script: call RemoveLocation(udg_Temp_Point2)
      • -------- ------------- --------
      • -------- If Config_MeatHHook is false then this variables means nothing (you can't grapple something if your hook doesn't accepts a target) --------
      • Set Config_MeatHGrapple = False
      • -------- if the target die in a hook, can the same hook hook a new target? --------
      • Set Config_MeatHRecicle = True
      • Set Config_MeatHDestroyTrees = True
      • -------- Distance from meat hook's head to caster upon cast --------
      • Set Config_MeatHStartOffset = 128.00
      • -------- Distance between the caster and the chain's tale --------
      • Set Config_MeatHOffset = 64.00
      • -------- sets the unit type for the head and chain --------
      • Set Config_MeatHHeadModel = Abilities\Weapons\GlaiveMissile\GlaiveMissile.mdl
      • Set Config_MeatHChainModel = Abilities\Weapons\WardenMissile\WardenMissile.mdl
      • Set Config_MeatHHeadScale = 100.00
      • Set Config_MeatHChainScale = 200.00
      • Set Config_MeatHLockOn = (Target unit of ability being cast)
      • -------- If MeatHIgnore is true, only the lockon unit can be hooked --------
      • -------- In this trigger, I only set MeatHIgnore to true if there is a LockOn unit to hook --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Config_MeatHLockOn Equal to No unit
        • Then - Actions
          • Set Config_MeatHIgnore = False
        • Else - Actions
          • Set Config_MeatHIgnore = True
      • Set Config_MeatHDistance = 2000.00
      • Set Config_MeatHlvlDistnace = 250.00
      • Set Config_MeatHSpeed = 25.00
      • Set Config_MeatHlvlSpeed = 0.00
      • Set Config_MeatHDamage = 100.00
      • Set Config_MeatHlvlDamage = 50.00
      • -------- target dps --------
      • Set Config_MeatHDamageLoop = 50.00
      • Set Config_MeatHlvlDamageLoop = 25.00
      • -------- ------------- --------
      • -------- AoE dps --------
      • -------- range --------
      • Set Config_MeatHDamageAoE = 200.00
      • Set Config_MeatHlvlDamageAoE = 0.00
      • -------- amount --------
      • Set Config_MeatHAoEDamage = 5.00
      • Set Config_MeatHlvlAoEDamage = 0.00
      • -------- ------------- --------
      • Set Config_MeatHDamageType = Hero
      • Set Config_MeatHAoE = 100.00
      • Set Config_MeatHlvlAoE = 0.00
      • -------- avoid a chain rate lower than MeatHSpeed (include MeatHlvlSpeed) | 0 = no chain --------
      • Set Config_MeatHChainRate = 60.00
      • Set Config_MeatHSFX = Objects\Spawnmodels\Critters\Albatross\CritterBloodAlbatross.mdl
      • Set Config_MeatHAoESFX = Abilities\Weapons\HydraliskImpact\HydraliskImpact.mdl
      • Trigger - Run Meathook ini <gen> (ignoring conditions)
      • Game - Display to (All players) the text: (ID of last created spell is: + (String(MeatHRef)))


Launces a hook towards a target point or unit that grabs the first target it encounters, dealing 325/400/475/550 damage and pulls the caster towards the target.
Range: 2250/2500/2750/3000
  • Grapple
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Grapple
    • Actions
      • Set Config_MeatHSpell = Grapple
      • Set Config_MeatHlvl = (Level of Meat Hook for (Triggering unit))
      • -------- set the angle --------
      • Set Temp_Point = (Position of (Triggering unit))
      • Set Temp_Point2 = (Target point of ability being cast)
      • Set Config_MeatHAngle = (Angle from Temp_Point to Temp_Point2)
      • Custom script: call RemoveLocation(udg_Temp_Point)
      • Custom script: call RemoveLocation(udg_Temp_Point2)
      • -------- ------------- --------
      • -------- If Config_MeatHHook is false then this variables means nothing (you can't grapple something if your hook don't accepts a target) --------
      • Set Config_MeatHGrapple = True
      • -------- if the target die in a hook, can the same hook hook a new target? --------
      • Set Config_MeatHRecicle = True
      • Set Config_MeatHDestroyTrees = True
      • -------- Distance from meat hook's head to caster upon cast --------
      • Set Config_MeatHStartOffset = 128.00
      • -------- Distance between the caster and the chain's tale --------
      • Set Config_MeatHOffset = 64.00
      • -------- sets the unit type for the head and chain --------
      • Set Config_MeatHHeadModel = Abilities\Weapons\SentinelMissile\SentinelMissile.mdl
      • Set Config_MeatHChainModel = Abilities\Weapons\AncestralGuardianMissile\AncestralGuardianMissile.mdl
      • Set Config_MeatHHeadScale = 200.00
      • Set Config_MeatHChainScale = 100.00
      • Set Config_MeatHLockOn = No unit
      • Set Config_MeatHIgnore = False
      • Set Config_MeatHDistance = 2000.00
      • Set Config_MeatHlvlDistnace = 250.00
      • Set Config_MeatHSpeed = 30.00
      • Set Config_MeatHlvlSpeed = 0.00
      • Set Config_MeatHDamage = 250.00
      • Set Config_MeatHlvlDamage = 75.00
      • -------- target dps --------
      • Set Config_MeatHDamageLoop = 50.00
      • Set Config_MeatHlvlDamageLoop = 25.00
      • -------- ------------- --------
      • -------- AoE dps --------
      • -------- range --------
      • Set Config_MeatHDamageAoE = 0.00
      • Set Config_MeatHlvlDamageAoE = 0.00
      • -------- amount --------
      • Set Config_MeatHAoEDamage = 0.00
      • Set Config_MeatHlvlAoEDamage = 0.00
      • -------- ------------- --------
      • Set Config_MeatHDamageType = Hero
      • Set Config_MeatHAoE = 100.00
      • Set Config_MeatHlvlAoE = 0.00
      • -------- avoid a chain rate lower than MeatHSpeed (include MeatHlvlSpeed) | 0 = no chain --------
      • Set Config_MeatHChainRate = 45.00
      • Set Config_MeatHSFX = Objects\Spawnmodels\Critters\Albatross\CritterBloodAlbatross.mdl
      • Set Config_MeatHAoESFX = Abilities\Weapons\HydraliskImpact\HydraliskImpact.mdl
      • Trigger - Run Meathook ini <gen> (ignoring conditions)


Blasts a powerful energy ball towards a target point, dealing 40/50/60/70 damage per second to nearby enemies.
Range: 2750/3000/3250/3500
  • Kamehameha
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Kamehameha
    • Actions
      • Set Config_MeatHSpell = Kamehameha
      • Set Config_MeatHlvl = (Level of Meat Hook for (Triggering unit))
      • -------- set the angle --------
      • Set Temp_Point = (Position of (Triggering unit))
      • Set Temp_Point2 = (Target point of ability being cast)
      • Set Config_MeatHAngle = (Angle from Temp_Point to Temp_Point2)
      • Custom script: call RemoveLocation(udg_Temp_Point)
      • Custom script: call RemoveLocation(udg_Temp_Point2)
      • -------- ------------- --------
      • -------- If Config_MeatHHook is false then this variables means nothing (you can't grapple something if your hook don't accepts a target) --------
      • Set Config_MeatHGrapple = False
      • -------- if the target die in a hook, can the same hook hook a new target? --------
      • Set Config_MeatHRecicle = True
      • Set Config_MeatHDestroyTrees = True
      • -------- Distance from meat hook's head to caster upon cast --------
      • Set Config_MeatHStartOffset = 32.00
      • -------- Distance between the caster and the chain's tale --------
      • Set Config_MeatHOffset = 32.00
      • -------- sets the unit type for the head and chain --------
      • Set Config_MeatHHeadModel = Abilities\Weapons\FarseerMissile\FarseerMissile.mdl
      • Set Config_MeatHChainModel = Abilities\Weapons\SludgeMissile\SludgeMissile.mdl
      • Set Config_MeatHHeadScale = 250.00
      • Set Config_MeatHChainScale = 100.00
      • Set Config_MeatHLockOn = No unit
      • Set Config_MeatHIgnore = False
      • Set Config_MeatHDistance = 2500.00
      • Set Config_MeatHlvlDistnace = 250.00
      • Set Config_MeatHSpeed = 45.00
      • Set Config_MeatHlvlSpeed = 0.00
      • Set Config_MeatHDamage = 0.00
      • Set Config_MeatHlvlDamage = 0.00
      • -------- target dps --------
      • Set Config_MeatHDamageLoop = 0.00
      • Set Config_MeatHlvlDamageLoop = 0.00
      • -------- ------------- --------
      • -------- AoE dps --------
      • -------- range --------
      • Set Config_MeatHDamageAoE = 300.00
      • Set Config_MeatHlvlDamageAoE = 0.00
      • -------- amount --------
      • Set Config_MeatHAoEDamage = 30.00
      • Set Config_MeatHlvlAoEDamage = 10.00
      • -------- ------------- --------
      • Set Config_MeatHDamageType = Hero
      • Set Config_MeatHAoE = 0.00
      • Set Config_MeatHlvlAoE = 0.00
      • -------- avoid a chain rate lower than MeatHSpeed (include MeatHlvlSpeed) | 0 = no chain --------
      • Set Config_MeatHChainRate = 80.00
      • Set Config_MeatHSFX = Objects\Spawnmodels\Critters\Albatross\CritterBloodAlbatross.mdl
      • Set Config_MeatHAoESFX = Abilities\Spells\Other\Incinerate\IncinerateBuff.mdl
      • Trigger - Run Meathook ini <gen> (ignoring conditions)
      • Game - Display to (All players) the text: (ID of last created spell is: + (String(MeatHRef)))
      • Set Kamehameha[(Custom value of (Triggering unit))] = MeatHRef
  • Kamehameha end
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Kamehameha
      • Kamehameha[(Custom value of (Triggering unit))] Not equal to 0
    • Actions
      • Set UDex = Kamehameha[(Custom value of (Triggering unit))]
      • Trigger - Run Meathook end <gen> (ignoring conditions)
      • Set Kamehameha[(Custom value of (Triggering unit))] = 0
  • on return
    • Events
      • Game - MeatHEvent becomes Equal to 5.00
    • Conditions
    • Actions
      • Game - Display to (All players) the text: ((Name of MeatHC[UDex]) + 's hook has reached it's maximum distance)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MeatHSpell[UDex] Equal to Kamehameha
        • Then - Actions
          • Trigger - Run Meathook end <gen> (ignoring conditions)
          • Set Kamehameha[(Custom value of MeatHC[UDex])] = 0
        • Else - Actions


Releases 16 electrical bolts in all directions, dealing 6/8/10/12 damage per second to nearby enemies.
AoE: 800
  • Tesla Coil
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Tesla Coil
    • Actions
      • Set Config_MeatHSpell = Tesla Coil
      • Set Config_MeatHlvl = (Level of Meat Hook for (Triggering unit))
      • -------- If Config_MeatHHook is false then this variables means nothing (you can't grapple something if your hook don't accepts a target) --------
      • Set Config_MeatHGrapple = False
      • -------- if the target die in a hook, can the same hook hook a new target? --------
      • Set Config_MeatHRecicle = True
      • Set Config_MeatHDestroyTrees = False
      • -------- Distance from meat hook's head to caster upon cast --------
      • Set Config_MeatHStartOffset = 150.00
      • -------- Distance between the caster and the chain's tale --------
      • Set Config_MeatHOffset = 150.00
      • -------- sets the unit type for the head and chain --------
      • Set Config_MeatHHeadScale = 150.00
      • Set Config_MeatHChainScale = 200.00
      • Set Config_MeatHLockOn = No unit
      • Set Config_MeatHIgnore = False
      • Set Config_MeatHHeadModel = Abilities\Weapons\FarseerMissile\FarseerMissile.mdl
      • Set Config_MeatHHeadModel = Abilities\Weapons\FarseerMissile\FarseerMissile.mdl
      • Set Config_MeatHDistance = 800.00
      • Set Config_MeatHlvlDistnace = 0.00
      • Set Config_MeatHSpeed = 20.00
      • Set Config_MeatHlvlSpeed = 0.00
      • Set Config_MeatHDamage = 100.00
      • Set Config_MeatHlvlDamage = 50.00
      • -------- target dps --------
      • Set Config_MeatHDamageLoop = 50.00
      • Set Config_MeatHlvlDamageLoop = 25.00
      • -------- ------------- --------
      • -------- AoE dps --------
      • -------- range --------
      • Set Config_MeatHDamageAoE = 150.00
      • Set Config_MeatHlvlDamageAoE = 0.00
      • -------- amount --------
      • Set Config_MeatHAoEDamage = 4.00
      • Set Config_MeatHlvlAoEDamage = 2.00
      • -------- ------------- --------
      • Set Config_MeatHDamageType = Hero
      • Set Config_MeatHAoE = 0.00
      • Set Config_MeatHlvlAoE = 0.00
      • -------- avoid a chain rate lower than MeatHSpeed (include MeatHlvlSpeed) | 0 = no chain --------
      • Set Config_MeatHChainRate = 0.00
      • Set Config_MeatHSFX = Objects\Spawnmodels\Critters\Albatross\CritterBloodAlbatross.mdl
      • Set Config_MeatHAoESFX = Abilities\Spells\Items\AIlb\AIlbSpecialArt.mdl
      • -------- set the angle --------
      • Set Config_MeatHAngle = (Facing of (Triggering unit))
      • -------- ------------- --------
      • For each (Integer Temp_Int) from 1 to 16, do (Actions)
        • Loop - Actions
          • Set Config_MeatHAngle = (Config_MeatHAngle + 22.50)
          • Trigger - Run Meathook ini <gen> (ignoring conditions)





requires Bribe's (or similar) unit indexer



fixed bug where damage per level is not applied correctly
added feature to hook only the targeted unit and ignores other targets


pauses chain dummies
removed unnecessary GroupClear() function
removed unnecessary variable and it's code
adding chains using CreateUnit() native
hook no longer follows a dead "locked on" unit
"on return" event now also fires when hook reaches map bounds (Kamehameha bug fix)


made chain offset configurable
removed some unnecessary code
added a spell property
improved the way chains are added and removed
a spell instance can now be removed on command
slightly improved performance
improved documentation
added +3 spell examples


fixed the way targets are chosen
removed an unnecessary variable and it's code
made slight improvement on how the chain return


removed 2 leaks


Fixed as suggested by BPower

BPower;2792751 said:
You move the chain members then you check for map boundaries.
That's not logical.

There is real onHook somewhere in the code. I guess it's from an older version.

The event real is never reset to 0.00 Therefore two equal events can't fire in a row.
This means that the event can't be fired for two different launching hooks.



removed 4 region leaks (thanks BPower)
removed havester's location leak
made spell level configuratable


greatly improved the method to create a new spell instance
tweaked conditions to improve performance
removed 2 unnecessary variables from the spell
spell is de-indexed more reliably
changed map boundary variables


increased performance by over 50%
also increased multicast performance
made damage-type configurable
accidently fixed a bug where chain rate becomes uneven
adjust chain rate with number of chain instances to further increase performance
improved some test conditions
improved the way how chain instances are removed
removed a memory leak
chain can now destroy trees
improved comments


grapple no longer removes target collusion
removed unnecessary variables and a spell
made changes as suggested by IcemanBo and Daffa the Mage
added 2 events
added instructions on how to add a custom property to the spell.


renamed some variables
optimized custom scripts
fixed bug when unit in grapple dies


added grapple
removed unnecessary actions
edited the chain's look
slightly improved performance


changed AoE from 75 to 100
changed chain rate from 60 to 50
removed a memory leak
when a hooked unit is hooked again, it will be removed from the first hook
fixed a bug where curves slows the head down




MortAr;1488353 said:
More ... hook ... spells ... please ... we ... need ... more ... !

cookies4you;1488465 said:
There there there, lets get you back to the hospital bed. He's suffering from Bad-Spell-Hook-Unoriginal-Owned Overload, an overload of a single spell being created on one single site. He'll recover soon, or at least that's what the doctors say. My estimate is once a few of a single type of spells are removed or edited to become original. If you want to cure him, fix your hook spell and create something new instead of standard mechanics.

... Please... more... inventory... systems...

Tell the doctors I have everything under control... except for the inventory systems :)

Modify it however you want. Please remember credits!

Keywords:
meat, hook, strike, grab, rope, chain, pudge, butcher, dota, grapple
Contents

[Spell] Meat Hook v4.2 (Map)

Reviews
24th Mar 2016 Your resource has been reviewed by BPower. In case of any questions or for reconfirming the moderator's rating, please make use of the Quick Reply function of this thread. Review: Ever since DotA was released Meathook is one...

Moderator

M

Moderator

24th Mar 2016

General Info

Your resource has been reviewed by BPower.
In case of any questions or for reconfirming the moderator's rating,
please make use of the Quick Reply function of this thread.
Review:

Ever since DotA was released Meathook is one of the most popular custom spells in Warcraft III.
As a consequence of its popularity, the spell has been coded multiple times on different modding homepages.
I approve it based on the time you invested to re-create the concept. Good job!
I tend to give you a rating of 3/5.
  • For concept(5) and uniqueness(1) ~3.
  • For API ~4
  • For coding ~3
  • For performance ~2
    Reason: Storing the all dummies per timeout into an array via ForGoup trigger execution requires a lot of extra computation.

Troubleshooting:

    • Custom script: if IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) == false then
    ^Rather use native IsPlayerEnemy.
  • Pausing dummies units improves performance.
  • Using ClearGroup is not required in your code.
  • There is a minimal chance for a group handle leak, but even if it occurs it will only happen once per game season.
 
Don' t hardcode. Create a config trigger where user can config the spell to his needs.
Add descriptive comments for the user. This is especially needed in config part.

I don't understand why you sometimes use custom scripts, if the GUI would do it, too. It's anyway a GUI spell.
But anyway, if you use custom script then use the most efficient method. For example avoid BJs or also what Maker mentioned above.

Don't name something like only "CValue" or "Temp_Real". It's okay for your test map,
but consider the user also uses his own variables which might come in conflict with yours.
So just make a standard and make for all your names for example "MHG_variableName".
 
Greetings hivers, I fixed the SetUnitX\Y problem. I will now try to eliminate the creation, accession and destruction of locations by storing and doing all calculations in X[] Y[] real variables and only send the results to SetUnitX\Y. I believe that this can boost performance to match the JASS version :D. This will now also fix the irritating behaviour in the map boundaries because SetUnitX\Y ignores them.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
http://www.hiveworkshop.com/forums/...?prev=search=meat%20hook&d=list&r=20&status=a

http://www.hiveworkshop.com/forums/...?prev=search=meat%20hook&d=list&r=20&status=a

http://www.hiveworkshop.com/forums/...?prev=search=meat%20hook&d=list&r=20&status=a

http://www.hiveworkshop.com/forums/...?prev=search=meat%20hook&d=list&r=20&status=a

Those are just some of the approved hooks. As a project to get this resource approved, please take some time to compare yours against the ones which have already been made so as to argue whether or not this one should get approved, too. Events are not enough.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I agree with Bribe. Did you compare your code to already existing Meat Hook spells?

short review:

1. Don't do this:
  • Custom script: call DestroyGroup(GetLastCreatedGroup())
Instead store the group into a global group variable and use that one.
There can be very special cases, where GetLastCreatedGroup() does not store the
group you wish to destroy.

Anyway, which group handle are you destroying here?

2. Instead of two GameEvent variables ( reals ) you could use just one.
HookEvent == 1, HookEvent == 2, HookEvent = 2.5, ....

3. udg_MeatHCLoc leaks location handles periodically per hook head.
 
Thanks BPower, I'll change them right away.

@Bribe:
I know that there are many hook spells that are quite good. Some are simple like in dota and other more advanced like in Pudge Wars. My favourite Meat hook is the one by BPower (also happens to be one of the mods in this spell) but the only thing that offends me is the amount of resources and experience you need to be able to use his spell. I aim to create an efficient GUI and simple version of his spell that the general user can understand. I am also open for ideas to add more features to this spell... anything to get it approved :)
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Current review:

boundaryX/Y should be replaced by minX, minY, maxX, maxY.
To get the correct boundary values GUI overs a function Min X Of Region, etc.

In Trigger - initialization you are leaking a location handle.

You do not reset you meat hook event variable real to 0 after the trigger fired.
That's why the trigger can't fire again.

In the grabble part exists a game message. Why so?
 
Last edited:
Level 2
Joined
Dec 29, 2015
Messages
8
Hello. how do i set this spell affect only heroes, since i want to make AI hook me trough non-hero units.
 
There is no configuration trigger added, where users can make level based settings.

What do you mean? These variables takes spell level into account...
  • Set Config_MeatHlvlDistnace = 250.00
  • Set Config_MeatHlvlDamage = 50.00
  • Set Config_MeatHlvlAoE = 0.00
  • ect...
However I've found that I sat spell level to meathook level in the Launch_MH function so when one would use a different spell ID, meathook level would have been 0. I fixed that in the new update ^^
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
You move the chain members then you check for map boundaries.
That's not logical.

There is real onHook somewhere in the code. I guess it's from an older version.

The event real is never reset to 0.00 Therefore two equal events can't fire in a row.
This means that the event can't be fired for two different launching hooks.
 
Level 5
Joined
Mar 6, 2015
Messages
130
I`v Tested your map Well Done but i found some leaks by Using Handle Counter
after 3 hooks the Handle Counter Showed me Approximately 1000 Leaks and thats not good
Use this Method to find them
  • Leak Finder
    • Events
      • Time - Every 0.09 seconds of game time
    • Conditions
    • Actions
      • Set Debug = (Point(0.00, 0.00))
      • Custom script: call BJDebugMsg(I2S(GetHandleId(udg_Debug)-0x100000))
      • Custom script: call RemoveLocation(udg_Debug)
 
Thank you for the leak finding trigger. I played around with it and founded the main cause:

  • Set Temp_Group = (Units within MeatHAoE[MeatHRef] of MeatHCurPoint matching ((Matching unit) Not equal to MeatHC[MeatHRef]))
  • Custom script: call DestroyGroup(udg_Temp_Group)
AND

  • Destructible - Pick every destructible within MeatHAoE[MeatHRef] of MeatHCurPoint and do (Actions)
    • Loop - Actions
      • Unit - Order harvester to Harvest (Picked destructible)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Current order of harvester) Equal to (Order(harvest))
        • Then - Actions
          • Unit - Order harvester to Stop
          • Destructible - Kill (Picked destructible)
        • Else - Actions


By disabling them, leaks are greatly reduced. However I have no idea how to fix it... o_O
 
Level 5
Joined
Mar 6, 2015
Messages
130
Thank you for the leak finding trigger. I played around with it and founded the main cause:

  • Set Temp_Group = (Units within MeatHAoE[MeatHRef] of MeatHCurPoint matching ((Matching unit) Not equal to MeatHC[MeatHRef]))
  • Custom script: call DestroyGroup(udg_Temp_Group)

AND

  • Destructible - Pick every destructible within MeatHAoE[MeatHRef] of MeatHCurPoint and do (Actions)
    • Loop - Actions
      • Unit - Order harvester to Harvest (Picked destructible)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Current order of harvester) Equal to (Order(harvest))
        • Then - Actions
          • Unit - Order harvester to Stop
          • Destructible - Kill (Picked destructible)
        • Else - Actions


By disabling them, leaks are greatly reduced. However I have no idea how to fix it... o_O

I'm glad that helped you for the second one I have one solution for you the (destructible-pick range) action has leak inside BJ file use this method instead of (range) I used this method to trim my system create a region with the custom script below:

  • Custom script: set TempRec = GetRectFromCircleBJ(point,radius)
Then pick destructibles in region and don't forget to remove the region via
  • Custom script: call RemoveRect(TempRect)
For the first leak use this method inspired from my system
  • Custom script: call GroupEnumUnitsInRange(group, GetLocationX(point), GetLocationY(point), radius, null)
Sry if its not clear enough I don't have worldedit right now
 
Last edited:
Thank you Skyflash, the destructables doesn't leak anymore ^^

About the unit group... Should I replace
  • Set Temp_Group = (Units within MeatHAoE[MeatHRef] of MeatHCurPoint matching ((Matching unit) Not equal to MeatHC[MeatHRef]))
with
  • Custom script: call GroupEnumUnitsInRange(udg_Temp_Group, GetLocationX(udg_MeatHCurPoint), GetLocationY(udg_MeatHCurPoint), udg_MeatHAoE[udg_MeatHRef], null)
?

This doesn't work because the group is always emty.
 
Level 5
Joined
Mar 6, 2015
Messages
130
Thank you Skyflash, the destructables doesn't leak anymore ^^

About the unit group... Should I replace
  • Set Temp_Group = (Units within MeatHAoE[MeatHRef] of MeatHCurPoint matching ((Matching unit) Not equal to MeatHC[MeatHRef]))
with
  • Custom script: call GroupEnumUnitsInRange(udg_Temp_Group, GetLocationX(udg_MeatHCurPoint), GetLocationY(udg_MeatHCurPoint), udg_MeatHAoE[udg_MeatHRef], null)
?

This doesn't work because the group is always emty.
Oh my bad I forgot to mention that you must create group first , use this custom script:
  • Custom script: set udg_group = CreateGroup()
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
The meat hook ability should be stored into an "Ability" variable.
While importing the spell triggers the raw code of the meat hook ability will most likely change.
User should only have to change the value of the variable in the configuration trigger
instead of going into the spell source code.

In GUI it's convenient to provide an array setup via configuration trigger for example Hook_Config_Damage[level] = value
That ensures that the user doesn't have to touch the on cast event trigger at all.

I saw that you make use of ExecuteFunc in your code. I assume you found it in GUI UnitIndexer code and wanted to try it out.
ExecuteFunc is a very powerful native, but comes along with a few downsides for instance it is very slow.
There should be a specific reason, why the usage of ExecuteFunc is required.
That would be for example to avoid running into an OP limit case, wait or like in UnitIndexer to squeeze the code into one trigger.
Otherwise ExecuteFunc should be avoided in public resources.
In your case ExecuteFunc is not required and should be removed.
If I would be you, I would move the code which executes after ExecuteFunc in the on cast trigger.

  • -------- > custom properties here < --------
^I don't have to mention that a normal user will not find that line.
As I said, I would strongly recommend an array based configuration via config trigger.

  • Custom script: if IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) == false then
^You don't need a "== false comparison", better go with
  • Custom script: if IsPlayerEnemy(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) then
Sometimes you use custom script for conditions ( see above ), sometimes if then else provided by the GUI.
That's not consistent and makes your code less read-able.

The option to set grapple == true is quite cool. Good job considering that option.

  • Custom script: call DestroyGroup(udg_Temp_Group)
^I don't see the purpose of that line.

After deallocating a meat hook index, you still run a widget ( unit, destructable ) detection.
The hook itself however doesn't exist no more.

  • Custom script: call RemoveLocation(udg_MeatHCLoc)
^You have this line after evaluating if the spell has ended. It's not required, as you do the same again a few lines below.
 
Last edited:
Level 12
Joined
Jan 2, 2016
Messages
973
  • Custom script: if IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) == false then
^You don't need a "== false comparison", better go with
  • Custom script: if IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) then

To avoid confusion, this should be
  • Custom script: if not IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) then
or
  • Custom script: if IsPlayerEnemy(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) then
 
The meat hook ability should be stored into an "Ability" variable.
While importing the spell triggers the raw code of the meat hook ability will most likely change.
User should only have to change the value of the variable in the configuration trigger
instead of going into the spell source code.
I'm not sure how to implement that. What if the end user has a meat hook and grapple ability? Shouldn't there be an ability variable for every spell that use this system?

In GUI it's convenient to provide an array setup via configuration trigger for example Hook_Config_Damage[level] = value
That ensures that the user doesn't have to touch the on cast event trigger at all.
The user can change the level factors in the cast trigger by changing the Config_MeatHlvl.... variables. The cast trigger is really a template or example on setting up a hook spell and it is encouraged for the user to fine tune the spell in that trigger. I will add more "cast" triggers as examples in the next update. Also my method supports infinite (2147483648) levels but in the array method you have to define each level explicitly.

I saw that you make use of ExecuteFunc in your code. I assume you found it in GUI UnitIndexer code and wanted to try it out.
ExecuteFunc is a very powerful native, but comes along with a few downsides for instance it is very slow.
There should be a specific reason, why the usage of ExecuteFunc is required.
That would be for example to avoid running into an OP limit case, wait or like in UnitIndexer to squeeze the code into one trigger.
Otherwise ExecuteFunc should be avoided in public resources.
In your case ExecuteFunc is not required and should be removed.
If I would be you, I would move the code which executes after ExecuteFunc in the on cast trigger.
Actually I saw that in the persistant beam system and I thought it would be cool to have the setup and looping code in one trigger. If that is discouraged then I'll split the code :thumbs_up:

  • -------- > custom properties here < --------
^I don't have to mention that a normal user will not find that line.
As I said, I would strongly recommend an array based configuration via config trigger.
I clearly explained where to find that in the instructions. I see the misunderstanding with the configuration trigger now. "Meathook cast" is actually the configuration trigger. I will work on the documentation to make that more clear.

  • Custom script: if IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) == false then
^You don't need a "== false comparison", better go with
  • Custom script: if IsPlayerAlly(GetOwningPlayer(udg_MeatHT[udg_MeatHRef]), GetOwningPlayer(udg_MeatHC[udg_MeatHRef])) then
I didn't know you can do that. Thanks for pointing that out :thumbs_up: however I'll need to change that to GUI and and I don't think that shortcut will work there...

Custom script: call DestroyGroup(udg_Temp_Group)
^I don't see the purpose of that line.
After fixing the leak that variable is no longer needed. I'll remove that. :thumbs_up:

After deallocating a meat hook index, you still run a widget ( unit, destructable ) detection.
The hook itself however doesn't exist no more.
I'll look into it, thanks.

  • Custom script: call RemoveLocation(udg_MeatHCLoc)
^You have this line after evaluating if the spell has ended. It's not required, as you do the same again a few lines below.
As far as I understand, when the spell ends, the trigger is turned off. That means that the function a few lines below won't be called, causing a memory leak. Please correct me if I am wrong.

Thank you BPower for the review. :pir:

@WareElf: I understood BPower but thanks for helping ^^

P.S There will be more features in the next update. I think it would be better to call this a chain system or something because many of the upcomming features don't even require the target to be hooked...
 
Level 1
Joined
May 28, 2016
Messages
3
I can't set the level damage. I mean, even when I'm testing your map, if I change the variable "Config_MeatHlvlDamage" like to 200 instead of 50, it doesn't apply my changes.

Am I doing it wrong ? Or is this variable bugged ? I don't know :)
 
Level 1
Joined
May 28, 2016
Messages
3
Hi, it's me again :p

I think I have found the solution.

When I was casting Meat Hook, damage per level were not actualised. So I checked your code, and think you forgot to set the variable "MeatHlvl_Damage" in the spell Meathook" and then "MeatHlvl_Damageloop" too.

Perhaps I'm wrong, I'm not that good, but now it works for me.

What do you think ?
 
Level 38
Joined
Feb 27, 2007
Messages
4,951
Where is "distance function" ? i can't find it
I have the same probleme like FirstLegacy.
In the map's Custom Script section you will find these functions:
JASS:
function distance takes real x1, real x2, real y1, real y2 returns real
    return SquareRoot((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
endfunction

//determine wheather a point is inside the configured map bounds
function IsOutsideMap takes real x, real y returns boolean
    return x < udg_minX or y < udg_minY or x > udg_maxX or y > udg_maxY
endfunction

//If MeatHLockOn != null and MeatHIgnore == true, this function is called to filter the locked unit
function FilterLockedUnit takes nothing returns boolean
    return ( GetFilterUnit() == udg_MeatHLockOn[udg_MeatHRef] )
endfunction
You can either put them in the same place in your map or you can put it all inside a library in any normal JASS trigger:
JASS:
library MeatHookUtils
function distance takes real x1, real x2, real y1, real y2 returns real
    return SquareRoot((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
endfunction

//determine wheather a point is inside the configured map bounds
function IsOutsideMap takes real x, real y returns boolean
    return x < udg_minX or y < udg_minY or x > udg_maxX or y > udg_maxY
endfunction

//If MeatHLockOn != null and MeatHIgnore == true, this function is called to filter the locked unit
function FilterLockedUnit takes nothing returns boolean
    return ( GetFilterUnit() == udg_MeatHLockOn[udg_MeatHRef] )
endfunction
endlibrary
 
Level 3
Joined
Jul 27, 2016
Messages
33
I have imported the functions into the map's Custom Script section. However I still have an error:

Line 3043: Invalid argument type - invalid argument type 'unknown type' in call on line 3043(unknown type)
call GroupEnumUnitsInRange(udg_Temp_Targets, udg_MeatHChainX[udg_MeatHRef], udg_MeatHChainY[udg_MeatHRef], udg_MeatHAoE[udg_MeatHRef], function FilterLockedUnit)


This line, but the function FilterLockedUnit is on the map's Custom Script, so why that don't work ?

The bug also appears on the test map, when we add a hero to the map.
 
Last edited:
Top