• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Hooks won't connect properly -_-

Status
Not open for further replies.
Level 8
Joined
Feb 3, 2013
Messages
277
Trouble with Meathook Spell -__-

NEW EDIT:
I cleand it up even more making sure every struct extends array and deleted all this other crap I felt it didn't need (to help me understand).

BTW credit to the original guy : Kenny on TH

JASS:
library LinkedMeatHook

/**************************************************************************/
/*                                                                        */
/*              Linked Meat Hook v1.0                                     */
/*                  by: msongyyy                                          */
/*                                                                        */ 
/*      HOW TO IMPORT:                                                    */
/*          1. Import dummy units MeatHook - head and chain and           */
/*             and the meathook ability                                   */
/*          2. Import this trigger and the headshot.wav file              */
/*          3. Setup configurables to your liking                         */
/*                                                                        */
/*             Enjoy ^^                                                   */
/*                                                                        */
/*      THANKS TO: (PLEASE READ)                                          */
/*          1. ****BIG THANKS TO KENNY, TROLLVOTEL, AND TOSSROCK*****     */
/*             THIS TRIGGER IS EDITED ON TOP OF KENNY'S, WHICH            */
/*             WAS INSPIRED BY TROLLVOTEL'S REINVENTION OF TOSSROCK'S     */
/*             MEAT HOOK SKILL IN HIS CUSTOM MOD PUGDE WARS.              */
/*                                                                        */
/*             NONE OF THIS WOULD BE POSSIBLE WITHOUT THEIR VIEWS         */
/*             AND ORIGINAL CREATION. I LEARNED A LITTLE BIT MORE         */
/*             THANKS TO KENNY'S ORIGINAL VERSION, SO TRULY THANKS        */
/*             TO HIM MORE THAN MOST)                                     */
/*                                                                        */
/*          2. THANKS TO MR_BEAN, FOR THAT ONE IMPORTANT READ             */
/*          3. THANKS TO HIVE, FOR GREAT COMMUNITY                        */
/*                                                                        */
/*                                                                        */
/*                HAVING SAID THAT, PLEASE CHECK KENNY'S                  */
/*                VERSION ON THE HELPER                                   */
/*                                                                        */
/*                                                                        */
/**************************************************************************/
    
    globals
        private constant integer    ABIL_ID          = 'A000'
        private constant integer    HEAD_ID          = 'h002'
        private constant integer    LINK_ID          = 'h001'
        private constant integer    LOCUST_ID        = 'Aloc'
    endglobals
    
/**************************************************************************/
/*      START OF CONFIGURABLES                                            */
/**************************************************************************/
    
    globals
        private constant real       MAX_HEIGHT       = 40.00
        private constant real       UNIT_RADIUS      = 225.00
        private constant real       BUILD_RADIUS     = 270.00
        private constant real       DEST_RADIUS      = 270.00
        private constant real       TIME_SCALE       = 1.00
        private constant real       HEAD_SCALE       = 5.00
        private constant real       LINK_SCALE       = 3.00
        private constant real       FLY_HEIGHT       = 75.00
        private constant real       DEST_DMG_PERC    = 0.00
        private constant real       HEADSHOT_DMG     = 999999999999999999999999999999.00
        
        private constant string     BLOOD_SFX        = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
        private constant string     BLOOD_POINT      = "origin"
        private constant string     HEADSHOT_FX      = "Units\\Undead\\Abomination\\AbominationExplosion.mdl"
        private constant string     HEADSHOT_SOUND   = "war3mapImported\\headshot.wav"
        private constant integer    HEADSHOT_VOL     = 127
        
        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_HEADSHOT   = true
        private constant boolean    ALLOW_PRELOAD    = true
        private constant boolean    ALLOW_BOUNCE     = true
        private constant boolean    DEST_BOUNCE      = true
        private constant boolean    ABOVE_CASTER     = false
        private constant boolean    DISCARD_TARGET   = false
        private constant boolean    KILL_DESTS       = false
        
        private constant timer      TMR              = CreateTimer()
        private constant real       INC              = 45.00
        private constant real       PERIOD           = .03125000
        private constant hashtable  HASH             = InitHashtable()
    endglobals

    private constant function MAXDIST takes integer lvl returns real
        return 5000.00 + (2000.00 * lvl)
    endfunction

    private constant function DAMAGE takes integer lvl returns real
        return 50.00 + (75.00 * lvl)
    endfunction
    
    private constant function SPEED takes integer lvl returns real
        return 2000.00 + (0000.00  * lvl)
    endfunction
    
    private function FilterUnits takes unit filter returns boolean
        return GetUnitFlyHeight(filter) < MAX_HEIGHT and GetUnitAbilityLevel(filter,LOCUST_ID) == 0
    endfunction
    
