Spell Pudge Wars (like) Meat Hook

emjlr3

Change can be a good thing
Reaction score
395
The most recent version of this spell requires just about every single system around. This update is much lighter, with very minimal script requirements, built in objectmerger calls, uses the optimized struct array timer method and contains a fix for the WC3 unit facing bug. Enjoy.

Pudge Wars (like) Meat Hook v1.00

Import Difficulty: Low

Units Affected:
Ground/Air

Target Type: Unit/Point - Enemy, Friend, Ground, Terrain, Structure

Spell Info
:

Launches a bloody hook at a unit or location. The hook will snag the first target it encounters, deal damage and drag the victim back to the caster.

Requirements
:

UnitAlive native
ObjectMerger Hotfix
Would also be a good idea to make use of Bound Sentinel

JASS:
scope MeatHook initializer Init
//*********************************************************************
//* Meat Hook v1.00
//* by: emjlr3
//* ----------
//*
//* Requirements:
//*     *A Unit/Point target ability
//*     *The Chain Link dummy unit
//*     *UnitAlive native, found in the custom script section of this map
//*     *A copy of this trigger
//*     *Objectmerger hotfix (<a href="http://www.wc3c.net/showpost.php?p=1050064&amp;postcount=7" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.wc3c.net/showpost.php?p=1050064&amp;postcount=7</a>)
//*         This is required for correct channel based ability mergers
//*
//* (requires vJass)   More abilities at <a href="http://www.thehelper.net/forums" class="link link--internal">http://www.thehelper.net/forums</a>
//*
//* Important:
//*     *There is maximum limit of 100 links/cast.  Make sure your Links
//*     function never returns a value greater then 100.  As such, there
//*     is also an instance limit of 81.  If this limitation does become
//*     a problem, let me know.
//*     *Object merger calls for ability and dummy unit supplied.  Use
//*     them if you want, but they are not required.  If you use the ability
//*     merger call, make sure you first have the aforementioned hotfix.
//*     *FACINGBUG can be used to remove the inherent WC3 facing bug, which
//*     causes non-instant facing upates.  Setting this to true alleviates
//*     this issue, but makes for a more hardware intensive spell.
//*     *SFX strings can be set to &quot;&quot; for no effect
//*
//********************************************************************

//====CONFIGURABLES====\\
//! external ObjectMerger w3u ushd link unam &quot;Chain Link&quot; unsf &quot;(Meat Hook)&quot; uico &quot;ReplaceableTextures\CommandButtons\BTNImpale.blp&quot; umdl &quot;Abilities\Weapons\WardenMissile\WardenMissile&quot; usca 2.0 umvt fly ucol 0.0 ufoo 0 usid 0 usin 0 uabi Aloc urac other utar invulnerable uacq 0.0 ushu &quot;&quot; uhom 1
//! external ObjectMerger w3a ANcl meat anam &quot;Meat Hook&quot; aret &quot;Learn Mea|cffffcc00t|r Hook - [|cffffcc00Level %d|r]&quot; arhk &quot;T&quot; ahky &quot;T&quot; acat &quot;&quot; aeat &quot;&quot; atat &quot;&quot; aart &quot;ReplaceableTextures\CommandButtons\BTNImpale.blp&quot; arar &quot;ReplaceableTextures\CommandButtons\BTNImpale.blp&quot; arut &quot;Launches a bloody hook at a unit or location.  The hook will snag the first target encountered, dealing damage then dragging the victim back to the Butcher.&quot; atp1 1 &quot;Mea|cffffcc00t|r Hook - [|cffffcc00Level 1|r]&quot; aub1 1 &quot;Fires a meat hook at a unit or location.  The hook will snag the first target encountered.&quot; alev 1 aani &quot;attack&quot; Ncl6 1 channel Ncl1 1 .2 atar 1 enemies,friend,ground,terrain,structure Ncl2 1 3 Ncl3 1 5
globals
    private integer     ABIL        = &#039;meat&#039; // Meat Hook ability rawcode
    private string      ATTACH      = &quot;chest&quot; // Attachement point for effects
    private attacktype  ATTACK      = ATTACK_TYPE_CHAOS // Ability damage attacktype
    private damagetype  DAMAGE      = DAMAGE_TYPE_UNIVERSAL // Ability damage damagetype
    private boolean     DISCARD     = true // Discard target if it dies during retract, allowing another target to be hit
    private real        DISTANCE    = 40.0 // Distance between links
    private boolean     FACINGBUG   = false // Correct facing bug
    private boolean     GRAPPLE     = false // Grapple on hit
    private string      HITSFX      = &quot;Objects\\Spawnmodels\\Human\\HumanBlood\\HeroBloodElfBlood.mdl&quot; // Effect created on target when hit 
    private boolean     KILLTREES   = true // Destroy destructables in path of links
    private string      KILLSFX     = &quot;Units\\Undead\\Abomination\\AbominationExplosion.mdl&quot; // Effect created on target if hit kills
    private integer     LINK        = &#039;link&#039; // Chain Link unit rawcode    
    private real        RADIUS      = 100.0 // Hook collision radius
    private boolean     REFLECT     = true // Reflect off structures
    private string      SLIDESFX    = &quot;Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl&quot; // Effect created on target during retract
    private real        TIMEOUT     = 0.033 // Periodic timeout interval
endglobals
private function Damage takes integer lvl returns real
    return 250. // Damage/lvl
endfunction
private function Links takes integer lvl returns integer
    return 30 // Links/lvl, must be &lt;100
endfunction
private function Bool takes unit target returns boolean
    return true // Custom target-boolean function
endfunction
private function onHit takes unit caster, unit target returns nothing
    return // Custom target-on-hit function
endfunction

//====NO TOUCHING!!!!====\\
private keyword data
globals
    private data I
    private unit T
    private group G=CreateGroup()
    private rect R
    
    private data array D
    private timer Tim=CreateTimer()
    private integer C=0
