Free of type error (Pui related)

Faust

You can change this now in User CP.
Reaction score
123
JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit] //check if an instance is already associated with whichUnit
        if dat == 0 then //if not
            set dat = Relocation.allocate() //allocate a new instance
            
            //insert whatever you want to happen when a new instance is created here
            set dat.transferFlag = false
            
            set Relocation[whichUnit] = dat //associate the newly allocate instance with whichUnit
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        //to make this function safer, you should check if targetUnit has an instance set before starting the transfer.
        set dat.transferFlag = true //anything in onDestroy should not be carried out for a transfering instance.
        
        //by releasing, the instance will be freed from the previous unit, and next in line to be allocated.
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        
        set Relocation[targetUnit] = dat //transfer complete
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            
            //this block will only be called whenever an instance is fully destroyed.
                        //transfered instances will be ignored
            
            call PauseTimer(.clock)
            call ClearTimerStructA(.clock)
            call DestroyTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == 852165
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == 852166 and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call ReplaceTower(dat.mover, dat.unitid, 'h01C')
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call PauseTimer(dat.clock)
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call PauseTimer(dat.clock)
    endif
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    local location l = GetOrderPointLoc()
    set dat.mover = GetTriggerUnit()
    set dat.x = GetLocationX(l)
    set dat.y = GetLocationY(l)
    set dat.clock = CreateTimer()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
    call RemoveLocation(l)
    set l = null
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call BJDebugMsg("Dat is null")
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg("dat is not null")
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), 'h02A', 'none')
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'H029'
endfunction

private function EntryUproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope


Now same thing happens, except there is only one red line with that error message :D
 

Builder Bob

Live free or don't
Reaction score
249
JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit] //check if an instance is already associated with whichUnit
        if dat == 0 then //if not
            set dat = Relocation.allocate() //allocate a new instance
            
            //insert whatever you want to happen when a new instance is created here
            set dat.transferFlag = false
            
            set Relocation[whichUnit] = dat //associate the newly allocate instance with whichUnit
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        //to make this function safer, you should check if targetUnit has an instance set before starting the transfer.
        set dat.transferFlag = true //anything in onDestroy should not be carried out for a transfering instance.
        
        //by releasing, the instance will be freed from the previous unit, and next in line to be allocated.
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        
        set Relocation[targetUnit] = dat //transfer complete
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            
            //this block will only be called whenever an instance is fully destroyed.
                        //transfered instances will be ignored
            
            call PauseTimer(.clock)
            call ClearTimerStructA(.clock)
            call DestroyTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == 852165
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == 852166 and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call ReplaceTower(dat.mover, dat.unitid, 'h01C')
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call PauseTimer(dat.clock)
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call PauseTimer(dat.clock)
    endif
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    local location l = GetOrderPointLoc()
    set dat.mover = GetTriggerUnit()
    set dat.x = GetLocationX(l)
    set dat.y = GetLocationY(l)
    set dat.clock = CreateTimer()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
    call RemoveLocation(l)
    set l = null
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call BJDebugMsg("Dat is null")
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg("dat is not null")
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), 'h02A', 'none')
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'H029'
endfunction

private function EntryUproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope


Now same thing happens, except there is only one red line with that error message :D

Every place you have:

JASS:
local Relocation dat = Relocation[GetTriggerUnit()]


replace it with:

JASS:
local Relocation dat = Relocation.Get(GetTriggerUnit())


Do not use Relocation[someUnitVariable] outside of Get or Transfer.

I'll check later why the PUI comes if it persists
 

Faust

