• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

TFS 1.X+ Monsters steal EXP

Tibia Idle

Active Member
Joined
Nov 23, 2023
Messages
164
Reaction score
36
Is there a way to turn off monsters stealing EXP? When a player has exp on frost dragons, when one dragon hits another, the player gets less EXP after killing it. How to change it? TFS 1.2
 
C++:
void Creature::onDeath()
{
    bool lastHitUnjustified = false;
    bool mostDamageUnjustified = false;
    Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
    Creature* lastHitCreatureMaster;
    if (lastHitCreature) {
        lastHitUnjustified = lastHitCreature->onKilledCreature(this);
        lastHitCreatureMaster = lastHitCreature->getMaster();
    } else {
        lastHitCreatureMaster = nullptr;
    }

    Creature* mostDamageCreature = nullptr;
    const int64_t timeNow = OTSYS_TIME();
    const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
    int32_t mostDamage = 0;
    std::map<Creature*, uint64_t> experienceMap;
    for (const auto& it : damageMap) {
        if (Creature* attacker = g_game.getCreatureByID(it.first)) {
            CountBlock_t cb = it.second;
            if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
                mostDamage = cb.total;
                mostDamageCreature = attacker;
            }

            if (attacker != this) {
                // Only consider experience for players, not for monsters
                if (Player* attackerPlayer = attacker->getPlayer()) {
                    attackerPlayer->removeAttacked(getPlayer());

                    Party* party = attackerPlayer->getParty();
                    if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
                        attacker = party->getLeader();
                    }

                    uint64_t gainExp = getGainedExperience(attacker);
                    auto tmpIt = experienceMap.find(attacker);
                    if (tmpIt == experienceMap.end()) {
                        experienceMap[attacker] = gainExp;
                    } else {
                        tmpIt->second += gainExp;
                    }
                }
            }
        }
    }

    // Distribute experience only to players, excluding monsters
    for (const auto& it : experienceMap) {
        it.first->onGainExperience(it.second, this);
    }

    if (mostDamageCreature) {
        if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
            Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
            if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
                mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
            }
        }
    }

    bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
    death(lastHitCreature);

    if (master) {
        setMaster(nullptr);
    }

    if (droppedCorpse) {
        g_game.removeCreature(this, false);
    }
}

not tested
second one with damagemap changes
C++:
void Creature::onDeath()
{
    bool lastHitUnjustified = false;
    bool mostDamageUnjustified = false;
    Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
    Creature* lastHitCreatureMaster;
    if (lastHitCreature) {
        lastHitUnjustified = lastHitCreature->onKilledCreature(this);
        lastHitCreatureMaster = lastHitCreature->getMaster();
    } else {
        lastHitCreatureMaster = nullptr;
    }

    Creature* mostDamageCreature = nullptr;
    const int64_t timeNow = OTSYS_TIME();
    const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
    int32_t mostDamage = 0;
    std::map<Player*, uint64_t> experienceMap;  // Changed to map Player* to uint64_t

    for (const auto& it : damageMap) {
        Creature* attacker = g_game.getCreatureByID(it.first);
        if (attacker) {
            CountBlock_t cb = it.second;
            if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
                mostDamage = cb.total;
                mostDamageCreature = attacker;
            }

            if (Player* attackerPlayer = attacker->getPlayer()) {
                attackerPlayer->removeAttacked(getPlayer());

                Party* party = attackerPlayer->getParty();
                if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
                    attackerPlayer = party->getLeader();
                }

                uint64_t gainExp = getGainedExperience(attackerPlayer);
                auto tmpIt = experienceMap.find(attackerPlayer);
                if (tmpIt == experienceMap.end()) {
                    experienceMap[attackerPlayer] = gainExp;
                } else {
                    tmpIt->second += gainExp;
                }
            }
        }
    }

    // Distribute experience to players only
    for (const auto& it : experienceMap) {
        it.first->onGainExperience(it.second, this);
    }

    if (mostDamageCreature) {
        if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
            Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
            if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
                mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
            }
        }
    }

    bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
    death(lastHitCreature);

    if (master) {
        setMaster(nullptr);
    }

    if (droppedCorpse) {
        g_game.removeCreature(this, false);
    }
}
either 1 of those should work