endglobals
private struct data
    unit cast
    unit targ=null
    unit array links[101]
    integer linkstotal=0
    integer linksmin=0
    player p
    boolean hit=false
    boolean extend=true
    boolean grapple=false
    real ang
    real distance=0.
    real maxdistance
    
    method onDestroy takes nothing returns nothing
        local integer i=1
        
        // Remove any left over links
        loop
            exitwhen i&gt;.linkstotal
            if UnitAlive(.links<i>) then
                call RemoveUnit(.links<i>)
            endif
            set i=i+1
        endloop
        // Update target pathing
        if .hit and .targ!=null and not .grapple then
            call SetUnitPathing(.targ,true)
        endif
        if .grapple then
            call SetUnitPathing(.cast,true)
        endif
    endmethod
    
    static method ValidDestructables takes nothing returns boolean
        if GetWidgetLife(GetFilterDestructable())&gt;.405 then
            call KillDestructable(GetFilterDestructable())
        endif
        return false
    endmethod
    
    static method Filt takes nothing returns boolean
        local data this=I
        local real theta
        local real tangent
        local real deflection
        set T=GetFilterUnit()
        
        // Hit a structure
        if IsUnitType(T,UNIT_TYPE_STRUCTURE)==true and UnitAlive(T) then
            call onHit(.cast,T)
            if GRAPPLE and not .hit then
                set .targ=T
                set .hit=not .hit
                set .grapple=not .grapple
                call SetUnitPathing(.cast,false)
            elseif REFLECT then
                set theta=Atan2(GetUnitY(T)-GetUnitY(.links[1]),GetUnitX(T)-GetUnitX(.links[1]))
                if theta&gt;.ang then
                    set tangent=theta+3.14159/2
                else
                    set tangent=theta-3.14159/2
                endif
                set deflection=theta-tangent
                set tangent=ModuloReal(tangent+3.14159, 6.28318)
                set .ang=tangent+deflection
            endif
        // Hit a unit
        elseif Bool(T) and IsUnitType(T,UNIT_TYPE_STRUCTURE)==false and UnitAlive(T) and not .hit and T!=.cast then
            call onHit(.cast,T)
            set .targ=T
            set .hit=not .hit
            if IsUnitEnemy(T,.p) then                
                call UnitDamageTarget(.cast,T,Damage(GetUnitAbilityLevel(.cast,ABIL)),false,false,ATTACK,DAMAGE,null)
                if not UnitAlive(T) then
                    call DestroyEffect(AddSpecialEffectTarget(KILLSFX,T,ATTACH))
                else
                    call DestroyEffect(AddSpecialEffectTarget(HITSFX,T,ATTACH))                    
                endif
            endif   
            if UnitAlive(T) then
                if GRAPPLE then
                    set .grapple = not.grapple
                else
                    call SetUnitPathing(T,false)
                endif
            endif
        endif
        return false
    endmethod
    
    static method Effects takes nothing returns nothing
        local data this
        local real cx
        local real cy
        local real x
        local real y
        local unit h
        local unit last
        local real lang
        local integer i
        
        local integer c=1        
        loop
        exitwhen c&gt;C
        set this=D[c]
        
        set cx=GetUnitX(.cast)
        set cy=GetUnitY(.cast)
        
        // Update target status
        if DISCARD then
            if (not UnitAlive(.targ) or .targ==null) and .hit then
                call SetUnitPathing(.targ,true)
                set .hit=not .hit
                set .targ=null
            endif
        endif
        
        // Filter through available targets
        if .linkstotal&gt;0 then
            call GroupClear(G)
            set I=this
            call GroupEnumUnitsInRange(G,GetUnitX(.links[1]),GetUnitY(.links[1]),RADIUS,Condition(function data.Filt)) 
        endif
        
        if .extend then            
            // Create head
            if .linkstotal==0 then                
                set .links[1]=CreateUnit(.p,LINK,cx+DISTANCE*Cos(.ang),cy+DISTANCE*Sin(.ang),.ang*bj_RADTODEG)
            else 
            // Link creation
                set .links[.linkstotal+1]=CreateUnit(.p,LINK,cx,cy,Atan2(GetUnitY(.links[.linkstotal])-cy,GetUnitX(.links[.linkstotal])-cx)*bj_RADTODEG)
            endif
            set .linkstotal=.linkstotal+1
            
            // Links extend
            set i=1
            set lang=.ang
            loop
                exitwhen i&gt;.linkstotal
                
                set h=.links<i>                
                set x=GetUnitX(h)
                set y=GetUnitY(h)
                if i&gt;1 then
                    set lang=Atan2(GetUnitY(last)-y,GetUnitX(last)-x)
                endif                
                if FACINGBUG then
                    set .links<i>=CreateUnit(.p,LINK,x+DISTANCE*Cos(lang),y+DISTANCE*Sin(lang),lang*bj_RADTODEG)
                    call RemoveUnit(h)
                else
                    call SetUnitX(h,x+DISTANCE*Cos(lang))
                    call SetUnitY(h,y+DISTANCE*Sin(lang))
                    call SetUnitFacing(h,lang*bj_RADTODEG)
                endif
                if KILLTREES then
                    call SetRect(R,GetUnitX(.links<i>)-RADIUS,GetUnitY(.links<i>)-RADIUS,GetUnitX(.links<i>)+RADIUS,GetUnitY(.links<i>)+RADIUS)
                    call EnumDestructablesInRect(R,Condition(function data.ValidDestructables),null)
                endif
                
                set last=.links<i>
                set i=i+1
            endloop
        
            set .distance=.distance+DISTANCE
            if .distance&gt;.maxdistance or .hit then
                set .extend=not .extend
            endif
        else            
            // All done
            if .linksmin&gt;=.linkstotal then
                set D[c]=D[C]
                set C=C-1
                set c=c-1
                call .destroy()
                return
            else
                if .hit and not .grapple then
                    call SetUnitX(.targ,GetUnitX(.links[1]))
                    call SetUnitY(.targ,GetUnitY(.links[1]))
                    if not .grapple then
                        call DestroyEffect(AddSpecialEffectTarget(SLIDESFX,.targ,&quot;origin&quot;))
                    endif
                elseif .grapple then
                    call DestroyEffect(AddSpecialEffectTarget(SLIDESFX,.cast,&quot;origin&quot;))
                endif
            
                // Links retract
                if GRAPPLE and .grapple then
                    // Grapple
                    call SetUnitX(.links[1],GetUnitX(.targ))
                    call SetUnitY(.links[1],GetUnitY(.targ))
                    set i=2
                    set last=.links[1]
                    loop
                        exitwhen i&gt;.linkstotal
                    
                        set h=.links<i>
                        set x=GetUnitX(h)
                        set y=GetUnitY(h)
                        if h==.links[.linkstotal-linksmin] then
                            call ShowUnit(h,false)
                            call SetUnitX(h,99999.)
                            call SetUnitY(h,99999.)
                            call RemoveUnit(h)
                            set lang=Atan2(GetUnitY(last)-GetUnitY(.cast),GetUnitX(last)-GetUnitX(.cast))
                            call SetUnitX(.cast,GetUnitX(last)-DISTANCE*Cos(lang))
                            call SetUnitY(.cast,GetUnitY(last)-DISTANCE*Sin(lang))
                            call SetUnitFacing(.cast,lang*bj_RADTODEG)
                        else
                            set lang=Atan2(GetUnitY(last)-y,GetUnitX(last)-x)
                            if FACINGBUG then
                                set .links<i>=CreateUnit(.p,LINK,GetUnitX(last)-DISTANCE*Cos(lang),GetUnitY(last)-DISTANCE*Sin(lang),lang*bj_RADTODEG)
                                call RemoveUnit(h)
                            else
                                call SetUnitX(h,GetUnitX(last)-DISTANCE*Cos(lang))
                                call SetUnitY(h,GetUnitY(last)-DISTANCE*Sin(lang))
                                call SetUnitFacing(h,lang*bj_RADTODEG)
                            endif
                            if KILLTREES then
                                call SetRect(R,GetUnitX(.links<i>)-RADIUS,GetUnitY(.links<i>)-RADIUS,GetUnitX(.links<i>)+RADIUS,GetUnitY(.links<i>)+RADIUS)
                                call EnumDestructablesInRect(R,Condition(function data.ValidDestructables),null)
                            endif                        
                        endif

                        set last=.links<i>                    
                        set i=i+1
                    endloop
                else
                    // Normal retract
                    set i=.linkstotal-.linksmin
                    set last=.cast
                    loop
                        exitwhen i==0
                
                        set h=.links<i>
                        set x=GetUnitX(h)
                        set y=GetUnitY(h)
                        if h==.links[.linkstotal-linksmin] then
                            call ShowUnit(h,false)
                            call SetUnitX(h,cx)
                            call SetUnitY(h,cy)
                        else
                            set lang=Atan2(GetUnitY(last)-y,GetUnitX(last)-x)
                            if FACINGBUG then
                                set .links<i>=CreateUnit(.p,LINK,GetUnitX(last)-DISTANCE*Cos(lang),GetUnitY(last)-DISTANCE*Sin(lang),(lang*bj_RADTODEG)+180.)
                                call RemoveUnit(h)
                            else
                                call SetUnitX(h,GetUnitX(last)-DISTANCE*Cos(lang))
                                call SetUnitY(h,GetUnitY(last)-DISTANCE*Sin(lang))
                                call SetUnitFacing(h,(lang*bj_RADTODEG)+180.)
                            endif
                            if KILLTREES then
                                call SetRect(R,GetUnitX(.links<i>)-RADIUS,GetUnitY(.links<i>)-RADIUS,GetUnitX(.links<i>)+RADIUS,GetUnitY(.links<i>)+RADIUS)
                                call EnumDestructablesInRect(R,Condition(function data.ValidDestructables),null)
                            endif                        
                        endif

                        set last=.links<i>
                        set i=i-1
                    endloop
                endif
                set .linksmin=.linksmin+1
            endif
        endif           
        
        set c=c+1
        endloop        
        if C==0 then
            call PauseTimer(Tim)
        endif
    endmethod
    
    method Begin takes nothing returns nothing        
        set .cast=GetTriggerUnit()
        set .p=GetOwningPlayer(.cast)
        set .ang=Atan2(GetSpellTargetY()-GetUnitY(.cast), GetSpellTargetX()-GetUnitX(.cast))
        set .maxdistance=Links(GetUnitAbilityLevel(.cast,ABIL))*DISTANCE
        
        set C=C+1
        set D[C]=this
        if C==1 then
            call TimerStart(Tim,TIMEOUT,true,function data.Effects)
        endif
    endmethod
