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

Dota 2 Meat Hook Ability v1.1.2


228981-albums7784-picture93604.jpg


Description


Pudge throws his hook towards a target point and drags back the first unit it touches. Deals damage to enemy units.

Level 1 - 90 damage / 800 distance
Level 2 - 120 damage / 900 distance
Level 3 - 240 damage / 1000 distance
Level 4 - 360 damage / 1100 distance

The chain breaks if Pudge is dead or goes too far from the hook.

Ingame Screenshots


228981-albums7784-picture93598.jpg

228981-albums7784-picture93599.jpg

228981-albums7784-picture93600.jpg

228981-albums7784-picture93601.jpg

228981-albums7784-picture93602.jpg

228981-albums7784-picture93603.jpg



Triggers



[trigger="MH Setup"]
MH Setup
Events
Map initialization
Conditions
Actions
-------- [Configuration] --------
Set HookAbility = Meat Hook
Set HookDummy = MH_DummyUnit
Set HookTravelDuration = 5.00
Set HookTravelSpeed = 1600.00
-------- Reads value of HookTravelSpeed instead of HookTravelDuration --------
Set HookUseSpeed = True
-------- Just set another HookDamage[Level] for multiple levels. --------
Set HookAttackType = Spells
Set HookDamageType = Universal
Set HookDamage[1] = 90.00
Set HookDamage[2] = 180.00
Set HookDamage[3] = 270.00
Set HookDamage[4] = 360.00
-------- Just set another HookTravelDistance[Level] for multiple levels. --------
Set HookTravelDistance[1] = 1000.00
Set HookTravelDistance[2] = 1100.00
Set HookTravelDistance[3] = 1200.00
Set HookTravelDistance[4] = 1300.00
-------- [ Others ] --------
Set HookAllowAllyMagicImmune = True
Set HookAllowEnemyMagicImmune = False
Set HookChainBreakDistance = 150.00
Set HookDisableWhileInUse = False
Set HookGrabRadius = 100.00
-------- [ Special Effects ] --------
-------- For Newbie GUI users, set HookUseLightningEx to False --------
-------- For experienced GUI/JASS users who wants a custom lightning effect, set HookUseLightningEx to True --------
-------- Once HookUseLightningEx is set to False, the code reads value of HookLightningEffect. (Standard) --------
-------- Once HookUseLightningEx is set to True, the code reads value of HookLightningEffectEx. (Custom) --------
Set HookUseLightningEx = False
Set HookLightningEffect = Drain Mana
Set HookLightningEffectEx = CHAI
Set HookSoundEffect = HuntressMissileLaunch <gen>
Set HookSpecialEffect = Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
-------- [End Configuration] --------
Set MH_Index1 = 0
Set MH_Index2 = 0
Set MH_OffsetConstant = 80.00
Custom script: if ( udg_HookUseLightningEx == true ) then
Custom script: set udg_HookLightningEffect = udg_HookLightningEffectEx
Custom script: endif

[/trigger]
[trigger="MH Cast"]
MH Cast
Events
Unit - A unit Starts the effect of an ability
Conditions
(Ability being cast) Equal to HookAbility
Actions
Set MH_Index1 = (MH_Index1 + 1)
Set MH_ApplyDamage[MH_Index1] = False
Set MH_Hooker[MH_Index1] = (Triggering unit)
Set MH_DistCounter[MH_Index1] = 0.00
Set MH_Level[MH_Index1] = (Level of HookAbility for MH_Hooker[MH_Index1])
Set MH_StartPoint = (Position of MH_Hooker[MH_Index1])
Set MH_Distance[MH_Index1] = (HookTravelDistance[MH_Level[MH_Index1]] + MH_OffsetConstant)
Set MH_HookOn[MH_Index1] = False
Set MH_EndPoint = (Target point of ability being cast)
Set MH_Angle[MH_Index1] = (Angle from MH_StartPoint to MH_EndPoint)
Set TempPoint = (MH_StartPoint offset by MH_OffsetConstant towards MH_Angle[MH_Index1] degrees)
Unit - Create 1 HookDummy for (Triggering player) at TempPoint facing MH_Angle[MH_Index1] degrees
Set MH_Hook[MH_Index1] = (Last created unit)
Set MH_HookerPos[MH_Index1] = (Position of MH_Hooker[MH_Index1])
Set MH_HookPos[MH_Index1] = (Position of MH_Hook[MH_Index1])
Lightning - Create a HookLightningEffect lightning effect from source MH_HookerPos[MH_Index1] to target MH_HookPos[MH_Index1]
Lightning - Change color of (Last created lightning effect) to (1.00 1.00 1.00) with 1.00 alpha
Set MH_HookChain[MH_Index1] = (Last created lightning effect)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
HookUseSpeed Equal to True
Then - Actions
Set MH_Dest = (HookTravelSpeed x 0.02)
Else - Actions
Set MH_Dest = ((MH_Distance[MH_Index1] / HookTravelDuration) / 10.00)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
HookDisableWhileInUse Equal to True
Then - Actions
Unit - Remove HookAbility from MH_Hooker[MH_Index1]
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
MH_Index1 Equal to 1
Then - Actions
Trigger - Turn on MH Loop <gen>
Else - Actions
Custom script: call RemoveLocation(udg_TempPoint)
Custom script: call RemoveLocation(udg_MH_StartPoint)
Custom script: call RemoveLocation(udg_MH_EndPoint)

