• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Error when importing spell?

Status
Not open for further replies.
Level 19
Joined
Feb 15, 2008
Messages
2,184
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 :p
 
if that's true, then he would have edited the post, and edited posts have an edit timestamp below, his post doesn't... else, it wouldn't make sense to even post it right?

anyway, checking his post:

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.

I can't see any error in there, just that he can't get it to work...
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Like my hook spell this has one major flaw. Actually I already fixed it, but haven't uploaded it yet.

It doesn't use a counter for maximum created links per spell instance. If you teleport the caster over a really huge distance while throwing the hook then you are so screwed.
Because:
  • You create hundreds if not thousands of units, which will inflict other resources aswell (especially any UnitIndexer)
  • You might force an overflow of the linked list
  • The game performance drops to an unplayable state (not permanent)

So be sure your caster won't be able to teleport such a huge distance in any case.
 
The edit only appears after someone has looked at it. Like this.

Edit 1: See no edit tag applied yet.

Edit 2: And again to show you.

Edit 3: The pics
 

Attachments

  • ex1.PNG
    ex1.PNG
    27.1 KB · Views: 68
  • ex2.PNG
    ex2.PNG
    69.7 KB · Views: 88
  • ex3.PNG
    ex3.PNG
    67.3 KB · Views: 64
Status
Not open for further replies.
Top