endstruct

private function Conditions takes nothing returns boolean
    local data d
    if GetSpellAbilityId()==ABIL then
        set d=data.create()        
        call d.Begin()
    endif
    return false
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trig=CreateTrigger( )    
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call RemoveUnit(CreateUnit(Player(15),LINK,0.,0.,0.))
    call Preload(HITSFX)
    call Preload(KILLSFX)
    if KILLTREES then
        set R=Rect(0.,0.,0.,0.)
    endif
endfunction

endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


Updates:
1.00
  • Initial release

Suggestions and requests are welcome.
FYI: I have managed to get this up to about 20 instances before lag w/o the facing bug fix, but only about 5 with it.
-emjlr3
 

Attachments

  • emjlr3 - Pudge Wars (like) Meat Hook v1.00.w3x
    112.9 KB · Views: 493

Nestharus

o-o
Reaction score
84
This is very bad practice
[ljass]//! external ObjectMerger w3u ushd link unam "Chain Link" unsf "(Meat Hook)" uico "ReplaceableTextures\CommandButtons\BTNImpale[/ljass]

Try this
http://www.thehelper.net/forums/showthread.php/162668-Lua_get_var_object

Is there a reason that these aren't constants? They are capitalized like they are, perhaps you forgot ;P.
JASS:

    private integer     ABIL        = &#039;meat&#039; // Meat Hook ability rawcode
    private string      ATTACH      = &quot;chest&quot; // Attachement point for effects
    private attacktype  ATTACK      = ATTACK_TYPE_CHAOS // Ability damage attacktype
    private damagetype  DAMAGE      = DAMAGE_TYPE_UNIVERSAL // Ability damage damagetype
    private boolean     DISCARD     = true // Discard target if it dies during retract, allowing another target to be hit
    private real        DISTANCE    = 40.0 // Distance between links
    private boolean     FACINGBUG   = false // Correct facing bug
    private boolean     GRAPPLE     = false // Grapple on hit
    private string      HITSFX      = &quot;Objects\\Spawnmodels\\Human\\HumanBlood\\HeroBloodElfBlood.mdl&quot; // Effect created on target when hit 
    private boolean     KILLTREES   = true // Destroy destructables in path of links
    private string      KILLSFX     = &quot;Units\\Undead\\Abomination\\AbominationExplosion.mdl&quot; // Effect created on target if hit kills
    private integer     LINK        = &#039;link&#039; // Chain Link unit rawcode    
    private real        RADIUS      = 100.0 // Hook collision radius
    private boolean     REFLECT     = true // Reflect off structures
    private string      SLIDESFX    = &quot;Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl&quot; // Effect created on target during retract
    private real        TIMEOUT     = 0.033 // Periodic timeout interval


