• 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!
  • New resources must be posted under Resources tab. A discussion thread will be created automatically, you can't open threads manually anymore.

Feature [TFS 1.3] Monster Levels

Greetings!
I have found yet a new bug on the system. And when we fix it, we dont need the logic in this post at all. Se further below for new code.
Monster Damage Bug

Greetings. I would like to point out a very impactful bug with this system and the fix for it:

onCombatChangeHealth is a recursive function and calls itself in case it has a onChangeHealth lua callback. In that case the damage is increases not only the first time but also the second time it goes into the function. Because the callback is only executed once, it is not infinitive. This is because they check "damage.origin != ORIGIN_NONE" to avoid that.
So this also must be checked for the monster bonus damage to not double it twice.

Example: (You use a onHealthChange creatureevent to reduce the damage by 10% )
1. you take damage and onCombatHealth activates, calculates monster damage
2. .. Reaches down to "target->getCreatureEvents(CREATURE_EVENT_HEALTHCHANGE)", check any change of damage on the onChangeHealth lua callback.
3. Returns modified damage ( 10% reduced damage) to onCombatHealth and sets damage.origin = ORIGIN_NONE
4. onCombatHealth activate, calculating monster damage again (increasing it again).
5. Ignores events this time due to ORIGIN_NONE.
6. deal damage to player.

This means that the intention of reducing damage, will actually increase it instead (of course based on your bonus damage)


Solution
Replace this:
C++:
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);
            }
        }
    }

with this, (do this for CombatChangeHealth and CombatChangeMana):
Code:
    Monster* monster = attacker ? attacker->getMonster() : nullptr;
    if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }


in combatChangeHealth, add "damage.origin = ORIGIN_NONE;" below "manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);"
This is to not activate onHealthChange events again if you took damage that broke your manashield.
C++:
SpectatorVec spectators;
if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
    int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
    if (manaDamage != 0) {
        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);
                }
                healthChange = damage.primary.value + damage.secondary.value;
                if (healthChange == 0) {
                    return true;
                }
                manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
                damage.origin = ORIGIN_NONE;
            }
        }

Background
When monsters perform an attack, the damage goes through a number of functions before it onHealth/onMana is triggered.
I discovered that the player will allways calculate the monster damage with the default attack values(from monster xml/rev file) in the "BlockHit" function.

Scenario
Monster Bonus damage = 0.029, Monster Level = 200, Damage caused = 100
Total bonus damage = 0.0029 * 25 * 100 + 100 = 158

What happens on Block hit? Lets say a total of armor and defense of the player is 120:
Damage = Damage caused(100) - 120 = -20(0) <--- Resulting in player blocking the damage, aka no hit.

What happens when we make sure that the bonus damage is calculated before BlockHit?
Damage = Damage caused(158) - 120 = 38 <-- Player is receving 38 in damage.

Because the monster damage is calculated in the onHealth which is too late, players will use the default values from monster file to "take" damage, doesnt matter how high lvl or how high bonus rate ur setting.

Note: This is not a Major bug, but will be mostly noticeable if your running a low rate server with some special creatures with high level/rates. But if not fixed, players will for sure block of damage they should not.

Solution

remove all monster bonus damage calculation from these two functions:
C++:
bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage)

bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)

in combat.cpp, include monster.h:
1750958974432.webp

in function Combat::doTargetCombat, add:


C++:
Player* casterPlayer = caster ? caster->getPlayer() : nullptr;
--BELOW HERE
Monster* monster = caster ? caster->getMonster() : nullptr;

if (monster) {
    float bonusDmg = g_config.getFloat(ConfigManager::MLVL_BONUSDMG) * monster->getLevel();
    if (bonusDmg != 0.0) {
        damage.primary.value += std::round(damage.primary.value * bonusDmg);
        damage.secondary.value += std::round(damage.secondary.value * bonusDmg);
    }
}


This should make sure that the damage is properly "interfaced" to the system.
 
I made this change in droploot to give a higher drop percentage for higher-level monsters... in my server there are only monsters from level 1 to 5...

Could someone analyze the code?

TFS 1.4.2

/data/scripts/eventcallbacks/monster/default_onDropLoot.lua



Do you think this will work?
LUA:
local ec = EventCallback