[/trigger]
[trigger="MH Loop"]
MH Loop
Events
Time - Every 0.03 seconds of game time
Conditions
Actions
For each (Integer MH_Index2) from 1 to MH_Index1, do (Actions)
Loop - Actions
Set MH_HookerPos[MH_Index2] = (Position of MH_Hooker[MH_Index2])
Set MH_HookPos[MH_Index2] = (Position of MH_Hook[MH_Index2])
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
MH_DistCounter[MH_Index2] Less than MH_Distance[MH_Index2]
(MH_Hooker[MH_Index2] is alive) Equal to True
Then - Actions
Set MH_DistCounter[MH_Index2] = (MH_DistCounter[MH_Index2] + MH_Dest)
Set MH_DestPoint = (MH_HookPos[MH_Index2] offset by MH_Dest towards MH_Angle[MH_Index2] degrees)
Unit - Move MH_Hook[MH_Index2] instantly to MH_DestPoint
Sound - Play HookSoundEffect at 100.00% volume, attached to MH_Hooker[MH_Index2]
Lightning - Move MH_HookChain[MH_Index2] to source MH_HookerPos[MH_Index2] and target MH_HookPos[MH_Index2]
Set MH_Detector = (Units within HookGrabRadius of MH_HookPos[MH_Index2])
Unit Group - Pick every unit in MH_Detector and do (Actions)
Loop - Actions
Set TempUnit = (Picked unit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(TempUnit is A structure) Not equal to True
(TempUnit is alive) Equal to True
TempUnit Not equal to MH_Hooker[MH_Index2]
TempUnit Not equal to MH_HookedUnit[MH_Index2]
(Unit-type of TempUnit) Not equal to HookDummy
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(TempUnit is Magic Immune) Equal to True
Then - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(TempUnit belongs to an ally of (Owner of MH_Hooker[MH_Index2])) Equal to True
HookAllowAllyMagicImmune Equal to True
Then - Actions
Set MH_HookedUnit[MH_Index2] = TempUnit
Set MH_HookOn[MH_Index2] = True
Set MH_DistCounter[MH_Index2] = MH_Distance[MH_Index2]
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(TempUnit belongs to an enemy of (Owner of MH_Hooker[MH_Index2])) Equal to True
HookAllowEnemyMagicImmune Equal to True
Then - Actions
Set MH_HookedUnit[MH_Index2] = TempUnit
Set MH_HookOn[MH_Index2] = True
Set MH_DistCounter[MH_Index2] = MH_Distance[MH_Index2]
Else - Actions
Else - Actions
Set MH_HookedUnit[MH_Index2] = TempUnit
Set MH_HookOn[MH_Index2] = True
Set MH_DistCounter[MH_Index2] = MH_Distance[MH_Index2]
Unit - Turn collision for MH_HookedUnit[MH_Index2] Off
Else - Actions
Custom script: call RemoveLocation(udg_MH_DestPoint)
Custom script: call DestroyGroup(udg_MH_Detector)
Else - Actions
Set MH_Angle[MH_Index2] = ((Angle from MH_HookerPos[MH_Index2] to MH_HookPos[MH_Index2]) + 180.00)
Set MH_DestPoint = (MH_HookPos[MH_Index2] offset by MH_Dest towards MH_Angle[MH_Index2] degrees)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
MH_HookOn[MH_Index2] Equal to True
Then - Actions
Unit - Move MH_HookedUnit[MH_Index2] instantly to MH_DestPoint
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(MH_Hooker[MH_Index2] is alive) Equal to True
MH_ApplyDamage[MH_Index2] Equal to False
(MH_HookedUnit[MH_Index2] belongs to an enemy of (Owner of MH_Hooker[MH_Index2])) Equal to True
Then - Actions
Set MH_ApplyDamage[MH_Index2] = True
Unit - Cause MH_Hooker[MH_Index2] to damage MH_HookedUnit[MH_Index2], dealing HookDamage[MH_Level[MH_Index2]] damage of attack type HookAttackType and damage type HookDamageType
Else - Actions
Else - Actions
Unit - Move MH_Hook[MH_Index2] instantly to MH_DestPoint
Unit - Make MH_Hook[MH_Index2] face (MH_Angle[MH_Index2] + 180.00) over 0.00 seconds
Sound - Play HookSoundEffect at 100.00% volume, attached to MH_Hooker[MH_Index2]
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
MH_HookedUnit[MH_Index2] Not equal to No unit
(MH_HookedUnit[MH_Index2] belongs to an ally of (Owner of MH_Hooker[MH_Index2])) Equal to False
Then - Actions
Special Effect - Create a special effect at MH_DestPoint using HookSpecialEffect
Special Effect - Destroy (Last created special effect)
Else - Actions
Lightning - Move MH_HookChain[MH_Index2] to source MH_HookerPos[MH_Index2] and target MH_DestPoint
Custom script: call RemoveLocation(udg_MH_DestPoint)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Or - Any (Conditions) are true
Conditions
(Distance between MH_HookerPos[MH_Index2] and MH_HookPos[MH_Index2]) Less than (MH_OffsetConstant - 25.00)
(Distance between MH_HookerPos[MH_Index2] and MH_HookPos[MH_Index2]) Greater than (MH_Distance[MH_Index2] + HookChainBreakDistance)
(MH_Hooker[MH_Index2] is dead) Equal to True
Then - Actions
Lightning - Destroy MH_HookChain[MH_Index2]
Unit - Remove MH_Hook[MH_Index2] from the game
Unit - Turn collision for MH_HookedUnit[MH_Index2] On
Set MH_ApplyDamage[MH_Index2] = False
Set MH_HookOn[MH_Index2] = False
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
HookDisableWhileInUse Equal to True
Then - Actions
Unit - Add HookAbility to MH_Hooker[MH_Index2]
Unit - Set level of HookAbility for MH_Hooker[MH_Index2] to MH_Level[MH_Index2]
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(MH_HookedUnit[MH_Index2] belongs to an enemy of (Owner of MH_HookedUnit[MH_Index2])) Equal to True
Then - Actions
Unit - Order MH_Hooker[MH_Index2] to Attack MH_HookedUnit[MH_Index2]
Else - Actions
Set MH_Angle[MH_Index2] = MH_Angle[MH_Index1]
Set MH_ApplyDamage[MH_Index2] = MH_ApplyDamage[MH_Index1]
Set MH_DistCounter[MH_Index2] = MH_DistCounter[MH_Index1]
Set MH_Distance[MH_Index2] = MH_Distance[MH_Index1]
Set MH_Level[MH_Index2] = MH_Level[MH_Index1]
Set MH_Hook[MH_Index2] = MH_Hook[MH_Index1]
Set MH_HookChain[MH_Index2] = MH_HookChain[MH_Index1]
Set MH_Hooker[MH_Index2] = MH_Hooker[MH_Index1]
Set MH_HookedUnit[MH_Index2] = MH_HookedUnit[MH_Index1]
Set MH_HookOn[MH_Index2] = MH_HookOn[MH_Index1]
Set MH_Hooker[MH_Index1] = No unit
Set MH_HookedUnit[MH_Index1] = No unit
Set MH_Hook[MH_Index1] = No unit
Set MH_Index1 = (MH_Index1 - 1)
Set MH_Index2 = (MH_Index2 - 1)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
MH_Index1 Equal to 0
Then - Actions
Trigger - Turn off (This trigger)
Else - Actions
Else - Actions
Custom script: call RemoveLocation(udg_MH_HookerPos[udg_MH_Index2])
Custom script: call RemoveLocation(udg_MH_HookPos[udg_MH_Index2])

[/trigger]



How To Use


- Make sure to enable "Automatically create unknown variables while pasting trigger data" on the General tab of your World Editor Preferences.
- Copy the whole Hook folder and paste in onto your Trigger Editor.
- Copy the Meat Hook ability and the MH_DummyUnit unit from the Object Editor and paste it onto yours. (If you don't want to create yours.)
- Make sure to configure everything in the MH Setup Trigger.


Changelogs


* Version 1.0.1 - initial release
* Version 1.0.1 - Fixed several leaks. Added few configuration options. Few terrain changes. Added sound.
* Version 1.0.2 - Optimized code. Now supports multiple level variables for HookDamage and HookDistance. Added HookDummy variable.
* Version 1.0.3 - Fixed some leaks. Added new configuration options. Modified some variables.
* Version 1.0.4 - Optimized code. Prevented some future bugs.
* Version 1.0.5 - As required, optimized variable names and made few changes on the triggers.
* Version 1.0.6 - Got rid of unused variables as well as reworked the test unit from a standard unit to hero. Modified ability from a unit to a hero ability type. Added Bot to play along. Also added additional variables for easy configuration.
* Version 1.0.7 - Relocated Hook Break code to hook return as mentioned and added MH_OffsetConstant for the hook creation and return detection offsets.
* Version 1.0.8 - Removed point leak and changed MH_StartPoint from an array variable to a regular one. Renamed MH_Point to MH_EndPoint and also de-arrayed.
* Version 1.0.9 - Reverted some variables in MH Loop regarding hook returning when magic immune enemy is detected and option of magic immunity check for enemy is false. Hook now successfully goes through magic immune enemies when the configuration is equal to false.
* Version 1.1.0 - Dearrayed some variables and removed MH_DestPoint from deindexing as mentioned. Also removed some variables. Fixed a bug regarding damage applied to a nearby enemy unit while MH_HookedUnit is not an enemy. Hook now breaks if caster is dead.
* Version 1.1.1 - Hook now detects Distance to Break on cast and not on the return of the hook. Added optional Lightning Effect parameter for advanced users. Imported optional skin for tests.
* Version 1.1.2 - As mentioned, added caster death check in Loop Trigger. Changed Hook Speed formula, speed is now the same as in-game projectile speeds. Corrected data and added a pause on cast. (as mentioned on the wiki)


Resources included:

[box]
Chain by stonneash (Optional - Recommended)
Link: http://www.hiveworkshop.com/forums/...d1355776281-manaburnbeam-blp-manaburnbeam.blp

Custom LightningData.slk (Optional - Recommended)

[/box]

"Don't forget! Credits for use."

Keywords:
hook,dota2,pudge,meat hook
Contents

Untitled (Map)

Reviews
13:40, 01st Feb 2015 Changed were made, and it works fine. Approved. 23:53, 27th Jan 2015 IcemanBo: Read my posts in thread. You don't change it in your updates. IcemanBo...

Moderator

M

Moderator

13:40, 01st Feb 2015
Changed were made, and it works fine. Approved.


23:53, 27th Jan 2015
IcemanBo: Read my posts in thread. You don't change it in your updates.

IcemanBo: http://www.hiveworkshop.com/forums/...ability-v2-0-a-258574/index3.html#post2643828

IcemanBo: http://www.hiveworkshop.com/forums/...ability-v1-9-a-258574/index3.html#post2642134
IcemanBo:
You leak onCast. (MH_Point[MH_Index1] is never removed)
The points don't need to be array variables. StartPoint included.. No need to index it.

IcemanBo: http://www.hiveworkshop.com/forums/...ability-v1-6-a-258574/index3.html#post2638544

IcemanBo: http://www.hiveworkshop.com/forums/spells-569/dota-2-meat-hook-ability-v1-6-a-258574/index3.html#post2638479

IcemanBo: http://www.hiveworkshop.com/forums/...ability-v1-5-a-258574/index3.html#post2638113

03:10, 7th Jan 2015
IcemanBo:
http://www.hiveworkshop.com/forums/...ability-v1-4-a-258574/index3.html#post2636900
 
Level 13
Joined
Jul 16, 2012
Messages
679
Please post the trigger to easy review :)

Code:
[trigger]CODE[/trigger]

--->

  • CODE
EDIT:
  • setup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set HookAbility = Meat Hook
      • Set HookTravelDistance = 800.00
      • Set HookDamage = 75.00
  • hook1
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to HookAbility
    • Actions
      • Set HookCallCount = (HookCallCount + 1)
      • Set Hooker[HookCallCount] = (Triggering unit)
      • Set TempPoint = (Position of (Triggering unit))
      • Set HookStartPoint[HookCallCount] = (Position of (Triggering unit))
      • Set HookDistance[HookCallCount] = HookTravelDistance
      • Set HookAngle[HookCallCount] = (Angle from (Position of (Triggering unit)) to (Target point of ability being cast))
      • Unit Group - Pick every unit in (Units in (Playable map area) matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is A structure) Not equal to True) and ((Matching unit) Not equal to (Triggering unit))))) and do (Actions)
        • Loop - Actions
          • Unit Group - Add (Picked unit) to AvailableTargets
      • Unit - Create 1 Chicken for (Triggering player) at TempPoint facing HookAngle[HookCallCount] degrees
      • Player - Disable Meat Hook for (Owner of Hooker[HookCallCount])
      • Set HookHead[HookCallCount] = (Last created unit)
      • Set ActiveHook[HookCallCount] = True
      • Custom script: call RemoveLocation(udg_TempPoint)
  • hook2
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer A) from 1 to HookCallCount, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ActiveHook[(Integer A)] Equal to True
            • Then - Actions
              • Set HookerPos[(Integer A)] = (Position of Hooker[(Integer A)])
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • And - All (Conditions) are true
                    • Conditions
                      • (Distance between HookStartPoint[(Integer A)] and (Position of HookHead[(Integer A)])) Less than HookDistance[(Integer A)]
                      • HookFlag[(Integer A)] Equal to False
                • Then - Actions
                  • Unit Group - Pick every unit in (Units within 75.00 of (Position of HookHead[(Integer A)]) matching ((((Matching unit) is A structure) Not equal to True) and ((((Matching unit) is alive) Equal to True) and ((Owner of (Matching unit)) Not equal to (Owner of HookHead[(Integer A)]))))) and do (Actions)
                    • Loop - Actions
                      • Set HookOn[(Integer A)] = True
                      • Set HookedUnit[(Integer A)] = (Picked unit)
                      • Set HookFlag[(Integer A)] = True
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) belongs to an enemy of (Owner of HookHead[(Integer A)])) Equal to True
                        • Then - Actions
                          • Unit - Cause Hooker[(Integer A)] to damage (Picked unit), dealing HookDamage damage of attack type Spells and damage type Divine
                        • Else - Actions
                  • Set DestPoint[(Integer A)] = ((Position of HookHead[(Integer A)]) offset by 45.00 towards HookAngle[(Integer A)] degrees)
                  • Unit - Move HookHead[(Integer A)] instantly to DestPoint[(Integer A)]
                  • Lightning - Destroy (Last created lightning effect)
                  • Lightning - Create a Magic Leash lightning effect from source HookerPos[(Integer A)] to target (Position of HookHead[(Integer A)])
                  • Custom script: call RemoveLocation(udg_DestPoint[GetForLoopIndexA()])
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • And - All (Conditions) are true
                        • Conditions
                          • (HookHead[(Integer A)] is in (Units within 90.00 of HookerPos[(Integer A)])) Equal to True
                          • HookFlag[(Integer A)] Equal to True
                    • Then - Actions
                      • Lightning - Destroy (Last created lightning effect)
                      • Unit - Remove HookHead[(Integer A)] from the game
                      • Player - Enable Meat Hook for (Owner of Hooker[(Integer A)])
                      • Set ActiveHook[(Integer A)] = False
                      • Set HookFlag[(Integer A)] = False
                      • Set HookOn[(Integer A)] = False
                    • Else - Actions
                      • Set HookFlag[(Integer A)] = True
                      • Set DestPoint[(Integer A)] = ((Position of HookHead[(Integer A)]) offset by 45.00 towards ((Angle from HookerPos[(Integer A)] to (Position of HookHead[(Integer A)])) + 180.00) degrees)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • HookOn[(Integer A)] Equal to True
                        • Then - Actions
                          • Unit - Move HookedUnit[(Integer A)] instantly to DestPoint[(Integer A)]
                        • Else - Actions
                      • Unit - Move HookHead[(Integer A)] instantly to DestPoint[(Integer A)]
                      • Unit - Make HookHead[(Integer A)] face (Angle from HookerPos[(Integer A)] to (Position of HookHead[(Integer A)])) over 0.00 seconds
                      • Lightning - Destroy (Last created lightning effect)
                      • Lightning - Create a Magic Leash lightning effect from source HookerPos[(Integer A)] to target (Position of HookHead[(Integer A)])
                      • Custom script: call RemoveLocation(udg_DestPoint[GetForLoopIndexA()])
              • Custom script: call RemoveLocation(udg_HookerPos[GetForLoopIndexA()])
            • Else - Actions
