• 🏆 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!

[JASS] Modify this spell

Status
Not open for further replies.
Level 8
Joined
Dec 16, 2007
Messages
252
This is a spell made by Trollvottel, it's a meat hook spell similar to the one in Pudge Wars, it bounces on buildings and end of the map.

JASS:
scope MeatHook

// ==================================MEAT HOOK BY TROLLVOTTEL==================================
// || How to import:                                                                         ||
// || *  Copy the systems TT and PUI and the library UsedFuncs into your map                 ||
// || *  Copy this trigger into your map, change it's name to MeatHook                       ||
// || *  Copy the chain dummy and the hookhead dummy into your map                           ||
// || *  Change the values below, the function have an argument (lvl) which refers to the    ||
// || *  level of the ability for the caster                                                 ||
// ============================================================================================

// WHAT IT DOES:
//    * It's a meathook quite similar to the one from pudge wars made by me
//    * It connects the hook and the caster with chains
//    * It is retracted before leaving the playable map area
//    * It bounces off buildings.
//    * It looks quite nice
// WHAT IS NEEDED:
//    * vJass
//    * TT (Timer Ticker)
//    * PUI (Perfect Unit Indexing)
//    * the UsedFuncs library, my personal code collection with useful functions


    globals
        private constant integer RAWID      = 'A000' // Ability id
        private constant integer CHAINID    = 'h001' // chain dummy id
        private constant integer HOOKHEADID = 'h000' // hook head id
        private constant real CHAINEVERY    = 30.    // every X wc3 units a chain link
        private constant integer MAXCHAINS  = 60     // max amount of chains
        private constant real RADIUS        = 80.    // radius to grab units
    endglobals
     
    private function Distance takes integer lvl returns real
        return 2000.
    endfunction

    private function Damage takes integer lvl returns real
        return 40.                  
    endfunction
    
    private function Speed takes integer lvl returns real
        return 600.
    endfunction
    
    
    
    //==============================SPELL BEGINS HERE==============================
    //------DONT CHANGE ANYTHING BELOW OR ANGELS WILL COME DOWN AND KILL YOU------\\
    globals 
        public boolean array ISHOOKED
    endglobals
        