/**************************************************************************/
/*      END OF CONFIGURABLES                                              */
/**************************************************************************/
    
    // To make peoples happy. To bad there is no WidgetAlive native.
    native UnitAlive takes unit id returns boolean
    
    private struct Link extends array // Individual links in the linked list for units.

        thistype next       // Next link in the list.
        thistype prev       // Previous link in the list.
        unit     link       // The actual chain link.
        
        static integer array rn
        static integer ic = 0
        
        static method create takes nothing returns thistype
            local thistype this = rn[0]
            
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else
                set rn[0] = rn[this]
            endif
            
            set .next = 0
            set .prev = 0
            set .link = null
        
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call RemoveUnit(this.link)
            set this.link = null
            
            set rn[this] = rn[0]
            set rn[0] = this
        endmethod
    endstruct
   
    //---------------------------------------------------------------------\\
    private struct List extends array // Linked list to hold all the units that make the chain.

        Link    head    // First link in the list.
        Link    last    // Last link in the list.
        integer size    // Size of the list.
        
        static integer array rn
        static integer ic = 0
        
        static method create takes nothing returns thistype
            local thistype this = rn[0]
            
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else
                set rn[0] = rn[this]
            endif
            
            set .head = 0
            set .last = 0
            set .size = 0
            
            return this
        endmethod
        
        // 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.
        method destroy takes nothing returns nothing
            // Just to make sure no links are left.
            loop
                exitwhen this.size == 0
                call this.detach(this.last)
            endloop
            
            set rn[this] = rn[0]
            set rn[0] = this
        endmethod
    
    endstruct
    //---------------------------------------------------------------------\\
    private struct Hook extends array// Struct that takes care of the rest.
    
        // Instance members.
        unit     cast       // The caster.
        unit     targ       // The possible target.
        unit     head       // The head of the chain.
        player   own        // The owner of the caster.
        
        real     ang        // The angle the chain is travelling in.
        real     dist       // The current distance travelled.
        real     max        // Maximum distance of the hook.
        real     cos        // Cos of the current angle.
        real     sin        // Sin of the current angle.
        real     speed      // Speed of the hook, saves function calls.
        
        integer  level      // Level of the Meat Hook spell for the caster.
        List     list       // Linked list needed to track chain links.
        
        boolean  ret        // If the hook is extending.
        boolean  hit        // If a unit has been hit.
        
        // 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.
        
        static integer array prev
        static integer array next
        static integer array rn
        static integer ic = 0
        
        // 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
            local sound shot
            set this.targ = target
            set this.hit  = true
    
            // 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
            
            if ALLOW_HEADSHOT then
                if HaveSavedBoolean(HASH, GetHandleId(this.targ), 0) then
                    call UnitDamageTarget(this.cast, this.targ, HEADSHOT_DMG, true, false, A_TYPE, D_TYPE, W_TYPE)
                    call DestroyEffect(AddSpecialEffect(HEADSHOT_FX, GetUnitX(this.targ), GetUnitY(this.targ)))
                    call FlushChildHashtable(HASH, GetHandleId(this.targ))
                    
                    set shot = CreateSound(HEADSHOT_SOUND,false,false,false,10,10,"")
                    call SetSoundVolume(shot, HEADSHOT_VOL)
                    call StartSound(shot)
                    call KillSoundWhenDone(shot)
                else
                    call SaveBoolean(HASH, GetHandleId(this.targ), 0, true)
                endif
            endif
                    
            // Stop the hook from moving.
            call SetUnitTimeScale(this.head,0.00)
            
            return true
        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(filt) then
                    if not this.hit then
                        call this.setTarget(filt)
                    endif
                endif
            endif
            
            set filt = null
            
            return false
        endmethod
        
        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(filt) then
                    static if ALLOW_BOUNCE then // If bouncing is allowed, then set the new angle.
                        call this.setAngle(GetUnitX(filt),GetUnitY(filt))
                    endif
                endif
            endif
            
            set filt = null
            
            return false
        endmethod
        
        // Retract the hook.
        method retract takes nothing returns nothing
            local Link    linkx = 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 > (INC) then   
                // Using a loop so the hooks work when great distances are covered in a short time.
                loop
                    exitwhen dist <= (INC) // Create as many links as needed to fill the gap.
                    set ang2 = Atan2((casy - temy),(casx - temx))
                    set temx = temx + (INC) * Cos(ang2)
                    set temy = temy + (INC) * 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)
                        
                    // 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 - INC
                endloop
            endif
            
            // 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 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
            
            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,(INC)) 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, INC) then
                    call this.list.detach(linkx)
                    // Detach the link if needed.
                endif
                
                // Set the chain links new position.
                call SetUnitX(temp,temx + this.speed * Cos(ang2))
                call SetUnitY(temp,temy + this.speed * Sin(ang2))
                
                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 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 > (INC) then 
                // Using a loop so the hooks work when great distances are covered in a short time.
                loop
                    exitwhen dist <= (INC) // Create as many links as needed to fill the gap.
                    set ang2 = Atan2((casy - temy),(casx - temx))
                    set temx = temx + (INC) * Cos(ang2)
                    set temy = temy + (INC) * 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)
                    
                    // 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 - INC
                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,(INC)) 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.
        static method periodic takes nothing returns nothing
            local thistype this = next[0]
            
            loop
                exitwhen this == 0 
                if this.list.size == 0 then // If the hook is done.
                    call this.list.destroy() // Destroy the unit list.
                    call FlushChildHashtable(HASH, GetHandleId(this.targ)) // Get rid of headshot boolean stored in unit

                    // Clear struct members.
                    set this.cast = null
                    set this.targ = null
                    set this.head = null
                    
                    set next[prev[this]] = next[this]
                    set prev[next[this]] = prev[this]
                    set rn[this] = rn[0]
                    set rn[0] = this
                else
                    if this.ret then        // If the hook is retracting.
                        call this.retract() // Keep retracting.
                    else                    // Otherwise.  
                        call this.extend()  // Extend it.
                    endif
                endif
                
                set this = next[this]
            endloop
            
            if next[0] == 0 then
                call PauseTimer(TMR)
            endif
        endmethod
        
        // Start of the hook, assembles struct members and stuff.
        static method actions takes nothing returns nothing
            local thistype this = rn[0]
            local real     casx = 0.00
            local real     casy = 0.00
            
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else
                set rn[0] = rn[this]
            endif
            
            // 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) * PERIOD
            set this.max   = MAXDIST(this.level)
            set this.dist  = 0.00
            
            set this.ret   = false 
            set this.hit   = false 
            
            
            // 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)
            
            // Basically do what T32 does for you
            set prev[this] = prev[0]
            set next[this] = 0
            set next[prev[0]] = this
            set prev[0] = this
            
            if prev[this] ==  0 then
                call TimerStart(TMR, PERIOD, true, function thistype.periodic)
            endif
        endmethod
        
        static method Cond takes nothing returns boolean
            local unit lvCaster = GetTriggerUnit()
            local real x 
            local real y
            
            if GetSpellAbilityId() == ABIL_ID then
                call thistype.actions()
            endif
            
            set lvCaster = null
            return false 
        endmethod
        
        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 trigger t = CreateTrigger()
            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 TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.Cond))
            
            // 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
                
                call TimerStart(CreateTimer(), .1, false, function thistype.loadSound)
            endif
            
            set t = null
        endmethod
        
    endstruct
    