============

  • Unit Group - Pick every unit in (Units in (Playable map area) matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is A structure) Not equal to True) and ((Matching unit) Not equal to (Triggering unit))))) and do (Actions)
    • Loop - Actions
      • Unit Group - Add (Picked unit) to AvailableTargets
You have Unit Group Leak

In Unit Group you must use ITE(IF THEN ELSE) instead using Unit Group for checking the condition.
Like this...
  • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
    • Loop - Actions
      • Set SaveYourPickedUnit = (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Put here your condition
        • Then - Actions
          • Unit Group - Add SaveYourPickedUnit to AvailableTargets
        • Else - Actions
You need to store the picked unit in variable

  • Set HookAngle[HookCallCount] = (Angle from (Position of (Triggering unit)) to (Target point of ability being cast))
You have point location leak here

  • For each (Integer A) from 1 to HookCallCount, do (Actions)
    • Loop - Actions
Dont use Integer A / B
use Integer Variable instead

  • Unit Group - Pick every unit in (Units within 75.00 of (Position of HookHead[(Integer A)]) matching ((((Matching unit) is A structure) Not equal to True) and ((((Matching unit) is alive) Equal to True) and ((Owner of (Matching unit)) Not equal to (Owner of HookHead[(Integer A)]))))) and do (Actions)
    • Loop - Actions
      • Set HookOn[(Integer A)] = True
      • Set HookedUnit[(Integer A)] = (Picked unit)
      • Set HookFlag[(Integer A)] = True
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Picked unit) belongs to an enemy of (Owner of HookHead[(Integer A)])) Equal to True
        • Then - Actions
          • Unit - Cause Hooker[(Integer A)] to damage (Picked unit), dealing HookDamage damage of attack type Spells and damage type Divine
        • Else - Actions
