Spell Pudge Wars Meat Hook Revisited

INCINERATE

New Member
Reaction score
12
hey kenny, when i try to update the pudge wars hook, i getting serious problems with AIDS, cause im using PUI system for another spell....

i got it to compile but the hook was going threw plain air and not targeting units .

so i back on the old pudge hook for now.. any thoughts?
 

Kenny

Back for now.
Reaction score
202
You can't use AIDS and PUI in the same map. Systems that use UserUnitData or whatever it is collide.

What I suggest you do is convert to AIDS, as PUI is outdated now. How many spells/systems do you have that use PUI?
 

Kenny

Back for now.
Reaction score
202
> why is pui considered outdated..?

More recent systems allow for auto indexing, which is incredibly handy and provides on-allocation and on-deallocation functionality (in regards to when a unit is given an index and when it is released).

And from what I've seen and read, the recycling algorithm in PUI is over complicated and less efficient than it could be, but that doesn't matter here.

Anywho, I will be updating this very soon.

The final script looks like this:

JASS:
//------------------------------------------------------------------------------------\\
//                         Pudge Wars Meat Hook [v1.1.0]                              \\
//                                   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          = 'A000'
        private constant integer    HEAD_ID          = 'h000'
        private constant integer    LINK_ID          = 'h001'
        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 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.25
        private constant real       LINK_SCALE       = 1.75
        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     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 <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />.
            if diff &gt;= 90.00 and diff &lt;= 270.00  then
                if ( ang2 &gt; 45.00 and ang2 &lt; 135.00 ) or ( ang2 &gt; 225.00 and ang2 &lt; 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) &gt; 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&#039;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&#039;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,&quot;&quot;)
                                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&#039;t a target, make it one.
                                call this.setTarget(filt)
                            endif
                        endif
                    else
                        // If we aren&#039;t allowing headshots, then just find a suitable unit and make it the target.
                        if not this.hit and IsTarget[filt] == 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 &gt; (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 &lt;= (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&#039;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&#039;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 &gt; (this.speed * 2.00) then 
                // Using a loop so the hooks work when great distances are covered in a short time.
                loop
                    exitwhen dist &lt;= (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 &gt; thistype.worldMaxX or newx &lt; thistype.worldMinX then
                        if this.ang &lt; 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 &gt; thistype.worldMaxY or newy &lt; thistype.worldMinY then
                        if this.ang &lt; 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 &gt;= MAXDIST(this.level) 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
            
            // 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,&quot;&quot;)
            
            // 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 &quot;starts effect&quot; 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 &quot;chain&quot; 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 &quot;head&quot; 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
 

BlackRose

Forum User
Reaction score
239
When's something so awesome gonna be approved ;D
Wonder if there is gonna be Pudge Wars Advanced rip offs now?
 

Kenny

Back for now.
Reaction score
202
Finally had time to update this.

Version 1.1.0 released. It is a pretty major update.

I think everything that was talked about over the few posts has been updated and implemented.

This spell now requires:

- GTrigger by Jesus4Lyf.
- AIDS by Jesus4Lyf.
- T32 by Jesus4Lyf.
- AutoFly by Azlier.
- The latest JassHelper.

I think this is finally at the stage I would like it to be, and ready for a decent review.
 

Jesus4Lyf

Good Idea™
Reaction score
397
hey kenny, when i try to update the pudge wars hook, i getting serious problems with AIDS, cause im using PUI system for another spell....
You know, you can import AIDS and delete PUI and nothing will change (don't need to change anything)?
When's something so awesome gonna be approved ;D
I think this is finally at the stage I would like it to be, and ready for a decent review.
Cool. Last time I reviewed it, BlackRose, I ran into bugs. I intend to take a look again some time. Not today, probably. :p
 

Kenny

Back for now.
Reaction score
202
>Cool. Last time I reviewed it, BlackRose, I ran into bugs. I intend to take a look again some time. Not today, probably.

Excellent, hopefully this time everything is working, I tested it well over 250+ times with no errors. Lets hope no one else finds anything wrong with it.

As long as someone has the intension to review this, I am happy. The time it takes is not important.
 

INCINERATE

New Member
Reaction score
12
i'd like to update it, but due to my badness , i cant . cause i got another spell using pui and i dont know how to recode it with aids..

i have never had a problem with your old hook though, so no harm done i guess :p
 

Kenny

Back for now.
Reaction score
202
i'd like to update it, but due to my badness , i cant . cause i got another spell using pui and i dont know how to recode it with aids..

If you read Jesus4Lyf's post just above my other two, you will read that you can just delete PUI, import AIDS, and everything -should- work fine. :D

You can also download the test map to test it for me if you like. :)
 

INCINERATE

New Member
Reaction score
12
ohh lol :p . well i did say "due to my badness" .. see how bad i am ? i didnt even know that i can just delete pui and put in aids , i assumed i needed both :p


okay ill try it out , whats the update really for?
 

Kenny

Back for now.
Reaction score
202
okay ill try it out , whats the update really for?

- Minor visual improvements. (So small that I am probably the only one to notice them).
- Efficiency updates.
- Major bug fix.
- Code improvements and de-bloating of code.
- Because I like making things as good as possible.
 

INCINERATE

New Member
Reaction score
12
okay i updated it,

i deleted pui, put in aids instead, and also put in the autofly , i also have T32 and Gt.

so on my first test, i casted hook, and it went threw all the units .. seems to not hit at all, so i said to myself i must have did something wrong,

so i reimported it, and im still getting the same result . the hook is going straight threw units and not targetting anything. just to make sure if its the aids system... i checked my other spell that was using Pui and it seems to be working 100% with aids. so i am not sure what the hell is going on, but i directly copy pasted from your test map your hook trigger and its not working :p

luckly i backed up my map b4 i did this. so for now i am going to stick on the old hook cause i never had a problem with it .

here is a screen shot

pq543.jpg
 

Kenny

Back for now.
Reaction score
202
Make sure you follow the implementation instructions for AIDS, otherwise the system will not work properly (make sure you are correctly implementing the object merger line or set USE_PERIODIC_RECYCLER to false).

I'm pretty sure that is where the problem is coming from.
 

INCINERATE

New Member
Reaction score
12
and then delete the "!" from the
// FAR left side of the next lines (so "external" will line up with this line):
// external ObjectMerger w3a Adef AIDS anam "State Detection" ansf "(AIDS)" aart "" arac 0


what does that piece of aids mean? i dont see anything on the far left side :confused: , what is even a far left side???
 

Immolation

Member
Reaction score
20
Copy over AIDS to your map. Save your map. Quit the editor. Open the editor. Open your map. Go to the AIDS trigger, replace this line:

JASS:

//! external ObjectMerger w3a Adef AIDS anam &quot;State Detection&quot; ansf &quot;(AIDS)&quot; aart &quot;&quot; arac 0

with this:
JASS:

// external ObjectMerger w3a Adef AIDS anam &quot;State Detection&quot; ansf &quot;(AIDS)&quot; aart &quot;&quot; arac 0
 

INCINERATE

New Member
Reaction score
12
i just did exactly that, and its still not working( going straight threw units)

and about the spell that used pui , it is working with aids instead and pui is deleted... so AIDS is working in my map...

.. my hunch is its not aids , its something else ..
 

INCINERATE

New Member
Reaction score
12
okay i just found out what is causing the bug.


its this line

JASS:
private constant boolean    ALLOW_HEADSHOT   = true


when i put that to false , the hook no longer grabs any unit

when i leave it as true, the hook works 100% .



i really dont want headshot in my map, cause if 2 pudges headshot a unit it instantly dies not so, sorta cheap gay way to die.. i didnt put this hook in cause i wanted pudge wars own , i put it in cause i found it was the coolest hook here :p

so i do not want headshot = true

any fix to this?
 

Kenny

Back for now.
Reaction score
202
*facepalm*

Now that's embarrassing. :p

Version 1.1.1 released. Fixed the bug found by INCINERATE.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top