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

Monsters levels deal low dmg when player has mana shield

Dran Ryszard

Active Member
Joined
Apr 25, 2023
Messages
154
Solutions
1
Reaction score
38
Location
Poland
Hi, have anyone fix for monsters levels (tfs 1.5 8.6)?
For now DMG bonus is apply only for health attacks, if player has utamo vita then attacks deal normal dmg like monster had in .xml file
 

I was changed all what was committed, but i don't see any about it?
Post automatically merged:

// Edit

yea i was check it and yep it changed

1761499106046.webp


full my Game::combatChangeMana
LUA:
bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)
{
    Player* targetPlayer = target->getPlayer();
    if (!targetPlayer) {
        return true;
    }

    Monster* monster = attacker ? attacker->getMonster() : nullptr;
    if (monster && monster->getLevel() > 0) {
        float bonusDmg = g_config.getFloat(ConfigManager::MLVL_BONUSDMG) * monster->getLevel();
        if (bonusDmg != 0.0) {
            if (damage.primary.value < 0) {
                damage.primary.value += std::round(damage.primary.value * bonusDmg);
            }
            if (damage.secondary.value < 0) {
                damage.secondary.value += std::round(damage.secondary.value * bonusDmg);
            }
        }
    }

    int32_t manaChange = damage.primary.value + damage.secondary.value;
    if (manaChange > 0) {
        if (attacker) {
            const Player* attackerPlayer = attacker->getPlayer();
            if (attackerPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(target) == SKULL_NONE) {
                return false;
            }
        }

        if (damage.origin != ORIGIN_NONE) {
            const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
            if (!events.empty()) {
                for (CreatureEvent* creatureEvent : events) {
                    creatureEvent->executeManaChange(target, attacker, damage);
                }
                damage.origin = ORIGIN_NONE;
                return combatChangeMana(attacker, target, damage);
            }
        }

int32_t beforeMana = targetPlayer->getMana();
targetPlayer->changeMana(manaChange);
int32_t afterMana = targetPlayer->getMana();

if (!targetPlayer->isInGhostMode()) {
    if (afterMana == beforeMana) {
        // Mana była pełna, ale nadal pokażemy informację
        addAnimatedText(fmt::format("+{:d}", manaChange), targetPlayer->getPosition(), TEXTCOLOR_DARKPURPLE);
    } else {
        // Częściowo lub w pełni została dodana mana – pokazujemy pełną wartość mikstury
        addAnimatedText(fmt::format("+{:d}", manaChange), targetPlayer->getPosition(), TEXTCOLOR_DARKPURPLE);
    }
}
    } else {
        const Position& targetPos = target->getPosition();
        if (!target->isAttackable()) {
            if (!target->isInGhostMode()) {
                addMagicEffect(targetPos, CONST_ME_POFF);
            }
            return false;
        }

        Player* attackerPlayer;
        if (attacker) {
            attackerPlayer = attacker->getPlayer();
        } else {
            attackerPlayer = nullptr;
        }

        if (attackerPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE) {
            return false;
        }

        int32_t manaLoss = std::min<int32_t>(targetPlayer->getMana(), -manaChange);
        BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
        if (blockType != BLOCK_NONE) {
            addMagicEffect(targetPos, CONST_ME_POFF);
            return false;
        }

        if (manaLoss <= 0) {
            return true;
        }

        if (damage.origin != ORIGIN_NONE) {
            const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
            if (!events.empty()) {
                for (CreatureEvent* creatureEvent : events) {
                    creatureEvent->executeManaChange(target, attacker, damage);
                }
                damage.origin = ORIGIN_NONE;
                return combatChangeMana(attacker, target, damage);
            }
        }

        targetPlayer->drainMana(attacker, manaLoss);

        std::string spectatorMessage;

        TextMessage message;
        std::ostringstream strManaLoss;
        strManaLoss << manaLoss;
        addAnimatedText(strManaLoss.str(), targetPos, TEXTCOLOR_BLUE);

        SpectatorVec spectators;
        map.getSpectators(spectators, targetPos, false, true);
        for (Creature* spectator : spectators) {
            Player* tmpPlayer = spectator->getPlayer();
            if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                message.type = MESSAGE_STATUS_DEFAULT;
                message.text = fmt::format("{:s} loses {:d} mana due to your attack.", target->getName(), manaLoss);
                message.text[0] = std::toupper(message.text[0]);
            } else if (tmpPlayer == targetPlayer) {
                message.type = MESSAGE_STATUS_DEFAULT;
                if (!attacker) {
                    message.text = fmt::format("You lose {:d} mana.", manaLoss);
                } else if (targetPlayer == attackerPlayer) {
                    message.text = fmt::format("You lose {:d} mana due to your own attack.", manaLoss);
                } else {
                    message.text = fmt::format("You lose {:d} mana due to an attack by {:s}.", manaLoss, attacker->getName());
                }
            } else {
                message.type = MESSAGE_STATUS_DEFAULT;
                if (spectatorMessage.empty()) {
                    if (!attacker) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana.", target->getName(), manaLoss);
                    } else if (attacker == target) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to {:s} own attack.", target->getName(), manaLoss, targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his");
                    } else {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to an attack by {:s}.", target->getName(), manaLoss, attacker->getName());
                    }
                    spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                }
            }
            tmpPlayer->sendTextMessage(message);
        }
    }

    return true;
}
 