local function getLevelBonus(monsterLevel)
    -- Ajuste os bônus ao seu gosto
    local bonuses = {
        [1] = 0.10, -- +10%
        [2] = 0.20, -- +20%
        [3] = 0.30, -- +30%
        [4] = 0.40, -- +4%
        [5] = 0.50, -- +50%
    }
    return bonuses[monsterLevel] or 0
end

ec.onDropLoot = function(self, corpse)
    if configManager.getNumber(configKeys.RATE_LOOT) == 0 then
        return
    end

    local player = Player(corpse:getCorpseOwner())
    local mType = self:getType()

    -- pega o level do monstro
    local monsterLevel = self.level or 1
    local bonusPercent = getLevelBonus(monsterLevel)

    if not player or player:getStamina() > 840 then
        local monsterLoot = mType:getLoot()

        for _, lootData in ipairs(monsterLoot) do

            -- chance original
            local baseChance = lootData.chance

            -- novo cálculo
            local bonus = math.floor(baseChance * bonusPercent)
            local finalChance = math.min(baseChance + bonus, 85000)

            -- rolagem de loot
            if math.random(85000) <= finalChance then
                local item = corpse:createLootItem(lootData)
                if not item then
                    print('[Warning] DropLoot:', 'Could not add loot item to corpse.')
                end
            end
        end

        -- Mensagem de loot
        if player then
            local text = ("Loot of %s (Lv.%d): %s"):format(
                mType:getNameDescription(), monsterLevel, corpse:getContentDescription()
            )
            local party = player:getParty()
            if party then
                party:broadcastPartyLoot(text)
            else
                player:sendTextMessage(MESSAGE_LOOT, text)
            end
        end
    else
        local text = ("Loot of %s: nothing (due to low stamina)"):format(mType:getNameDescription())
        local party = player:getParty()
        if party then
            party:broadcastPartyLoot(text)
        else
            player:sendTextMessage(MESSAGE_LOOT, text)
        end
    end
end

ec:register()
 
I made this change in droploot to give a higher drop percentage for higher-level monsters... in my server there are only monsters from level 1 to 5...

Could someone analyze the code?

TFS 1.4.2

/data/scripts/eventcallbacks/monster/default_onDropLoot.lua



Do you think this will work?
LUA:
local ec = EventCallback

local function getLevelBonus(monsterLevel)
    -- Ajuste os bônus ao seu gosto
    local bonuses = {
        [1] = 0.10, -- +10%
        [2] = 0.20, -- +20%
        [3] = 0.30, -- +30%
        [4] = 0.40, -- +4%
        [5] = 0.50, -- +50%
    }
    return bonuses[monsterLevel] or 0
end

ec.onDropLoot = function(self, corpse)
    if configManager.getNumber(configKeys.RATE_LOOT) == 0 then
        return
    end

    local player = Player(corpse:getCorpseOwner())
    local mType = self:getType()

    -- pega o level do monstro
    local monsterLevel = self.level or 1
    local bonusPercent = getLevelBonus(monsterLevel)

    if not player or player:getStamina() > 840 then
        local monsterLoot = mType:getLoot()

        for _, lootData in ipairs(monsterLoot) do

            -- chance original
            local baseChance = lootData.chance

            -- novo cálculo
            local bonus = math.floor(baseChance * bonusPercent)
            local finalChance = math.min(baseChance + bonus, 85000)

            -- rolagem de loot
            if math.random(85000) <= finalChance then
                local item = corpse:createLootItem(lootData)
                if not item then
                    print('[Warning] DropLoot:', 'Could not add loot item to corpse.')
                end
            end
        end

        -- Mensagem de loot
        if player then
            local text = ("Loot of %s (Lv.%d): %s"):format(
                mType:getNameDescription(), monsterLevel, corpse:getContentDescription()
            )
            local party = player:getParty()
            if party then
                party:broadcastPartyLoot(text)
            else
                player:sendTextMessage(MESSAGE_LOOT, text)
            end
        end
    else
        local text = ("Loot of %s: nothing (due to low stamina)"):format(mType:getNameDescription())
        local party = player:getParty()
        if party then
            party:broadcastPartyLoot(text)
        else
            player:sendTextMessage(MESSAGE_LOOT, text)
        end
    end
end

ec:register()

I added my version of it in previous page

 
Solution