You can change this now in User CP.
Reaction score
123
JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit] //check if an instance is already associated with whichUnit
        if dat == 0 then //if not
            set dat = Relocation.allocate() //allocate a new instance
            
            //insert whatever you want to happen when a new instance is created here
            set dat.transferFlag = false
            
            set Relocation[whichUnit] = dat //associate the newly allocate instance with whichUnit
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        //to make this function safer, you should check if targetUnit has an instance set before starting the transfer.
        set dat.transferFlag = true //anything in onDestroy should not be carried out for a transfering instance.
        
        //by releasing, the instance will be freed from the previous unit, and next in line to be allocated.
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        
        set Relocation[targetUnit] = dat //transfer complete
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            
            //this block will only be called whenever an instance is fully destroyed.
                        //transfered instances will be ignored
            
            call PauseTimer(.clock)
            call ClearTimerStructA(.clock)
            call DestroyTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == 852165
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == 852166 and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call ReplaceTower(dat.mover, dat.unitid, 'h01C')
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call PauseTimer(dat.clock)
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call PauseTimer(dat.clock)
    endif
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    local location l = GetOrderPointLoc()
    set dat.mover = GetTriggerUnit()
    set dat.x = GetLocationX(l)
    set dat.y = GetLocationY(l)
    set dat.clock = CreateTimer()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
    call RemoveLocation(l)
    set l = null
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    if dat == null then
     call BJDebugMsg("Dat is null")
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg("dat is not null")
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), 'h02A', 'none')
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'H029'
endfunction

private function EntryUproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope


Well, now no error message, but something else...
The hero unit keeps changing to itself. I mean, it gets replaced a few times per second by itself (I know because hero proper names change, and also the animation resets).
 

Builder Bob

Live free or don't
Reaction score
249
JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit] //check if an instance is already associated with whichUnit
        if dat == 0 then //if not
            set dat = Relocation.allocate() //allocate a new instance
            
            //insert whatever you want to happen when a new instance is created here
            set dat.transferFlag = false
            
            set Relocation[whichUnit] = dat //associate the newly allocate instance with whichUnit
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        //to make this function safer, you should check if targetUnit has an instance set before starting the transfer.
        set dat.transferFlag = true //anything in onDestroy should not be carried out for a transfering instance.
        
        //by releasing, the instance will be freed from the previous unit, and next in line to be allocated.
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        
        set Relocation[targetUnit] = dat //transfer complete
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            
            //this block will only be called whenever an instance is fully destroyed.
                        //transfered instances will be ignored
            
            call PauseTimer(.clock)
            call ClearTimerStructA(.clock)
            call DestroyTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == 852165
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == 852166 and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call ReplaceTower(dat.mover, dat.unitid, 'h01C')
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call PauseTimer(dat.clock)
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call PauseTimer(dat.clock)
    endif
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    local location l = GetOrderPointLoc()
    set dat.mover = GetTriggerUnit()
    set dat.x = GetLocationX(l)
    set dat.y = GetLocationY(l)
    set dat.clock = CreateTimer()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
    call RemoveLocation(l)
    set l = null
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    if dat == null then
     call BJDebugMsg("Dat is null")
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg("dat is not null")
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), 'h02A', 'none')
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'H029'
endfunction

private function EntryUproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope


Well, now no error message, but something else...
The hero unit keeps changing to itself. I mean, it gets replaced a few times per second by itself (I know because hero proper names change, and also the animation resets).

I attempted to create a test map with your trigger, but I'm having a very hard time navigating with all those indescriptive names used.

What hero keeps changing itself? Is he the tower being replaced?

What is 'H029', 'h02A', 'h01C' and 'none'?



JASS:
    if dat == null then
     call BJDebugMsg("Dat is null")
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg("dat is not null")
    endif

This is redundant as it is already done in the method Relocation.Get()

JASS:
private function EntryUproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    if dat == null then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction

I don't see what this does really.


I feel like I'm stumbling to help you now. A test map would be very helpful.
 

Faust

You can change this now in User CP.
Reaction score
123
I attempted to create a test map with your trigger, but I'm having a very hard time navigating with all those indescriptive names used.

What hero keeps changing itself? Is he the tower being replaced?

What is 'H029', 'h02A', 'h01C' and 'none'?

I successfully recreated the problem in a testmap, which I'm uploading now.

'none' is just none. That is rawcode of nothing, so ReplaceTower doesn't place anything there (as a moving unit should not have ground texture).

This is redundant as it is already done in the method Relocation.Get()

I got rid of it now.


I don't see what this does really.

You see, whenever a unit enters the game and has root, it automatically is rooted. This also applies when any unit receives the ability, they are automatically rooted.
Since I'm making a maul type game, and the training building will somewhere in the maze, it wouldn't be wise to create a blocking unit when the round is on and creeps are coming through the maze.
 

