• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Solved (Tfs 1.1) onPrepareDeath Bug -- Player still dying

Apollos

Dude who does stuff
Joined
Apr 22, 2009
Messages
829
Solutions
123
Reaction score
655
Location
United States
Have an onPrepareDeath function for an event, but for some reason the mob is hitting my character again after the creature event is executed and can kill players. I've tried canceling killer target, setting ghost mode, addEvent to unregister event the onPrepareDeath after a few seconds, unregistering PlayerDeath and DropLoot, and maybe some more I can't rememeber. Any help appreciated, been a pain, my brain is now mush.

Lua:
dofile("data/lib/dota_lib.lua")

function onPrepareDeath(cid, lastHitKiller, mostDamageKiller)
    local player = Player(cid)
    local killer = Creature(lastHitKiller)
    local temple = player:getTown():getTemplePosition()
    player:addHealth(player:getMaxHealth())
    player:addMana(player:getMaxMana())
    player:teleportTo(temple)
    player:setDirection(SOUTH)
    temple:sendMagicEffect(CONST_ME_TELEPORT)
    player:removeCondition(CONDITION_OUTFIT)
    player:sendTextMessage(19, 'You have been eliminated from the Dota event.')
    dota.playerCount = dota.playerCount - 1   
   
    addEvent(
        function()   
            player:registerEvent('PlayerDeath')
            player:registerEvent('DropLoot')
            player:unregisterEvent("dotaPlayerDeath")
            player:addHealth(player:getMaxHealth())
        end, 2000
    )
       
    for i = 1, #dota.blueTeam do
        if player:getName() == dota.blueTeam[i] then
            dota.blueTeam[i] = nil
        end
    end   
   
    for i = 1, #dota.redTeam do
        if player:getName() == dota.redTeam[i] then
            dota.redTeam[i] = nil
        end
    end

    if dota.playerCount == 0 then
        endDota()
    end
    return true
end
 
Solution
If you dont want the player to die you need to create a onStatsChange to create the code. You can execute what you want then block the damage that would kill the player from happening.
If you dont want the player to die you need to create a onStatsChange to create the code. You can execute what you want then block the damage that would kill the player from happening.
 
Solution
If you dont want the player to die you need to create a onStatsChange to create the code. You can execute what you want then block the damage that would kill the player from happening.

Seems to be working well, thanks for your help.

solution:

Lua:
dofile("data/lib/dota_lib.lua")

function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if isPlayer(creature) then
        local player = Player(creature)
        local nextHealth = (player:getHealth() - primaryDamage)
        if nextHealth < 1 then
            primaryDamage, primaryType = 0, 0
            local temple = player:getTown():getTemplePosition()
            player:addHealth(player:getMaxHealth())
            player:addMana(player:getMaxMana())
            player:teleportTo(temple)
            player:setDirection(SOUTH)
            temple:sendMagicEffect(CONST_ME_TELEPORT)
            player:removeCondition(CONDITION_OUTFIT)
            player:unregisterEvent("dotaPlayerDeath")
            player:sendTextMessage(19, 'You have been eliminated from the Dota event.')
            dota.playerCount = dota.playerCount - 1   
               
            for i = 1, #dota.blueTeam do
                if player:getName() == dota.blueTeam[i] then
                    dota.blueTeam[i] = nil
                end
            end   
           
            for i = 1, #dota.redTeam do
                if player:getName() == dota.redTeam[i] then
                    dota.redTeam[i] = nil
                end
            end

            if dota.playerCount == 0 then
                endDota()
            end
        end
    end
    return primaryDamage, primaryType
end
 
Seems to be working well, thanks for your help.

solution:

Lua:
dofile("data/lib/dota_lib.lua")