endlibrary
Now... the part that confuses me the most.
JASS:
    private struct Link extends array // Individual links in the linked list for units.

        thistype next       // Next link in the list.
        thistype prev       // Previous link in the list.
        unit     link       // The actual chain link.
        
        static integer array rn
        static integer ic = 0
        
        static method create takes nothing returns thistype
            local thistype this = rn[0]
            
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else
                set rn[0] = rn[this]
            endif
            
            set .next = 0
            set .prev = 0
            set .link = null
        
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call RemoveUnit(this.link)
            set this.link = null
            
            set rn[this] = rn[0]
            set rn[0] = this
        endmethod
    endstruct
   
    //---------------------------------------------------------------------\\
    private struct List extends array // Linked list to hold all the units that make the chain.

        Link    head    // First link in the list.
        Link    last    // Last link in the list.
        integer size    // Size of the list.
        
        static integer array rn
        static integer ic = 0
        
        static method create takes nothing returns thistype
            local thistype this = rn[0]
            
            if this == 0 then
                set ic = ic + 1
                set this = ic
            else
                set rn[0] = rn[this]
            endif
            
            set .head = 0
            set .last = 0
            set .size = 0
            
            return this
        endmethod
        
        // 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.
        method destroy takes nothing returns nothing
            // Just to make sure no links are left.
            loop
                exitwhen this.size == 0
                call this.detach(this.last)
            endloop
            
            set rn[this] = rn[0]
            set rn[0] = this
        endmethod
    
    endstruct
I don't fully understand this concept - the second struct, has two members of struct type 'Link' - but after it gets compiled, it will turn into integer arrays not 'Link' arrays. So how can something like lead to being capable of holding 8191 units in a total of 8191 instances??? I mean it works but I'm just so confused... ned help again :<

I'm not sure if this make sense but it's like taking something 2D and making it 3D? Wat da heck?
Like I could imagine setting a static integer array member and capping a max instance number,... but this is like having an array member in an array struct.
ㄱㄱㄱㄱㄱㄱ
 

Attachments

  • Linked Meathook v1.0.w3x
    60 KB · Views: 64
Last edited:
Level 8
Joined
Feb 3, 2013
Messages
277
yea same here, I made the regular meat hook probably at least like 10 times, but I didn't undersatnd how to make it linked and stuff... btw a lot of this is ripped off another guy's code - What I did was take out all the systems it relies on, cleaned it to the bare minimum so I can understand how his code works.

btw anyone know what ModuloReal and Rabs is for in math?
 
Status
Not open for further replies.
Top