Unit Group leak
need ITE also


You must add Turn Off / Turn On function
in your Loop Trigger
 
Last edited:

Deleted member 219079

D

Deleted member 219079

Dont use Integer A / B
I'm curious, what's wrong with

JASS:
    set bj_forLoopAIndex = 1
    set bj_forLoopAIndexEnd = 10
    loop
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop

With own variable it'd transform to:
JASS:
    set udg_i = 1
    loop
        exitwhen udg_i > 10
        set udg_i = udg_i + 1
    endloop
If it's about assigning bj_forLoopAIndexEnd, this isn't a JASS forum. Integer assigment doesn't have visual impact afaik.



  • For each (Integer TempHookIndex) from 1 to HookCallCount, do (Actions)
    • Loop - Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
    • ActiveHook[TempHookIndex] Equal to True
This is a creative way of looping, but I recommend checking:
http://www.hiveworkshop.com/forums/...orials-279/visualize-dynamic-indexing-241896/
http://www.hiveworkshop.com/forums/spells-569/gui-dynamic-indexing-template-144325/



  • (HookHead[TempHookIndex] is in (Units within 90.00 of HookerPos[TempHookIndex])) Equal to True
) is an unit group, I recommend creating variable group g, and doing it like this:
  • Set g = Units within 90.00 of HookerPos[TempHookIndex]
  • ... (use the group) ...
  • Custom Script - call DestroyGroup(udg_g)
