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
    
    method onDestroy takes nothing returns nothing
        call PauseTimer(.clock)
        //call DestroyTimer(.clock)
    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')
     set Relocation[bj_lastCreatedUnit] = dat
     //set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call PauseTimer(dat.clock)
     call DestroyTimer(dat.clock)
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call PauseTimer(dat.clock)
     call DestroyTimer(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)
    set Relocation[bj_lastCreatedUnit] = dat
    //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


The old thread's title wasn't very related to the problem, so I thought bumping wouldn't be a good idea, as the problem quite different too.

Well, the problem is I get the error message: Double free of type Relocation__Relocation

I don't know what it means or how to fix it, after a few uses the "system" bugs up, sometimes not replacing the unit or replacing it with another one.

Please help I really need this very much ><
 

Tom Jones

N/A
Reaction score
437
It means that you destroy the same instance of a struct twice. The problem your experiencing is probably that PUI also destroys the struct, so you should in fact use the release method and let PUI handle the destruction of your struct.
 

SerraAvenger

Cuz I can
Reaction score
234
please don't inline these constants
use
Code:
constant integer HERO_ID = 'H000'
if id == HERO_ID then...
instead...

Do as tom proposed...
And clean the struct from the timer.
 

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
    
    method onDestroy takes nothing returns nothing
        call PauseTimer(.clock)
        call ClearTimerStructA(.clock)
        call DestroyTimer(.clock)
    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, &#039;h01C&#039;)
     set Relocation[bj_lastCreatedUnit] = dat
     //set dat.mover = bj_lastCreatedUnit
     call SetHeroXP(bj_lastCreatedUnit, dat.xp, false)
     call dat.release()
    endif
    if GetUnitCurrentOrder(dat.mover) != 852165 then
     call dat.release()
    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(&quot;Dat is null&quot;)
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg(&quot;dat is not null&quot;)
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), &#039;h02A&#039;, &#039;none&#039;)
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    set Relocation[bj_lastCreatedUnit] = dat
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == &#039;H029&#039;
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 this just made it worse, if I clear the struct or release whatever, the EntryUproot will always have dat == null, which leads me back to the original problem, the unit will instantly turn back to the movable building unit.

You see I always re-bond the struct to the newly created unit. That's the point (well part of it).
I also tried commenting out one of the Pause and DestroyTimer 's in the RootHandle, but that didn't do a thing.
 

Tom Jones

N/A
Reaction score
437
Don't destroy the instance then, which actually makes a lot of sense. You allocate an instance for a unit and keep that instance untill the unit leaves the game or the player does.
 

Faust

You can change this now in User CP.
Reaction score
123
Exactly. But we are now back to step one.
The double free of type stuff still keeps showing up after a few uses.

JASS:
scope Relocation initializer I

private struct Relocation
    //! runtextmacro PUI()
    unit mover
    real x
    real y
    integer xp
    timer clock = CreateTimer()
    integer unitid
    
    //method onDestroy takes nothing returns nothing
        //call PauseTimer(.clock)
        //call ClearTimerStructA(.clock)
        //call DestroyTimer(.clock)
    //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, &#039;h01C&#039;)
     set Relocation[bj_lastCreatedUnit] = dat
     //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(&quot;Dat is null&quot;)
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg(&quot;dat is not null&quot;)
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), &#039;h02A&#039;, &#039;none&#039;)
    call IssueImmediateOrderById(bj_lastCreatedUnit, 852166)
    set Relocation[bj_lastCreatedUnit] = dat
    //set dat.mover = bj_lastCreatedUnit
endfunction

private function C1 takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == &#039;H029&#039;
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
 

Builder Bob

Live free or don't
Reaction score
249
If you are not sure how to allocate instances for units you can use this method which will do it all for you.

Relocation.Get(whichUnit) will give you the right instance for any unit at any time. You don't have to worry about creating or destroying instances.

JASS:
static method Get takes unit whichUnit returns Relocation
    local Relocation dat = Relocation[whichUnit]
    if dat == 0 then
        set dat = Relocation.allocate()
        set Relocation[whichUnit] = dat
    endif
    return dat
endmethod