.032500000 is a better timeout for TIMEOUT since wc3 runs code 32x a second. Better yet, you could use T32.

It also seems better to instantiate hooks. For example, what if we wanted to create a hook type weapon? A little dynamism goes a long way.

You can put this into a boolexpr var [ljass]Condition(function data.Filt)[/ljass]

etc, etc, I can look through more of it later.

Also these should be static ifs
[ljass]if KILLTREES then[/ljass]

And yea, stuff like this is really bad
[ljass]method onDestroy takes nothing returns nothing[/ljass]
 

emjlr3

Change can be a good thing
Reaction score
395
This is very bad practice
[ljass]//! external ObjectMerger w3u ushd link unam "Chain Link" unsf "(Meat Hook)" uico "ReplaceableTextures\CommandButtons\BTNImpale[/ljass]

Try this
http://www.thehelper.net/forums/showthread.php/162668-Lua_get_var_object

people do not have to use it - its there for convenience if desired - and quite frankly it makes things more streamlined if people know what they are doing
Is there a reason that these aren't constants? They are capitalized like they are, perhaps you forgot ;P.
JASS:
    private integer     ABIL        = &#039;meat&#039; // Meat Hook ability rawcode
    private string      ATTACH      = &quot;chest&quot; // Attachement point for effects
    private attacktype  ATTACK      = ATTACK_TYPE_CHAOS // Ability damage attacktype
    private damagetype  DAMAGE      = DAMAGE_TYPE_UNIVERSAL // Ability damage damagetype
    private boolean     DISCARD     = true // Discard target if it dies during retract, allowing another target to be hit
    private real        DISTANCE    = 40.0 // Distance between links
    private boolean     FACINGBUG   = false // Correct facing bug
    private boolean     GRAPPLE     = false // Grapple on hit
    private string      HITSFX      = &quot;Objects\\Spawnmodels\\Human\\HumanBlood\\HeroBloodElfBlood.mdl&quot; // Effect created on target when hit 
    private boolean     KILLTREES   = true // Destroy destructables in path of links
    private string      KILLSFX     = &quot;Units\\Undead\\Abomination\\AbominationExplosion.mdl&quot; // Effect created on target if hit kills
    private integer     LINK        = &#039;link&#039; // Chain Link unit rawcode    
    private real        RADIUS      = 100.0 // Hook collision radius
    private boolean     REFLECT     = true // Reflect off structures
    private string      SLIDESFX    = &quot;Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl&quot; // Effect created on target during retract
    private real        TIMEOUT     = 0.033 // Periodic timeout interval

slipped my mind - and really it only matters if you use the optimizer which inlines all constant global references
.032500000 is a better timeout for TIMEOUT since wc3 runs code 32x a second. Better yet, you could use T32.

It also seems better to instantiate hooks. For example, what if we wanted to create a hook type weapon? A little dynamism goes a long way.

what is an instantiate hook? or dynamism? if you are referring to a grapple effect, that has been included in the config. section
You can put this into a boolexpr var [ljass]Condition(function data.Filt)[/ljass]

etc, etc, I can look through more of it later.
i could also leave it as it with no harm done
Also these should be static ifs
[ljass]if KILLTREES then[/ljass]
what is a static if?
And yea, stuff like this is really bad
[ljass]method onDestroy takes nothing returns nothing[/ljass]
why is that?

I'm not sure which version you are exactly referring to, is it perhaps this?
that would be the one - personally i don't care for spells that rely so heavily on other systems - hell I have seen spells in the past that are a few lines at most, and are 85% other peoples work - especially with so many of the same damn thing to go around, and the ones that are out always changing their ways
 

Nestharus

o-o
Reaction score
84
onDestroy is evaluated in a trigger whereas destroy is not. The trigger is normally only generated if the struct is extended upon.

what is a static if?

If you make your booleans constant, you can use a static if. A static if removes the code if the boolean is false and keeps it in if the boolean is true.

what is an instantiate hook? or dynamism? if you are referring to a grapple effect, that has been included in the config. section

