Klank
Althea ¤ A New World Developer
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.
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:
in combat.cpp, include monster.h:

in function Combat::doTargetCombat, add:
This should make sure that the damage is properly "interfaced" to the system.
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:

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.