JASS:
//TESH.scrollpos=0
//TESH.alwaysfold=0
//------------------------------------------------------------------------------------\\
// Pudge Wars Meat Hook [v1.1.2] \\
// By kenny! \\
// Constructed using vJASS \\
// Requires NewGen WE, GT, AIDS, T32 & AutoFly (optional). \\
//------------------------------------------------------------------------------------\\
library MeatHook requires GT, AIDS, T32, optional AutoFly
globals
private constant integer ABIL_ID = 'A018'
private constant integer HEAD_ID = 'h000'
private constant integer LINK_ID = 'h002'
private constant integer LOCUST_ID = 'Aloc'
private constant integer MAX_LINKS = 8191
private constant integer ANIM_INDEX = 2
private constant integer UNITS_PER_INT = 10
private constant integer HEADSHOT_VOL = 120
private constant real MAX_HEIGHT = 40.00
private constant real UNIT_RADIUS = 100.00
private constant real BUILD_RADIUS = 128.00
private constant real DEST_RADIUS = 128.00
private constant real TIME_SCALE = 1.00
private constant real HEAD_SCALE = 1.00
private constant real LINK_SCALE = 1.25
private constant real FLY_HEIGHT = 75.00
private constant real DEST_DMG_PERC = 0.00
private constant string BLOOD_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
private constant string BLOOD_POINT = "origin"
private constant string HEADSHOT_TEXT = "HEADSHOT!"
private constant string TEXT_COLOUR = "|cFFFF0000"
private constant string HEADSHOT_SOUND = "war3mapImported\\headshot.wav"
private constant attacktype A_TYPE = ATTACK_TYPE_CHAOS
private constant damagetype D_TYPE = DAMAGE_TYPE_UNIVERSAL
private constant weapontype W_TYPE = WEAPON_TYPE_WHOKNOWS
private constant boolean ALLOW_PRELOAD = true
private constant boolean ALLOW_BOUNCE = true
private constant boolean ALLOW_HEADSHOT = true
private constant boolean DEST_BOUNCE = true
private constant boolean ALLOW_GRAPPLE = false
private constant boolean ABOVE_CASTER = false
private constant boolean DISCARD_TARGET = false
private constant boolean KILL_DESTS = false
endglobals
//---------------------------------------------------------------------\\
private constant function MAXDIST takes integer lvl returns real
return 800.00 + (400.00 * lvl)
endfunction
private constant function DAMAGE takes integer lvl returns real
return 0.00 + (100.00 * lvl)
endfunction
private constant function SPEED takes integer lvl returns real
return 1000.00 + (0.00 * lvl)
endfunction
private function FilterUnits takes unit caster, unit filter returns boolean
return GetUnitFlyHeight(filter) < MAX_HEIGHT and GetUnitAbilityLevel(filter,LOCUST_ID) == 0
endfunction
//---------------------------------------------------------------------\\
// \\
// DO NOT TOUCH PAST THIS POINT UNLESS YOU KNOW WHAT YOUR ARE DOING! \\
// \\
//---------------------------------------------------------------------\\
// To make peoples happy. To bad there is no WidgetAlive native.
native UnitAlive takes unit id returns boolean
private struct Link[MAX_LINKS] // Individual links in the linked list for units.
thistype next = 0 // Next link in the list.
thistype prev = 0 // Previous link in the list.
unit link = null // The actual chain link.
// Reset all the members for this struct instance.
private method onDestroy takes nothing returns nothing
// Remove the chain link.
call RemoveUnit(this.link)
set this.link = null
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct List // Linked list to hold all the units that make the chain.
Link head = 0 // First link in the list.
Link last = 0 // Last link in the list.
integer size = 0 // Size of the list.
// Attach a link to the list.
method attach takes nothing returns Link
local Link curr = Link.create() // Create a link.
// Restructuring the start of the list.
if this.head == 0 then
// If there is nothing in the first, set the new link to the head.
set this.head = curr
else
// Otherwise, attach the new link to the end of the list.
set curr.prev = this.last
set this.last.next = curr
endif
// Setting the rest of this link and incrementing list size.
set this.last = curr
set this.size = this.size + 1
return curr
endmethod
// Detach a link from the list.
method detach takes Link curr returns nothing
// Removing a link from the list.
if curr.next == 0 then
// If we are removing the last node, reset last.
set this.last = curr.prev
else
set curr.next.prev = curr.prev
endif
set curr.prev.next = curr.next
// Destroy the link.
call curr.destroy()
// Decrement size of list.
set this.size = this.size - 1
endmethod
// Destroy the list.
private method onDestroy takes nothing returns nothing
// Just to make sure no links are left.
loop
exitwhen this.size == 0
call this.detach(this.last)
endloop
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct IsTarget extends array // To check if a unit is already a target.
//! runtextmacro AIDS()
integer level // This gets incremented by 1 every time a unit becomes a target, and decremented when discarded.
private static method AIDS_filter takes unit u returns boolean
return GetUnitAbilityLevel(u,LOCUST_ID) == 0
endmethod
private method AIDS_onCreate takes nothing returns nothing
set this.level = 0 // Initialise the variable.
endmethod
private method AIDS_onDestroy takes nothing returns nothing
set this.level = 0 // Set it to 0 upon death.
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct IsGrappling extends array // To check if a unit is already grappling.
//! runtextmacro AIDS()
integer level // This gets incremented by 1 every time a unit starts grappling, and decremented when it finishes.
private static method AIDS_filter takes unit u returns boolean
return GetUnitAbilityLevel(u,LOCUST_ID) == 0
endmethod
private method AIDS_onCreate takes nothing returns nothing
set this.level = 0 // Initialise the variable.
endmethod
private method AIDS_onDestroy takes nothing returns nothing
set this.level = 0 // Set it to 0 upon death.
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct Hook // Struct that takes care of the rest.
// Instance members.
unit cast = null // The caster.
unit targ = null // The possible target.
unit head = null // The head of the chain.
player own = null // The owner of the caster.
real ang = 0.00 // The angle the chain is travelling in.
real dist = 0.00 // The current distance travelled.
real max = 0.00 // Maximum distance of the hook.
real cos = 0.00 // Cos of the current angle.
real sin = 0.00 // Sin of the current angle.
real speed = 0.00 // Speed of the hook, saves function calls.
integer level = 0 // Level of the Meat Hook spell for the caster.
List list = 0 // Linked list needed to track chain links.
boolean ret = false // If the hook is extending.
boolean hit = false // If a unit has been hit.
boolean grap = false // If the caster is grappling.
// Static members.
static thistype tempData = 0 // Temp struct needed for data transfer.
static rect enumRect = null // Rect for bouncing off destructables.
static group enumGroup = null // Group for enumerating units and buildings.
static code enumDests = null // Filter function for finding destructables.
static boolexpr enumUnits = null // Filter function for finding units.
static boolexpr enumBuild = null // Filter function for finding buildings.
static real worldMaxX = 0.00 // Map boundaries.
static real worldMaxY = 0.00 // Map boundaries.
static real worldMinX = 0.00 // Map boundaries.
static real worldMinY = 0.00 // Map boundaries.
// Clean up the struct instance and finish the spell.
method destroy takes nothing returns nothing
call this.list.destroy() // Destroy the unit list.
// If there is a target, set it to a position infront of the caster. If you don't like this, make DISTANCE 0.00.
if this.targ != null then
set IsTarget[this.targ].level = IsTarget[this.targ].level - 1
endif
if this.grap then
set IsGrappling[this.cast].level = IsGrappling[this.cast].level - 1
call SetUnitPathing(this.cast,true)
endif
// Clear struct members.
set this.cast = null
set this.targ = null
set this.head = null
set this.ret = false
set this.hit = false
set this.grap = false
call this.deallocate()
endmethod
// Quick text tag for easy use.
method setTextTag takes nothing returns nothing
local texttag text = CreateTextTag()
static if ABOVE_CASTER then
call SetTextTagPos(text,GetUnitX(this.cast),GetUnitY(this.cast),0.00)
else
call SetTextTagPos(text,GetUnitX(this.head),GetUnitY(this.head),0.00)
endif
call SetTextTagPermanent(text,false)
call SetTextTagText(text,TEXT_COLOUR + HEADSHOT_TEXT + "|r",0.023)
call SetTextTagVelocity(text,Cos(1.57079) * 0.0355,Sin(1.57079) * 0.0355)
call SetTextTagLifespan(text,3.00)
call SetTextTagFadepoint(text,1.50)
set text = null
endmethod
// Set the new angle for bouncing.
method setAngle takes real tempx, real tempy returns boolean
local real ang1 = this.ang * bj_RADTODEG
local real ang2 = ModuloReal(Atan2((GetUnitY(this.head) - tempy),(GetUnitX(this.head) - tempx)) * bj_RADTODEG,360.00)
local real diff = RAbsBJ(ang2 - ang1)
// Lots of math stuff :).
if diff >= 90.00 and diff <= 270.00 then
if ( ang2 > 45.00 and ang2 < 135.00 ) or ( ang2 > 225.00 and ang2 < 315.00 ) then
set this.ang = -ang1 * bj_DEGTORAD
else
set this.ang = (180.00 - ang1) * bj_DEGTORAD
endif
// Set the new travelling angle.
set this.sin = Sin(this.ang)
set this.cos = Cos(this.ang)
return true
endif
return false
endmethod
// Sets the target unit.
method setTarget takes unit target returns boolean
set this.targ = target
set this.hit = true
set IsTarget[this.targ].level = IsTarget[this.targ].level + 1
// Damage the target if it is an enemy.
if IsUnitEnemy(this.targ,this.own) then
call UnitDamageTarget(this.cast,this.targ,DAMAGE(this.level),true,false,A_TYPE,D_TYPE,W_TYPE)
call DestroyEffect(AddSpecialEffectTarget(BLOOD_SFX,this.targ,BLOOD_POINT))
endif
// Stop the hook from moving.
call SetUnitTimeScale(this.head,0.00)
return true
endmethod
// Find any destructables in range of the head and bounce off them.
static method getDest takes nothing returns nothing
local thistype this = thistype.tempData
local destructable dest = GetEnumDestructable()
// Only bounce off alive destructables.
if GetWidgetLife(dest) > 0.406 then
call this.setAngle(GetWidgetX(dest),GetWidgetY(dest))
// Kill them if you want.
static if KILL_DESTS then
call KillDestructable(dest)
else
call UnitDamageTarget(this.cast,dest,(DAMAGE(this.level) * DEST_DMG_PERC),true,false,A_TYPE,D_TYPE,W_TYPE)
endif
endif
set dest = null
endmethod
// Searches for buildings to bounce off.
static method getBuild takes nothing returns boolean
local thistype this = thistype.tempData
local unit filt = GetFilterUnit()
if UnitAlive(filt) and IsUnitType(filt,UNIT_TYPE_STRUCTURE) == true and GetUnitTypeId(filt) != LINK_ID and GetUnitTypeId(filt) != HEAD_ID then
if this.cast != filt and FilterUnits(this.cast,filt) then
static if ALLOW_BOUNCE then // If bouncing is allowed, then set the new angle.
call this.setAngle(GetUnitX(filt),GetUnitY(filt))
else
// Else find out if grappling is allowed.
static if ALLOW_GRAPPLE then
if not this.grap then
if IsGrappling[this.cast].level == 0 then
// If grappling is allowed and the caster is not grappling already, make it grapple.
set IsGrappling[this.cast].level = IsGrappling[this.cast].level + 1
set this.hit = true
set this.grap = true
call SetUnitPathing(this.cast,false)
call SetUnitTimeScale(this.head,0.00)
else
// If the caster is already grappling, but has two hooks that want to grapple, make one retract.
set this.hit = true
endif
endif
endif
endif
endif
endif
set filt = null
return false
endmethod
// Searches for units to become the hook's target.
static method getUnit takes nothing returns boolean
local thistype this = thistype.tempData
local unit filt = GetFilterUnit()
local sound shot = null
if UnitAlive(filt) and IsUnitType(filt,UNIT_TYPE_STRUCTURE) == false and GetUnitTypeId(filt) != LINK_ID and GetUnitTypeId(filt) != HEAD_ID then
if this.cast != filt and FilterUnits(this.cast,filt) then
static if ALLOW_HEADSHOT then // If headshots are allowed continue on.
if not this.hit then // If a unit hasn't been it continue on.
if IsTarget[filt].level != 0 then // If the possible unit is already a target continue.
// Play the sound.
set shot = CreateSound(HEADSHOT_SOUND,false,false,false,10,10,"")
call SetSoundVolume(shot,HEADSHOT_VOL)
call StartSound(shot)
call KillSoundWhenDone(shot)
// Create a text tag.
call this.setTextTag()
// Kill the unit.
call UnitDamageTarget(this.cast,filt,1000000.00,true,false,A_TYPE,D_TYPE,W_TYPE)
call DestroyEffect(AddSpecialEffectTarget(BLOOD_SFX,filt,BLOOD_POINT))
set this.hit = true // Set hit to true
else
// If the unit isn't a target, make it one.
call this.setTarget(filt)
endif
endif
else
// If we aren't allowing headshots, then just find a suitable unit and make it the target.
if not this.hit and IsTarget[filt].level == 0 then
call this.setTarget(filt)
endif
endif
endif
endif
set filt = null
return false
endmethod
// Retract the hook.
method retract takes nothing returns nothing
local Link linkx = 0
local integer count = 0
local unit temp = this.list.last.link
local unit prev = null
local unit dumm = null
local real casx = GetUnitX(this.cast)
local real casy = GetUnitY(this.cast)
local real temx = GetUnitX(temp)
local real temy = GetUnitY(temp)
local real newx = 0.00
local real newy = 0.00
local real ang2 = 0.00
local real dist = SquareRoot((temx - casx) * (temx - casx) + (temy - casy) * (temy - casy))
// If the distance between the caster and the last link is too much, create more links.
if dist > (this.speed * 2.00) and not this.grap then
// Using a loop so the hooks work when great distances are covered in a short time.
loop
exitwhen dist <= (this.speed * 2.00) or count == UNITS_PER_INT// Create as many links as needed to fill the gap.
set ang2 = Atan2((casy - temy),(casx - temx))
set temx = temx + (this.speed * 2.00) * Cos(ang2)
set temy = temy + (this.speed * 2.00) * Sin(ang2)
// Create a new chain link.
set linkx = this.list.attach()
set linkx.link = CreateUnit(this.own,LINK_ID,temx,temy,(ang2 * bj_RADTODEG) + 180.00)
// Set its height and size.
call SetUnitScale(linkx.link,LINK_SCALE,LINK_SCALE,LINK_SCALE)
static if LIBRARY_AutoFly then
call SetUnitFlyHeight(linkx.link,FLY_HEIGHT,0.00)
endif
// Set the new last link in the chain to the last created link.
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
set dist = dist - this.speed
set count = count + 1
endloop
endif
// If the caster is grappling, change its position.
if this.grap then
set temx = GetUnitX(this.list.last.link)
set temy = GetUnitY(this.list.last.link)
set ang2 = Atan2((temy - casy),(temx - casx))
// Set the caster's new position using SetUnitPosition() to stop extra casting.
call SetUnitPosition(this.cast,casx + this.speed * Cos(ang2),casy + this.speed * Sin(ang2))
else
// If the caster is no grappling, check for a target unit.
if this.targ != null then
// If there is a target unit, set it's new position.
call SetUnitX(this.targ,GetUnitX(this.head))
call SetUnitY(this.targ,GetUnitY(this.head))
static if DISCARD_TARGET then
// Check if it is bead so it can be discarded.
if not UnitAlive(this.targ) then
set IsTarget[this.targ].level = IsTarget[this.targ].level - 1
set this.targ = null
call SetUnitTimeScale(this.head,TIME_SCALE)
endif
endif
else
// Otherwise, find a new unit.
call GroupEnumUnitsInRange(thistype.enumGroup,GetUnitX(this.head),GetUnitY(this.head),UNIT_RADIUS,thistype.enumUnits)
endif
endif
set linkx = this.list.last
// This is used to remove the unneeded links and to set their new position if they are needed.
loop
exitwhen linkx == 0
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
if linkx.prev.prev != 0 then
set dumm = linkx.prev.prev.link
if IsUnitInRange(temp,dumm,(this.speed * 1.50)) then
call this.list.detach(linkx.prev)
call SetUnitFacing(temp,(Atan2((GetUnitY(dumm) - temy),(GetUnitX(dumm) - temx)) * bj_RADTODEG) + 180.00)
endif
endif
// Find the angle that the chain link should be facing.
if temp == this.list.last.link then
set ang2 = Atan2((casy - temy),(casx - temx))
else
set ang2 = Atan2((GetUnitY(prev) - temy),(GetUnitX(prev) - temx))
endif
if linkx == this.list.last and IsUnitInRange(temp,this.cast,this.speed) then
call this.list.detach(linkx)
// Detach the link if needed.
endif
// Set the chain links new position.
if not this.grap then
call SetUnitX(temp,temx + this.speed * Cos(ang2))
call SetUnitY(temp,temy + this.speed * Sin(ang2))
endif
call SetUnitFacing(temp,(ang2 * bj_RADTODEG) + 180.00)
set prev = temp
set linkx = linkx.prev
endloop
set temp = null
set prev = null
set dumm = null
endmethod
// Extend the hook.
method extend takes nothing returns nothing
local Link linkx = 0
local integer count = 0
local unit temp = this.list.last.link
local unit next = null
local unit dumm = null
local real casx = GetUnitX(this.cast)
local real casy = GetUnitY(this.cast)
local real temx = GetUnitX(temp)
local real temy = GetUnitY(temp)
local real newx = 0.00
local real newy = 0.00
local real ang2 = 0.00
local real dist = SquareRoot((temx - casx) * (temx - casx) + (temy - casy) * (temy - casy))
// If the distance between the caster and the last link is too much, create more links.
if dist > (this.speed * 2.00) then
// Using a loop so the hooks work when great distances are covered in a short time.
loop
exitwhen dist <= (this.speed * 2.00) or count == UNITS_PER_INT // Create as many links as needed to fill the gap.
set ang2 = Atan2((casy - temy),(casx - temx))
set temx = temx + (this.speed * 2.00) * Cos(ang2)
set temy = temy + (this.speed * 2.00) * Sin(ang2)
// Create a new chain link.
set linkx = this.list.attach()
set linkx.link = CreateUnit(this.own,LINK_ID,temx,temy,(ang2 * bj_RADTODEG) + 180.00)
// Set its height and size.
call SetUnitScale(linkx.link,LINK_SCALE,LINK_SCALE,LINK_SCALE)
static if LIBRARY_AutoFly then
call SetUnitFlyHeight(linkx.link,FLY_HEIGHT,0.00)
endif
// Set the new last link of the chain the the last created link.
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
set dist = dist - this.speed
set count = count + 1
endloop
endif
set linkx = this.list.head
// This loop moves all the current links in the chain.
loop
exitwhen linkx == 0
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
if linkx.next.next != 0 then
set dumm = linkx.next.next.link
if IsUnitInRange(temp,dumm,(this.speed * 1.50)) then
call this.list.detach(linkx.next)
call SetUnitFacing(temp,(Atan2((GetUnitY(dumm) - temy),(GetUnitX(dumm) - temx)) * bj_RADTODEG) + 180.00)
endif
endif
// Set the new angle for each chain link.
if temp == this.head then
set ang2 = this.ang // If it is the head link, get the angle to the travelling angle.
else
set ang2 = Atan2((GetUnitY(next) - temy),(GetUnitX(next) - temx))
endif
set newx = temx + this.speed * Cos(ang2)
set newy = temy + this.speed * Sin(ang2)
// If the new point is outside the map, find a new point and make the hook bounce.
if temp == this.head then
if newx > thistype.worldMaxX or newx < thistype.worldMinX then
if this.ang < 0.00 then
set this.ang = -1.57079 + (-1.57079 - this.ang)
else
set this.ang = 1.57079 - (this.ang - 1.57079)
endif
set this.cos = Cos(this.ang)
set this.sin = Sin(this.ang)
elseif newy > thistype.worldMaxY or newy < thistype.worldMinY then
if this.ang < 1.57079 then
set this.ang = 0.00 - this.ang
else
set this.ang = -this.ang
endif
set this.cos = Cos(this.ang)
set this.sin = Sin(this.ang)
endif
// Search for units, buildings and destructables.
set thistype.tempData = this
call GroupEnumUnitsInRange(thistype.enumGroup,newx,newy,UNIT_RADIUS,thistype.enumUnits)
call GroupEnumUnitsInRange(thistype.enumGroup,newx,newy,BUILD_RADIUS,thistype.enumBuild)
static if DEST_BOUNCE then
call SetRect(thistype.enumRect,newx - DEST_RADIUS,newy - DEST_RADIUS,newx + DEST_RADIUS,newy + DEST_RADIUS)
call EnumDestructablesInRect(thistype.enumRect,null,thistype.enumDests)
endif
endif
// Set the new position of each hook.
call SetUnitX(temp,newx)
call SetUnitY(temp,newy)
call SetUnitFacing(temp,ang2 * bj_RADTODEG)
set next = temp
set linkx = linkx.next
endloop
// If the max distance has been reached or a unit has been hit, stop extending.
if this.dist >= this.max or this.hit then
set this.ret = true
else
set this.dist = this.dist + this.speed
endif
set temp = null
set next = null
set dumm = null
endmethod
// The handler method, makes things much easier.
method periodic takes nothing returns nothing
if this.list.size == 0 then // If the hook is done.
call this.stopPeriodic()
call this.destroy() // Clean up the struct.
else
if this.ret then // If the hook is retracting.
call this.retract() // Keep retracting.
else // Otherwise.
call this.extend() // Extend it.
endif
endif
endmethod
implement T32x
// Start of the hook, assembles struct members and stuff.
static method actions takes nothing returns boolean
local thistype this = thistype.allocate()
local real casx = 0.00
local real casy = 0.00
// Sets struct members.
set this.cast = GetTriggerUnit()
set this.own = GetOwningPlayer(this.cast)
set casx = GetUnitX(this.cast)
set casy = GetUnitY(this.cast)
set this.ang = Atan2((GetSpellTargetY() - casy),(GetSpellTargetX() - casx))
set this.cos = Cos(this.ang)
set this.sin = Sin(this.ang)
set this.list = List.create()
set this.level = GetUnitAbilityLevel(this.cast,ABIL_ID)
set this.speed = SPEED(this.level) * T32_PERIOD
set this.max = MAXDIST(this.level)
// Create the head of the chain.
set this.head = CreateUnit(this.own,HEAD_ID,casx + this.speed * this.cos,casy + this.speed * this.sin,this.ang * bj_RADTODEG)
set this.list.attach().link = this.head
// Set up the head unit.
call SetUnitTimeScale(this.head,TIME_SCALE)
call SetUnitScale(this.head,HEAD_SCALE,HEAD_SCALE,HEAD_SCALE)
static if LIBRARY_AutoFly then
call SetUnitFlyHeight(this.head,FLY_HEIGHT,0.00)
endif
// Play a casting animation.
call SetUnitAnimationByIndex(this.cast,ANIM_INDEX)
// Add this instance to T32.
call this.startPeriodic()
// Return a boolean value to work with GTrigger.
return false
endmethod
// Needed this so that the sound worked first go.
static method loadSound takes nothing returns nothing
local timer time = GetExpiredTimer()
local sound shot = CreateSound(HEADSHOT_SOUND,false,false,false,10,10,"")
// Play the sound, but quietly.
call SetSoundVolume(shot,0)
call StartSound(shot)
call KillSoundWhenDone(shot)
// Using the static timer for this, seeing as no one will cast hook at 0.00 seconds game time.
call PauseTimer(time)
call DestroyTimer(time)
set time = null
set shot = null
endmethod
// Initialisation method.
static method onInit takes nothing returns nothing
local unit dummy = null
// Set all the static struct members.
set thistype.enumRect = Rect(0.00,0.00,1.00,1.00)
set thistype.enumGroup = CreateGroup()
set thistype.enumDests = function thistype.getDest
set thistype.enumUnits = Filter(function thistype.getUnit)
set thistype.enumBuild = Filter(function thistype.getBuild)
set thistype.worldMaxX = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00
set thistype.worldMaxY = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00
set thistype.worldMinX = GetRectMinX(bj_mapInitialPlayableArea) + 64.00
set thistype.worldMinY = GetRectMinY(bj_mapInitialPlayableArea) + 64.00
// Add a "starts effect" event to the spell.
call GT_AddStartsEffectAction(function thistype.actions,ABIL_ID)
// Needed to load the sound properly.
call TimerStart(CreateTimer(),0.00,false,function thistype.loadSound)
// If preloading is allowed, then preload.
static if ALLOW_PRELOAD then
// Load the "chain" unit and add the crow form ability to load that too.
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),LINK_ID,0.00,0.00,0.00)
call RemoveUnit(dummy)
// Load the "head" unit.
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),HEAD_ID,0.00,0.00,0.00)
call RemoveUnit(dummy)
set dummy = null
endif
endmethod
endstruct
endlibrary
I changed 3 lines. Did i miss anything.
I changed Ability ID Hook ID and Chain ID.
What do i more have to change to get it working.
imported from here.
http://www.thehelper.net/threads/pudge-wars-meat-hook-revisited.119312/
Also how do i change the speed of the hook?
sry my mistake forgot to see it uses newgen WE