Talking about creating hook objects*, so like being able to set the unit type for a given hook object. Imagine an ORPG where a person wants different types of hook weapons. If you just add a little* more functionality, you can support that.

i could also leave it as it with no harm done

You could increase the number of meat hook thingies w/o lagging the map :p. With periodic type systems, you want to really work at the efficiency so that you can up the maximum instance count.

slipped my mind - and really it only matters if you use the optimizer which inlines all constant global references

Untrue, it matters for static ifs too :p.

people do not have to use it - its there for convenience if desired - and quite frankly it makes things more streamlined if people know what they are doing

You should never generate objects that way, it's unsafe =). If someone wants to generate an object, they should either do it in the object editor or use LUA_GET_VAR_OBJECT. Every other method is chaotic as you can have colliding values and so on. Are you going to make a mapper look through thousands of values in a map to make sure that none of them collide whenever they add in something new? I know I wouldn't ask anyone to do that, that's why I made LUA_GET_VAR_OBJECT, cuz it does it for you : P.
 

BlackRose

Forum User
Reaction score
239
that would be the one - personally i don't care for spells that rely so heavily on other systems - hell I have seen spells in the past that are a few lines at most, and are 85% other peoples work - especially with so many of the same damn thing to go around, and the ones that are out always changing their ways

I don't know if you're targeting Kenny's version within that spell category as system-dependent, but if you are I'd like to take this chance to show it is not the case (considering you also said that it required "just about every single system around"). His version requires three systems, one optional, and even then, these systems aren't the bulk of his ability code.

Kenny's Edition's Requirements said:
GTrigger by Jesus4Lyf.
AIDS by Jesus4Lyf.
T32 by Jesus4Lyf.
AutoFly by Azlier (optional).

GTrigger could easily be removed. Reducing the amount of necessary systems to two. T32 could become hardcoded into the code (and was previously), reducing the needed systems to one. AIDS is actually the only necessary external system for Kenny's version of "Pudge Wars (like) Meat Hook".

It is therefore incorrect to state "The most recent version of this spell requires just about every single system around.".

I will move onto the actual comments relating to your submission.

I find there are things lacking in the demonstration map. Why is the submission ability contained within an item with no descriptive tooltip. "Cast Meat Hook" as a tooltip will not suffice. It should be a learnable hero ability that is levelable, and with a description.

The Meat Hook also barely resembles the behaviour of the Meat Hook in Pudge Wars. The only thing that separates this resource from the generic linear Meat Hook that DotA has is the fact that this hook is not linear! It curves.

JASS:
//*     There is maximum limit of 100 links/cast.  Make sure your Links
//*     function never returns a value greater then 100.  As such, there
//*     is also an instance limit of 81.  If this limitation does become
//*     a problem, let me know.


Seeing as you see this as a lighter version of Kenny's, I'll use his as comparison to this edition. This edition has a maximum instance of 81. Whether that particular instance count will be reached is improbable, but is still an imposing limit due to the fact that each hook can only have 100 links. Kenny's edition does not have this limit, the amount of links (8191 max) able to be sustained is quite high before any noticeable lag comes in.

The behaviour of your edition is ugly like DotAs. Pudge War's hook (Kenny's edition) has a speed setting, for example: it would extend and retract at 800 MS. Yours however does not use this concept of speed. Instead users are forced to use the [LJASS]DISTANCE[/LJASS] variable as some sort of speed modification. The hook is basically a projectile, so you should incorporate the variable speed as a configurable.

The movement is very choppy, have you tried casting Blink with a Meat Hook instance active? It's so awkward and ugly, I have no idea where to begin with trying to explain the faults and bad things about it. I would say this is the result of how you coded this.

You probably were not looking to as accurately recreate the Meat Hook in Pudge Wars as Kenny did, only the smooth visual curve movement. I assume this because of how you state this as a Pudge Wars-like Meat Hook. Even so, it's done badly!

In my opinion, Kenny's edition totally rolls this edition, anyone looking for a Meat Hook ability should use his, not this. The implementation, the configurable options, the neatly laid out code, the comments to assist understand the code, the documentation, and the almost exact recreation of the Pudge Wars [Advanced] Meat Hook is superb. Kenny's edition offers loads more than yours does. The spell section at TheHelper.net already has this ability - it doesn't need an inferiorly done duplicate.

i could also leave it as it with no harm done

One function call every 0.033 seconds, things can quickly add up, efficiency really matters in periodically called code, as Nestharus has mentioned.