Faust

You can change this now in User CP.
Reaction score
123
Bump

JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit] //check if an instance is already associated with whichUnit
        if dat == 0 then //if not
            set dat = Relocation.allocate() //allocate a new instance
            
            //insert whatever you want to happen when a new instance is created here
            set dat.transferFlag = false
            
            set Relocation[whichUnit] = dat //associate the newly allocate instance with whichUnit
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        //to make this function safer, you should check if targetUnit has an instance set before starting the transfer.
        set dat.transferFlag = true //anything in onDestroy should not be carried out for a transfering instance.
        
        //by releasing, the instance will be freed from the previous unit, and next in line to be allocated.
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        
        set Relocation[targetUnit] = dat //transfer complete
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            
            //this block will only be called whenever an instance is fully destroyed.
                        //transfered instances will be ignored
            
            call PauseTimer(.clock)
            call ClearTimerStructA(.clock)
            call DestroyTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == 852165
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == 852166 and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    call BJDebugMsg("RootHandle")
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call ReplaceTower(dat.mover, dat.unitid, 'h01C')
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call PauseTimer(dat.clock)
     call BJDebugMsg("RH 1")
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call BJDebugMsg("RH 2")
     call PauseTimer(dat.clock)
    endif
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    local location l = GetOrderPointLoc()
    call BJDebugMsg("Root")
    set dat.mover = GetTriggerUnit()
    set dat.x = GetLocationX(l)
    set dat.y = GetLocationY(l)
    set dat.clock = CreateTimer()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
    call RemoveLocation(l)
    set l = null
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    call BJDebugMsg("Uproot")
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), 'h02A', 'none')
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'H029'
endfunction

private function EntryUproot takes nothing returns nothing
    local Relocation dat = Relocation[GetTriggerUnit()]
    call BJDebugMsg("EntryUproot")
    if dat == null then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope



Don't leave me alone Builder T.T

Added debugmsges, apparently, roothandle doesn't stop.
When the problem is "happening", the following is spammed on my screen:
RootHandle
RH 1
RH 2
EntryUproot
~repeat~
 

Builder Bob

Live free or don't
Reaction score
249
Bump

(---)

Don't leave me alone Builder T.T

Added debugmsges, apparently, roothandle doesn't stop.
When the problem is "happening", the following is spammed on my screen:
RootHandle
RH 1
RH 2
EntryUproot
~repeat~

Sorry that I couldn't help you yesterday. I was checking out the testmap yesterday, and it helped quite a bit. Unfortunately I didn't have enough time to find the whole solution to the problem right away.

It looks like the EntryUproot function causes the problem with an endless stream of root/uproot orders which makes the unit get replaced over and over.

I'm going to see how it can be avoided in a little bit.

By the way, would you be open to use Chaos to change the unit into another instead of replacing it? You'd probably have to make the caravan a hero so it won't crash, but the issue about newly created units triggering the EnterRegion event won't be there anymore.
 

Faust

You can change this now in User CP.
Reaction score
123
I know chaos, it's a wonder tool... But I don't know how much lag it would cause.
And I'm not sure if chaos doesn't trigger entering unit anyway...

And most importantly, there will be many units in that race (I estimate 50), and creating 50 chaos ability, is not very practical.

I was thinking about what could separate the newly trained units from the replaced one, and I think I have an idea. Brb :p


EDIT: It's DEFINITELY not the EntryUproot what causes the problem (at least not only that).

While reading your last post, I came up with 2 ideas
#1, add the ReplaceTower created unit into a unitgroup, and in EntryUproot, check if that unit is in the group.
But I thought it might be too slow, and I don't fancy globals anyway, so I tried
#2, the newly created unit in ReplaceTower is called bj_lastCreatedUnit, and there is no delay.
So why not check for that? if GetTriggerUnit() != bj_lastCreatedUnit then
And it kept doing the same thing

So I was like wtf, I commented out the EntryUproot's IssueImmediate order, so I can uproot the entering unit manually, which I did, and when I wanted to root it down, it STILL kept doing the same thing (replacing the hero unit with hero unit).

