• 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!

TFS 1.X+ Problem when play dies MANA goes to zero and HEALTH increase

henkas

Well-Known Member
Joined
Jul 8, 2015
Messages
1,058
Solutions
5
Reaction score
62
Hi
So i have this weird problem when player dies mana goes to zero and health increase randomly. How to fix it?
 
Hi
So i have this weird problem when player dies mana goes to zero and health increase randomly. How to fix it?
We need more information than just this issue. We need to know did you alter the sources and if so all the changes you made? Are you using custom scripts? What version of TFS is it? You can't just say 1.x because they differ from distribution to distribution. The more information you can provide the easier it is for someone to help you find a solution.
 
We need more information than just this issue. We need to know did you alter the sources and if so all the changes you made? Are you using custom scripts? What version of TFS is it? You can't just say 1.x because they differ from distribution to distribution. The more information you can provide the easier it is for someone to help you find a solution.
Yes i did some source changes but they had nothing to do with health/mana all i did is some color changes and simple stuff like this that has nothing to do with health. My scripts are not custom pretty much my server is still default i haven't done anything crazy without transformation system. I'm using TFS 1.2 downgraded by ninja for 860 protocol
 
Yes i did some source changes but they had nothing to do with health/mana all i did is some color changes and simple stuff like this that has nothing to do with health. My scripts are not custom pretty much my server is still default i haven't done anything crazy without transformation system. I'm using TFS 1.2 downgraded by ninja for 860 protocol
There is your problem right there "I'm using TFS 1.2 downgraded by ninja for 860 protocol"
 
There is your problem right there "I'm using TFS 1.2 downgraded by ninja for 860 protocol"
Lul dont say that i have to pick new tfs? Just because its downgraded 1.2? A lot of otland people are using downgraded ninja edit so maybe they can share solution
 
It is uncommon behavior.
We just aren't able to help you as long we don't know what and where you (or someone) made changes in source or added some custom lua script (or changed some already existing)
You need to provide those info or give someone full access to your server files (not recommended)

Anyway for blind analysis I can suggest looking into void Player::death(Creature* lastHitCreature) in player.cpp (death function setting player stats after death) or any Lua script that executes while player dies.
 
It is uncommon behavior.
We just aren't able to help you as long we don't know what and where you (or someone) made changes in source or added some custom lua script (or changed some already existing)
You need to provide those info or give someone full access to your server files (not recommended)

Anyway for blind analysis I can suggest looking into void Player::death(Creature* lastHitCreature) in player.cpp (death function setting player stats after death) or any Lua script that executes while player dies.
This is the server. You can look to the source here and other stuff because its the same stuff what i have
ninjalulz/forgottenserver