(That's all from me about the coding.)
 

emjlr3

Change can be a good thing
Reaction score
395
this is going to get LARGE

onDestroy is evaluated in a trigger whereas destroy is not. The trigger is normally only generated if the struct is extended upon.
if there is another way to run a destroy method, I don't know of it, could you give me an example? I have been out of the game for far too long and I am sure JASSHelper has updated syntax and functionality I know nothing of (not to mention Vexs Engrish leaves much to be desired)



If you make your booleans constant, you can use a static if. A static if removes the code if the boolean is false and keeps it in if the boolean is true.
sounds like fun, now I know.


Talking about creating hook objects*, so like being able to set the unit type for a given hook object. Imagine an ORPG where a person wants different types of hook weapons. If you just add a little* more functionality, you can support that.
I think the user simply making a second trigger with a new unit is sufficient for that need(at least thats always been the way it worked), unless I misunderstand - and if I allow multiple link or head types, how do I allow the user the dynamically select which is for which? ABIL integer arrays? thats seems ugly to me - only the user really knows how they want to implement such a feature, as with bonuses or upgrades, and how dynamic they need them to be


You could increase the number of meat hook thingies w/o lagging the map :p. With periodic type systems, you want to really work at the efficiency so that you can up the maximum instance count.
numbers please, numbers - i doubt not setting that to a boolexpr changes much from a performance standpoint, unless you have proof otherwise...



You should never generate objects that way, it's unsafe =). If someone wants to generate an object, they should either do it in the object editor or use LUA_GET_VAR_OBJECT. Every other method is chaotic as you can have colliding values and so on. Are you going to make a mapper look through thousands of values in a map to make sure that none of them collide whenever they add in something new? I know I wouldn't ask anyone to do that, that's why I made LUA_GET_VAR_OBJECT, cuz it does it for you : P.
again, one more system people need to use - I think some additional implementation explanation for objectmergers will dispell these apparent issues - objectmergers work fine IMO, if used properly, and my rawcodes are a stretch from the norm

I don't know if you're targeting Kenny's version within that spell category as system-dependent, but if you are I'd like to take this chance to show it is not the case (considering you also said that it required "just about every single system around"). His version requires three systems, one optional, and even then, these systems aren't the bulk of his ability code.
i am not targeting anyone or anything, however bold your claims may be - I simply had this lying around, since about '08 if I recall correctly, and decided to upload it, because it had some features Kennys did not, and removed some of the limitations inherant with that version - again, as i stated, I am a fan of lightweight and portable, which the aforementioned wasn't - this is, and some people may appreciate that, because I know I do



GTrigger could easily be removed. Reducing the amount of necessary systems to two. T32 could become hardcoded into the code (and was previously), reducing the needed systems to one. AIDS is actually the only necessary external system for Kenny's version of "Pudge Wars (like) Meat Hook".

It is therefore incorrect to state "The most recent version of this spell requires just about every single system around.".
whether or not it takes little effort to port a spell from one system to another, or to use no system at all is irrelavent - the previous requires many systems, that quite frankly most people probably don't employ - requiring them to bloat their map with previously unrequired script to satisfy the needs of one spell is a silly limitation - and expecting the individual who actually needs or wants to use spells from the TH inventory to be able to accomplish said feat is unrealistic at best


I find there are things lacking in the demonstration map. Why is the submission ability contained within an item with no descriptive tooltip. "Cast Meat Hook" as a tooltip will not suffice. It should be a learnable hero ability that is levelable, and with a description.
that is the route I went. the first post sums it up pretty well - and sticking it in an item allows the user to quickly get into the action without the need for leveling a hero or abilities - whats important, the demonstration of the ability or a pretty tooltip? there are plenty of friendly and enemy units about - though I should throw some buildings in - and that reminds me to add in the functionality of bouncing off raised terrain

The Meat Hook also barely resembles the behaviour of the Meat Hook in Pudge Wars. The only thing that separates this resource from the generic linear Meat Hook that DotA has is the fact that this hook is not linear! It curves.
not true. just from the outside looking in, without respect for the actual code(where the differences are absolute), some obvious differences are - allowing the user to move while casting, deflection off buildings, ability to discard targets mid hook, differentiation between grab only and grab kill sfx, ability to instate a grapple effect, destruction of trees in path of hook links, slide sfx, relastic location and swing update of hook links dynamically, and with respect for the coding, well, the comparisons stop at simply the spell name
JASS:
//*     There is maximum limit of 100 links/cast.  Make sure your Links
//*     function never returns a value greater then 100.  As such, there
//*     is also an instance limit of 81.  If this limitation does become
//*     a problem, let me know.


Seeing as you see this as a lighter version of Kenny's, I'll use his as comparison to this edition. This edition has a maximum instance of 81. Whether that particular instance count will be reached is improbable, but is still an imposing limit due to the fact that each hook can only have 100 links. Kenny's edition does not have this limit, the amount of links (8191 max) able to be sustained is quite high before any noticeable lag comes in.
first off, lets get things straight - this is not a light version of kennys - i did not even look at his code, apart from the system reqs, its a light version of meat hook, with respect for previous versions released
now your objection is just silly, 100 links is massive, first off, and is a simple thing to alleviate, if, like I mention, anyone manages to reach that cap - I could have used linked lists, like the previous, but there is another system requirement - beyond that, approaching 81 instances is even sillier, as I doubt most cpus could handle even half that - now seeing what he did, the reason his has no cap (or the built in WC3 instance cap) is because he's creating and using multiple structs per unit(or link), which I doubt bodes well for performance - I don't have time to compare fps drops, but I am pretty sure I know which will come out on top
The behaviour of your edition is ugly like DotAs. Pudge War's hook (Kenny's edition) has a speed setting, for example: it would extend and retract at 800 MS. Yours however does not use this concept of speed. Instead users are forced to use the [LJASS]DISTANCE[/LJASS] variable as some sort of speed modification. The hook is basically a projectile, so you should incorporate the variable speed as a configurable.
speed isn't an option, which seems to be your first valid argument - interval and distance can be used simply enough to create a feel of speed (1/interval)*distance=speed - thats not a half bad suggestion
The movement is very choppy, have you tried casting Blink with a Meat Hook instance active? It's so awkward and ugly, I have no idea where to begin with trying to explain the faults and bad things about it. I would say this is the result of how you coded this.
here is where one of the major differences comes into play -unlike Pudge Wars(or what I can remember of it), and this version, Kennys updates link length as the hero moves, independant of the total chain length, which is just silly - if the chain is to extend X distance, why would it extend X+Y if the caster moves Y in some direction - it would still extend X, but now the difference between where it would have extended to and where it will extend to will be Y (assuming scalar movement) - that is really for the user to decide what they want - to me this method makes more sense, rather than spawning links out of thin air

Even so, it's done badly!
i beg to differ

In my opinion, Kenny's edition totally rolls this edition, anyone looking for a Meat Hook ability should use his, not this. The implementation, the configurable options, the neatly laid out code, the comments to assist understand the code, the documentation, and the almost exact recreation of the Pudge Wars [Advanced] Meat Hook is superb. Kenny's edition offers loads more than yours does. The spell section at TheHelper.net already has this ability - it doesn't need an inferiorly done duplicate.
i don't really think his offers anything this doesn't, but it does however lack some of those bonuses this version has to offer (such as unit facing correction)
this code is very neat, and commented for developers - implementation is straight forward, and overall much easier and more streamlined

