Weird KillUnit() on heroes issue !

Status
Not open for further replies.
Level 12
Joined
Jan 30, 2020
Messages
875
Hello there !

Alright, after converting my amp to Lua, I am trying to optimize it a bit further.
So far things worked great, but I hit a strange issue with the KillUnit native:

My map is a 4 players TD with "Balls" as creeps. At map init, I create all Balls of different type for every player. To make it easier to recycle them. That is also why I made them as heroes to be able to revive them.

Before the optimization attempt, I used to just hide Balls on creation,, or when they reached their final destination (when the player loses a life ^^).
But I also used to revive them at an arbitrary position (StoreX, StoreY) and hide them when they are killed.

The fact is, I detect the end of the levels when the neutral hostile player owning the Balls (I called him BallsMaster) food usage gets to 0.
So when I stored the Balls in the 3 circumstances, I used to have to switch the owner to the PLAYER_NEUTRAL_PASSIVE.

But now, I try to avoid using that extra Player, and just want the Balls to be dead when stored.
This avoids having to store them at a specific position, having to change their owner, and having to hide them.

But it does not work properly.

First here are my functions to create the balls :
Lua:
function CreateBall(bn, id)
    local ball=CreateUnit(BallsMaster, id, StoreX, StoreY, 0.0)
    SetUnitUserData(ball, bn)
    Destination[bn]=0
    AddEventsBallTriggers(ball, bn)
    DisableBallTriggers(bn)
    KillUnit(ball)
    return ball
end

function CreateBalls()
    BallID,FlyingBallID,GiantBallID,GiantFlyingID=FourCC("U005"),FourCC("U006"),FourCC("U003"),FourCC("U001")
    BallNumber,NumberOfBalls,BallsPerLevel,TBallsLeft,PBallsLeft=0,0,6,0,__jarray(0)
    InitialSize,BallSize,FlyingSize,GiantSize,GiantFlyingSize,StrongSize,MiniGiantSize=1.0,1.0,0.9,2.0,1.5,1.5,1.8
    CurrentMaxHP,MinSize,ResizeFactor=0.0,0.25,1.00
    -- Balls Arrays
    Ball,Flying,Giant,GiantFlying={},{},{},{}
    -- Ball trigger arrays
    StoppedBall,DamagedBall,KilledBall={},{},{}
    -- The Store is the position on the map where all Balls are stored when not shown ingame
    -- It will be arbitrary put at the position of the first player's Protector
    StoreX,StoreY=-7600.0,7600.0
    for i=1, 4 do
        if Playing[i] then
            for j=1, BallsPerLevel do
                local bn=(i-1)*BallsPerLevel+j
                InitBallTriggers(bn)
                Ball[bn]=CreateBall(bn, BallID)
                Flying[bn]=CreateBall(bn, FlyingBallID)
            end
            local bn=(i-1)*BallsPerLevel+1
            Giant[bn]=CreateBall(bn, GiantBallID)
            GiantFlying[bn]=CreateBall(bn, GiantFlyingID)
        end
    end
end
Playing is an array created earlier in the game with boolean values set to true if the player is playing.
Note that I checked, Balls are all properly created.

Just in case, here are the Ball trigger functions mentioned in these functions :
Lua:
function InitBallTriggers(bn)
    StoppedBall[bn]=CreateTrigger()
    DamagedBall[bn]=CreateTrigger()
    KilledBall[bn]=CreateTrigger()
    TriggerAddAction(StoppedBall[bn], StoppedBallActions)
    TriggerAddAction(DamagedBall[bn], DamagedBallActions)
    TriggerAddAction(KilledBall[bn], KilledBallActions)
end

function AddEventsBallTriggers(b, bn)
    TriggerRegisterUnitEvent(StoppedBall[bn], b, EVENT_UNIT_ISSUED_ORDER)
    TriggerRegisterUnitEvent(DamagedBall[bn], b, EVENT_UNIT_DAMAGED)
    TriggerRegisterUnitEvent(KilledBall[bn], b, EVENT_UNIT_DEATH)
end

function EnableBallTriggers(bn)
    EnableTrigger(StoppedBall[bn])
    EnableTrigger(DamagedBall[bn])
    EnableTrigger(KilledBall[bn])
end

function DisableBallTriggers(bn)
    DisableTrigger(StoppedBall[bn])
    DisableTrigger(DamagedBall[bn])
    DisableTrigger(KilledBall[bn])
