• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Solved] How can a hero be removed without hooking RemoveUnit

Status
Not open for further replies.

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,537
The title should be AKA what's wrong with this script?

JASS:
library TestRecycler requires Orianna
    globals
        private unit array oris
        private integer index=-1
    endglobals
    
    public function release takes unit u returns nothing
        if UnitAlive(u) then
            call KillUnit(u)
        endif
        set index=index+1
        set oris[index]=u
        call BJDebugMsg("index = "+I2S(index)+"; Released: "+GetUnitName(oris[index]))
    endfunction
    
    public function get takes player owner returns unit
        local unit u
        if index>-1 then
            set u=oris[index]
            call SetUnitOwner(u,owner,true)
            set index=index-1
            call BJDebugMsg("index = "+I2S(index)+"; Got: "+GetUnitName(u))
        else
            set u=CreateUnit(owner,Orianna.ID,0.,0.,0.)
            call KillUnit(u)
            call BJDebugMsg("index = "+I2S(index)+"; Got NEW: "+GetUnitName(u))
        endif
        return u
    endfunction
endlibrary

Something wonderfully peculiar happens with this script.

Let's follow the following sequence of events:

* TestRecycle_get() 10 times

* TestRecycle_release() all 10 instances

* TestRecycle_get() 10 times

But what happens when I do that is peculiar:

* I get 10 "Got NEW ...." messages as expected

* I get 10 "Releaased ...." messages as expected

* I get 6 "Got ...." messages as expected - followed by 4 "Got <BLANK>" messages! Indicies 3->0 contain no unit!