Code:
void Player::death(Creature* _lastHitCreature)
{
    loginPosition = town->getTemplePosition();

    if (skillLoss) {

        //Magic level loss
        uint64_t sumMana = 0;
        uint64_t lostMana = 0;

        //sum up all the mana
        for (uint32_t i = 1; i <= magLevel; ++i) {
            sumMana += vocation->getReqMana(i);
        }

        sumMana += manaSpent;

        double deathLossPercent = getLostPercent();

        lostMana = static_cast<uint64_t>(sumMana * deathLossPercent);

        while (lostMana > manaSpent && magLevel > 0) {
            lostMana -= manaSpent;
            manaSpent = vocation->getReqMana(magLevel);
            magLevel--;
        }

        manaSpent -= lostMana;

        uint64_t nextReqMana = vocation->getReqMana(magLevel + 1);
        if (nextReqMana > vocation->getReqMana(magLevel)) {
            magLevelPercent = Player::getPercentLevel(manaSpent, nextReqMana);
        } else {
            magLevelPercent = 0;
        }

        //Skill loss
        for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { //for each skill
            uint64_t sumSkillTries = 0;
            for (uint16_t c = 11; c <= skills[i].level; ++c) { //sum up all required tries for all skill levels
                sumSkillTries += vocation->getReqSkillTries(i, c);
            }

            sumSkillTries += skills[i].tries;

            uint32_t lostSkillTries = static_cast<uint32_t>(sumSkillTries * deathLossPercent);
            while (lostSkillTries > skills[i].tries) {
                lostSkillTries -= skills[i].tries;

                if (skills[i].level <= 10) {
                    skills[i].level = 10;
                    skills[i].tries = 0;
                    lostSkillTries = 0;
                    break;
                }

                skills[i].tries = vocation->getReqSkillTries(i, skills[i].level);
                skills[i].level--;
            }

            skills[i].tries = std::max<int32_t>(0, skills[i].tries - lostSkillTries);
            skills[i].percent = Player::getPercentLevel(skills[i].tries, vocation->getReqSkillTries(i, skills[i].level));
        }

        //Level loss
        uint64_t expLoss = static_cast<uint64_t>(experience * deathLossPercent);
        g_events->eventPlayerOnLoseExperience(this, expLoss);

        if (expLoss != 0) {
            uint32_t oldLevel = level;

            if (vocation->getId() == VOCATION_NONE || level > 7) {
                experience -= expLoss;
            }

            while (level > 1 && experience < Player::getExpForLevel(level)) {
                --level;
                healthMax = std::max<int32_t>(0, healthMax - vocation->getHPGain());
                manaMax = std::max<int32_t>(0, manaMax - vocation->getManaGain());
                capacity = std::max<int32_t>(0, capacity - vocation->getCapGain());
            }

            if (oldLevel != level) {
                std::ostringstream ss;
                ss << "You were downgraded from Level " << oldLevel << " to Level " << level << '.';
                sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
            }

            uint64_t currLevelExp = Player::getExpForLevel(level);
            uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
            if (nextLevelExp > currLevelExp) {
                levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
            } else {
                levelPercent = 0;
            }
        }

        std::bitset<6> bitset(blessings);
        if (bitset[5]) {
            Player* lastHitPlayer;

            if (_lastHitCreature) {
                lastHitPlayer = _lastHitCreature->getPlayer();
                if (!lastHitPlayer) {
                    Creature* lastHitMaster = _lastHitCreature->getMaster();
                    if (lastHitMaster) {
                        lastHitPlayer = lastHitMaster->getPlayer();
                    }
                }
            } else {
                lastHitPlayer = nullptr;
            }

            if (lastHitPlayer) {
                bitset.reset(5);
                blessings = bitset.to_ulong();
            } else {
                blessings = 32;
            }
        } else {
            blessings = 0;
        }

        sendStats();
        sendSkills();
        sendReLoginWindow();

        if (getSkull() == SKULL_BLACK) {
            health = 40;
            mana = 0;
        } else {
            health = healthMax;
            mana = manaMax;
        }

        auto it = conditions.begin(), end = conditions.end();
        while (it != end) {
            Condition* condition = *it;
            if (condition->isPersistent()) {
                it = conditions.erase(it);

                condition->endCondition(this);
                onEndCondition(condition->getType());
                delete condition;
            } else {
                ++it;
            }
        }
    } else {
        setLossSkill(true);

        auto it = conditions.begin(), end = conditions.end();
        while (it != end) {
            Condition* condition = *it;
            if (condition->isPersistent()) {
                it = conditions.erase(it);

                condition->endCondition(this);
                onEndCondition(condition->getType());
                delete condition;
            } else {
                ++it;
            }
        }

        health = healthMax;
        g_game.internalTeleport(this, getTemplePosition(), true);
        g_game.addCreatureHealth(this);
        onThink(EVENT_CREATURE_THINK_INTERVAL);
        onIdleStatus();
        sendStats();
    }
}
 
Seems like its original unmodified method. The problem might also lies somewhere in Lua functions that your server is running. Anyway some debugging would be best method to find the mistake.