I think the problem is in RootHandle, the timer doesn't pause, so it keeps checking if the place where the unit is correct. As it is correct, it gets replaced.

... a few tests ...

Indeed. I fixed it! for now...

I moved the PauseTimer function before ReplaceTower, and woot.

... testing for the original problem ...

No free of type error messages appearing! Grand succes!

Thank you zillion times ! I hope it won't bug up. I'm having problem with unit evading condition though :p
 

Builder Bob

Live free or don't
Reaction score
249
And most importantly, there will be many units in that race (I estimate 50), and creating 50 chaos ability, is not very practical.

I was thinking about what could separate the newly trained units from the replaced one, and I think I have an idea. Brb :p

oh, 50 units. You're right. It does sound like a lot of hassle. I'll wait and see what you find out before going any further.
 

Faust

You can change this now in User CP.
Reaction score
123
Done and thanks (See my previous post)

EDIT: More problems may arise now... As the rooting command can be canceled. Testing ^^

EDIT2: For now, there are no problems whatsoever with that :) AWESOME
 

Builder Bob

Live free or don't
Reaction score
249
Done and thanks (See my previous post)

EDIT: More problems may arise now... As the rooting command can be canceled. Testing ^^

EDIT2: For now, there are no problems whatsoever with that :) AWESOME

Great job! Sound like you're getting quite good with debugging and figuring out where the problem arises.

I hope no more bugs arises.


A few small issues I saw in your code before:
  • The member clock has initial value CreateTimer(). Additionally clock is set to CreateTimer() on every root order.
  • If you order a unit to root repeatedly within .2 seconds, multiple timers will be created for that unit.
This can cause many leaks and bugs as multiple different timers may expire for the same unit.
What I'd suggest as a solution would be to give clock the initial value CreateTimer(), and never destroy it. ClearTimerStructA on destroy, and SetTimerStructA on creation. Both clear and set on transfer.

On root orders you won't have to create any timers or set any timer data.
 

Faust

You can change this now in User CP.
Reaction score
123
JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit] //check if an instance is already associated with whichUnit
        if dat == 0 then //if not
            set dat = Relocation.allocate() //allocate a new instance
            
            //insert whatever you want to happen when a new instance is created here
            set dat.transferFlag = false
            
            set Relocation[whichUnit] = dat //associate the newly allocate instance with whichUnit
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        //to make this function safer, you should check if targetUnit has an instance set before starting the transfer.
        set dat.transferFlag = true //anything in onDestroy should not be carried out for a transfering instance.
        
        //by releasing, the instance will be freed from the previous unit, and next in line to be allocated.
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        
        set Relocation[targetUnit] = dat //transfer complete
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            
            //this block will only be called whenever an instance is fully destroyed.
                        //transfered instances will be ignored
            
            call PauseTimer(.clock)
            call ClearTimerStructA(.clock)
            call DestroyTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == 852165
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == 852166 and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    call BJDebugMsg("RH running")
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call PauseTimer(dat.clock)
     //call ClearTimerStructA(dat.clock)
    endif
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call PauseTimer(dat.clock)
     call ReplaceTower(dat.mover, dat.unitid, 'h01C')
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call ClearTimerStructA(dat.clock)
    endif
    
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    local location l = GetOrderPointLoc()
    set dat.mover = GetTriggerUnit()
    set dat.x = GetLocationX(l)
    set dat.y = GetLocationY(l)
    set dat.clock = CreateTimer()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
    call RemoveLocation(l)
    set l = null
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), 'h02A', 'none')
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'H029'
endfunction

private function EntryUproot takes nothing returns nothing
    if GetTriggerUnit() != bj_lastCreatedUnit then
     call IssueImmediateOrderById(GetTriggerUnit(), 852166)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope


Current code.

If I reorder the unit (no need 0.2 seconds), I mean the unit is moving somewhere to root, and I reorder it to root somewhere else, the RH messages begin to show at a doubled rate.

I tried what you wanted, and now whenever the unit is created to the hero rooted one (the one created in RootHandle), I get an error:

ERROR: ClearTimerStructA[bunchofnumbers] - clear attempt on bad key.

When I combine the two error, the latter shows up a faster rate too of course.