As for why you're experiencing your problem, I think it could be in the function Uproot.
JASS:
local Relocation dat = Relocation[GetTriggerUnit()]
(...)
call ReplaceTower(GetTriggerUnit(), &#039;h02A&#039;, &#039;none&#039;)
set Relocation[bj_lastCreatedUnit] = dat


This looks dodgy, but I have no idea what happens in ReplaceTower, so who knows.


If you want to carry on a struct instance from one unit to another, then you might want to mention that.
 

Faust

You can change this now in User CP.
Reaction score
123
JASS:
function ReplaceTower takes unit oldu, integer newui, integer otherui returns nothing
    local real x = GetUnitX(oldu)
    local real y = GetUnitY(oldu)
    local player p = GetOwningPlayer(oldu)
    call RemoveUnit(oldu)
    set bj_lastCreatedUnit = CreateUnit(p, newui, x, y, 0)
    call CreateUnit(p, otherui, x, y, 0)
endfunction


This is ReplaceTower :)

And please tell me about this allocate stuff, I've never used it before, I don't know what it does.
I put the static method in my struct, but how do I use it in my script?
Please edit my last posted one to include it and its use.
I will be forever grateful ^^
 

_whelp

New Member
Reaction score
54
You have a weird naming convention, which took me about 20 minutes to decode it...
 

Faust

You can change this now in User CP.
Reaction score
123
I don't get it, what is so weird about it?
And how does that comment help me? :D
 

SerraAvenger

Cuz I can
Reaction score
234
And how does that comment help me? :D

Comments about your way to code/name/not name stuff will help you indirectly. If you choose to change to the normal naming conventions, stop hardcoding constants etc, then others will be much better at helping you coding, you will be much better at maintaining your code, and you will get a couple of friends.

JASS:
    call RemoveUnit(oldu)


Is not accepted if you're using PUI that way...

You'll get double free of types quite soon.

Which is, obviously, your problem.

Pui will destroy your struct once the unit is gone - which happens once you replace it.
Then you add a destroyed struct to your unit... which works well until the unit is destroyed.
 

Faust

You can change this now in User CP.
Reaction score
123
I think my "naming" is flawless. Hardcoding stuff... What the hell can anyone win to make something like a unit id a constant? o_O

Anyway, this is far from finished.


Pui will destroy your struct once the unit is gone - which happens once you replace it.
Then you add a destroyed struct to your unit... which works well until the unit is destroyed.

But I bond the struct to another unit exactly for that reason.

JASS:
  call ReplaceTower(dat.mover, dat.unitid, &#039;h01C&#039;)
     set Relocation[bj_lastCreatedUnit] = dat

what should I do?
 

Builder Bob

Live free or don't
Reaction score
249
JASS:
function ReplaceTower takes unit oldu, integer newui, integer otherui returns nothing
    local real x = GetUnitX(oldu)
    local real y = GetUnitY(oldu)
    local player p = GetOwningPlayer(oldu)
    call RemoveUnit(oldu)
    set bj_lastCreatedUnit = CreateUnit(p, newui, x, y, 0)
    call CreateUnit(p, otherui, x, y, 0)
endfunction


This is ReplaceTower :)

And please tell me about this allocate stuff, I've never used it before, I don't know what it does.
I put the static method in my struct, but how do I use it in my script?
Please edit my last posted one to include it and its use.
I will be forever grateful ^^

Now that I see ReplaceTower doing what I thought it did, it's clear this is the problem.

When you set the same instance for two units, both of these units will attempt to destroy the struct instance when they die. That's bound to cause problems.

PUI doesn't seem to have any built-in support for transfering indexes from unit to unit. Releasing and allocating an index should do the job though.

Here's a simple draft. It's freehand as I can't really test this in any realistic way. I've tried to explain a bit about the thoughts behind the methods so you can make use of it.

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 nothing
        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[whichUnit] = 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, &#039;h01C&#039;)
     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.Get(GetTriggerUnit())
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), &#039;h02A&#039;, &#039;none&#039;)
    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()) == &#039;H029&#039;
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




I think my "naming" is flawless. Hardcoding stuff... What the hell can anyone win to make something like a unit id a constant? o_O
I say this not to hurt you, but to help you: Your naming may be good for you, but it's hell for me and most others trying to understand what's going on. Making good constant names is also something which helps so much for keeping things clean and readable without having to look up what this and that is along the way.