third version with summons -> master consideration
C++:
void Creature::onDeath()
{
    bool lastHitUnjustified = false;
    bool mostDamageUnjustified = false;
    Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
    Creature* lastHitCreatureMaster;
    if (lastHitCreature) {
        lastHitUnjustified = lastHitCreature->onKilledCreature(this);
        lastHitCreatureMaster = lastHitCreature->getMaster();
    } else {
        lastHitCreatureMaster = nullptr;
    }

    Creature* mostDamageCreature = nullptr;
    const int64_t timeNow = OTSYS_TIME();
    const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
    int32_t mostDamage = 0;
    std::map<Player*, uint64_t> experienceMap;

    for (const auto& it : damageMap) {
        Creature* attacker = g_game.getCreatureByID(it.first);
        if (attacker) {
            CountBlock_t cb = it.second;
            if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
                mostDamage = cb.total;
                mostDamageCreature = attacker;
            }

            Player* attackerPlayer = nullptr;

            // Check if the attacker is a player or a summon
            if (Player* player = attacker->getPlayer()) {
                // If the attacker is a player, they are directly added to experience calculations
                attackerPlayer = player;
            } else if (Creature* summon = attacker->getSummon()) {
                // If the attacker is a summon, use its master (player)
                if (Player* summonMaster = summon->getMaster()->getPlayer()) {
                    attackerPlayer = summonMaster;
                }
            }

            if (attackerPlayer) {
                attackerPlayer->removeAttacked(getPlayer());

                Party* party = attackerPlayer->getParty();
                if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
                    attackerPlayer = party->getLeader();
                }

                uint64_t gainExp = getGainedExperience(attackerPlayer);
                auto tmpIt = experienceMap.find(attackerPlayer);
                if (tmpIt == experienceMap.end()) {
                    experienceMap[attackerPlayer] = gainExp;
                } else {
                    tmpIt->second += gainExp;
                }
            }
        }
    }

    // Distribute experience to players only
    for (const auto& it : experienceMap) {
        it.first->onGainExperience(it.second, this);
    }

    if (mostDamageCreature) {
        if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
            Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
            if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
                mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
            }
        }
    }

    bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
    death(lastHitCreature);

    if (master) {
        setMaster(nullptr);
    }

    if (droppedCorpse) {
        g_game.removeCreature(this, false);
    }
}
Post automatically merged:

4th version with monster->summon->not player logic

C++:
void Creature::onDeath()
{
    bool lastHitUnjustified = false;
    bool mostDamageUnjustified = false;
    Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
    Creature* lastHitCreatureMaster;
    if (lastHitCreature) {
        lastHitUnjustified = lastHitCreature->onKilledCreature(this);
        lastHitCreatureMaster = lastHitCreature->getMaster();
    } else {
        lastHitCreatureMaster = nullptr;
    }

    Creature* mostDamageCreature = nullptr;
    const int64_t timeNow = OTSYS_TIME();
    const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
    int32_t mostDamage = 0;
    std::map<Player*, uint64_t> experienceMap;

    for (const auto& it : damageMap) {
        Creature* attacker = g_game.getCreatureByID(it.first);
        if (attacker) {
            CountBlock_t cb = it.second;
            if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
                mostDamage = cb.total;
                mostDamageCreature = attacker;
            }

            Player* attackerPlayer = nullptr;

            // Check if the attacker is a player or a summon controlled by a player
            if (Player* player = attacker->getPlayer()) {
                attackerPlayer = player;
            } else if (Creature* summon = attacker->getSummon()) {
                if (Creature* master = summon->getMaster()) {
                    if (Player* masterPlayer = master->getPlayer()) {
                        attackerPlayer = masterPlayer;
                    }
                }
            }

            if (attackerPlayer) {
                attackerPlayer->removeAttacked(getPlayer());

                Party* party = attackerPlayer->getParty();
                if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
                    attackerPlayer = party->getLeader();
                }

                uint64_t gainExp = getGainedExperience(attackerPlayer);
                auto tmpIt = experienceMap.find(attackerPlayer);
                if (tmpIt == experienceMap.end()) {
                    experienceMap[attackerPlayer] = gainExp;
                } else {
                    tmpIt->second += gainExp;
                }
            }
        }
    }

    // Distribute experience to players only
    for (const auto& it : experienceMap) {
        it.first->onGainExperience(it.second, this);
    }

    if (mostDamageCreature) {
        if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
            Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
            if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
                mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
            }
        }
    }

    bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
    death(lastHitCreature);

    if (master) {
        setMaster(nullptr);
    }

    if (droppedCorpse) {
        g_game.removeCreature(this, false);
    }
}
 
Last edited:
Back
Top