not quite sure why you are so far up someones ass, or seem to want to denounce everything I have done, especially in the abscence of defamation from myself, but its getting old fast.


One function call every 0.033 seconds, things can quickly add up, efficiency really matters in periodically called code, as Nestharus has mentioned.
where is this coming from?
 

Nestharus

o-o
Reaction score
84
[ljass]method destroy takes nothing returns nothing[/ljass]

requires deallocate be called

numbers please, numbers - i doubt not setting that to a boolexpr changes much from a performance standpoint, unless you have proof otherwise...

Reading a variable is faster than calling a native =p, and again, remember this runs almost 32x a second. You should really use .031250000

where is this coming from?

He just means that wc3 can only execute so much code per second, so you adding on to the code w/o a care in the world increases the map's chance to lag. This is the reason why, whenever doing low period period code, you have to make it as efficient as possible by inlining every single call and reducing the amount of locals allocated to the bare minimum and reducing global reads/array reads to the minimum and reducing native calls to the minimum. Function call minimum is almost always 0.
 

emjlr3

Change can be a good thing
Reaction score
395
where does it say WC3 runs code 32x a second? and why would decreasing my timer interval increase performance?

so "method destroy" would run just the same as "method onDestroy" when calling .destroy ?? only its faster??? what is deallocate? either way its not a periodic function call

different natives are slower then others - and globals are generally slower to boot (compared to locals) - I somehow doubt that storing the Condition to a global makes it execute faster, especially since either way you are calling a function, no?

so you adding on to the code w/o a care in the world increases the map's chance to lag
where did I do this? I recall one subjective optimization suggestion, other then the "static if" one - unless I really missed something, I don't see places for massive efficiency improvement
 

Nestharus

o-o
Reaction score
84
[ljass]exitwhen i>.linkstotal[/ljass]

loop backwards

[ljass]call .destroy()[/ljass]
should be inlined, use a struct that extends an array with your own allocation/deallocation
so you can inline


.031250000 won't increase performance, but it's the lowest possible period as wc3 runs code 32x a second. It's used for projectiles and etc and is kind of a standard period. The 0s are required, or it'll be .031250002


See
http://www.hiveworkshop.com/forums/...ls-280/coding-efficient-vjass-structs-187477/


Also, destroy doesn't automatically call deallocate when it's used. Normally, destroy is auto generated to call deallocate and then evaluate the trigger for onDestroy.

When you create a destroy, if you are not using a struct that extends an array, you have to deallocate the instance first, then do your stuff.

I again suggest a struct that extends an array so you can inline the deallocation and destruction to increase efficiency.


And reading from a global array is faster than calling a native. It was proven with the player conversion natives, which are faster than the Condition conversion natives =P. You can be dern sure that reading from a plain global is faster than reading from a global array =P.
 

emjlr3

Change can be a good thing
Reaction score
395
call .destroy()
should be inlined, use a struct that extends an array with your own allocation/deallocation
so you can inline

english please, my background does not lend well to programming lingo
 

Nestharus

o-o
Reaction score
84
JASS:

struct MyStruct extends array
    private static integer instanceCount = 0 //total instances of your struct
    private static integer array recycler       //recycles instances
    debug private static boolean array allocated

    static method create takes nothing returns thistype
        local thistype this
        if (recycler[0] == 0) then //create a new instance
            set instanceCount = instanceCount + 1
            set this = instanceCount
        else //use a previously destroyed instance
            set this = recycler[0]
            set recycler[0] = recycler[this]
        endif
        debug set allocate[this] = true

        //perform creation code

        return this
    endmethod

    method destroy takes nothing returns nothing
        debug if (allocate[this]) then //only destroy allocated
            debug set allocated[this] = false
            set recycler[this] = recycler[0]
            set recycler[0] = this

            //destruction code
        debug endif
    endmethod
endstruct


I'm saying to essentially do that so you can inline the destroy
JASS:

            set recycler[this] = recycler[0]
            set recycler[0] = this

            //destruction code


Inline means that rather than calling destroy, you cnp the code you need into the calling method. For example, wherever you call destroy, you'd replace it with its inner code ;P

JASS:

        loop
            exitwhen i&gt;.linkstotal
            if UnitAlive(.links<i>) then
                call RemoveUnit(.links<i>)
            endif
            set i=i+1
        endloop
        // Update target pathing
        if .hit and .targ!=null and not .grapple then
            call SetUnitPathing(.targ,true)
        endif
        if .grapple then
            call SetUnitPathing(.cast,true)
        endif
</i></i>


This cuts down the function calls and increases speed at the cost of maintainability and readability. Normally, it doesn't really matter, but with low period timer things like this, it really does =P.

Also, it would help if you made all of your variable names short. Long variable names are slower than short ones, and they really matter in low period timers =P.
 

BlackRose

Forum User
Reaction score
239
Indeed it shall get large :3

i am not targeting anyone or anything, however bold your claims may be - I simply had this lying around, since about '08 if I recall correctly, and decided to upload it, because it had some features Kennys did not, and removed some of the limitations inherant with that version - again, as i stated, I am a fan of lightweight and portable, which the aforementioned wasn't - this is, and some people may appreciate that, because I know I do

Okay.

whether or not it takes little effort to port a spell from one system to another, or to use no system at all is irrelavent - the previous requires many systems, that quite frankly most people probably don't employ - requiring them to bloat their map with previously unrequired script to satisfy the needs of one spell is a silly limitation - and expecting the individual who actually needs or wants to use spells from the TH inventory to be able to accomplish said feat is unrealistic at best

T32, AIDS, and GT are quite common systems. But okay, you're right, the fact is not everyone is going to use them, and indeed, the possibility of importing systems that are used by one thing is silly.