Otherwise you'll keep your memory employed for nothing.
Alt. way is to use:
  • Custom script: set bj_wantDestroyGroup = true
Before using temporary groups.



This is a good start and the spell is practical and balanced, but I hope you'll check the dynamic indexing links I gave you :)
Train hard and you might become the next god of WC3 modding ;P
 
Level 13
Joined
Jul 16, 2012
Messages
679
@Jondrean
I'm curious, what's wrong with

JASS:
    set bj_forLoopAIndex = 1
    set bj_forLoopAIndexEnd = 10
    loop
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop

With own variable it'd transform to:
JASS:
    set udg_i = 1
    loop
        exitwhen udg_i > 10
        set udg_i = udg_i + 1
    endloop
If it's about assigning bj_forLoopAIndexEnd, this isn't a JASS forum. Integer assigment doesn't have visual impact afaik.

cuz of bj
You need to avoid the bj

You can use Integer A / B
but its slower
 

Deleted member 219079

D

Deleted member 219079

cuz of bj
You need to avoid the bj
I dunno who the hell have taught you so...

Not all BJs are bad. In this case bj_forLoopAIndexEnd and bj_forLoopAIndex are only global variables. Even though when using own integer, end index will get inlined, there is no visual impact compared to the bj one.

Something like:
JASS:
function CameraSetSmoothingFactorBJ takes real factor returns nothing
    call CameraSetSmoothingFactor(factor)
