Meat Hook ability by Daelin

SFilip

Gone but not forgotten
Reaction score
634
Well since alot of people asked for this and it got lost after the crash i decided to post it again. Look down for instructions on how to implement this.
Code:
//RAWCODE FUNCTIONS

constant function HookUnit takes nothing returns integer
    return 'h000'
endfunction

constant function HookDistance_Limit takes nothing returns real
    return 1000.00 //maximum range of hook
endfunction

constant function HookRange takes nothing returns real
    return 75.00 //distance between chain and hooked unit
endfunction

constant function HookDistances takes nothing returns real
    return 25.00 //distance between two chains of the hook
endfunction

//********************
//CONDITION FUNCTIONS

function HookFilter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetHandleUnit(GetExpiredTimer(), "cast"))) and GetWidgetLife(GetFilterUnit())>0.00 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)==false
endfunction

function Trig_Meathook_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

//*****************
//ACTION FUNCTIONS

function HookGrab takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit cast = GetHandleUnit(t, "cast")
    local unit hook = GetHandleUnit(t, "hook")
    local real dist = GetHandleReal(t, "dist")
    local unit targ = GetHandleUnit(t, "targ")
    local real angle = GetHandleReal(t, "angle")
    local real PolarX = GetUnitX(cast) + dist * Cos(angle)
    local real PolarY = GetUnitY(cast) + dist * Sin(angle)

    call SetHandleHandle(t, "hook", GetHandleUnit(hook, "prev"))
    call FlushHandleLocals(hook) 
    call RemoveUnit(hook)
    set hook = null
    
    call SetUnitPosition(targ, PolarX, PolarY)
    
    if dist<=10.00 then
        call FlushHandleLocals(t)
        call PauseTimer(t)
        call DestroyTimer(t)
    else  
    call SetHandleReal(t, "dist", dist-HookDistances())
    endif
    
    set targ = null
    set t = null
    set cast = null
    set hook = null  
endfunction

function MeatHookCreate takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit prev = GetHandleUnit(t, "prev")
local unit cast = GetHandleUnit(t, "cast")
local real angle = GetHandleReal(t, "angle")   
local real dist = GetHandleReal(t, "dist") 
local real PolarX = GetUnitX(cast) + dist * Cos(angle)
local real PolarY = GetUnitY(cast) + dist * Sin(angle)
local unit hook = CreateUnit(GetOwningPlayer(cast), HookUnit(), PolarX, PolarY, bj_RADTODEG*angle)
local group aux = CreateGroup()
local timer trix
local real count
local unit targ = null

call SetHandleHandle(hook, "prev", prev)

call GroupEnumUnitsInRange(aux, PolarX, PolarY, HookRange(), Condition(function HookFilter))
set count = CountUnitsInGroup(aux)
if count>0 then
    set targ = GroupPickRandomUnit(aux)
endif

if count>0 or dist>=HookDistance_Limit() then
    call PauseTimer(t)
    call DestroyTimer(t)
    call FlushHandleLocals(t)
    set trix = CreateTimer()
    call SetHandleHandle(trix, "cast", cast)
    call SetHandleHandle(trix, "targ", targ)
    call SetHandleReal(trix, "dist", dist)
    call SetHandleHandle(trix, "hook", hook)
    call SetHandleReal(trix, "angle", angle)
    call TimerStart(trix, 0.035, true, function HookGrab)
    set trix = null   
else
    call SetHandleReal(t, "dist", dist+HookDistances())
    call SetHandleHandle(t, "prev", hook)
endif
call DestroyGroup(aux)
set hook = null
set prev = null
set targ = null
set aux = null
set t = null
set cast = null    
endfunction

function Trig_Meathook_Actions takes nothing returns nothing

local unit cast = GetTriggerUnit()
local real X = GetLocationX(GetSpellTargetLoc())
local real Y = GetLocationY(GetSpellTargetLoc())
local timer t = CreateTimer()
local real angle = Atan2(Y-GetUnitY(cast),X-GetUnitX(cast))

call SetHandleHandle(t, "cast", cast)
call SetHandleHandle(t, "prev", null)
call SetHandleReal(t, "angle", angle)
call SetHandleReal(t, "dist", 0.25)
call TimerStart(t, 0.035, true, function MeatHookCreate)