remove all monster bonus damage calculation from these two functions:
bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage) bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)
Can you explain this part further?
I followed all your reforms, but I don't understand this part. I'm afraid I'll cause a disaster in my source.
I use TFS 1.5
LUA:
bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage)
{
    const Position& targetPos = target->getPosition();
    if (damage.primary.value > 0) {
        if (target->getHealth() <= 0) {
            return false;
        }

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

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

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

        int32_t realHealthChange = target->getHealth();
        target->gainHealth(attacker, damage.primary.value);
        realHealthChange = target->getHealth() - realHealthChange;

        if (realHealthChange > 0 && !target->isInGhostMode()) {
            auto damageString = fmt::format("{:d} hitpoint{:s}", realHealthChange, realHealthChange != 1 ? "s" : "");

            std::string spectatorMessage;

            TextMessage message;
            std::ostringstream strHealthChange;
            strHealthChange << realHealthChange;
            addAnimatedText(strHealthChange.str(), targetPos, TEXTCOLOR_MAYABLUE);

            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("You heal {:s} for {:s}.", target->getNameDescription(), damageString);
                } else if (tmpPlayer == targetPlayer) {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    if (!attacker) {
                        message.text = fmt::format("You were healed for {:s}.", damageString);
                    } else if (targetPlayer == attackerPlayer) {
                        message.text = fmt::format("You healed yourself for {:s}.", damageString);
                    } else {
                        message.text = fmt::format("You were healed by {:s} for {:s}.", attacker->getNameDescription(), damageString);
                    }
                } else {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    if (spectatorMessage.empty()) {
                        if (!attacker) {
                            spectatorMessage = fmt::format("{:s} was healed for {:s}.", target->getNameDescription(), damageString);
                        } else if (attacker == target) {
                            spectatorMessage = fmt::format("{:s} healed {:s}self for {:s}.", attacker->getNameDescription(), targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "him") : "it", damageString);
                        } else {
                            spectatorMessage = fmt::format("{:s} healed {:s} for {:s}.", attacker->getNameDescription(), target->getNameDescription(), damageString);
                        }
                        spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                    }
                    message.type = MESSAGE_STATUS_DEFAULT;
                }
                tmpPlayer->sendTextMessage(message);
            }
        }
    } else {
        if (!target->isAttackable()) {
            if (!target->isInGhostMode()) {
                addMagicEffect(targetPos, CONST_ME_POFF);
            }
            return true;
        }

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

        Player* targetPlayer = target->getPlayer();
        if (attackerPlayer && targetPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE) {
            return false;
        }
        
        Monster* monster = attacker ? attacker->getMonster() : nullptr;
        if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }

        damage.primary.value = std::abs(damage.primary.value);
        damage.secondary.value = std::abs(damage.secondary.value);

        int32_t healthChange = damage.primary.value + damage.secondary.value;
        if (healthChange == 0) {
            return true;
        }

        TextMessage message;

        SpectatorVec spectators;
     if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
    int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
    if (manaDamage != 0) {
        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);
                }
                healthChange = damage.primary.value + damage.secondary.value;
                if (healthChange == 0) {
                    return true;
                }
                manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
                damage.origin = ORIGIN_NONE;
            }
        }

                targetPlayer->drainMana(attacker, manaDamage);
                map.getSpectators(spectators, targetPos, true, true);
                addMagicEffect(spectators, targetPos, CONST_ME_LOSEENERGY);

                std::string spectatorMessage;

                std::ostringstream strManaDamage;
                strManaDamage << manaDamage;
                addAnimatedText(strManaDamage.str(), targetPos, TEXTCOLOR_BLUE);

                for (Creature* spectator : spectators) {
                    Player* tmpPlayer = spectator->getPlayer();
                    if (tmpPlayer->getPosition().z != targetPos.z) {
                        continue;
                    }

                    if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                        message.type = MESSAGE_STATUS_DEFAULT;
                        message.text = fmt::format("{:s} loses {:d} mana due to your attack.", target->getNameDescription(), manaDamage);
                        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.", manaDamage);
                        } else if (targetPlayer == attackerPlayer) {
                            message.text = fmt::format("You lose {:d} mana due to your own attack.", manaDamage);
                        } else {
                            message.text = fmt::format("You lose {:d} mana due to an attack by {:s}.", manaDamage, attacker->getNameDescription());
                        }
                    } else {
                        message.type = MESSAGE_STATUS_DEFAULT;
                        if (spectatorMessage.empty()) {
                            if (!attacker) {
                                spectatorMessage = fmt::format("{:s} loses {:d} mana.", target->getNameDescription(), manaDamage);
                            } else if (attacker == target) {
                                spectatorMessage = fmt::format("{:s} loses {:d} mana due to {:s} own attack.", target->getNameDescription(), manaDamage, targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his");
                            } else {
                                spectatorMessage = fmt::format("{:s} loses {:d} mana due to an attack by {:s}.", target->getNameDescription(), manaDamage, attacker->getNameDescription());
                            }
                            spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                        }
                    }
                    tmpPlayer->sendTextMessage(message);
                }

                damage.primary.value -= manaDamage;
                if (damage.primary.value < 0) {
                    damage.secondary.value = std::max<int32_t>(0, damage.secondary.value + damage.primary.value);
                    damage.primary.value = 0;
                }
            }
        }

        int32_t realDamage = damage.primary.value + damage.secondary.value;
        if (realDamage == 0) {
            return true;
        }

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

        int32_t targetHealth = target->getHealth();
        if (damage.primary.value >= targetHealth) {
            damage.primary.value = targetHealth;
            damage.secondary.value = 0;
        } else if (damage.secondary.value) {
            damage.secondary.value = std::min<int32_t>(damage.secondary.value, targetHealth - damage.primary.value);
        }

        realDamage = damage.primary.value + damage.secondary.value;
        if (realDamage == 0) {
            return true;
        }

        if (spectators.empty()) {
            map.getSpectators(spectators, targetPos, true, true);
        }

        message.primary.value = damage.primary.value;
        message.secondary.value = damage.secondary.value;

        uint8_t hitEffect;
        if (message.primary.value) {
            combatGetTypeInfo(damage.primary.type, target, message.primary.color, hitEffect);
            if (hitEffect != CONST_ME_NONE) {
                addMagicEffect(spectators, targetPos, hitEffect);
            }

            if (message.primary.color != TEXTCOLOR_NONE) {
                std::ostringstream strPrimaryDamage;
                strPrimaryDamage << message.primary.value;
                addAnimatedText(strPrimaryDamage.str(), targetPos, message.primary.color);
            }
        }

        if (message.secondary.value) {
            combatGetTypeInfo(damage.secondary.type, target, message.secondary.color, hitEffect);
            if (hitEffect != CONST_ME_NONE) {
                addMagicEffect(spectators, targetPos, hitEffect);
            }

            if (message.secondary.color != TEXTCOLOR_NONE) {
                std::ostringstream strSecondaryDamage;
                strSecondaryDamage << message.secondary.value;
                addAnimatedText(strSecondaryDamage.str(), targetPos, message.secondary.color);
            }
        }

        if (message.primary.color != TEXTCOLOR_NONE || message.secondary.color != TEXTCOLOR_NONE) {
            auto damageString = fmt::format("{:d} hitpoint{:s}", realDamage, realDamage != 1 ? "s" : "");

            std::string spectatorMessage;

            for (Creature* spectator : spectators) {
                Player* tmpPlayer = spectator->getPlayer();
                if (tmpPlayer->getPosition().z != targetPos.z) {
                    continue;
                }

                if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    message.text = fmt::format("{:s} loses {:s} due to your attack.", target->getNameDescription(), damageString);
                    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 {:s}.", damageString);
                    } else if (targetPlayer == attackerPlayer) {
                        message.text = fmt::format("You lose {:s} due to your own attack.", damageString);
                    } else {
                        message.text = fmt::format("You lose {:s} due to an attack by {:s}.", damageString, attacker->getNameDescription());
                    }
                } else {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    if (spectatorMessage.empty()) {
                        if (!attacker) {
                            spectatorMessage = fmt::format("{:s} loses {:s}.", target->getNameDescription(), damageString);
                        } else if (attacker == target) {
                            spectatorMessage = fmt::format("{:s} loses {:s} due to {:s} own attack.", target->getNameDescription(), damageString, targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his") : "its");
                        } else {
                            spectatorMessage = fmt::format("{:s} loses {:s} due to an attack by {:s}.", target->getNameDescription(), damageString, attacker->getNameDescription());
                        }
                        spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                    }
                    message.text = spectatorMessage;
                }
                tmpPlayer->sendTextMessage(message);
            }
        }

        if (realDamage >= targetHealth) {
            for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
                if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
                    return false;
                }
            }
        }

        target->drainHealth(attacker, realDamage);
        addCreatureHealth(spectators, target);
    }

    return true;
}

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 && damage.origin != ORIGIN_NONE) {
        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 realManaChange = targetPlayer->getMana();
        targetPlayer->changeMana(manaChange);
        realManaChange = targetPlayer->getMana() - realManaChange;
    } 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->getNameDescription(), 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->getNameDescription());
                }
            } else {
                message.type = MESSAGE_STATUS_DEFAULT;
                if (spectatorMessage.empty()) {
                    if (!attacker) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana.", target->getNameDescription(), manaLoss);
                    } else if (attacker == target) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to {:s} own attack.", target->getNameDescription(), manaLoss, targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his");
                    } else {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to an attack by {:s}.", target->getNameDescription(), manaLoss, attacker->getNameDescription());
                    }
                    spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                }
            }
            tmpPlayer->sendTextMessage(message);
        }
    }

    return true;
}
 