function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if isPlayer(creature) then
        local player = Player(creature)
        local nextHealth = (player:getHealth() - primaryDamage)
        if nextHealth < 1 then
            primaryDamage, primaryType = 0, 0
            local temple = player:getTown():getTemplePosition()
            player:addHealth(player:getMaxHealth())
            player:addMana(player:getMaxMana())
            player:teleportTo(temple)
            player:setDirection(SOUTH)
            temple:sendMagicEffect(CONST_ME_TELEPORT)
            player:removeCondition(CONDITION_OUTFIT)
            player:unregisterEvent("dotaPlayerDeath")
            player:sendTextMessage(19, 'You have been eliminated from the Dota event.')
            dota.playerCount = dota.playerCount - 1  
              
            for i = 1, #dota.blueTeam do
                if player:getName() == dota.blueTeam[i] then
                    dota.blueTeam[i] = nil
                end
            end  
          
            for i = 1, #dota.redTeam do
                if player:getName() == dota.redTeam[i] then
                    dota.redTeam[i] = nil
                end
            end

            if dota.playerCount == 0 then
                endDota()
            end
        end
    end
    return primaryDamage, primaryType
end

This would lag lot the server if you have many players I guess, right?
 
This would lag lot the server if you have many players I guess, right?
doubt it but the code could be optimized
there's no need to call player:getName() x times, can just create a variable for it and call it once
also there should be a "found" variable for the name being found in the loops, if the name is in blue team and it deletes it, there should be a break to break the loop and set a variable "found" to true, so you don't have to initialize another loop afterwards for no reason
either way once the index is deleted it's no longer a linear array, meaning the next time you use a loop like that and compare a string with possibly a nil value, the code would break
the players should be indexed by cid so there's O(1) access instead of a loop with O(n)
unless of course the array gets reset or w/e
also isPlayer(creature) to creature:isPlayer(), since isPlayer is a compat function that constructs a new player object
 
I have a code similar to this one, that prevents the deaths of certain players as a "protection system":

Lua:
local minLevel = 80
local ITEM_MALE_CORPSE = 3058
local ITEM_FEMALE_CORPSE = 3065
local ITEM_BLOOD_TYPE = 2016

function onPrepareDeath(creature, killer)
    if not killer then
        return true
    end

    if creature:getLevel() < minLevel then
        if killer:isMonster() then
            local master = killer:getMaster()
            if master and master:isPlayer() then
                killer = master
            end
        end
       

        --[[if creature:isPzLocked() then
            return true
        end]]
       
        if creature:getSkull() < SKULL_WHITE  or creature:getSkull() == SKULL_YELLOW or creature:getSkull() == SKULL_ORANGE then
            local sex = creature:getSex()
            local pos = creature:getPosition()

            if killer and killer:isPlayer() then
                killer:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The murder of ".. creature:getName() .. " was not justified. But you won't receive frag, since the player is below level ".. minLevel ..", meaning he has adventurer's blessing.")
            end
           
            creature:teleportTo(creature:getTown():getTemplePosition())
            creature:addHealth(creature:getMaxHealth() - creature:getHealth())
            creature:addMana(creature:getMaxMana() - creature:getMana())

            local blood = Game.createItem(ITEM_BLOOD_TYPE, 2, pos)
            blood:decay()
            local corpse = Game.createItem(sex == PLAYERSEX_FEMALE and ITEM_FEMALE_CORPSE or ITEM_MALE_CORPSE, 1, pos)
            corpse:decay()
            corpse:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("You recognize %s. %s was killed by %s.", creature:getName(), sex == PLAYERSEX_FEMALE and "She" or "He", killer:getName()))

            creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You were murdered by ".. killer:getName() .. ", but it was not justfified. Also you are below level ".. minLevel ..", meaning you have adventurer's blessing, so you didn't lose any items, experience and skills.")
            creature:remove()
            return false
        end
    end
    return true
end

Today found a bug when the player was killed with a RANGE_ATTACK, the server crashed in some conditions, so I am considering to change onPrepareDeath() to onHealthChange() as you mentioned.