Last edited:
I was add a debug print with gpt but im not understand why here is no attacker?
(DMG where i hit for 3k+ dmg its a spell called "manadrain" in monster .xml, others is melee and earth

Code:
[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -9, damage.secondary.value: 0, origin: 2, target mana: 115973[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -225, damage.secondary.value: 0, origin: 0, target mana: 115973[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3638, damage.secondary.value: 0, origin: 2, target mana: 110348[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3638, damage.secondary.value: 0, origin: 0, target mana: 110348[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3732, damage.secondary.value: 0, origin: 2, target mana: 113821[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3732, damage.secondary.value: 0, origin: 0, target mana: 113821[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -7, damage.secondary.value: 0, origin: 2, target mana: 117573[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -175, damage.secondary.value: 0, origin: 0, target mana: 117573[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3677, damage.secondary.value: 0, origin: 2, target mana: 113198[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3677, damage.secondary.value: 0, origin: 0, target mana: 113198[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -7, damage.secondary.value: 0, origin: 2, target mana: 116655[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -175, damage.secondary.value: 0, origin: 0, target mana: 116655[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3767, damage.secondary.value: 0, origin: 2, target mana: 112280[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3767, damage.secondary.value: 0, origin: 0, target mana: 112280[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -9, damage.secondary.value: 0, origin: 2, target mana: 116057[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -225, damage.secondary.value: 0, origin: 0, target mana: 116057[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3648, damage.secondary.value: 0, origin: 2, target mana: 110432[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3648, damage.secondary.value: 0, origin: 0, target mana: 110432[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3713, damage.secondary.value: 0, origin: 2, target mana: 114090[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3713, damage.secondary.value: 0, origin: 0, target mana: 114090[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -7, damage.secondary.value: 0, origin: 2, target mana: 117608[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -175, damage.secondary.value: 0, origin: 0, target mana: 117608[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3716, damage.secondary.value: 0, origin: 2, target mana: 113233[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3716, damage.secondary.value: 0, origin: 0, target mana: 113233[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -7, damage.secondary.value: 0, origin: 2, target mana: 116794[DEBUG] combatChangeMana() -> Monster: Toxic Dog, Level: 3000[DEBUG] damage.primary.value: -175, damage.secondary.value: 0, origin: 0, target mana: 116794[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3714, damage.secondary.value: 0, origin: 2, target mana: 112244[DEBUG] combatChangeMana() -> No attacker[DEBUG] damage.primary.value: 3714, damage.secondary.value: 0, origin: 0, target mana: 112244
 
Last edited:
Try this code and share output
C++:
bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)
{
    Player* targetPlayer = target->getPlayer();
    if (!targetPlayer) {
        return true;
    }
    Monster* monster = attacker ? attacker->getMonster() : nullptr;
    if (monster && monster->getLevel() > 0) {
        std::cout<<"monsterLevel: " << monster->getLevel() << std::endl;
        float bonusDmg = g_config.getFloat(ConfigManager::MLVL_BONUSDMG) * monster->getLevel();
        std::cout<<"bonusDmg: " << bonusDmg << std::endl;
        if (bonusDmg != 0.0) {
            if (damage.primary.value < 0) {
                std::cout<<"primary before: " << damage.primary.value << std::endl;
                damage.primary.value += std::round(damage.primary.value * bonusDmg);
                std::cout<<"primary after: " << damage.primary.value << std::endl;
            }
            if (damage.secondary.value < 0) {
                damage.secondary.value += std::round(damage.secondary.value * bonusDmg);
            }
        }
    }
    int32_t manaChange = damage.primary.value + damage.secondary.value;
    if (manaChange > 0) {
        if (attacker) {
            const Player* attackerPlayer = attacker->getPlayer();
            if (attackerPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(target) == SKULL_NONE) {
                return false;
            }
        }
        if (damage.origin != ORIGIN_NONE) {
            const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
            if (!events.empty()) {
                for (CreatureEvent* creatureEvent : events) {
                    creatureEvent->executeManaChange(target, attacker, damage);
                }
                damage.origin = ORIGIN_NONE;
                return combatChangeMana(attacker, target, damage);
            }
        }
int32_t beforeMana = targetPlayer->getMana();
targetPlayer->changeMana(manaChange);
int32_t afterMana = targetPlayer->getMana();
if (!targetPlayer->isInGhostMode()) {
    if (afterMana == beforeMana) {
        // Mana była pełna, ale nadal pokażemy informację
        addAnimatedText(fmt::format("+{:d}", manaChange), targetPlayer->getPosition(), TEXTCOLOR_DARKPURPLE);
    } else {
        // Częściowo lub w pełni została dodana mana – pokazujemy pełną wartość mikstury
        addAnimatedText(fmt::format("+{:d}", manaChange), targetPlayer->getPosition(), TEXTCOLOR_DARKPURPLE);
    }
}
    } else {
        const Position& targetPos = target->getPosition();
        if (!target->isAttackable()) {
            if (!target->isInGhostMode()) {
                addMagicEffect(targetPos, CONST_ME_POFF);
            }
            return false;
        }
        Player* attackerPlayer;
        if (attacker) {
            attackerPlayer = attacker->getPlayer();
        } else {
            attackerPlayer = nullptr;
        }
        if (attackerPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE) {
            return false;
        }
        int32_t manaLoss = std::min<int32_t>(targetPlayer->getMana(), -manaChange);
        BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
        if (blockType != BLOCK_NONE) {
            addMagicEffect(targetPos, CONST_ME_POFF);
            return false;
        }
        if (manaLoss <= 0) {
            return true;
        }
        if (damage.origin != ORIGIN_NONE) {
            const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
            if (!events.empty()) {
                for (CreatureEvent* creatureEvent : events) {
                    creatureEvent->executeManaChange(target, attacker, damage);
                }
                damage.origin = ORIGIN_NONE;
                return combatChangeMana(attacker, target, damage);
            }
        }
        targetPlayer->drainMana(attacker, manaLoss);
        std::string spectatorMessage;
        TextMessage message;
        std::ostringstream strManaLoss;
        strManaLoss << manaLoss;
        addAnimatedText(strManaLoss.str(), targetPos, TEXTCOLOR_BLUE);
        SpectatorVec spectators;
        map.getSpectators(spectators, targetPos, false, true);
        for (Creature* spectator : spectators) {
            Player* tmpPlayer = spectator->getPlayer();
            if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                message.type = MESSAGE_STATUS_DEFAULT;
                message.text = fmt::format("{:s} loses {:d} mana due to your attack.", target->getName(), manaLoss);
                message.text[0] = std::toupper(message.text[0]);
            } else if (tmpPlayer == targetPlayer) {
                message.type = MESSAGE_STATUS_DEFAULT;
                if (!attacker) {
                    message.text = fmt::format("You lose {:d} mana.", manaLoss);
                } else if (targetPlayer == attackerPlayer) {
                    message.text = fmt::format("You lose {:d} mana due to your own attack.", manaLoss);
                } else {
                    message.text = fmt::format("You lose {:d} mana due to an attack by {:s}.", manaLoss, attacker->getName());
                }
            } else {
                message.type = MESSAGE_STATUS_DEFAULT;
                if (spectatorMessage.empty()) {
                    if (!attacker) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana.", target->getName(), manaLoss);
                    } else if (attacker == target) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to {:s} own attack.", target->getName(), manaLoss, targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his");
                    } else {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to an attack by {:s}.", target->getName(), manaLoss, attacker->getName());
                    }
                    spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                }
            }
            tmpPlayer->sendTextMessage(message);
        }
    }
    return true;
}
 
@krecikondexin no errors but no prints too ;D Monsters attacking me but in console i dont have any prints

For test i was swap code from changeHealth to mana and nothing change xD I think problem must be in other file/class
(Ofc i mean about few lines:

This:
LUA:
    Monster* monster = attacker ? attacker->getMonster() : nullptr;
    if (monster && monster->getLevel() > 0) {
        float bonusDmg = g_config.getFloat(ConfigManager::MLVL_BONUSDMG) * monster->getLevel();
        if (bonusDmg != 0.0) {
            if (damage.primary.value < 0) {
                damage.primary.value += std::round(damage.primary.value * bonusDmg);
            }
            if (damage.secondary.value < 0) {
                damage.secondary.value += std::round(damage.secondary.value * bonusDmg);
            }
        }
    }

i was swap with version from health
Post automatically merged:

//////////////// edit
that fix work: Feature - [TFS 1.3] Monster Levels (https://otland.net/threads/tfs-1-3-monster-levels.260470/post-2775760)
 
Last edited:
Back
Top