Can you explain this part further?
I followed all your reforms, but I don't understand this part. I'm afraid I'll cause a disaster in my source.
I use TFS 1.5
LUA:
bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage)
{
    const Position& targetPos = target->getPosition();
    if (damage.primary.value > 0) {
        if (target->getHealth() <= 0) {
            return false;
        }

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

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

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

        int32_t realHealthChange = target->getHealth();
        target->gainHealth(attacker, damage.primary.value);
        realHealthChange = target->getHealth() - realHealthChange;

        if (realHealthChange > 0 && !target->isInGhostMode()) {
            auto damageString = fmt::format("{:d} hitpoint{:s}", realHealthChange, realHealthChange != 1 ? "s" : "");

            std::string spectatorMessage;

            TextMessage message;
            std::ostringstream strHealthChange;
            strHealthChange << realHealthChange;
            addAnimatedText(strHealthChange.str(), targetPos, TEXTCOLOR_MAYABLUE);

            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("You heal {:s} for {:s}.", target->getNameDescription(), damageString);
                } else if (tmpPlayer == targetPlayer) {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    if (!attacker) {
                        message.text = fmt::format("You were healed for {:s}.", damageString);
                    } else if (targetPlayer == attackerPlayer) {
                        message.text = fmt::format("You healed yourself for {:s}.", damageString);
                    } else {
                        message.text = fmt::format("You were healed by {:s} for {:s}.", attacker->getNameDescription(), damageString);
                    }
                } else {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    if (spectatorMessage.empty()) {
                        if (!attacker) {
                            spectatorMessage = fmt::format("{:s} was healed for {:s}.", target->getNameDescription(), damageString);
                        } else if (attacker == target) {
                            spectatorMessage = fmt::format("{:s} healed {:s}self for {:s}.", attacker->getNameDescription(), targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "him") : "it", damageString);
                        } else {
                            spectatorMessage = fmt::format("{:s} healed {:s} for {:s}.", attacker->getNameDescription(), target->getNameDescription(), damageString);
                        }
                        spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                    }
                    message.type = MESSAGE_STATUS_DEFAULT;
                }
                tmpPlayer->sendTextMessage(message);
            }
        }
    } else {
        if (!target->isAttackable()) {
            if (!target->isInGhostMode()) {
                addMagicEffect(targetPos, CONST_ME_POFF);
            }
            return true;
        }

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

        Player* targetPlayer = target->getPlayer();
        if (attackerPlayer && targetPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE) {
            return false;
        }
       
        Monster* monster = attacker ? attacker->getMonster() : nullptr;
        if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }

        damage.primary.value = std::abs(damage.primary.value);
        damage.secondary.value = std::abs(damage.secondary.value);

        int32_t healthChange = damage.primary.value + damage.secondary.value;
        if (healthChange == 0) {
            return true;
        }

        TextMessage message;

        SpectatorVec spectators;
     if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
    int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
    if (manaDamage != 0) {
        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);
                }
                healthChange = damage.primary.value + damage.secondary.value;
                if (healthChange == 0) {
                    return true;
                }
                manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
                damage.origin = ORIGIN_NONE;
            }
        }

                targetPlayer->drainMana(attacker, manaDamage);
                map.getSpectators(spectators, targetPos, true, true);
                addMagicEffect(spectators, targetPos, CONST_ME_LOSEENERGY);

                std::string spectatorMessage;

                std::ostringstream strManaDamage;
                strManaDamage << manaDamage;
                addAnimatedText(strManaDamage.str(), targetPos, TEXTCOLOR_BLUE);

                for (Creature* spectator : spectators) {
                    Player* tmpPlayer = spectator->getPlayer();
                    if (tmpPlayer->getPosition().z != targetPos.z) {
                        continue;
                    }

                    if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                        message.type = MESSAGE_STATUS_DEFAULT;
                        message.text = fmt::format("{:s} loses {:d} mana due to your attack.", target->getNameDescription(), manaDamage);
                        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.", manaDamage);
                        } else if (targetPlayer == attackerPlayer) {
                            message.text = fmt::format("You lose {:d} mana due to your own attack.", manaDamage);
                        } else {
                            message.text = fmt::format("You lose {:d} mana due to an attack by {:s}.", manaDamage, attacker->getNameDescription());
                        }
                    } else {
                        message.type = MESSAGE_STATUS_DEFAULT;
                        if (spectatorMessage.empty()) {
                            if (!attacker) {
                                spectatorMessage = fmt::format("{:s} loses {:d} mana.", target->getNameDescription(), manaDamage);
                            } else if (attacker == target) {
                                spectatorMessage = fmt::format("{:s} loses {:d} mana due to {:s} own attack.", target->getNameDescription(), manaDamage, targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his");
                            } else {
                                spectatorMessage = fmt::format("{:s} loses {:d} mana due to an attack by {:s}.", target->getNameDescription(), manaDamage, attacker->getNameDescription());
                            }
                            spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                        }
                    }
                    tmpPlayer->sendTextMessage(message);
                }

                damage.primary.value -= manaDamage;
                if (damage.primary.value < 0) {
                    damage.secondary.value = std::max<int32_t>(0, damage.secondary.value + damage.primary.value);
                    damage.primary.value = 0;
                }
            }
        }

        int32_t realDamage = damage.primary.value + damage.secondary.value;
        if (realDamage == 0) {
            return true;
        }

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

        int32_t targetHealth = target->getHealth();
        if (damage.primary.value >= targetHealth) {
            damage.primary.value = targetHealth;
            damage.secondary.value = 0;
        } else if (damage.secondary.value) {
            damage.secondary.value = std::min<int32_t>(damage.secondary.value, targetHealth - damage.primary.value);
        }

        realDamage = damage.primary.value + damage.secondary.value;
        if (realDamage == 0) {
            return true;
        }

        if (spectators.empty()) {
            map.getSpectators(spectators, targetPos, true, true);
        }

        message.primary.value = damage.primary.value;
        message.secondary.value = damage.secondary.value;

        uint8_t hitEffect;
        if (message.primary.value) {
            combatGetTypeInfo(damage.primary.type, target, message.primary.color, hitEffect);
            if (hitEffect != CONST_ME_NONE) {
                addMagicEffect(spectators, targetPos, hitEffect);
            }

            if (message.primary.color != TEXTCOLOR_NONE) {
                std::ostringstream strPrimaryDamage;
                strPrimaryDamage << message.primary.value;
                addAnimatedText(strPrimaryDamage.str(), targetPos, message.primary.color);
            }
        }

        if (message.secondary.value) {
            combatGetTypeInfo(damage.secondary.type, target, message.secondary.color, hitEffect);
            if (hitEffect != CONST_ME_NONE) {
                addMagicEffect(spectators, targetPos, hitEffect);
            }

            if (message.secondary.color != TEXTCOLOR_NONE) {
                std::ostringstream strSecondaryDamage;
                strSecondaryDamage << message.secondary.value;
                addAnimatedText(strSecondaryDamage.str(), targetPos, message.secondary.color);
            }
        }

        if (message.primary.color != TEXTCOLOR_NONE || message.secondary.color != TEXTCOLOR_NONE) {
            auto damageString = fmt::format("{:d} hitpoint{:s}", realDamage, realDamage != 1 ? "s" : "");

            std::string spectatorMessage;

            for (Creature* spectator : spectators) {
                Player* tmpPlayer = spectator->getPlayer();
                if (tmpPlayer->getPosition().z != targetPos.z) {
                    continue;
                }

                if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    message.text = fmt::format("{:s} loses {:s} due to your attack.", target->getNameDescription(), damageString);
                    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 {:s}.", damageString);
                    } else if (targetPlayer == attackerPlayer) {
                        message.text = fmt::format("You lose {:s} due to your own attack.", damageString);
                    } else {
                        message.text = fmt::format("You lose {:s} due to an attack by {:s}.", damageString, attacker->getNameDescription());
                    }
                } else {
                    message.type = MESSAGE_STATUS_DEFAULT;
                    if (spectatorMessage.empty()) {
                        if (!attacker) {
                            spectatorMessage = fmt::format("{:s} loses {:s}.", target->getNameDescription(), damageString);
                        } else if (attacker == target) {
                            spectatorMessage = fmt::format("{:s} loses {:s} due to {:s} own attack.", target->getNameDescription(), damageString, targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his") : "its");
                        } else {
                            spectatorMessage = fmt::format("{:s} loses {:s} due to an attack by {:s}.", target->getNameDescription(), damageString, attacker->getNameDescription());
                        }
                        spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                    }
                    message.text = spectatorMessage;
                }
                tmpPlayer->sendTextMessage(message);
            }
        }

        if (realDamage >= targetHealth) {
            for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
                if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
                    return false;
                }
            }
        }

        target->drainHealth(attacker, realDamage);
        addCreatureHealth(spectators, target);
    }

    return true;
}

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 && damage.origin != ORIGIN_NONE) {
        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 realManaChange = targetPlayer->getMana();
        targetPlayer->changeMana(manaChange);
        realManaChange = targetPlayer->getMana() - realManaChange;
    } 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->getNameDescription(), 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->getNameDescription());
                }
            } else {
                message.type = MESSAGE_STATUS_DEFAULT;
                if (spectatorMessage.empty()) {
                    if (!attacker) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana.", target->getNameDescription(), manaLoss);
                    } else if (attacker == target) {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to {:s} own attack.", target->getNameDescription(), manaLoss, targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his");
                    } else {
                        spectatorMessage = fmt::format("{:s} loses {:d} mana due to an attack by {:s}.", target->getNameDescription(), manaLoss, attacker->getNameDescription());
                    }
                    spectatorMessage[0] = std::toupper(spectatorMessage[0]);
                }
            }
            tmpPlayer->sendTextMessage(message);
        }
    }

    return true;
}