call RemoveLocation(GetSpellTargetLoc())
set cast = null
set t = null
endfunction

//===========================================================================
function InitTrig_Meathook takes nothing returns nothing
    set gg_trg_Meathook = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Meathook, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Meathook, Condition( function Trig_Meathook_Conditions ) )
    call TriggerAddAction( gg_trg_Meathook, function Trig_Meathook_Actions )
endfunction

How to implement:

Make a new trigger called Meathook, go to Edit -> Convert to Custom Text and press OK. Delete everything the trigger editor created for you and replace it with the jass code above.
Now you need to create a dummy unit that will be used to create the hook chain.
Base it of any unit (for example a footman) and change these fields:
Abilties - Normal
Delete all, add Locust.

Art - Model File
Change to Warden, Maiev under Units - Missiles.

Art - Scaling Value
Experiment a bit. I used 1.50.

Art - Shadow Image (Unit) = None.

Art - Special
Remove everything here.

Combat - Attacks Enabled = None.

Movement - Height
Also needs experimenting. I used 50.00.

Movement - Type = Fly.

Pathing - Collision Size
Set to 0 (although you probably don't need this because you have locust).

Stats - Can Flee = False

Stats - Food Cost = 0

Techtree - Upgrades Used
Remove everything.

All done! Now press Ctrl+D. Your chain unit's name should change.
For example Footman becomes h000:hfoo (Footman).
Write down the bold text (h000 in this case although it could be different for you), press Ctrl+D again to restore the old name and switch to the code in the trigger editor.
In the first lines you will see
Code:
constant function HookUnit takes nothing returns integer
    return 'h000'
endfunction
If the text I marked bold wasn't h000 for you then change return 'h000' to something else.

Now you need to create the actual ability.
Base it of Channel (Neutral Hostile -> Heroes -> Channel) and change these fields:
Art - Animation Names
Remove all and add attack if you want it dota like. If you don't then put whatever you want.

Art - Caster, Art - Caster Attachment Point 1, Art - Effect, Art - Target, Art - Target Attachment Point 1
Remove everything from these.

Stats - Levels
Anything you want.

If the above is larger than 1 then you need to set these fields for every level:
Data - Art Duration = 0
Data - Disable Other Abilities = False
Data - Follow Through Time = 1.50, you can change this if you think its too long
Data - Options = check Visible and Physical Spell
Data - Target Type = Unit or Point Target
Stats - Cast Range = whatever you want

Again press Ctrl+D. You will see something like A000:ANcl (Meat Hook). Once again remember the bold part if it isn't A000 and press Ctrl+D again. Now in the trigger code find
Code:
function Trig_Meathook_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction
and change return GetSpellAbilityId() == 'A000' if the bold part wasn't A000 for you.

Now you need to implement kattana's handle vars. Go here and copy the code to your map's header (its the first line in the left part of the trigger editor, has the same name as your map).
Now go to the variable editor (Ctrl+B) and add a new variable called GameCache of type Game Cache.
Find this function in the handle vars code:
Code:
function LocalVars takes nothing returns gamecache
    // Replace InitGameCache("jasslocalvars.w3v") with a global variable!!
    return InitGameCache("jasslocalvars.w3v")
endfunction
and replace return InitGameCache("jasslocalvars.w3v") with return udg_GameCache.
Make a new trigger and add map initialization event. now add a custom script action and input this code:
Code:
set udg_GameCache = InitGameCache("jasslocalvars.w3v")

And it's finally over! Now just add the spell to some unit and enjoy ;)

Credit Daelin if you use this!!
The only thing I did here is the implementation guide. Hope you had no trouble understanding it. ;)
 

Daelin

Kelani Mage
Reaction score
172
When I think at this spell, I think at a spell which taught me a lot of stuff about how Handle vars actually work. I had quite some problems with them. Took me a lot to fix because of a stupid error. Anyway, thanks for the big font which mentions the credits. :)

~Daelin
 
I

i-SCREAM

Guest
Wow... You explained it so perfectly, like too perfect I think. For some reason when I kept saving my map, it came up with errors like missing a ")" or "," in some lines. I have no idea how those punctuation marks disappeared! I copied it word for word! Thanks!