that is the route I went. the first post sums it up pretty well - and sticking it in an item allows the user to quickly get into the action without the need for leveling a hero or abilities - whats important, the demonstration of the ability or a pretty tooltip? there are plenty of friendly and enemy units about - though I should throw some buildings in - and that reminds me to add in the functionality of bouncing off raised terrain

Even though the submission post is nice, the aim behind it all is to make it as presentable as possible. I don't really like the idea of putting the ability inside an item just for user convienence, it takes seconds to levelup, and learn the ability. It simply looks neater and more consistant when it's a hero ability. The ability demonstratation is obviously more important, but it doesn't hurt to make things more presentable when you have the opportunity to do so.

not true. just from the outside looking in, without respect for the actual code(where the differences are absolute), some obvious differences are - allowing the user to move while casting, deflection off buildings, ability to discard targets mid hook, differentiation between grab only and grab kill sfx, ability to instate a grapple effect, destruction of trees in path of hook links, slide sfx, relastic location and swing update of hook links dynamically, and with respect for the coding, well, the comparisons stop at simply the spell name

Okay, perhaps I did wrongly compare. DotA's Meat Hook is just terrible :C I shouldn't have said there was minimal difference, that was wrong of me.

first off, lets get things straight - this is not a light version of kennys - i did not even look at his code, apart from the system reqs, its a light version of meat hook, with respect for previous versions released

Okay.

now your objection is just silly, 100 links is massive, first off, and is a simple thing to alleviate, if, like I mention, anyone manages to reach that cap - I could have used linked lists, like the previous, but there is another system requirement

Someone may want to have a super long hook. Users will want to keep the distance spacing the same to make it look smooth, but still be able to have a long hook range. 4000 is the max range for your version (as it is now), there could be longer hooks than this. If it helps, I don't see what's so bad about the system requirement. You can even do the linked list code inside the meat hook scope to avoid it.

- beyond that, approaching 81 instances is even sillier, as I doubt most cpus could handle even half that - now seeing what he did, the reason his has no cap (or the built in WC3 instance cap) is because he's creating and using multiple structs per unit(or link), which I doubt bodes well for performance - I don't have time to compare fps drops, but I am pretty sure I know which will come out on top

Reaching that instance count can still happen.

here is where one of the major differences comes into play -unlike Pudge Wars (or what I can remember of it), and this version, Kennys updates link length as the hero moves, independant of the total chain length, which is just silly - if the chain is to extend X distance, why would it extend X+Y if the caster moves Y in some direction - it would still extend X, but now the difference between where it would have extended to and where it will extend to will be Y (assuming scalar movement) - that is really for the user to decide what they want - to me this method makes more sense, rather than spawning links out of thin air

I don't really understand this unfortunately. Do you mind explaining more?

i beg to differ

Lol. Sorry about that, I shouldn't have added that.

i don't really think his offers anything this doesn't, but it does however lack some of those bonuses this version has to offer (such as unit facing correction)

Correct unit facing is quite taxing on performance, unit creating/removing that is. Also, why is there a need for a 'unit facing correction'? It looked fine, or so it did in Pudge Wars. I have no idea what you have done. I believe it was the design of how you coded it (I noticed a few other strange things as well when I tested it.) I shall elaborate more on this later.

this code is very neat, and commented for developers - implementation is straight forward, and overall much easier and more streamlined

Depending on your definition of neat and the context, I would say the complete opposite! I find the presentation, the variable naming, the spacing, the formatting, and so on, rather messy. Stuff like this is something I can't bear to read, which is why I didn't really say anything about the code. This is just me though.

JASS:
.
            if .linkstotal==0 then   // It&#039;s just me, but I can&#039;t stand it, lol.             
                set .links[1]=CreateUnit(.p,LINK,cx+DISTANCE*Cos(.ang),cy+DISTANCE*Sin(.ang),.ang*bj_RADTODEG)
            else


The commenting is basic, his basically gives a step-by-step explanation on everything, something I like and others do too.

As for implementation, yeah, I guess yours is much simpler, directly just copy paste, save map to generate objects, and then run that random object merger fix.
 

emjlr3

Change can be a good thing
Reaction score
395
I don't really understand this unfortunately. Do you mind explaining more?

lets say the user wants X number of hooks, or by extrapolation, a link Y distance in length

in my version, if the hero moves, or blinks, to another spot, the chain still extends y distance in length, like the user wanted

however, in Kennys, if this happens, the chain now extends abs(scalar diff. between past and curr hero loc)+y total distance - which to me makes no sense

Correct unit facing is quite taxing on performance, unit creating/removing that is. Also, why is there a need for a 'unit facing correction'? It looked fine, or so it did in Pudge Wars. I have no idea what you have done. I believe it was the design of how you coded it (I noticed a few other strange things as well when I tested it.) I shall elaborate more on this later.

in WC3, when you use the SetUnitFacing native, units slowly update their facing to that angle specified, its not instant, as it should be in a spell such as this - perhaps Pudge Wars uses an updated link model with instant facing updates, I have no clue - and yes this is incredible taxing on the cpu, which I mention in the documentation

run that random object merger fix.

the random object merge fix is actually a hotfix released for objectmerger that everyone should have updeated to at some point (they are executable updates), but unfortuantely the change was not documented or marketed well

@Nestharus - that looks like too much damned extra work to me :(
 

Nestharus

o-o
Reaction score
84
Well, your script can be improved, so you should do them ;P. It's not like you'll ever look at the code again once you've got it perfect, right? = ).

I know I haven't looked at the code in UnitIndexer or UnitEvent in a very long time ;D.
 

tooltiperror

Super Moderator
Reaction score
231
Well, seeing as this was closed, I would assume it was by emjlr himself, as he wanted to update it.

But it's been awhile, and for the sake of keeping T&R restricted to resources being actively worked on, I will graveyard it.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top