If you previously added the orginal code, just remove the code in healthchange where it calculates bonus damage. Its not needed there anymore (if you now follow my previous post).
 
If you previously added the orginal code, just remove the code in healthchange where it calculates bonus damage. Its not needed there anymore (if you now follow my previous post).
Yes I am following your new changes but I still dont fully understand this part
I made three changes should I delete them?
If I delete the new changes should I replace them with the old code?
1
C++:
        Monster* monster = attacker ? attacker->getMonster() : nullptr;
        if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }
2
C++:
        SpectatorVec spectators;
     if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
    int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
    if (manaDamage != 0) {
        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);
                }
                healthChange = damage.primary.value + damage.secondary.value;
                if (healthChange == 0) {
                    return true;
                }
                manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
                damage.origin = ORIGIN_NONE;
            }
        }
3
C++:
    Monster* monster = attacker ? attacker->getMonster() : nullptr;
    if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }
This is my game.cpp file
 
Yes I am following your new changes but I still dont fully understand this part
I made three changes should I delete them?
If I delete the new changes should I replace them with the old code?
1
C++:
        Monster* monster = attacker ? attacker->getMonster() : nullptr;
        if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }
2
C++:
        SpectatorVec spectators;
     if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
    int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
    if (manaDamage != 0) {
        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);
                }
                healthChange = damage.primary.value + damage.secondary.value;
                if (healthChange == 0) {
                    return true;
                }
                manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
                damage.origin = ORIGIN_NONE;
            }
        }
3
C++:
    Monster* monster = attacker ? attacker->getMonster() : nullptr;
    if (monster && monster->getLevel() > 0 && damage.origin != ORIGIN_NONE) {
        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);
            }
        }
    }
This is my game.cpp file
Just remove 1 & 3. its added in combat instead.

We dont need the bonus calculation in game.cpp because everything is handled during combat (before any healthchange or manachange).
 
Just remove 1 & 3. its added in combat instead.

We dont need the bonus calculation in game.cpp because everything is handled during combat (before any healthchange or manachange).
Okay thank you for your help I appreciate it
 
Back
Top