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

C++ Teleport player (death) to temple without logout TFS 0.4 or otx 2.9

Izaack

Member
Joined
Jun 18, 2012
Messages
70
Solutions
1
Reaction score
17
Location
México
What sources should I modify to perform this action? I am new to this and I would like if you could help me, I use otx 2.9.
this action is for a war 8.60 ot server.
 
in player.cpp
in bool Player::eek:nDeath()
after
Lua:
    if(!Creature::onDeath())
    {
        if(preventDrop)
            setDropLoot(LOOT_DROP_FULL);

        return false;
    }
add
Code:
    std::string value;
    getStorage(xxxx, value);
    check = (int32_t)(atoi(value.c_str()));
if(check >=1)
{
        gainHealth(this, getMaxHealth());
        g_game.combatChangeMana(this, this, getMaxMana());
        setNoMove(false);
        setHideHealth(false);
        g_game.addCreatureHealth(this);
        g_game.internalTeleport(this, Position(1000, 1000, 7), true);
}
done
if you want all players to use this add-in login storage xxxx = 1 so all players will use this if you want it for quest add this storage in quest
if u want player doesn't lose exp use removeExperience( false); and skill use setLossSkill(false);

change xxxx to storage you want and 1000,1000,7 to temple postion
 
Last edited:
in player.cpp
in bool Player::eek:nDeath()
after
Lua:
    if(!Creature::onDeath())
    {
        if(preventDrop)
            setDropLoot(LOOT_DROP_FULL);

        return false;
    }
add
Code:
    std::string value;
    getStorage(xxxx, value);
    check = (int32_t)(atoi(value.c_str()));
if(check >=1)
{
        gainHealth(this, getMaxHealth());
        g_game.combatChangeMana(this, this, getMaxMana());
        setNoMove(false);
        setHideHealth(false);
        g_game.addCreatureHealth(this);
        g_game.internalTeleport(this, Position(1000, 1000, 7), true);
}
done
if you want all players to use this add-in login storage xxxx = 1 so all players will use this if you want it for quest add this storage in quest
if u want player doesn't lose exp use removeExperience( false); and skill use setLossSkill(false);

change xxxx to storage you want and 1000,1000,7 to temple postion
I've been testing, and it works.
but a very important detail

Once the player dies, he is still receiving experience (from monster or player pvp-e). for facts that the player would have done before dying
Since at the time of death he does not logout, he is teleported to the temple



example:
If they are on a pvp server
During a war, the player dies.
(the war continues)
the player who died, continues to receive experience from the temple for the assists he did before his death


Tfs 0.4 . (8.60)
Is there a way to fix it?
 
I've been testing, and it works.
but a very important detail

Once the player dies, he is still receiving experience (from monster or player pvp-e). for facts that the player would have done before dying
Since at the time of death he does not logout, he is teleported to the temple



example:
If they are on a pvp server
During a war, the player dies.
(the war continues)
the player who died, continues to receive experience from the temple for the assists he did before his death


Tfs 0.4 . (8.60)
Is there a way to fix it?
sorry for digging it out just call for player in there when he is teleported to cancel his combatstatus (reset it?)

damageMap.end() (wild guess) e.g Creature::Creature->Creature.damageMap.end() or creature or however it is for ur engine
 
sorry for digging it out just call for player in there when he is teleported to cancel his combatstatus (reset it?)

damageMap.end() (wild guess) e.g Creature::Creature->Creature.damageMap.end() or creature or however it is for ur engine
I just saw the comment xd. I'm sorry
replicate this in 1.5
C++:
Player::damageMap.end();

here 👇
C++:
void Player::death(Creature* lastHitCreature)
...

    health = healthMax;

 Player::damageMap.end();   <---- here
    g_game.internalTeleport(this, getTemplePosition(), true);
    g_game.addCreatureHealth(this);
    onThink(EVENT_CREATURE_THINK_INTERVAL);
    onIdleStatus();
    sendStats();

Error: vs
C++:
`1>\src\player.cpp(2171,23): warning C4834: discarding return value of function with 'nodiscard' attribute`



but I get that error in vs
(although it also makes the release and not work)
what is the correct way ?

edit:

the solution seems to be

