Spell Pudge Wars Meat Hook

Trollvottel

never aging title
Reaction score
262
I know there is already one made by me but it was graveyarded and is not very nice. So i made a new one.
Needs vJass, TT, PUI and my custom function library.
Yeah i know its not 100% the pudge wars meat hook, but it looks quite similar.

A few (bad) screenshots:
neubitmap2qc7.jpg

neubitmapdr0.jpg

Well.... better test it yourself.. ;)




Now the (terrible) code (well, 450 lines + the custom functions):

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 1050. + 200. * lvl
    endfunction

    private function Damage takes integer lvl returns real
        return 110.  + 50.  * lvl // configure your damage
    endfunction
    
    private function Speed takes integer lvl returns real
        return 450. + 150.  * lvl // configure your speed
    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
                
                if hook.len == 0 then
                    
                    set angletonext = hook.directionangle
                    
                    set hook.link[hook.len] = CreateUnit(GetOwningPlayer(hook.hooker), CHAINID, nx , ny ,angletonext)
                else
                    set hook.link[hook.len] = CreateUnit(GetOwningPlayer(hook.hooker), CHAINID, llx+CHAINEVERY*Cos(angletonext*DTR) , lly+CHAINEVERY*Sin(angletonext*DTR) ,angletonext-180)
                endif
                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_MeatHook = CreateTrigger (                                                 )
    call TriggerRegisterAnyUnitEventBJ  ( gg_trg_MeatHook, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction               ( gg_trg_MeatHook,           function Actions     )
    call TriggerAddCondition            ( gg_trg_MeatHook, Condition(function Conditions) )
endfunction

endscope

And now the map:
YOU NEED THE JASS NEWGEN PACK TO USE THIS SPELL!!!!
View attachment Meathook.w3xView attachment Meathook.w3x
 

BRUTAL

I'm working
Reaction score
118
looks nice from the screenshots
i dont got newgen so i cant test it out XD
 

T.s.e

Wish I was old and a little sentimental
Reaction score
133
> Kunai?
Some knife-like throwing weapon thingy used by ninjas.

Nice spell btw, I just have to do this:
fishystick.jpg

+Rep
 

Trollvottel

never aging title
Reaction score
262
thank you :)
okay now i googled what a kunai is ^^.

New version:
-made the movement better and disabled the attack of the chain members (they tried to attack enemys -.-)
 

waaaks!

Zinctified
Reaction score
255
nice....please make more and be unique, not copying spells from other games...+rep

ill use this in RotG Reborn if this is approved
 

Trollvottel

never aging title
Reaction score
262
thank you :)

well this spell needs indeed improvement, but i am working on it.

New version out:

- Better chain/move system
- A few Bugfixes

to do:

- make a better bounce system
 

Trollvottel

never aging title
Reaction score
262
i didnt test it in an AoS, but it doesnt lagg in my tests (with up to 5 hooks at the same time). If you want a good performance you can reduce the max amount of chain-dummys and increase the CHAINEVERY integer so you need less chains for the same distance. I think ill test the performance soon.

fixed stupid bug which messed up the hook when hook a unit when retracting the chain (it simply stopped)

Major update:

Bouncing works perfectly now.
Hook bounces before leaving the map.
 

waaaks!

Zinctified
Reaction score
255
hey...how about structures? maybe the hook will snag structures...

EDIT:
ok tested it and it doesnt snag structures, how about cliffs? does it bounce to cliffs? its better if u add an option if the hook bounces on a cliff or not

because there are some people who wanted to make the hook bounce on cliffs, and some dont want to bounce on cliffs, like me
 

Insane!

Shh I didn't edit this, go away.
Reaction score
122
can you add an option to where the hook hits a building it snags it (doesnt retract) and does dammage (then retracts).
 

Kazuga

Let the game begin...
Reaction score
110
Is there anything special I need to do or download in order to use this spell in a custom map? Reason to this post is that I have had huge problems with importing jass spells earlier =/
 

Trollvottel

never aging title
Reaction score
262
all you need is listed in the spell comment

// WHAT IS NEEDED:
// * vJass (Jass NewGen Pack)
// * TT (Timer Ticker)
// * PUI (Perfect Unit Indexing)
// * the UsedFuncs library, my personal code collection with useful functions
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    So what it really is me trying to implement some kind of better site navigation not change the whole theme of the site
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/

      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