You can run debug mode and watch variables while dying or put prints there to know what values are there. If you will do that, Id also uggest add prints in int LuaScriptInterface::luaCreatureSetMaxHealth(lua_State* L) to check Lua change max hp script usages in that time.


If you dont want to do the debugging/dont know how/cant compile/whatever. Theres a chance you might find smth in Lua player onDeath function files.
 
Seems like its original unmodified method. The problem might also lies somewhere in Lua functions that your server is running. Anyway some debugging would be best method to find the mistake.

You can run debug mode and watch variables while dying or put prints there to know what values are there. If you will do that, Id also uggest add prints in int LuaScriptInterface::luaCreatureSetMaxHealth(lua_State* L) to check Lua change max hp script usages in that time.


If you dont want to do the debugging/dont know how/cant compile/whatever. Theres a chance you might find smth in Lua player onDeath function files.
You mean compile source as debug? Well yea i dont really know how to print maybe something like
cout << code << "\n"; or printf("%s\n", code .c_str()
but yea i'm not sure how to print. In playerdeath.lua there is nothing i'm pretty sure
Code:
local deathListEnabled = true
local maxDeathRecords = 5

function onDeath(player, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified)
    local playerId = player:getId()
    if nextUseStaminaTime[playerId] ~= nil then
        nextUseStaminaTime[playerId] = nil
    end

    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
    if not deathListEnabled then
        return
    end

    local byPlayer = 0
    local killerName
    if killer ~= nil then
        if killer:isPlayer() then
            byPlayer = 1
        else
            local master = killer:getMaster()
            if master and master ~= killer and master:isPlayer() then
                killer = master
                byPlayer = 1
            end
        end
        killerName = killer:getName()
    else
        killerName = "field item"
    end

    local byPlayerMostDamage = 0
    local mostDamageKillerName
    if mostDamageKiller ~= nil then
        if mostDamageKiller:isPlayer() then
            byPlayerMostDamage = 1
        else
            local master = mostDamageKiller:getMaster()
            if master and master ~= mostDamageKiller and master:isPlayer() then
                mostDamageKiller = master
                byPlayerMostDamage = 1
            end
        end
        mostDamageName = mostDamageKiller:getName()
    else
        mostDamageName = "field item"
    end

    local playerGuid = player:getGuid()
    db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. byPlayer .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (unjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
    local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)

    local deathRecords = 0
    local tmpResultId = resultId
    while tmpResultId ~= false do
        tmpResultId = result.next(resultId)
        deathRecords = deathRecords + 1
    end

    if resultId ~= false then
        result.free(resultId)
    end

    local limit = deathRecords - maxDeathRecords
    if limit > 0 then
        db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
    end

    if byPlayer == 1 then
        local targetGuild = player:getGuild()
        targetGuild = targetGuild and targetGuild:getId() or 0
        if targetGuild ~= 0 then
            local killerGuild = killer:getGuild()
            killerGuild = killerGuild and killerGuild:getId() or 0
            if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
                local warId = false
                resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
                if resultId ~= false then
                    warId = result.getDataInt(resultId, "id")
                    result.free(resultId)
                end

                if warId ~= false then
                    db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(player:getName()) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
                end
            end
        end
    end
end
 
I dont see anything wrong in this Lua.

To display msgs you can use both cout or printf.
Death function will execute every time some player die and the prints will show up in console.
There you can track actual players mana value at variable mana and maxHP on var healthMax . You can set printf at start and end of that method but I dont think it will give us smth because that method seems fine.

I'd suggest setting prints in lua function (luascripts.cpp) int LuaScriptInterface::luaCreatureSetMaxHealth(lua_State* L) to checkout how many times it will be executed everytime some player dies. Then we will know how many scripts are running on your server.
 
If i good remember, you have spells that transform player and modify health etc. Disable this spell/mod and check the HP/SP has it returned to normal . If everything back to normal without bugs then you found a problem.
 
Last edited:
Back
Top