endfunction
Is a shadow caller, which will cost you a function call.
But something like:
JASS:
function RMaxBJ takes real a, real b returns real
    if (a < b) then
        return b
    else
        return a
    endif
endfunction
Is very useful, and there is no need for recreating such a function.
 

Deleted member 219079

D

Deleted member 219079

I'm planning to index each caster and edd them in a unit group. Will that cause any leaks?
So you will use Unit Indexer?

Then I'm pretty sure that's called Paladon's indexing. It's just fine and pretty efficient too :)

I'd say go for it, it sounds good.

About leaks, it's up to you to succesfully get rid of any leaks. Post the code here to get feedback.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
I dunno who the hell have taught you so...

Not all BJs are bad. In this case bj_forLoopAIndexEnd and bj_forLoopAIndex are only global variables. Even though when using own integer, end index will get inlined, there is no visual impact compared to the bj one.

I told GywGod133 about the integer A/B.

They never get inlined. Take a look at this for example.

  • For each (Integer A) from 1 to 10, do (Actions)
    • Loop - Actions
      • Game - Display to (All players) the text: (String((Integer A)))
Gets changed to this.
JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    set bj_forLoopAIndex = 1
    set bj_forLoopAIndexEnd = 10
    loop
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
        call DisplayTextToForce( GetPlayersAll(), I2S(GetForLoopIndexA()) )
        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop
endfunction

You can see that Integer A/B use a function call whenever the looping integer is used. This causes slower performance and is just lazy coding when all it takes is one variable to create.

No, I'm not using any plugins. It's just the idea of it that's I'm going to implement. I'll update the description.

A Unit Indexer is not a plug in. It is a system on the hive. It is very useful in some cases. I don't see a reason that you need it in here though.

These still leak a location.
  • Distance between HookStartPoint[TempHookIndex] and (Position of HookHead[TempHookIndex])) Less than HookDistance[TempHookIndex]
  • Unit - Make HookHead[TempHookIndex] face (Angle from HookerPos[TempHookIndex] to (Position of HookHead[TempHookIndex])) over 0.00 seconds
These should be stored as it is used more than once.
  • Owner of Hooker[TempHookIndex])
  • ((HookDistance[TempHookIndex] / HookTravelDuration) / 10.00)
Remove this
  • And - All (Conditions) are true
After De-Indexing you should null all variables except integers / reals / strings. (I might be forgetting one.)
 

Deleted member 219079

D

Deleted member 219079

They never get inlined.
I didn't say they do? Re-read my post.

You can see that Integer A/B use a function call whenever the looping integer is used.
+rep FINALLY! A sensible answer for why A/B is bad;
cuz of bj
You need to avoid the bj
This tells me nothing.

After De-Indexing you should null all variables except integers / reals / strings. (I might be forgetting one.)
You don't need to null variables which extend handle, null everything which extends widget or agent: http://warcraft.ingame.de/maps/mappedia/Common.j
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
You don't need to null variables which extend handle, null everything which extends widget or agent: http://warcraft.ingame.de/maps/mappedia/Common.j

That is not true. You need to null everything except strings / integers / reals. And as said I may be missing one. Handles do leak when not nulled. There handles are never removed so they take up space when not being used.
 

Deleted member 219079

D

Deleted member 219079

Please prove me wrong. Sources are appreciated.
 

Deleted member 219079

D

Deleted member 219079

That is no source. But please if you have a way to prove me wrong then do so, currently I have following statement in my tutorial:

Certain non-nullied locals can cause performance impact. Abstract is something conceptual, for example an unit; we define unit by certain properties and unit is always a subject to change in-game.

Something not abstract is integer, we are certain 3 is 3.
To null local use set myLocal = null
For further learning about which variable types should be nullied, open up this page. Null everything which extends widget or agent; these have abstract properties so you need to null them.

And you're the first one to say that stands wrong. Just any post regarding such benchmarks is appreciated :)

Run some tests yourself and see.
Gimme a code to test and I shall test it.

Also I am saying what most mods here say about nulling.
I've never seen a mod say so.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
That is no source. But please if you have a way to prove me wrong then do so, currently I have following statement in my tutorial:



And you're the first one to say that stands wrong. Just any post regarding such benchmarks is appreciated :)


Gimme a code to test and I shall test it.


I've never seen a mod say so.