C++:
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;
        }
    }
 
Last edited:
I just saw the comment xd. I'm sorry
replicate this in 1.5
C++:
Player::damageMap.end();

here 👇
C++:
void Player::death(Creature* lastHitCreature)
...

    health = healthMax;

 Player::damageMap.end();   <---- here
    g_game.internalTeleport(this, getTemplePosition(), true);
    g_game.addCreatureHealth(this);
    onThink(EVENT_CREATURE_THINK_INTERVAL);
    onIdleStatus();
    sendStats();

Error: vs
C++:
`1>\src\player.cpp(2171,23): warning C4834: discarding return value of function with 'nodiscard' attribute`



but I get that error in vs
(although it also makes the release and not work)
what is the correct way ?

edit:

the solution seems to be

C++:
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;
        }
    }
where to add that i use tfs 1.5
 
where to add that i use tfs 1.5
I leave you the complete code that works for me but need to add that Player::damageMap.end();
that doesn't work
xd

I do not recommend it, the mapdamage when not logging continues, the player gains less experience, and the dead player continues to gain experience from prior to his death

PD: surely there is abundant or unused or non-optimal code, xd

Lua:
//wena compare
void Player::death(Creature* lastHitCreature)
{
    loginPosition = town->getTemplePosition();





    if (skillLoss) {
        //uint8_t unfairFightReduction = 100;
        bool lastHitPlayer = Player::lastHitIsPlayer(lastHitCreature);

        /*if (lastHitPlayer) {
            uint32_t sumLevels = 0;
            uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
            for (const auto& it : damageMap) {
                CountBlock_t cb = it.second;
                if ((OTSYS_TIME() - cb.ticks) <= inFightTicks) {
                    Player* damageDealer = g_game.getPlayerByID(it.first);
                    if (damageDealer) {
                        sumLevels += damageDealer->getLevel();
                    }
                }
            }

            if (sumLevels > level) {
                double reduce = level / static_cast<double>(sumLevels);
                unfairFightReduction = std::max<uint8_t>(20, std::floor((reduce * 100) + 0.5));
            }
        }*/



        //double deathLossPercent = getLostPercent() * (unfairFightReduction / 100.);
        double deathLossPercent = getLostPercent();


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

            sumSkillTries += skills[i].tries;

            removeSkillTries(static_cast<skills_t>(i), sumSkillTries * deathLossPercent, false);
        }

        //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) {
                sendTextMessage(MESSAGE_EVENT_ADVANCE, fmt::format("You were downgraded from Level {:d} to Level {:d}.", oldLevel, level));
            }

            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;
            }
        }

        if (blessings.test(5)) {
            if (lastHitPlayer) {
                blessings.reset(5);
            } else {
                blessings.reset();
                blessings.set(5);
            }
        } else {
            blessings.reset();
        }

        sendStats();
        sendSkills();


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

        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 {
        setSkillLoss(true);
        
    

        
    }
    health = healthMax;
    g_game.internalTeleport(this, getTemplePosition(), true);
    g_game.addCreatureHealth(this);
    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;
        }
    }

    onThink(EVENT_CREATURE_THINK_INTERVAL);
    onIdleStatus();
    sendStats();
    
}
 
Well I'd rather do that in LUA with use of events (TFS 1.x)
Lua:
local playerDeath = CreatureEvent("PlayerOnDeath")

function playerDeath.onPrepareDeath(creature, killer)
    local town = creature:getTown()
    creature:teleportTo(town:getTemplePosition(), true)
    return false
end

playerDeath:register()

local loginEvent = CreatureEvent("PlayerLoginRegister")
loginEvent:type("login")

function loginEvent.onLogin(player)
    player:registerEvent("PlayerOnDeath")
    return true
end
loginEvent:register()
Note: not tested, it's just a POC code
 
Besides the teleport, you have to reset the damages and perform some other actions, in other words -> its full source side
 
Hmm yea some lua functions are missing to do these post death things but cloud be easily added:
C++:
registerMethod("Creature", "clearDamageMap", LuaScriptInterface::luaCreatureClearDamageMap);
C++:
int LuaScriptInterface::luaCreatureClearDamageMap(lua_State* L)
{
    // creature:clearDamageMap()
    Creature* creature = getUserdata<Creature>(L, 1);
    if (!creature) {
        lua_pushnil(L);
        return 1;
    }

    creature->damageMap.clear();
    pushBoolean(L, true);
    return 1;
}