What I am considering, is that the onPrepareDeath() is executed when the hit is >= than the hp left, besides onHealthChange() is being executed all the time, that's why I think this could not work properly on a crowded server.

If you don't mind, could you help on optimize this script in order to don't let use much resource?
 
I have a code similar to this one, that prevents the deaths of certain players as a "protection system":

Lua:
local minLevel = 80
local ITEM_MALE_CORPSE = 3058
local ITEM_FEMALE_CORPSE = 3065
local ITEM_BLOOD_TYPE = 2016

function onPrepareDeath(creature, killer)
    if not killer then
        return true
    end

    if creature:getLevel() < minLevel then
        if killer:isMonster() then
            local master = killer:getMaster()
            if master and master:isPlayer() then
                killer = master
            end
        end
      

        --[[if creature:isPzLocked() then
            return true
        end]]
      
        if creature:getSkull() < SKULL_WHITE  or creature:getSkull() == SKULL_YELLOW or creature:getSkull() == SKULL_ORANGE then
            local sex = creature:getSex()
            local pos = creature:getPosition()

            if killer and killer:isPlayer() then
                killer:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The murder of ".. creature:getName() .. " was not justified. But you won't receive frag, since the player is below level ".. minLevel ..", meaning he has adventurer's blessing.")
            end
          
            creature:teleportTo(creature:getTown():getTemplePosition())
            creature:addHealth(creature:getMaxHealth() - creature:getHealth())
            creature:addMana(creature:getMaxMana() - creature:getMana())

            local blood = Game.createItem(ITEM_BLOOD_TYPE, 2, pos)
            blood:decay()
            local corpse = Game.createItem(sex == PLAYERSEX_FEMALE and ITEM_FEMALE_CORPSE or ITEM_MALE_CORPSE, 1, pos)
            corpse:decay()
            corpse:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("You recognize %s. %s was killed by %s.", creature:getName(), sex == PLAYERSEX_FEMALE and "She" or "He", killer:getName()))

            creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You were murdered by ".. killer:getName() .. ", but it was not justfified. Also you are below level ".. minLevel ..", meaning you have adventurer's blessing, so you didn't lose any items, experience and skills.")
            creature:remove()
            return false
        end
    end
    return true
end

Today found a bug when the player was killed with a RANGE_ATTACK, the server crashed in some conditions, so I am considering to change onPrepareDeath() to onHealthChange() as you mentioned.

What I am considering, is that the onPrepareDeath() is executed when the hit is >= than the hp left, besides onHealthChange() is being executed all the time, that's why I think this could not work properly on a crowded server.

If you don't mind, could you help on optimize this script in order to don't let use much resource?
where is RANGE_ATTACK defined?
i've never seen this constant
 
The bug consist basically when the player is teleported to the temple (for example temple of Ankrahmun, floor 8) and the player was killing on the main floor (floor 7), there is an animation trough the ranged attack, where the server doesn't know what to do and it crashes.

We tried to fix it, but we haven't been able, so that's why when we investigated reached this thread which could be a possible solution to fix this crashing bug which I am facing right now.


Btw: If you created the feature onSpawn(), please let me congratulate you, since we have used it too much, really good function.
 
The bug consist basically when the player is teleported to the temple (for example temple of Ankrahmun, floor 8) and the player was killing on the main floor (floor 7), there is an animation trough the ranged attack, where the server doesn't know what to do and it crashes.

We tried to fix it, but we haven't been able, so that's why when we investigated reached this thread which could be a possible solution to fix this crashing bug which I am facing right now.


Btw: If you created the feature onSpawn(), please let me congratulate you, since we have used it too much, really good function.
doesn't sound like it's the animation causing the crash.
if that was the case, the crash would be through your client and not the engine since the engine doesn't do anything with the animation.
i wasn't the first to make onSpawn but i made the one in my signature, yes.
 
Back
Top