Need Help with a Trip Wire Spell (and mysterious null variables)

Jonnycakes

New Member
Reaction score
6
Hi, I have been trying to make a trip wire ability-the premise is that the user targets two trees and then a trip wire is created between the two trees. If an enemy unit crosses the wire, it explodes. I am using Anitarf's spell here as a reference, but I am still running into a lot of problems.

The initial ability ('A00N') is based off of sentinel-when it is cast, the trigger stops the unit and forces the owner to hit the hotkey (T for trip wire) again, creating another tree selection cursor. Now the fun stuff happens-the unit gets a new instant cast dummy ability based on channel and the trigger spams its hotkey (L) for the player. If the second tree targeting is canceled, the dummy spell will be used, canceling the cast and triggering a clean-up of any variables involved.

This is where I am having issues. The function that is supposed to be spamming "L" is running, but the player variable that stores the owner of the casting unit (this.owner) is null for some reason. I can't figure out why this is, because when the struct (target) is created, .owner is NOT null. Shortly afterward, it is. Can anyone help me out on this one? (If you find other errors, that is appreciated as well!)

NOTE: I have only worked on the first part of this spell, which sets up the trip wire. It is fully functional as is-it just doesn't actually set up the trip wire. I will add the second half when I figure this out.

EDIT: Attached a test map. The unit is the mechanic, the spell is trip wire, and the current trigger is Trip Wire NEW. There are some BJDebugs that may get annoying as well-just a warning.


JASS:
scope tripwire initializer init

globals
    private hashtable h=InitHashtable()
endglobals

private function CheckTree takes destructable tree1, destructable tree2 returns boolean
    local real x=GetDestructableX(tree1)
    local real y=GetDestructableY(tree1)
    local real xx=GetDestructableX(tree2)
    local real yy=GetDestructableY(tree2)
    return true
    //return SquareRoot((xx-x)*(xx-x)+(yy-y)*(yy-y))<=600 and tree1!=tree2
endfunction

private struct trip
    unit caster
    player owner
    destructable tree1
    destructable tree2
    lightning l
    real duration
    
    private integer index
    private static trip array wire
    private static integer count=0
    private static timer time
endstruct