What is most understandable at a glance?

JASS:
return GetIssuedOrderId() == 852165
or
return GetIssuedOrderId() == ROOT
 

Faust

You can change this now in User CP.
Reaction score
123
Well you convinced me, I'll try to make it more readable next time, but I find it difficult to be concerned with readability while creating a subsystem from zero.

The raw codes of stuff are put in the trigger comment :D

Anyway... I was always dumb to understand explained things. You can put infinite amounts of comment lines with the clearest explaining, although I understand them (I think), I can't put them to a use.

I learned everything from examples, reading tutorials or things like these never helped.

So, I put those methods into the struct. But how the hell do I use them? Please edit my code :\

By the way I put the methods in but it doesn't compile.

JASS:
static method Transfer takes unit sourceUnit, unit targetUnit returns nothing
        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[whichUnit] = dat //transfer complete
        return dat
    endmethod


set Relocation[whichUnit] = dat tells me whichUnit is undeclared. I guess you meant source unit, or target unit. I don't know
return dat ----- can't return from a function that returns nothing.
 

Builder Bob

Live free or don't
Reaction score
249
Well you convinced me, I'll try to make it more readable next time, but I find it difficult to be concerned with readability while creating a subsystem from zero.

The raw codes of stuff are put in the trigger comment :D
I'm glad :)

Changing one's practice takes time. It may seem difficult now, but later it'll feel like the only natural thing to do.

Anyway... I was always dumb to understand explained things. You can put infinite amounts of comment lines with the clearest explaining, although I understand them (I think), I can't put them to a use.

I learned everything from examples, reading tutorials or things like these never helped.

So, I put those methods into the struct. But how the hell do I use them? Please edit my code :\

By the way I put the methods in but it doesn't compile.

JASS:
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


set Relocation[whichUnit] = dat tells me whichUnit is undeclared. I guess you meant source unit, or target unit. I don't know
return dat ----- can't return from a function that returns nothing.

Sorry about that. It should be:
JASS:
set Relocation[targetUnit] = dat //transfer complete



You can use the methods Get like this:

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

this makes dat the instance associated with GetTriggerUnit(). If an instance was allocated to the unit from before, that instance will be used. Else, a new one will be allocated for it.


Use Transfer like this:

JASS:
local Relocation dat = Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)
or
call Relocation.Transfer(GetTriggerUnit(), bj_lastCreatedUnit)

this will transfer the instance associated with GetTriggerUnit() to the unit bj_lastCreatedUnit. If GetTriggerUnit() had no instance associated with it from before, a new one will be allocated and then transfered.

The return value is the instance now associated with bj_lastCreatedUnit.

Transfer does not take into account whether bj_lastCreatedUnit had an instance associated with it from before, so use with care.


@SerraAvenger: a pleasure :)
 

Faust

You can change this now in User CP.
Reaction score
123
Still doesn't compile, as I said, function can't return the "dat", as it returns nothing
 

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, &#039;h01C&#039;)
     call Relocation.Transfer(GetTriggerUnit(), 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(&quot;Dat is null&quot;)
     set dat = Relocation.create()
     //call SetTimerStructA(dat.clock, dat)
    else
     call BJDebugMsg(&quot;dat is not null&quot;)
    endif
    set dat.xp = GetHeroXP(GetTriggerUnit())
    call KillDummy(GetTriggerUnit())
    set dat.unitid = GetUnitTypeId(GetTriggerUnit())
    call ReplaceTower(GetTriggerUnit(), &#039;h02A&#039;, &#039;none&#039;)
    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()) == &#039;H029&#039;
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


I think I'm doing it wrong, when I train a unit, and want to relocate it (root it), when the unit gets there it just vanishes, and I get 3 lines reading the same:
ERROR - PUI - Index requested for null unit
 

Builder Bob

Live free or don't
Reaction score
249
JASS:


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, &#039;h01C&#039;)
     call Relocation.Transfer(GetTriggerUnit(), 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


I think I'm doing it wrong, when I train a unit, and want to relocate it (root it), when the unit gets there it just vanishes, and I get 3 lines reading the same:
ERROR - PUI - Index requested for null unit

There is no trigger unit when the timer expires. it should be dat.mover. The unit you just replaced.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top