I don't code in WC3 much anymore. If you want benchmarks then make it yourself it is not hard.
Repeatedly create a new lightning then destroy it. Then show handle id to see. It is maybe 3 or 4 GUI actions so not hard to show that it is bad to not null.
The handle id does not get released unless they are nulled.
 

Deleted member 219079

D

Deleted member 219079

Repeatedly create a new lightning then destroy it.
No difference between this
JASS:
scope a initializer init {
    include "cj_types.j"
    integer i = 0
    player p = Player(0)
    void f () {
        i = i + 1
        lightning l = AddLightning("CLPB", false, 0, 0, 100, 100)
        DestroyLightning(l)
        DisplayTextToPlayer(p, 0, 0, I2S(i)+" "+I2S(GetHandleId(l)))
        l = null
    }
    void init () {
        PanCameraTo(0,0)
        FogEnable(false)
        FogMaskEnable(false)
        TimerStart(CreateTimer(), 0.001, true, function f)
    }
}
and this
JASS:
scope a initializer init {
    include "cj_types.j"
    integer i = 0
    player p = Player(0)
    void f () {
        i = i + 1
        lightning l = AddLightning("CLPB", false, 0, 0, 100, 100)
        DestroyLightning(l)
        DisplayTextToPlayer(p, 0, 0, I2S(i)+" "+I2S(GetHandleId(l)))
    }
    void init () {
        PanCameraTo(0,0)
        FogEnable(false)
        FogMaskEnable(false)
        TimerStart(CreateTimer(), 0.001, true, function f)
    }
}
Both became unresponsive after a while.
Then show handle id to see.
It gave me 1 the whole time.
The handle id does not get released unless they are nulled.
My sensei Malhorne didn't say my statement is wrong (I'm talking about the tutorial), though I'm not sure how accurately he looked at it. I could beg for his wisdom ask him again if you insist.

It might be that I've made the benchmark wrong, tell me if I have.
 

Deleted member 219079

D

Deleted member 219079

Since you're the teacher of my sensei I have to believe you :(
 

Deleted member 219079

D

Deleted member 219079

Feel free to report here, I'll make necessary changes to my tutorial then, it has been in the submissions since may... :'(
 
Level 1
Joined
Sep 29, 2014
Messages
2
Sir can you help me with these bugs?
.
.
:vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf:
i implemented your spell on Multiple Units,
when my Character and the AI Enemy uses the Hook at the same time,
these Happens:
:fp::fp::fp: when my Hookhead Reach's the Return Detector of AI Enemy
my Character Blink's Instantly to Enemy's Position.
:vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf::vw_wtf:
HELP SIR PLSS
:fp::goblin_cry::goblin_cry::goblin_cry::goblin_cry::goblin_cry::goblin_cry:
 
Level 3
Joined
Nov 11, 2014
Messages
14
In "hook1" trigger:
  • Set Hooker[HookCallCount] = (Triggering unit)
  • Set TempPoint = (Position of (Triggering unit))
  • Set HookStartPoint[HookCallCount] = (Position of (Triggering unit))
  • Set HookerPos[HookCallCount] = (Position of Hooker[HookCallCount])
What's the point of saving the same point into 3 different variables?
After saving Triggering Unit into Hooker variable you should use him while setting other variables: Position of (Triggering unit) ---> Position of Hooker[HookCallCount]
 
You don't need all these "And All Conditions" blocks in your loop. They are linked with a logical and by default.

I was able to test lightning it looks like Malhorne must have tested some more things than I did. You do not not to null lightning variables but I'm not sure about the others.
It's is because you don't have to null all handles. But agents. player is an exxception, because it is an constant agent, that doesn't have to be nulled.
Here is the list of all handles (agents included): http://jass.sourceforge.net/doc/api/BUILT_IN-types-handle.shtml
 
  • Provide an in-game screenshot.
  • Make a short, but informative spell description.
  • Your SetUp trigger must run automatically after map initialization. User should not have to run it himself.
  • Make the configuration to support levels.
  • I would suggest you to get rid of the import data. Spells should be as stand alone as possible and easy to import. How ever you simply could suggest the icon and model in your thread and share a link to them.
  • Give all your triggers and variables decent names. For example: prefix_Name. ("DMH_MaxIndex" as example)
  • For now I only had a very quick look over the code, but you don't need these "And - All Condtions" blocks. You can see condtions in GUI as automatically linked with a logical and.
  • The check to turn off the loop should be moved into the deindex part.

Needs Fix
 
@Almia, I checked some of older approved resources, and found out they don't fit the modern standards.

So it might be ok to have one well coded GUI version. :)

Now to the hook:

- Add import instructions.
- Give your dummy a decent name. "Chicken" might be confusing.
- Change the ability to "Hero Ability", so heroes can learn them. Don't forget to add a learn tooltip for it, once it's a hero ability.
- MH_Flag boolen is not needed. You can solve this only by operating with the counter.
- Effec should be set in config.
- Attack- Damage type should be set in config.
- If no target was found in time, no need to do certain operations. So directly make the check on top if it needs to be deindexed or not.

Needs Fix
 
Level 5
Joined
May 14, 2013
Messages
48
Add import instructions.

Ok, Is my How To Use section in thread don't supply enough information on how to import?

If no target was found in time, no need to do certain operations. So directly make the check on top if it needs to be deindexed or not.