private struct target
    unit caster
    player owner
    destructable tree1
    
    private integer index=1
    static target array targ
    private static integer count=1
    private static timer time
    
    static method create takes unit u, destructable tree returns target
        local target t=target.allocate()
        set t.caster=u
        set t.owner=GetOwningPlayer(u)
        set t.tree1=tree
        set t.index=-1
        return t
    endmethod
    
    static method spam takes nothing returns nothing
        local integer i=1
        loop
            exitwhen i==target.count
            if GetLocalPlayer()==target.targ<i>.owner then
                call ForceUIKey(&quot;l&quot;)
            endif
            //if target.targ<i>.owner==null then
                //call BJDebugMsg(&quot;null &quot;+I2S(i))
            //endif
            set i=i+1
        endloop
    endmethod
    
    
    method start takes nothing returns nothing
        set .index=target.count
        call UnitAddAbility(.caster, &#039;A00C&#039;)
        call SaveInteger(h, GetHandleId(.caster), 0, .index)
        if GetLocalPlayer()==.owner then
            call ForceUIKey(&quot;t&quot;)
        endif
        if .owner==null then
            call BJDebugMsg(&quot;null owner&quot;)
        endif
        if target.count==1 then
            call TimerStart(target.time, .1, true, function target.spam)
        endif
        set target.count=target.count+1
        call BJDebugMsg(&quot;start  &quot;+I2S(target.count))
    endmethod
    
    method stop takes nothing returns nothing
        set target.count=target.count-1
        set target.targ[target.count].index=.index
        set target.targ[.index]=target.targ[target.count]
        set .index=-1
        if target.count==1 then
            call PauseTimer(target.time)
        endif
        call BJDebugMsg(&quot;stop  &quot;+I2S(target.count))
    endmethod
    
    static method onInit takes nothing returns nothing
        set target.time=CreateTimer()
    endmethod
        
endstruct

private function spellcast takes nothing returns boolean
    local unit u
    local target t
    local destructable tree
    
    if GetIssuedOrderId()==OrderId(&quot;sentinel&quot;) then
        set u=GetTriggerUnit()
        set tree=GetOrderTargetDestructable()
        if LoadInteger(h, GetHandleId(u), 0)==null then  //the unit has not cast the first target
            set t=target.create(u, tree)
            if t.caster==null or t.owner==null or t.tree1==null then
                call BJDebugMsg(&quot;null struct create&quot;)
            endif
            call DisableTrigger(GetTriggeringTrigger())
            call PauseUnit(u, true)
            call IssueImmediateOrder(u, &quot;stop&quot;)
            call PauseUnit(u, false)
            call EnableTrigger(GetTriggeringTrigger())
            call t.start()
        else    //the unit HAS cast the first target, validate second now...
            set t=target.targ[LoadInteger(h, GetHandleId(u), 0)]
            call t.stop()
            call FlushChildHashtable(h, GetHandleId(u))
            call UnitRemoveAbility(u, &#039;A00C&#039;)
            if CheckTree(t.tree1, tree) then
            else
                call DisableTrigger(GetTriggeringTrigger())
                call PauseUnit(u, true)
                call IssueImmediateOrder(u, &quot;stop&quot;)
                call PauseUnit(u, false)
                call EnableTrigger(GetTriggeringTrigger())
                call t.start()
            endif
        endif
        set u=null
        set tree=null
    endif
    return false
endfunction

private function spelleffect takes nothing returns boolean
    local unit u
    local target t
    
    if GetSpellAbilityId()==&#039;A00N&#039; then
        set u=GetTriggerUnit()
        set t=target.targ[LoadInteger(h, GetHandleId(u), 0)]
        call trip.create()
        //call t.destroy()
        call FlushChildHashtable(h, GetHandleId(u))
        call UnitRemoveAbility(u, &#039;A00C&#039;)
        set u=null
    endif
    
    return false
endfunction

private function cancel takes nothing returns boolean
    local unit u
    local target t
    if GetIssuedOrderId()==OrderId(&quot;channel&quot;) then
        set u=GetOrderedUnit()
        set t=target.targ[LoadInteger(h, GetHandleId(u), 0)]
        call t.stop()
        call FlushChildHashtable(h, GetHandleId(u))
        call UnitRemoveAbility(u, &#039;A00C&#039;)
        call t.destroy()
        set u=null
    endif
    return false
endfunction

private function herotype takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit())==&#039;H003&#039;
endfunction

//===========================================================================
private function init takes nothing returns nothing
    local trigger t=CreateTrigger()
    local integer x=0
    call TriggerAddCondition(t, Condition(function spellcast))
    loop
        exitwhen x==12
        call TriggerRegisterPlayerUnitEvent(t, Player(x), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, Filter(function herotype))
        set x=x+1
    endloop
    
    set x=0
    set t=CreateTrigger()
    call TriggerAddCondition(t, Condition(function spelleffect))
    loop
        exitwhen x==12
        call TriggerRegisterPlayerUnitEvent(t, Player(x), EVENT_PLAYER_UNIT_SPELL_EFFECT, Filter(function herotype))
        set x=x+1
    endloop
    
    set x=0
    set t=CreateTrigger()
    call TriggerAddCondition(t, Condition(function cancel))
    loop
        exitwhen x==12
        call TriggerRegisterPlayerUnitEvent(t, Player(x), EVENT_PLAYER_UNIT_ISSUED_ORDER, Filter(function herotype))
        set x=x+1
    endloop
    set t=null
endfunction
endscope</i></i>
 

Attachments

  • Trip Wire Test.w3x
    53 KB · Views: 131

Viikuna

No Marlo no game.
Reaction score
265
Not sure yet, you should however think if it is safe to use player variable there in the first place. Units owner might change and fuck the things up, which is probably why Anitarf did it like this: [lJASS]GetLocalPlayer()==GetOwningPlayer(trg.cancelList.caster)[/lJASS].

The other option would be to [lJASS]hook SetUnitOwner[/lJASS] native, if thats the only source of owner change in your map.



Anyways, dont really know what could change that owner variable like that... Lemme think this a little.

Providing a test map would be cool. Also these multi targetting scripts tend to be tricky. I remember Pyrogasm having some nasty problems with his Multi targetting system, and Im not even sure if that Tripwire works properly.
 

Jonnycakes

New Member
Reaction score
6
Well, the owner of the unit should never change. The map is a style which each player gets to choose one hero, and they will never change ownership, especially not in the middle of casting a (this) spell. I will attach a test map to the initial post once i figure out how :p

EDIT: done and done.
 

Viikuna

No Marlo no game.
Reaction score
265
Been testing it over and over again, with no luck. Cancel detection seems to be broken, and owner just is somehow null.


Anyways, Im trying something new now. I hope it works...


edit. Got frustrated to that shit and made a different kind of tripwire mechanic demo thinggy for you.

This method has its own downsides, though. I think its still worth of checking out.


edit2. Hrm. Silly me. If you wanted to do it this way, youd naturally use SpellChannelResponse first tree, which triggers before actually casting, and would save you from lot of trouble, cause you could simply abort the spell before Effect responses trigger... Not having to worry about making that cast not look like a cast...

Anyways. Damn.
 

Attachments

  • Trip Wire Test.w3x
    66.4 KB · Views: 131

Jonnycakes

New Member
Reaction score
6
Well, I think your method works a lot better than Anitarf's XD I looked through your test map and liked it a lot (especially how you add the lightning before the second cast). I may add in the spell channel event later, but I have a nice, working version now. Here is the new one that I created-there are a few new features:

-can't cast a tripwire that is too long or targets the same tree (it changes color if the caster moves out of range after targeting the first tree)

-the targeting sequence is aborted if the first tree is destroyed

-the cancel skill now gets added after the first tree is targeted so the player can abort the targeting manually (the icon is a cancel button)



Thank you for creating that demo map! It helped me a lot! +rep (nm, won't let me :()

JASS:
scope tripwire initializer init

globals
    private hashtable h=InitHashtable()
endglobals

private struct target
    unit caster
    real x1
    real y1
    real x2
    real y2
    destructable tree
    lightning l
    
    private integer index=1
    static target array targ
    private static integer count=1
    private static timer time
    
    static method render takes nothing returns nothing
        local real x
        local integer i=1
        local target t
        
        loop
            exitwhen i==target.count
            set t=target.targ<i>
            set t.x2=GetUnitX(t.caster)
            set t.y2=GetUnitY(t.caster)
            set x=1
            if SquareRoot((t.x2-t.x1)*(t.x2-t.x1)+(t.y2-t.y1)*(t.y2-t.y1))&gt;600 then
                set x=.5
            endif
            call MoveLightning(t.l, true, t.x1, t.y1, t.x2, t.y2)
            if GetLocalPlayer()==GetOwningPlayer(t.caster) then
                call SetLightningColor(t.l, x, x, x, 1)
            endif
            if GetDestructableLife(t.tree)&lt;=0 then
                call t.destroy()
                set i=i-1
            endif
            set i=i+1
        endloop
    endmethod
    
    static method create takes unit u, destructable tree returns target
        local target t=target.allocate()
        set t.caster=u
        call UnitAddAbility(u, &#039;A00C&#039;)
        set t.tree=tree
        set t.x1=GetDestructableX(tree)
        set t.y1=GetDestructableY(tree)
        set t.x2=GetUnitX(u)
        set t.y2=GetUnitY(u)
        set t.l=AddLightning(&quot;DRAM&quot;, true, t.x1, t.y1, t.x2, t.y2)
        call SetLightningColor(t.l, 1, 1, 1, 0)
        set t.index=target.count
        call SaveInteger(h, GetHandleId(u), 0, t.index)
        set target.targ[target.count]=t
        set target.count=target.count+1
        if target.count==2 then 
            call TimerStart(target.time, .04, true, function target.render)
        endif
        return t
    endmethod
    
    method onDestroy takes nothing returns nothing
        call DestroyLightning(.l)
        call UnitRemoveAbility(.caster, &#039;A00C&#039;)
        call FlushChildHashtable(h, GetHandleId(.caster))
        set target.count=target.count-1
        set target.targ[.index]=target.targ[target.count]
        set target.targ[.index].index=.index
        if target.count==1 then
            call PauseTimer(target.time)
        endif
    endmethod
    
    private static method onInit takes nothing returns nothing
        set target.time=CreateTimer()
    endmethod
        
endstruct

private struct tripwire
    unit caster
    player owner
    destructable tree1
    destructable tree2
    real x1
    real y1
    real x2
    real y2
    real duration
    unit dummy
    real angle
    real distance
    lightning l
    
    private integer index
    private static tripwire array trip
    private static integer count=1
    private static timer time
    
    private static method armed takes nothing returns nothing
        local integer i=1
        local tripwire t
    endmethod
    
    static method create takes target targ, destructable tree returns tripwire
        local tripwire t=tripwire.allocate()
        set t.caster=targ.caster
        set t.owner=GetOwningPlayer(t.caster)
        set t.tree1=targ.tree
        set t.tree2=tree
        set t.x1=targ.x1
        set t.y1=targ.y1
        set t.x2=GetDestructableX(tree)
        set t.y2=GetDestructableY(tree)
        set t.duration=0
        set t.angle=Atan2(t.y2-t.y1, t.x2-t.x1)
        set t.distance=SquareRoot((t.x2-t.x1)*(t.x2-t.x1)+(t.y2-t.y1)*(t.y2-t.y1))
        set t.l=AddLightning(&quot;DRAM&quot;, true, t.x1, t.y1, t.x2, t.y2)
        set t.dummy=CreateUnit(t.owner, &#039;h007&#039;, t.x1+t.distance*Cos(t.angle)/2, t.y1+t.distance*Sin(t.angle)/2, 0)
        set t.index=tripwire.count
        set tripwire.trip[t.index]=t
        set tripwire.count=tripwire.count+1
        if tripwire.count==2 then
            call TimerStart(tripwire.time, .04, true, function tripwire.armed)
        endif
        call targ.destroy()
        return t
    endmethod
    
    private static method onInit takes nothing returns nothing
        set tripwire.time=CreateTimer()
    endmethod
    
endstruct



private function actions takes nothing returns boolean
    local unit u
    local destructable tree
    local target t
    if GetSpellAbilityId()==&#039;A00C&#039; then
        set u=GetTriggerUnit()
        set t=target.targ[LoadInteger(h, GetHandleId(u), 0)]
        call t.destroy()
        set u=null
    elseif GetSpellAbilityId()==&#039;A00N&#039; then
        set u=GetTriggerUnit()
        set tree=GetSpellTargetDestructable()
        if LoadInteger(h, GetHandleId(u), 0)==null then
            call IssueImmediateOrder(u, &quot;stop&quot;)
            call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA)+10)
            set t=target.create(u, tree)
        else
            set t=target.targ[LoadInteger(h, GetHandleId(u), 0)]
            if SquareRoot((t.x2-t.x1)*(t.x2-t.x1)+(t.y2-t.y1)*(t.y2-t.y1))&lt;=600 and tree!=t.tree then
                call tripwire.create(t, tree)
            else
                call IssueImmediateOrder(u, &quot;stop&quot;)
                if GetLocalPlayer()==GetOwningPlayer(u) then
                    call StartSound(gg_snd_Error)
                endif
            endif
        endif
        set u=null
        set tree=null
    endif        
    return false
endfunction

private function herotype takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit())==&#039;H003&#039;
endfunction

//===========================================================================
private function init takes nothing returns nothing
    local trigger t=CreateTrigger()
    local integer x=0
    call TriggerAddCondition(t, Condition(function actions))
    loop
        exitwhen x==12
        call TriggerRegisterPlayerUnitEvent(t, Player(x), EVENT_PLAYER_UNIT_SPELL_EFFECT, Filter(function herotype))
        set x=x+1
    endloop
    set t=null
endfunction
endscope</i>


EDIT: finished the entire thing, splosions and all, and it works gloriously!
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top