Also, if I don't set dat.clock = CreateTimer() in the Root function, every time I order root I get this:
Warning: SetTimerStructA[bunchofnumber] - index blah collision 1, then 2, then 3, etc.
 

Builder Bob

Live free or don't
Reaction score
249
Clearing and Setting the data on the timers must be done very carefully.

Here's a working map. Ask if you're unsure about any of the changes I made.

JASS:
scope Relocation initializer I

globals
    private constant integer ROOT = 852165
    private constant integer UNROOT = 852166
    private constant integer CARAVANUNIT = 'h002'
    private constant integer HEROUNIT1 = 'H000'
    private constant integer HEROUNIT2 = 'H001'
    private constant integer ADDITIONALUNIT = 'h003'
endglobals

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock
    integer unitid
    boolean transferFlag
        
    static method Get takes unit whichUnit returns Relocation
        local Relocation dat = Relocation[whichUnit]
        if dat == 0 then
            set dat = Relocation.allocate()
            
            set dat.transferFlag = false
            set dat.mover = whichUnit
            if dat.clock == null then
                set dat.clock = CreateTimer()
            endif
            call SetTimerStructA(dat.clock, dat)
            
            set Relocation[whichUnit] = dat
        endif
        return dat
    endmethod
    
    static method Transfer takes unit sourceUnit, unit targetUnit returns Relocation
        local Relocation dat = Relocation.Get(sourceUnit)
        set dat.transferFlag = true
        if dat.clock != null then
        endif
        
        call dat.release()
        set dat = Relocation.allocate()
        
        set dat.transferFlag = false
        set dat.mover = targetUnit
        
        set Relocation[targetUnit] = dat
        return dat
    endmethod
    
    method onDestroy takes nothing returns nothing
        if not .transferFlag then
            call ClearTimerStructA(.clock)
            call PauseTimer(.clock)
        endif
    endmethod


endstruct

private function C2 takes nothing returns boolean
    return GetIssuedOrderId() == ROOT
endfunction

private function C3 takes nothing returns boolean
    return GetIssuedOrderId() == UNROOT and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true
endfunction

private function RootHandle takes nothing returns nothing
    local Relocation dat = GetTimerStructA(GetExpiredTimer())
    call BJDebugMsg("RH running " + I2S(dat))
    if GetUnitCurrentOrder(dat.mover) != ROOT then
     call PauseTimer(dat.clock)
    endif
    if GetUnitX(dat.mover) == dat.x and GetUnitY(dat.mover) == dat.y then
     call PauseTimer(dat.clock)
     call ReplaceTower(dat.mover, dat.unitid, ADDITIONALUNIT)
     call Relocation.Transfer(dat.mover, bj_lastCreatedUnit)
     set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
    endif
    
endfunction

private function Root takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    set dat.x = GetOrderPointX()
    set dat.y = GetOrderPointY()
    call TimerStart(dat.clock, 0.2, true, function RootHandle)
endfunction

private function Uproot takes nothing returns nothing
    local Relocation dat = Relocation.Get(GetTriggerUnit())
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), CARAVANUNIT, 'none')
    call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
    call IssueImmediateOrderById(bj_lastCreatedUnit, UNROOT)
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == HEROUNIT1 or GetUnitTypeId(GetFilterUnit()) == HEROUNIT2
endfunction

private function EntryUproot takes nothing returns nothing
    if GetTriggerUnit() != bj_lastCreatedUnit then
     call IssueImmediateOrderById(GetTriggerUnit(), UNROOT)
    else
    endif
endfunction


//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region r = CreateRegion()
    call RegionAddRect(r, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t, r, Condition(function C1))
    call TriggerAddAction(t, function EntryUproot)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(t, Condition(function C2))
    call TriggerAddAction(t, function Root)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(t, Condition(function C3))
    call TriggerAddAction(t, function Uproot)
endfunction

endscope
 

Attachments

  • RootRelocation.w3x
    32.6 KB · Views: 140

Faust

You can change this now in User CP.
Reaction score
123
I shit you not, that was the code I made, and then you read my elder test map code, and tried to give instructions thinking about that, and that's why I messed it up. Rotfl.

Thank you again and again!
 
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