I tried hooking RemoveUnit to see if some other code is obscuring this script but the heroes in indicies 3->0 (the first 4 heroes _release()'d) disappear.

I am completely perplexed now. I also made a test to verify that creating/killing 20 heroes does NOT remove them from the game.

Edit: Here's the script I use it in:

JASS:
//Big Fling Test
//10 Oriannas Command: Attack to a location near a unit, and they all
//Command: Shockwave at the same time, sending it flying

scope test2 initializer i
    globals
        private constant integer DH_ID='Edem'
        private constant real NEW_X=-785.
        private constant real NEW_Y=-585.
        private constant real CLOCK_PERIOD=1./30.
        private boolean ready=true
        private unit array oris[10]
        private unit dh
        private timer time=CreateTimer()
        private integer kf
    endglobals
    
    private function p takes nothing returns nothing
        local integer index=0
        set kf=kf+1
        if kf==15 then
            loop
                exitwhen index>9
                call IssuePointOrder(oris[index],"absorb",NEW_X-128.,NEW_Y-256.)
                set index=index+1
            endloop
        elseif kf==45 then
            loop
                exitwhen index>9
                call IssueImmediateOrder(oris[index],"ambush")
                set index=index+1
            endloop
        elseif kf==150 then
            call RemoveUnit(dh)
            loop
                exitwhen index>9
                call TestRecycler_release(oris[index])
                set index=index+1
            endloop
            call PauseTimer(time)
            set ready=true
        endif
    endfunction
    
    private function c takes nothing returns boolean
        local integer index=0
        if Game.singlePlayer and ready then
            set ready=false
            call PanCameraToTimed(NEW_X,NEW_Y,0.)
            loop
                exitwhen index>9
                set oris[index]=TestRecycler_get(Player(1))
                if index<5 then
                    call ReviveHero(oris[index],NEW_X-100*index,NEW_Y+490.,false)
                else
                    call ReviveHero(oris[index],NEW_X-100*(index-5),NEW_Y+390.,false)
                endif
                call UnitRemoveAbility(oris[index],'Aatk')
                call SetHeroLevel(oris[index],6,false)
                call SelectHeroSkill(oris[index],Orianna.COMMAND_SHOCKWAVE_ID)
                call SelectHeroSkill(oris[index],Orianna.COMMAND_ATTACK_ID)
                set index=index+1
            endloop
            set dh=CreateUnit(Player(2),DH_ID,NEW_X-256.,NEW_Y-256.,270.)
            call UnitRemoveAbility(dh,'Aatk')
            set kf=0
            call TimerStart(time,CLOCK_PERIOD,true,function p)
        endif
        return false
    endfunction
    
    private function i takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerChatEvent(t,Player(0),"-test2",true)
        call TriggerAddCondition(t,Condition(function c))
        set t=null
    endfunction
endscope
 
Last edited by a moderator:
Level 22
Joined
Sep 24, 2005
Messages
4,821
I think killing hero units don't remove them, since a dead hero can be resurrected via script.
 

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,537
I think killing hero units don't remove them, since a dead hero can be resurrected via script.

Yes, I verified that as well. But my script still contains null values, and I hooked RemoveUnit to verify that all heroes still exist.

Either the heroes were removed by a bug, or the script has an error.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Hmm IIRC a player can't own more than 6 heros simultaneously, right ?
I don't remember if it's an hardcoded limit or can be defined with some constant.

So, if your code is correct, i suppose the issue should be related to this limit, debug it with more checks and text messages.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I tested it too, I got 7 heroes, the other three gets lost. Still, debugging though.
EDIT: I don't get errors when I don't kill the heroes. I get all 10. You must be right with the limit thing.

EDIT: The bug doesn't happen if you avoid killing the hero dummy unit. I attached the map I was testing with.
 

Attachments

  • dummy.w3x
    13.2 KB · Views: 40
Last edited:

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,537
Hmm IIRC a player can't own more than 6 heros simultaneously, right ?
I don't remember if it's an hardcoded limit or can be defined with some constant.

So, if your code is correct, i suppose the issue should be related to this limit, debug it with more checks and text messages.

Yes, you were right! It seems the limit is 7 though.

I verified it using this:

JASS:
scope test3 initializer i
    globals
        private constant real CLOCK_PERIOD=1./30.
        private unit array oris[100]
        private timer time=CreateTimer()
        private integer kf
    endglobals
    
    private function p takes nothing returns nothing
        local integer index=0
        set kf=kf+1
        if kf==50 then
            loop
                exitwhen index>99
                call KillUnit(oris[index])
                set index=index+1
            endloop
        elseif kf==150 then
            loop
                exitwhen index>99
                call BJDebugMsg(I2S(GetUnitTypeId(oris[index])))
                set index=index+1
            endloop
            call PauseTimer(time)
        endif
    endfunction
    
    private function c takes nothing returns boolean
        local integer index=0
        loop
            exitwhen index>99
            set oris[index]=CreateUnit(Player(0),'Hmkg',0.,0.,0.)
            set index=index+1
        endloop
        set kf=0
        call TimerStart(time,CLOCK_PERIOD,true,function p)
        return false
    endfunction
    
    private function i takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterPlayerChatEvent(t,Player(0),"-test3",true)
        call TriggerAddCondition(t,Condition(function c))
        set t=null
    endfunction
endscope

It's so odd though - it seems excess heroes are only removed after they've been dead for some small amount of time (here the test shows after 5 seconds)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
"-1" -> 2 character , "0" -> 1 character.
And also comparing to 0 instead of "-1" will make it more "efficient".

Ofc i realize that it will hardly matter, i'm just trying to make an exhaustive list of why my personal taste is better ^^

EDIT : If you still want to recycle heroes maybe you can try to play with ShowUnit.
But frankly unit recycling brings more problems than improvements (angle of rotation, unit events and other data linked with them, ...), excepted if such units are used as special effects.
 
Last edited:

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,537
EDIT : If you still want to recycle heroes maybe you can try to play with ShowUnit.
But frankly unit recycling brings more problems than improvements (angle of rotation, unit events and other data linked with them, ...), excepted if such units are used as special effects.

I won't recycle heroes when this problem exists. I just added code to properly garbage collect my custom hero when its removed. Problem solved :)

The reason I was avoiding it was that the destructor actually takes 17 lines due to many associated units (dummys)

Anyway, problem solved, and thanks again for the help!
 
Status
Not open for further replies.
Top