end

The problem I have is that the Balls are not properly killed on creation.
Here is my function to Spawn the balls , called by a repeating timer at level start :
Lua:
function SpawnABall()
    if (BallNumber<=NumberOfBalls) then
        for i=1,4 do
            if Playing[i] then
                local b,bn,index=nil,0,(i-1)*BallsPerLevel
                if IsGiant then
                    bn=index+1
                    b=Giant[bn]
                else
                    if IsGiantFlying then
                        bn=index+1
                        b=GiantFlying[bn]
                    else
                        bn=index+BallNumber
                        if IsFlying then
                            b=Flying[bn]
                        else
                            b=Ball[bn]
                        end
                    end
                end
                local wpNb=i*10
print(b,", dead =", IsUnitType(b, UNIT_TYPE_DEAD))
                BlzSetUnitMaxHP(b, CurrentMaxHP)
                ReviveHero(b, WPx[wpNb], WPy[wpNb], true)
print(b,", dead =", IsUnitType(b, UNIT_TYPE_DEAD))
                SetUnitScale(b, InitialSize, InitialSize, InitialSize)
                if (Level>(MaxLevel-2)) then
                    SetUnitVertexColor(b, 200, 100, 80, 255)
                    UnitAddAbility(b, FourCC('Alsr'))
                    UnitAddAbility(b, FourCC('ACmi'))
                    BlzSetHeroProperName(b, "mini-Giant Ball")
                end
                if (Level>45) and (Level<48) then
                    SetUnitVertexColor(b, 80, 120, 80, 255)
                    BlzSetHeroProperName(b, "Strong Ball")
                end
                wpNb=wpNb+1
                Destination[bn]=wpNb
                EnableBallTriggers(bn)
                IssuePointOrder(b, "move", WPx[wpNb], WPy[wpNb])
            end
        end
        BallNumber=BallNumber+1
    else
        PauseTimer(NextBallTimer)
    end
end

As you can see I added two prints to check each spawned Ball and its "dead" status before and after the revive. Fact is they cannot be revived as they are not dead !!!

Here is the screenshot taken in the middle of the spawning :

WC3ScrnShot_042720_103015_001.png


This means that the KillUnit() I use when creating the Balls does not kill them !

How can this be ? KillUnit does not work on heroes ?

Note : Balls all have are set to "Can Raise, Does Not Decay"

Edit : the strange thing is even if they cannot be revived because they are not dead, they are nowhere to be seen on the map !
EDIT 2:
Side note : how do I use native UnitAlive takes unit id returns boolean from common.ai in Lua ? I know in jass I just have to declare the native, but how do you do that in Lua ?
EDIT 3 :
I added more prints to debug the issue, and fun enough Balls are indeed dead on creation,,so I decided to display the Balls numbers that are dead with a repeating timer of 1s, and it seems only Balls and Flying Balls with number 5 and 6 stay dead, others are not considered dead anymore shortly after creation.

This is disturbing, because I searched my whole map script in Notepad++ for another operation made on the Ball global arrays and there are none.

EDIT 4: This is really strange.
If I comment out the lines creating the Flying Balls, Giant Balls and Giant Flying Balls, the normal Balls all work as intended.

There seems to be a collision between the 4 arrays for reasons beyond my comprehension....

EDIT 5:
Well this is pure Twilight Zone.

After hours of testing, I can confirm that the problem lies in the function KillUnit.

If I don't kill the units after creation, they're all showing at the Store position.
If I remove all occurrences of "KillUnit" in my map, the Balls always remain onsidered as DEAD when DEAD, but with KillUnit, they are DEAD for a short time only.
They don't reappear, but they're not dead anymore !!!!!

IS there an entry in the game constants that could end up messing the DEAD status of Heroes ???


IF not this is pure nonsense unless the native KillUnit does not work properly...

EDIT 5:
I gave up. thats not something I often resign myself to, but I have found no way to fix this precise situation.

KillUnit native simply is bugged with Heroes, this is something I don't remember happening back in 2004, or maybe thats why I chose to not use KillUnit and swap owners back in the days in the ancestor map of this project... I honestly can't remember after so many years.

Anyways, I don't like to post something that will end up being useless for others, so If anyone is reading this, my advice is to AVOID using KillUnit() on hero units... take care !!!
 
Last edited:
Status
Not open for further replies.
Top