I'm a bit confused about this one? Don't understand what it meant. Can you rephrase that?

Thanks.!
 
  • (Unit-type of TempUnit) != (Unit-type of MH_Hook[MH_Index2])
->
  • (Unit-type of TempUnit) != HookDummy)

Only move HookedUnit if it exists. As you do with creating special effect.

Instead of a DistCounter you just could check for hook's distance.

In loop when hook cathes a unit after this check:
  • (TempUnit is Immun gegen Magie) == True
... you do similar operations twice. It can restructured and merged a bit.

UnitGroup Detector2 is not needed at all. Just checking for distance would suffice.

Some short and useful documentation in main code is always appreciated.

Yes, you are right import instructions exist in thread. I think it's acceptable, too.
It was a personal preference, because I think it's more useful to add them direcly in your spell folder. But it's up to you.

It's a nice looking hook. I like it!

Still some changes needed, Needs Fix.
 
Level 5
Joined
May 14, 2013
Messages
48
Only move HookedUnit if it exists. As you do with creating special effect.
The hooked unit only moves if MH_HookOn is True which is set along in checking for a hooked unit. What is the error in that?
Instead of a DistCounter you just could check for hook's distance.
I did in previous versions but a bug seems to pop and MUI capabilities are stripped off that's why I switched to a counter. Works well now.
UnitGroup Detector2 is not needed at all. Just checking for distance would suffice.
Right, I forgot some editing along and didn't realize that. Good thing you noticed. Updating...
In loop when hook cathes a unit after this check:
  • (TempUnit is Immun gegen Magie) == True
... you do similar operations twice. It can restructured and merged a bit.
Yeah, you're right quick fix and its good to go.
It's a nice looking hook. I like it!
Cool right, and it glows too. Haha...

Thanks.!
 
^No error is in it. It's okay.

For deindexing:

  • (Distance between MH_HookerPos[MH_Index2] and MH_HookPos[MH_Index2]) <= 98.00
I do not like this check. Your creation offset is 80.00. So distance check must be a lower value. Not 98. Else it may be that the hook will be deindexed immediatly. (happened in my test)
So better make it a lower constant value. Best -> make it a (not for user) variable in config trigger, to ensure the distance value for deindex is always lower than the distance creation value.

Change it and it can be approved. Also please give your file a proper name with version number. For example: "Meat Hook v1.6"

Needs Fix
 
Your played sound is set once in setup trigger. It is always constant. No neeed to use an array variable and index it for each instance.

DestPoint doesn't need to be an array. And why do you want do deindex it dynamicly? I don't see the sense, because you create and remove in each loop run.

^Same for Angle.

Basicly... If you evaluate new values each iteration, there is no need at all to index/deindex the variable.
Only use array variable, and index it if really needed.

The hook should end, if caster is dead or removed.

Needs Fix
 
If caster is not alive the hook goes on, and then will disappear when going back.

It probably would be even better, if it would instantly disappear, so also before it reached the max distance.

Also if caster is dead, operations/checks for movement of dummy or damaging the hooked unit is not really needed. Only deindexing neeeded to be done. (if there is a hooked unit, you would try to damage it, even caster is dead or removed)

The Angle does not to be an array. You evaluate it each iteration depanding on given points. So also no need to index/deindex it.
 
Level 5
Joined
May 14, 2013
Messages
48
Major Update Reasons

How come the angle doesn't need to be an array? I don't understand why. I use it once on hook launch, then use it again on return but that is well the same variable. Should I just use a TempReal variable over the Angle one? You couldn't really tell if damaging a hooked unit while caster died is really a problem now. The damage check for the hooked unit is a bug solution that removes the bug which damages a nearby enemy unit within the hook's search radius while it is not the hooked unit. About the overdoing of variables in the loop code, I reverted it because there's a bug that the hook returns on a magic immune enemy unit rather than pass through it if the config is set to false. Should I remove attachments? It's optional though, it still works without it and its editable in the config. (Updated)
 
In your loop, in your first condition block:

  • (MH_DistCounter[MH_Index2] < MH_Distance[MH_Index2])
  • [/stable]
add a check if caster is alive. Hook should be stopped then:
  • (MH_DistCounter[MH_Index2] < MH_Distance[MH_Index2])
  • (MH_Hooker[MH_Index2] is dead) == False
  • [/stable]
Rest might be negligible.

Remove attachments? No I think you do good with it.
 
  • Like
Reactions: Kam
Yeah, the deindexing now works correctly. Good. But actually no need to run the HookBackwards if unit is dead, too. You currently do:

Current structure:

If Caster == Alive and HookingFowards then
DoHookForwards()​
else
DoHookBackwards()​
endif

If Caster == Dead or HookFinished then
Deindex()​
endif

The "DoHookBackwards()" will have no real affect. You will do checks/operations for nothing here. (though it will only run once, if caster is dead)
So you could do...

Alternative structure:

If Caster == Alive then
if HookForwards then​
DoHookForwards()​
else​
DoHookBackwards()​
endif​
else
Deindex()​
endif

However, it works.

Approved

Note that you potentially call the function "OwnerOfHooker" more often. You could reduce the amount of these function calls to one, if you index the player onCast.
 
Top