But I see there's quite a lot of things to reset after "real death" so might not be worth, but anyway It'd be solution that can be easily customized if it's moved to LUA.

lastHitCreatureId - most likely no need to reset it as next received damage would anyway override it
clearPlayerPoints() - not sure about that as had no time to look at it but would also require custom lua function to be created.
 
Yes, something like that. However that function only clears self damage which equlas to Creature::onIdleStatus()
 
I leave you the complete code that works for me but need to add that Player::damageMap.end();
that doesn't work
xd

I do not recommend it, the mapdamage when not logging continues, the player gains less experience, and the dead player continues to gain experience from prior to his death

PD: surely there is abundant or unused or non-optimal code, xd

Lua:
//wena compare
void Player::death(Creature* lastHitCreature)
{
    loginPosition = town->getTemplePosition();





    if (skillLoss) {
        //uint8_t unfairFightReduction = 100;
        bool lastHitPlayer = Player::lastHitIsPlayer(lastHitCreature);

        /*if (lastHitPlayer) {
            uint32_t sumLevels = 0;
            uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
            for (const auto& it : damageMap) {
                CountBlock_t cb = it.second;
                if ((OTSYS_TIME() - cb.ticks) <= inFightTicks) {
                    Player* damageDealer = g_game.getPlayerByID(it.first);
                    if (damageDealer) {
                        sumLevels += damageDealer->getLevel();
                    }
                }
            }

            if (sumLevels > level) {
                double reduce = level / static_cast<double>(sumLevels);
                unfairFightReduction = std::max<uint8_t>(20, std::floor((reduce * 100) + 0.5));
            }
        }*/



        //double deathLossPercent = getLostPercent() * (unfairFightReduction / 100.);
        double deathLossPercent = getLostPercent();


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

            sumSkillTries += skills[i].tries;

            removeSkillTries(static_cast<skills_t>(i), sumSkillTries * deathLossPercent, false);
        }

        //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) {
                sendTextMessage(MESSAGE_EVENT_ADVANCE, fmt::format("You were downgraded from Level {:d} to Level {:d}.", oldLevel, level));
            }

            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;
            }
        }

        if (blessings.test(5)) {
            if (lastHitPlayer) {
                blessings.reset(5);
            } else {
                blessings.reset();
                blessings.set(5);
            }
        } else {
            blessings.reset();
        }

        sendStats();
        sendSkills();


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

        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 {
        setSkillLoss(true);
       
   

       
    }
    health = healthMax;
    g_game.internalTeleport(this, getTemplePosition(), true);
    g_game.addCreatureHealth(this);
    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;
        }
    }

    onThink(EVENT_CREATURE_THINK_INTERVAL);
    onIdleStatus();
    sendStats();
   
}

🤣chatgpt gave me the solution xd.

it works for whoever wants it.
but i don't know if it's optimized xd


C:
std::cout << "damageMap:" << std::endl;
    for (const auto& it : damageMap) {
        uint32_t attackerId = it.first;
        const CountBlock_t& countBlock = it.second;


        std::cout << "Attacker ID: " << attackerId << std::endl;
        std::cout << "Total damage: " << countBlock.total << std::endl;
        std::cout << "Ticks: " << countBlock.ticks << std::endl;
        std::cout << std::endl;
    }


    uint32_t deadPlayerId = getID();


    const auto& otherPlayers = g_game.getPlayers();


    for (const auto& playerIt : otherPlayers) {
        Player* otherPlayer = playerIt.second;


        auto damageIt = otherPlayer->damageMap.find(deadPlayerId);
        if (damageIt != otherPlayer->damageMap.end()) {
            otherPlayer->damageMap.erase(damageIt);
            std::cout << "Player delete of damageMap of  " << otherPlayer->getName() << std::endl;
        }
        else
        {
            std::cout << "PLAYER NOT FOUND IN ANY DAMAGEMAP" << std::endl;
        }
    }
 
Back
Top