Edit: **IMPORTANT** What do I have to do to this code to make it be able to target allies?
 

BlueSin

New Member
Reaction score
37
Wow... You explained it so perfectly, like too perfect I think. For some reason when I kept saving my map, it came up with errors like missing a ")" or "," in some lines. I have no idea how those punctuation marks disappeared! I copied it word for word! Thanks!

Edit: **IMPORTANT** What do I have to do to this code to make it be able to target allies?


Delete the bold:

Code:
function HookFilter takes nothing returns boolean
    return [B]IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetHandleUnit(GetExpiredTimer(), "cast"))) and [/B]GetWidgetLife(GetFilterUnit())>0.00 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)==false
endfunction

:)
 
I

i-SCREAM

Guest
I did that and now the unit cannot cast meat hook. So nothing happens if I delete that bold part. Also, what would I do to make the meat hook work on only paused units? Thanks!
 

BlueSin

New Member
Reaction score
37
You must have done something wrong.

Code:
function HookFilter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetHandleUnit(GetExpiredTimer(), "cast"))) and GetWidgetLife(GetFilterUnit())>0.00 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)==false
endfunction

This is the filter, the conditions for what can be affected. Wherever he checks the condition boolexpr HookFilter it checks if it returns true. In the case above it checks:
-Is the Unit being checked an Enemy of the owner of the handle unit named cast
-Is the unit alive (health > 0)
-Is the unit NOT a structure

So you can easily add or remove conditions yourself. For example add IsUnitPaused(GetFilterUnit()). Though I'm not sure if that's a valid condition, been a while since I've played warcraft.
 
C

C. Finster

Guest
Very nice!

I'm confused though, where would i place the trigger to be sure it works? I am modifying a map i used to play a lot before i got addicted to DotA. (It's a Footmen Frenzy map) There are a few trigger folders, and i am unsure as to which one to place it into. The folders are as follows:

1. Initilization
2. Spell (which is the one i was leaning towards, but i figured i'd ask first before i ruin it)
3. Begin Game
4. Hero or Item Choosing
5. Spawning of Forces
6. Player Loses
7. Laden Zone (1 to 4)
8. Remove Shops
9. Win Condition

any help would be appreciated very much. I've only been messing with the Map Editor for about four days now, due to a request from my friend who wants to see the map have better heroes. It's going okay i guess, but I'm still stuck on custom icons and how to get it to work.

- C. Finster
 

SFilip

Gone but not forgotten
Reaction score
634
> You must have done something wrong.
Actually the problem is that its right...so right that it targets the caster right after you do it.
To make it target allies replace
IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetHandleUnit(GetExpiredTimer(), "cast"))) and
with
(GetFilterUnit() != GetHandleUnit(GetExpiredTimer(), "cast")) and

@C. Finster
Wait, is it your map?
Well anyway the trigger group names (aka folders) mean nothing, just used for organization. In other words it will work regardless of the place you put it, but for the sake of making your life easier you should do it in Spells.
 
C

C. Finster

Guest
>wait, is it your map?<

No, it is not my map. like i said in my original post, i am modifying a Footmen Frenzy map i used to play all the time before i started playing DotA. Due to a request from my friend, he asked me to make it better by adding more heroes with better abilities, better Footmen, etc.

But thanks for enlightening me. Keep up the good work.

- C. Finster
 

Proskillz

New Member
Reaction score
0
Damage

Hey, i have been reading this thread and is trying to implement the meat hook skill for a hero of mine. Can you please give me some detailed instructions on how to make the hook have damage when it hits the target and how to make the hook go fast? Thanks :)
 
G

gwingetinkoq

Guest
ARGH, You must mention before that the trigger name must be EXACTLY Meathook , or else it will not ACTIVATE.
and how to fasten the chain speed?
 

trigger_newb

Active Member
Reaction score
3
wowowowowowow
i've tried this thing a billion times for like 5 hours
my freaken head hurts..
this thing doesnt work.
there's a crap load of errors
whenever i try to save the map..
PLZPLZPLZPLZPLZPLZPZPZLZLPZPLZL HELP ME!!!:banghead: :banghead:

can someone make this for me??
and plz send me the map...
just the trigger stuff.
i REALLY REALLY cant do it...
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top