private struct Meathook 
    unit array  link            [MAXCHAINS]
    integer     len             = 0
    real        movement 
    unit        hooker
    unit        hookhead
    boolean     hooked          = false
    unit        hooktarg        = null
    real        directionangle
    real        angleCos
    real        angleSin
    real        dis             = 0.
    real        rangepassed     = 0.
    real        distance        = 0.
    
        method launch takes unit which, real direction returns nothing
            set .hooker         = which
            set .directionangle = direction
            set .movement       = Speed     ( GetUnitAbilityLevel( .hooker, RAWID ) ) * TT_PERIOD
            set .angleCos       = Cos       ( direction * DTR ) *.movement
            set .angleSin       = Sin       ( direction * DTR ) *.movement
            set .hookhead       = CreateUnit( GetOwningPlayer( which ), HOOKHEADID, GetUnitX( which ), GetUnitY( which ), direction)
            set .distance       = Distance  ( GetUnitAbilityLevel( .hooker, RAWID ) ) 
            call TT_Start(function Meathook.fly, this)
        endmethod
        
        static method fly takes nothing returns boolean
            local Meathook hook = TT_GetData(             )
            local real cx       = GetUnitX  ( hook.hooker )
            local real cy       = GetUnitY  ( hook.hooker )
            local real nx
            local real ny
            local real lx 
            local real ly 
            local real llx 
            local real lly
            local real angletonext
            local real distance
            local real angle
            local real angle2
            local real absmod
            
            local integer index = hook.len
            local group g
            local unit u
            local boolean flag = false
            

            
            // Chain moving
            
            loop
               
                
                set lx  = GetUnitX(hook.link[index])
                set ly  = GetUnitY(hook.link[index])
                
                set llx = GetUnitX(hook.link[index-1])
                set lly = GetUnitY(hook.link[index-1])
            
                set angletonext = Atan2(ly-lly,lx-llx)
                call SetSafeX(hook.link[index],llx+CHAINEVERY * Cos(angletonext))
                call SetSafeY(hook.link[index],lly+CHAINEVERY * Sin(angletonext))
                call SetUnitFacingTimed(hook.link[index], angletonext * RTD - 180,0)
                               
                
                
                set index = index - 1
                exitwhen index < 1
            endloop
            
            set lx  = GetUnitX(hook.link[0])
            set ly  = GetUnitY(hook.link[0])

        
            set llx = GetUnitX(hook.hookhead)
            set lly = GetUnitY(hook.hookhead)
            
            set angletonext = Atan2( lly - ly, llx - lx )
            
            set nx = lx + hook.movement * Cos(angletonext) 
            set ny = ly + hook.movement * Sin(angletonext) 
            
            call SetSafeX(hook.link[0],GetUnitX(hook.hookhead))
            call SetSafeY(hook.link[0],GetUnitY(hook.hookhead))
            call SetUnitFacingTimed(hook.link[0], angletonext, 0)
            
            // Hook forward and avoid leaving the map
            
            set lx = GetUnitX(hook.hookhead)
            set ly = GetUnitY(hook.hookhead)
            
            set nx = lx + hook.angleCos
            set ny = ly + hook.angleSin
            
            if not IsPointInMap(nx,ny) then
            
                if ny != SafeY(ny) then
                    set hook.directionangle = -hook.directionangle
                else
                    set hook.directionangle = 180-hook.directionangle               
                endif
                
                set hook.angleCos = hook.movement * Cos(hook.directionangle * DTR)
                set hook.angleSin = hook.movement * Sin(hook.directionangle * DTR)
                set nx = lx + hook.angleCos
                set ny = ly + hook.angleSin
            endif
   
            call SetSafeX(hook.hookhead,nx)
            call SetSafeY(hook.hookhead,ny)
            
            
            
   
   
   
            // new chain link
            set hook.dis = hook.dis + hook.movement
            if  hook.dis >= CHAINEVERY and hook.len < 2 then
                set llx = GetUnitX(hook.link[hook.len-1])
                set lly = GetUnitY(hook.link[hook.len-1])
                
                
                set angletonext = Atan2(cy-lly,cx-llx) * RTD
                
 
                set hook.link[hook.len] = CreateUnit(GetOwningPlayer(hook.hooker), CHAINID, llx+CHAINEVERY*Cos(angletonext*DTR) , lly+CHAINEVERY*Sin(angletonext*DTR) ,angletonext-180)
                set hook.len = hook.len + 1                
                set hook.dis = 0.
                if hook.len > MAXCHAINS-2 then
                    set flag = true
                endif
            endif
            
            set lx = GetUnitX(hook.link[hook.len-1])
            set ly = GetUnitY(hook.link[hook.len-1])
            
            set distance = SquareRoot(SquareDistance(lx,ly,cx,cy))
            
            if distance >= CHAINEVERY and hook.len > 1 and flag == false then
                set hook.dis = 0.
                set angletonext = Atan2(cy-ly,cx-lx)
                set nx = lx + CHAINEVERY * Cos(angletonext)
                set ny = ly + CHAINEVERY * Sin(angletonext)
                set hook.link[hook.len] = CreateUnit(GetOwningPlayer(hook.hooker), CHAINID, nx , ny ,angletonext*RTD-180)
                set hook.len = hook.len + 1
                

            
                if hook.len > MAXCHAINS-2  then
                    set flag = true
                endif
            endif
            
            set hook.rangepassed = hook.rangepassed + hook.movement
            
            if hook.rangepassed >= hook.distance then
                set flag = true
            endif
            
            //  Getting Units
            set lx = GetUnitX(hook.hookhead)
            set ly = GetUnitY(hook.hookhead)
            
            set g = CreateGroup()
            call GroupEnumUnitsInRange(g,lx,ly,RADIUS,AliveGroundFilter)
            
            loop
                set u = FirstOfGroup(g)
                call GroupRemoveUnit(g,u)
                
                exitwhen u == null
                
                if  hook.hooker != u  then
                    
                    if IsUnitEnemy( u, GetOwningPlayer(hook.hookhead)) then
                        call UnitDamageTarget(hook.hooker,u, Damage(GetUnitAbilityLevel(hook.hooker, RAWID)), true, false, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                    endif
                    if ISHOOKED[GetUnitIndex(u)] != true then
                        set ISHOOKED[GetUnitIndex(u)] = true
                        set hook.hooked = true
                        set hook.hooktarg = u
                        call SetUnitTimeScale(hook.hookhead,0)
                    else 
                        call CreateTextTagDefault("HEADSHOT!!", "|cffff0000", GetUnitX(hook.hookhead), GetUnitX(hook.hookhead))
                        call UnitDamageTarget(hook.hooker,u, 1000000000., true, false, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                    endif
                    set flag = true
                    exitwhen true
                endif
            endloop
            call DestroyGroup(g)
            set g = null
            
            // Bounce off buildings
            if flag == false then
                set g = CreateGroup()
                set lx = GetUnitX(hook.hookhead)
                set ly = GetUnitY(hook.hookhead)
                set angle = hook.directionangle
                
                call GroupEnumUnitsInRange(g,lx,ly,RADIUS*1.55,AliveBuildingFilter)
                
                loop 
                    set u = FirstOfGroup(g)
                    
                    exitwhen u == null
                    
                    call GroupRemoveUnit(g,u)
                
                    set llx = GetUnitX(u)
                    set lly = GetUnitY(u)
                    
                    set angle2 = ModuloReal(Atan2(ly-lly, lx-llx) * bj_RADTODEG,360)
                    set absmod = RAbsBJ(angle2 - angle)
                    
                    if absmod >= 90 and absmod <= 270  then
                        if ( angle2 > 45 and angle2 < 135 ) or ( angle2 > 225 and angle2 < 315 ) then
                            set hook.directionangle = -angle
                        else
                            set hook.directionangle = 180-angle
                        endif
                                
                        set hook.angleSin = Sin( hook.directionangle * DTR ) * hook.movement
                        set hook.angleCos = Cos( hook.directionangle * DTR ) * hook.movement
                    endif
                    set u = null
            
                endloop
                call DestroyGroup(g)
                set g = null
            endif
            
           
            
            
            
            
            if flag == true then
                call TT_Start(function Meathook.reverse, hook)
            endif
            return flag
        endmethod
        
        static method reverse takes nothing returns boolean
            local Meathook hook = TT_GetData()
            local real cx = GetUnitX(hook.hooker)
            local real cy = GetUnitY(hook.hooker)
            local real nx
            local real ny
            local real lx 
            local real ly 
            local real llx 
            local real lly
            
            local integer index = 0
            local real angletonext
            local real distance
            local group g
            local unit u
            local boolean flag = false
 
            //link remove
            set lx = GetUnitX(hook.link[hook.len-1])
            set ly = GetUnitY(hook.link[hook.len-1])
            
            set nx = lx-cx
            set ny = ly-cy
            set distance = SquareRoot(nx*nx+ny*ny)
            
            if distance <= CHAINEVERY then
                call KillUnit(hook.link[hook.len-1])
                call ShowUnit(hook.link[hook.len-1],false)
                set hook.len = hook.len - 1
                if hook.len <= 1 then
                    set flag = true
                endif
            else
                set angletonext = Atan2(cy-ly,cx-lx)
                set nx = lx + hook.movement * Cos(angletonext)
                set ny = ly + hook.movement * Sin(angletonext)
                call SetSafeX(hook.link[hook.len-1],nx)
                call SetSafeY(hook.link[hook.len-1],ny)
                call SetUnitFacingTimed(hook.link[hook.len-1], (angletonext)*RTD+180,0)             
            endif
            
            if hook.len <= 1 then
                    set flag = true
            endif
            
            

            //chain move
            
            loop
                exitwhen index > hook.len - 2
                
                set lx = GetUnitX(hook.link[index])
                set ly = GetUnitY(hook.link[index])
                
                set llx = GetUnitX(hook.link[index+1])
                set lly = GetUnitY(hook.link[index+1])
                
                set distance = SquareRoot(SquareDistance(lx,ly,llx,lly))
                
                if distance <= CHAINEVERY then
                
                    set angletonext = Atan2(lly-ly,llx-lx)
                    
                    set nx = lx + hook.movement * Cos(angletonext)
                    set ny = ly + hook.movement * Sin(angletonext)
                    
                    call SetSafeX(hook.link[index],nx)
                    call SetSafeY(hook.link[index],ny)
                    call SetUnitFacing(hook.link[index], (angletonext)*RTD+180)
                
                else
                
                    set angletonext = Atan2(ly-lly,lx-llx)
                    
                    set nx = llx + CHAINEVERY * Cos(angletonext)
                    set ny = lly + CHAINEVERY * Sin(angletonext)
                    
                    call SetSafeX(hook.link[index],nx)
                    call SetSafeY(hook.link[index],ny)
                    call SetUnitFacing(hook.link[index], (angletonext)*RTD)
 
                endif
                
                set index = index + 1
            endloop
            
            //hook move
            
            set lx = GetUnitX(hook.hookhead)
            set ly = GetUnitY(hook.hookhead)
            set llx = GetUnitX(hook.link[0])
            set lly = GetUnitY(hook.link[0])
            

            

                set angletonext = Atan2(ly-lly,lx-llx)
                
                set nx = llx + CHAINEVERY * Cos(angletonext)
                set ny = lly + CHAINEVERY * Sin(angletonext)           

            call SetSafeX(hook.hookhead,nx)
            call SetSafeY(hook.hookhead,ny)
                
            if hook.hooked == true then
                call SetSafeX(hook.hooktarg,nx)
                call SetSafeY(hook.hooktarg,ny)
            else
                set g = CreateGroup()
                call GroupEnumUnitsInRange(g,nx,ny,RADIUS,AliveGroundFilter)
                loop
                    set u = FirstOfGroup(g)
                    call GroupRemoveUnit(g,u)
                
                    exitwhen u == null
                    
                    if  hook.hooker != u  then
                    
                        if IsUnitEnemy( u, GetOwningPlayer(hook.hookhead)) then
                            call UnitDamageTarget(hook.hooker,u, Damage(GetUnitAbilityLevel(hook.hooker, RAWID)), true, false, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                        endif
                        if ISHOOKED[GetUnitIndex(u)] != true then
                            set ISHOOKED[GetUnitIndex(u)] = true
                            set hook.hooked = true
                            set hook.hooktarg = u
                            call SetUnitTimeScale(hook.hookhead,0)
                        else
                            call CreateTextTagDefault("HEADSHOT!!", "|cffff0000", GetUnitX(hook.hookhead), GetUnitY(hook.hookhead))
                            call UnitDamageTarget(hook.hooker,u, 1000000000., true, false, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                        endif
                        exitwhen true
                        
                    endif                
                endloop
            
            endif
            
            
            if flag == true then
                call hook.destroy()
            endif
            
            return flag
        endmethod
        
        method onDestroy takes nothing returns nothing
            call KillUnit(.hookhead)
            call ShowUnit(.hookhead,false)
            call KillUnit(.link[0])
            call ShowUnit(.link[0],false)
            if .hooked == true then
                call SetUnitX(.hooktarg,GetUnitX(.hooker))
                call SetUnitY(.hooktarg,GetUnitY(.hooker))
                set ISHOOKED[GetUnitIndex(.hooktarg)] = false
            endif
        endmethod
endstruct

private function Actions takes nothing returns nothing
    local Meathook hook = Meathook.create()
    local unit cast = GetTriggerUnit()
    local real cx = GetUnitX(cast)
    local real cy = GetUnitY(cast)
    local location loc = GetSpellTargetLoc()
    local real tx = GetLocationX(loc)
    local real ty = GetLocationY(loc)
    local real angle = Atan2(ty-cy,tx-cx) * RTD
    call RemoveLocation(loc)
    set loc = null
    call hook.launch(cast,angle)
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == RAWID
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    set gg_trg_Snipehook = CreateTrigger (                                                 )
    call TriggerRegisterAnyUnitEventBJ  ( gg_trg_Snipehook, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction               ( gg_trg_Snipehook,           function Actions     )
    call TriggerAddCondition            ( gg_trg_Snipehook, Condition(function Conditions) )
endfunction

endscope

Can someone please post me a code where this spell also bounces on a specific terrain type? For example Square Tiles from Citycape.

I think it's this part that bounces on buildings, but I have no idea how to modify it so it will bounce on a specific terrain type.

JASS:
          set lx = GetUnitX(hook.hookhead)
            set ly = GetUnitY(hook.hookhead)
            
            set g = CreateGroup()
            call GroupEnumUnitsInRange(g,lx,ly,RADIUS,AliveGroundFilter)
            
            loop
                set u = FirstOfGroup(g)
                call GroupRemoveUnit(g,u)
                
                exitwhen u == null
                
                if  hook.hooker != u  then
                    
                    if IsUnitEnemy( u, GetOwningPlayer(hook.hookhead)) then
                        call UnitDamageTarget(hook.hooker,u, Damage(GetUnitAbilityLevel(hook.hooker, RAWID)), true, false, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                    endif
                    if ISHOOKED[GetUnitIndex(u)] != true then
                        set ISHOOKED[GetUnitIndex(u)] = true
                        set hook.hooked = true
                        set hook.hooktarg = u
                        call SetUnitTimeScale(hook.hookhead,0)
                    else 
                        call CreateTextTagDefault("HEADSHOT!!", "|cffff0000", GetUnitX(hook.hookhead), GetUnitX(hook.hookhead))
                        call UnitDamageTarget(hook.hooker,u, 1000000000., true, false, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                    endif
                    set flag = true
                    exitwhen true
                endif
            endloop
            call DestroyGroup(g)
            set g = null
            
            // Bounce off buildings
            if flag == false then
                set g = CreateGroup()
                set lx = GetUnitX(hook.hookhead)
                set ly = GetUnitY(hook.hookhead)
                set angle = hook.directionangle
                
                call GroupEnumUnitsInRange(g,lx,ly,RADIUS*1.55,AliveBuildingFilter)
                
                loop 
                    set u = FirstOfGroup(g)
                    
                    exitwhen u == null
                    
                    call GroupRemoveUnit(g,u)
                
                    set llx = GetUnitX(u)
                    set lly = GetUnitY(u)
                    
                    set angle2 = ModuloReal(Atan2(ly-lly, lx-llx) * bj_RADTODEG,360)
                    set absmod = RAbsBJ(angle2 - angle)
                    
                    if absmod >= 90 and absmod <= 270  then
                        if ( angle2 > 45 and angle2 < 135 ) or ( angle2 > 225 and angle2 < 315 ) then
                            set hook.directionangle = -angle
                        else
                            set hook.directionangle = 180-angle
                        endif
                                
                        set hook.angleSin = Sin( hook.directionangle * DTR ) * hook.movement
                        set hook.angleCos = Cos( hook.directionangle * DTR ) * hook.movement
                    endif
                    set u = null
            
                endloop
                call DestroyGroup(g)
                set g = null
            endif
 
Last edited:
Right, done it...

underneath this:
JASS:
globals
        private constant integer RAWID = 'A000' // Ability id
        private constant integer CHAINID = 'h001' // chain dummy id
        private constant integer HOOKHEADID = 'h000' // hook head id
        private constant real CHAINEVERY = 30. // every X wc3 units a chain link
        private constant integer MAXCHAINS = 60 // max amount of chains
        private constant real RADIUS = 80. // radius to grab units
    endglobals

    private function Distance takes integer lvl returns real
        return 2000.
    endfunction

    private function Damage takes integer lvl returns real
        return 40.
    endfunction

    private function Speed takes integer lvl returns real
        return 600.
    endfunction
put this:
JASS:
private function IsTerrainTypeBounce takes integer typeId returns boolean
        return typeId == 'Ysqd'
    endfunction
Don't forget to change that return value to what you want. BTW 'Ysqd' is cityscape square tiles.


also, replace this:
JASS:
// Bounce off buildings
            if flag == false then
                set g = CreateGroup()
                set lx = GetUnitX(hook.hookhead)
                set ly = GetUnitY(hook.hookhead)
                set angle = hook.directionangle

                call GroupEnumUnitsInRange(g,lx,ly,RADIUS*1.55,AliveBuildingFilter)

                loop
                    set u = FirstOfGroup(g)

                    exitwhen u == null

                    call GroupRemoveUnit(g,u)

                    set llx = GetUnitX(u)
                    set lly = GetUnitY(u)

                    set angle2 = ModuloReal(Atan2(ly-lly, lx-llx) * bj_RADTODEG,360)
                    set absmod = RAbsBJ(angle2 - angle)

                    if absmod >= 90 and absmod <= 270 then
                        if ( angle2 > 45 and angle2 < 135 ) or ( angle2 > 225 and angle2 < 315 ) then
                            set hook.directionangle = -angle
                        else
                            set hook.directionangle = 180-angle
                        endif

                        set hook.angleSin = Sin( hook.directionangle * DTR ) * hook.movement
                        set hook.angleCos = Cos( hook.directionangle * DTR ) * hook.movement
                    endif
                    set u = null

                endloop
                call DestroyGroup(g)
                set g = null
            endif
with this:
JASS:
set lx = GetUnitX(hook.hookhead)
            set ly = GetUnitY(hook.hookhead)
            
            // Bounce off buildings
            if flag == false then
                set g = CreateGroup()
                set angle = hook.directionangle

                call GroupEnumUnitsInRange(g,lx,ly,RADIUS*1.55,AliveBuildingFilter)

                loop
                    set u = FirstOfGroup(g)

                    exitwhen u == null

                    call GroupRemoveUnit(g,u)

                    set llx = GetUnitX(u)
                    set lly = GetUnitY(u)

                    set angle2 = ModuloReal(Atan2(ly-lly, lx-llx) * bj_RADTODEG,360)
                    set absmod = RAbsBJ(angle2 - angle)

                    if absmod >= 90 and absmod <= 270 then
                        if ( angle2 > 45 and angle2 < 135 ) or ( angle2 > 225 and angle2 < 315 ) then
                            set hook.directionangle = -angle
                        else
                            set hook.directionangle = 180-angle
                        endif

                        set hook.angleSin = Sin( hook.directionangle * DTR ) * hook.movement
                        set hook.angleCos = Cos( hook.directionangle * DTR ) * hook.movement
                    endif
                    set u = null

                endloop
                call DestroyGroup(g)
                set g = null
            endif
            
            //bounce off terrain types
            if IsTerrainTypeBounce(GetTerrainType(lx, ly)) then
                set angle = hook.directionangle
                
                set llx = GetUnitX(u)
                set lly = GetUnitY(u)

                set angle2 = ModuloReal(Atan2(ly-lly, lx-llx) * bj_RADTODEG,360)
                set absmod = RAbsBJ(angle2 - angle)

                if absmod >= 90 and absmod <= 270 then
                    if ( angle2 > 45 and angle2 < 135 ) or ( angle2 > 225 and angle2 < 315 ) then
                        set hook.directionangle = -angle
                    else
                        set hook.directionangle = 180-angle
                    endif
                        
                    set hook.angleSin = Sin( hook.directionangle * DTR ) * hook.movement
                    set hook.angleCos = Cos( hook.directionangle * DTR ) * hook.movement
                endif
            endif
 
Status
Not open for further replies.
Top