• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

C++ Damage / Healing in Percent

S

Shadow_

Guest
i'm trying to make the DMG/healing anything related to mana/health change to be in percent, so i did the following in game.cpp but i don't understand what im doing wrong to always get 0, more info in the screenshot

C++:
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;
        }

        double bonusRebirth = 0.0;
        if(attackerPlayer != nullptr){
            bonusRebirth = attackerPlayer->rebirth * g_config.getNumber(ConfigManager::REBORN_DMGBONUS);
            bonusRebirth /= 10;
            bonusRebirth /= 100;
            bonusRebirth += 1;
        }
        else
            bonusRebirth = 1.0;


        damage.primary.value = std::abs(damage.primary.value) * bonusRebirth;
        damage.secondary.value = std::abs(damage.secondary.value * bonusRebirth);
        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);
            }
        }

        int64_t realHealthChange = damage.primary.value;
        target->gainHealth(attacker, damage.primary.value);
        realHealthChange = ( realHealthChange / target->getMaxHealth() ) * 100;
        if (realHealthChange > 0 && !target->isInGhostMode()) {
            std::stringstream ss;

            ss << realHealthChange << (realHealthChange != 1 ? "% hitpoints." : "% hitpoint.");
            std::string damageString = ss.str();

            std::string spectatorMessage;

            TextMessage message;
            message.position = targetPos;
            message.primary.value = realHealthChange;
            message.primary.color = TEXTCOLOR_PASTELRED;

            SpectatorHashSet spectators;
            map.getSpectators(spectators, targetPos, false, true);
            for (Creature* spectator : spectators) {
                Player* tmpPlayer = spectator->getPlayer();
                if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                    ss.str({});
                    ss << "You heal " << target->getNameDescription() << " for " << damageString;
                    message.type = MESSAGE_HEALED;
                    message.text = ss.str();
                } else if (tmpPlayer == targetPlayer) {
                    ss.str({});
                    if (!attacker) {
                        ss << "You were healed";
                    } else if (targetPlayer == attackerPlayer) {
                        ss << "You healed yourself";
                    } else {
                        ss << "You were healed by " << attacker->getNameDescription();
                    }
                    ss << " for " << damageString;
                    message.type = MESSAGE_HEALED;
                    message.text = ss.str();
                } else {
                    if (spectatorMessage.empty()) {
                        ss.str({});
                        if (!attacker) {
                            ss << ucfirst(target->getNameDescription()) << " was healed";
                        } else {
                            ss << ucfirst(attacker->getNameDescription()) << " healed ";
                            if (attacker == target) {
                                ss << (targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "herself" : "himself") : "itself");
                            } else {
                                ss << target->getNameDescription();
                            }
                        }
                        ss << " for " << damageString;
                        spectatorMessage = ss.str();
                    }
                    message.type = MESSAGE_HEALED_OTHERS;
                    message.text = spectatorMessage;
                }
                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) {
            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);
            }
        }

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

        if (damage.primary.value + damage.secondary.value == 0) {
            return true;
        }
        if (attackerPlayer) {
            uint16_t chance = attackerPlayer->getSkillLevel(SKILL_LIFE_LEECH_CHANCE);
            if (chance != 0 && uniform_random(1, 100) <= chance) {
                CombatDamage lifeLeech;
                lifeLeech.primary.value = std::round((damage.primary.value + damage.secondary.value) * (attackerPlayer->getSkillLevel(SKILL_LIFE_LEECH_AMOUNT) / 100.));
                g_game.combatChangeHealth(nullptr, attackerPlayer, lifeLeech);
            }

            chance = attackerPlayer->getSkillLevel(SKILL_MANA_LEECH_CHANCE);
            if (chance != 0 && uniform_random(1, 100) <= chance) {
                CombatDamage manaLeech;
                manaLeech.primary.value = std::round((damage.primary.value + damage.secondary.value) * (attackerPlayer->getSkillLevel(SKILL_MANA_LEECH_AMOUNT) / 100.));
                g_game.combatChangeMana(nullptr, attackerPlayer, manaLeech);
            }

            chance = attackerPlayer->getSkillLevel(SKILL_CRITICAL_HIT_CHANCE);
            if (chance != 0 && uniform_random(1, 100) <= chance) {
                damage.primary.value += std::round(damage.primary.value * (attackerPlayer->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE) / 100.));
                damage.secondary.value += std::round(damage.secondary.value * (attackerPlayer->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE) / 100.));
                g_game.addMagicEffect(attacker->getPosition(), CONST_ME_CRITICAL_DAMAGE);
            }
        }

        int64_t healthChange = damage.primary.value + damage.secondary.value;

        TextMessage message;
        message.position = targetPos;

        SpectatorHashSet spectators;
        if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
            int64_t manaDamage = std::min<int64_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<int64_t>(targetPlayer->getMana(), healthChange);
                    }
                }

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

                std::stringstream ss;
                int64_t manap = (manaDamage / targetPlayer->getMaxMana()) * 100;
                std::string damageString = std::to_string(manap);

                std::string spectatorMessage;

                message.primary.value = manap;
                message.primary.color = TEXTCOLOR_BLUE;

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

                    if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                        ss.str({});
                        ss << ucfirst(target->getNameDescription()) << " loses " << damageString + "% mana due to your attack.";
                        message.type = MESSAGE_DAMAGE_DEALT;
                        message.text = ss.str();
                    } else if (tmpPlayer == targetPlayer) {
                        ss.str({});
                        ss << "You lose " << damageString << "% mana";
                        if (!attacker) {
                            ss << '.';
                        } else if (targetPlayer == attackerPlayer) {
                            ss << " due to your own attack.";
                        } else {
                            ss << " due to an attack by " << attacker->getNameDescription() << '.';
                        }
                        message.type = MESSAGE_DAMAGE_RECEIVED;
                        message.text = ss.str();
                    } else {
                        if (spectatorMessage.empty()) {
                            ss.str({});
                            ss << ucfirst(target->getNameDescription()) << " loses " << damageString + "% mana";
                            if (attacker) {
                                ss << " due to ";
                                if (attacker == target) {
                                    ss << (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her own attack" : "his own attack");
                                } else {
                                    ss << "an attack by " << attacker->getNameDescription();
                                }
                            }
                            ss << '.';
                            spectatorMessage = ss.str();
                        }
                        message.type = MESSAGE_DAMAGE_OTHERS;
                        message.text = spectatorMessage;
                    }
                    tmpPlayer->sendTextMessage(message);
                }

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

        int64_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);
            }
        }
        int64_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<int64_t>(damage.secondary.value, targetHealth - damage.primary.value);
        }

        realDamage = damage.primary.value + damage.secondary.value;
        if (realDamage == 0) {
            return true;
        }
        int64_t prealDamage = (realDamage / target->getMaxHealth()) * 100;
        int64_t pridmg = (damage.primary.value / target->getMaxHealth()) * 100;
        int64_t secdmg = (damage.secondary.value / target->getMaxHealth()) * 100;
        if (spectators.empty()) {
            map.getSpectators(spectators, targetPos, true, true);
        }

            message.primary.value = pridmg;
            message.secondary.value = secdmg;

        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.secondary.value) {
            combatGetTypeInfo(damage.secondary.type, target, message.secondary.color, hitEffect);
            if (hitEffect != CONST_ME_NONE) {
                addMagicEffect(spectators, targetPos, hitEffect);
            }
        }

        if (message.primary.color != TEXTCOLOR_NONE || message.secondary.color != TEXTCOLOR_NONE) {
            std::stringstream ss;

            ss << prealDamage << (prealDamage != 1 ? "% hitpoints" : "% hitpoint");
            std::string damageString = ss.str();
            std::string spectatorMessage;

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

                if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                    ss.str({});
                    ss << ucfirst(target->getNameDescription()) << " loses " << damageString << " due to your attack.";
                    message.type = MESSAGE_DAMAGE_DEALT;
                    message.text = ss.str();
                } else if (tmpPlayer == targetPlayer) {
                    ss.str({});
                    ss << "You lose " << damageString;
                    if (!attacker) {
                        ss << '.';
                    } else if (targetPlayer == attackerPlayer) {
                        ss << " due to your own attack.";
                    } else {
                        ss << " due to an attack by " << attacker->getNameDescription() << '.';
                    }
                    message.type = MESSAGE_DAMAGE_RECEIVED;
                    message.text = ss.str();
                } else {
                    message.type = MESSAGE_DAMAGE_OTHERS;

                    if (spectatorMessage.empty()) {
                        ss.str({});
                        ss << ucfirst(target->getNameDescription()) << " loses " << damageString;
                        if (attacker) {
                            ss << " due to ";
                            if (attacker == target) {
                                if (targetPlayer) {
                                    ss << (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her own attack" : "his own attack");
                                } else {
                                    ss << "its own attack";
                                }
                            } else {
                                ss << "an attack by " << attacker->getNameDescription();
                            }
                        }
                        ss << '.';
                        spectatorMessage = ss.str();
                    }

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

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

        int64_t realManaChange = manaChange;
        targetPlayer->changeMana(manaChange);
        realManaChange = (realManaChange / targetPlayer->getMaxMana()) * 100;
        if (realManaChange > 0 && !targetPlayer->isInGhostMode()) {
            TextMessage message(MESSAGE_HEALED, "You gained " + std::to_string(realManaChange) + "% mana.");
            message.position = target->getPosition();
            message.primary.value = realManaChange;
            message.primary.color = TEXTCOLOR_MAYABLUE;
            targetPlayer->sendTextMessage(message);
        }
    } 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;
        }

        int64_t manaLoss = std::min<int64_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::stringstream ss;
        int64_t manalossP = (manaLoss / targetPlayer->getMaxMana()) * 100;
        std::string damageString = std::to_string(manalossP);

        std::string spectatorMessage;

        TextMessage message;
        message.position = targetPos;
        message.primary.value = manalossP;
        message.primary.color = TEXTCOLOR_BLUE;

        SpectatorHashSet spectators;
        map.getSpectators(spectators, targetPos, false, true);
        for (Creature* spectator : spectators) {
            Player* tmpPlayer = spectator->getPlayer();
            if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
                ss.str({});
                ss << ucfirst(target->getNameDescription()) << " loses " << damageString << "% mana due to your attack.";
                message.type = MESSAGE_DAMAGE_DEALT;
                message.text = ss.str();
            } else if (tmpPlayer == targetPlayer) {
                ss.str({});
                ss << "You lose " << damageString << "% mana";
                if (!attacker) {
                    ss << '.';
                } else if (targetPlayer == attackerPlayer) {
                    ss << " due to your own attack.";
                } else {
                    ss << " mana due to an attack by " << attacker->getNameDescription() << '.';
                }
                message.type = MESSAGE_DAMAGE_RECEIVED;
                message.text = ss.str();
            } else {
                if (spectatorMessage.empty()) {
                    ss.str({});
                    ss << ucfirst(target->getNameDescription()) << " loses " << damageString << "% mana";
                    if (attacker) {
                        ss << " due to ";
                        if (attacker == target) {
                            ss << (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her own attack" : "his own attack");
                        } else {
                            ss << "an attack by " << attacker->getNameDescription();
                        }
                    }
                    ss << '.';
                    spectatorMessage = ss.str();
                }
                message.type = MESSAGE_DAMAGE_OTHERS;
                message.text = spectatorMessage;
            }
            tmpPlayer->sendTextMessage(message);
        }
    }
    return true;
}
1624346442343.png
In this screenshot i went from 100% to 0% and then move to 50% HP and everything gives zeros
 
try
realHealthChange = ( realHealthChange / (target->getMaxHealth() / 100.));
Freakin’ weird but it did it, nice catch😉
--[Edit]
worked, got the dmg in percent but it crashes the server after several hits, i tried to do some changes but i couldn't find the reason yet.
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;
}

double bonusRebirth = 0.0;
if(attackerPlayer != nullptr){
bonusRebirth = attackerPlayer->rebirth * g_config.getNumber(ConfigManager::REBORN_DMGBONUS);
bonusRebirth /= 10;
bonusRebirth /= 100;
bonusRebirth += 1;
}
else
bonusRebirth = 1.0;


damage.primary.value = std::abs(damage.primary.value) * bonusRebirth;
damage.secondary.value = std::abs(damage.secondary.value * bonusRebirth);
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);
}
}

double realHealthChange = damage.primary.value;
target->gainHealth(attacker, damage.primary.value);
realHealthChange = ( realHealthChange / (attacker->getMaxHealth() / 100.));
if (realHealthChange > 0 && !target->isInGhostMode()) {
std::stringstream ss;

ss << realHealthChange << (realHealthChange != 1 ? "% HP." : "% HP.");
std::string damageString = ss.str();

std::string spectatorMessage;

TextMessage message;
message.position = targetPos;
message.primary.value = std::ceil(realHealthChange);
message.primary.color = TEXTCOLOR_PASTELRED;

SpectatorHashSet spectators;
map.getSpectators(spectators, targetPos, false, true);
for (Creature* spectator : spectators) {
Player* tmpPlayer = spectator->getPlayer();
if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
ss.str({});
ss << "You heal " << target->getNameDescription() << " for " << damageString;
message.type = MESSAGE_HEALED;
message.text = ss.str();
} else if (tmpPlayer == targetPlayer) {
ss.str({});
if (!attacker) {
ss << "You were healed";
} else if (targetPlayer == attackerPlayer) {
ss << "You healed yourself";
} else {
ss << "You were healed by " << attacker->getNameDescription();
}
ss << " for " << damageString;
message.type = MESSAGE_HEALED;
message.text = ss.str();
} else {
if (spectatorMessage.empty()) {
ss.str({});
if (!attacker) {
ss << ucfirst(target->getNameDescription()) << " was healed";
} else {
ss << ucfirst(attacker->getNameDescription()) << " healed ";
if (attacker == target) {
ss << (targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "herself" : "himself") : "itself");
} else {
ss << target->getNameDescription();
}
}
ss << " for " << damageString;
spectatorMessage = ss.str();
}
message.type = MESSAGE_HEALED_OTHERS;
message.text = spectatorMessage;
}
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) {
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);
}
}

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

if (damage.primary.value + damage.secondary.value == 0) {
return true;
}
if (attackerPlayer) {
uint16_t chance = attackerPlayer->getSkillLevel(SKILL_LIFE_LEECH_CHANCE);
if (chance != 0 && uniform_random(1, 100) <= chance) {
CombatDamage lifeLeech;
lifeLeech.primary.value = std::round((damage.primary.value + damage.secondary.value) * (attackerPlayer->getSkillLevel(SKILL_LIFE_LEECH_AMOUNT) / 100.));
g_game.combatChangeHealth(nullptr, attackerPlayer, lifeLeech);
}

chance = attackerPlayer->getSkillLevel(SKILL_MANA_LEECH_CHANCE);
if (chance != 0 && uniform_random(1, 100) <= chance) {
CombatDamage manaLeech;
manaLeech.primary.value = std::round((damage.primary.value + damage.secondary.value) * (attackerPlayer->getSkillLevel(SKILL_MANA_LEECH_AMOUNT) / 100.));
g_game.combatChangeMana(nullptr, attackerPlayer, manaLeech);
}

chance = attackerPlayer->getSkillLevel(SKILL_CRITICAL_HIT_CHANCE);
if (chance != 0 && uniform_random(1, 100) <= chance) {
damage.primary.value += std::round(damage.primary.value * (attackerPlayer->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE) / 100.));
damage.secondary.value += std::round(damage.secondary.value * (attackerPlayer->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE) / 100.));
g_game.addMagicEffect(attacker->getPosition(), CONST_ME_CRITICAL_DAMAGE);
}
}

int64_t healthChange = damage.primary.value + damage.secondary.value;

TextMessage message;
message.position = targetPos;

SpectatorHashSet spectators;
if (targetPlayer && target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) {
int64_t manaDamage = std::min<int64_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<int64_t>(targetPlayer->getMana(), healthChange);
}
}

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

std::stringstream ss;
double manap = (manaDamage / (targetPlayer->getMaxMana() / 100.));
std::string damageString = std::to_string(manap);

std::string spectatorMessage;

message.primary.value = std::ceil(manap);
message.primary.color = TEXTCOLOR_BLUE;

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

if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
ss.str({});
ss << ucfirst(target->getNameDescription()) << " loses " << damageString + "% MP due to your attack.";
message.type = MESSAGE_DAMAGE_DEALT;
message.text = ss.str();
} else if (tmpPlayer == targetPlayer) {
ss.str({});
ss << "You lose " << damageString << "% MP";
if (!attacker) {
ss << '.';
} else if (targetPlayer == attackerPlayer) {
ss << " due to your own attack.";
} else {
ss << " due to an attack by " << attacker->getNameDescription() << '.';
}
message.type = MESSAGE_DAMAGE_RECEIVED;
message.text = ss.str();
} else {
if (spectatorMessage.empty()) {
ss.str({});
ss << ucfirst(target->getNameDescription()) << " loses " << damageString + "% MP";
if (attacker) {
ss << " due to ";
if (attacker == target) {
ss << (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her own attack" : "his own attack");
} else {
ss << "an attack by " << attacker->getNameDescription();
}
}
ss << '.';
spectatorMessage = ss.str();
}
message.type = MESSAGE_DAMAGE_OTHERS;
message.text = spectatorMessage;
}
tmpPlayer->sendTextMessage(message);
}

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

int64_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);
}
}
int64_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<int64_t>(damage.secondary.value, targetHealth - damage.primary.value);
}

realDamage = damage.primary.value + damage.secondary.value;
if (realDamage == 0) {
return true;
}
double prealDamage = (realDamage / (target->getMaxHealth() / 100.));
if (spectators.empty()) {
map.getSpectators(spectators, targetPos, true, true);
}

message.primary.value = std::ceil(prealDamage);
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.secondary.value) {
combatGetTypeInfo(damage.secondary.type, target, message.secondary.color, hitEffect);
if (hitEffect != CONST_ME_NONE) {
addMagicEffect(spectators, targetPos, hitEffect);
}
}

if (message.primary.color != TEXTCOLOR_NONE || message.secondary.color != TEXTCOLOR_NONE) {
std::stringstream ss;

ss << prealDamage << (prealDamage != 1 ? "% HP" : "% HP");
std::string damageString = ss.str();
std::string spectatorMessage;

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

if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
ss.str({});
ss << ucfirst(target->getNameDescription()) << " loses " << damageString << " due to your attack.";
message.type = MESSAGE_DAMAGE_DEALT;
message.text = ss.str();
} else if (tmpPlayer == targetPlayer) {
ss.str({});
ss << "You lose " << damageString;
if (!attacker) {
ss << '.';
} else if (targetPlayer == attackerPlayer) {
ss << " due to your own attack.";
} else {
ss << " due to an attack by " << attacker->getNameDescription() << '.';
}
message.type = MESSAGE_DAMAGE_RECEIVED;
message.text = ss.str();
} else {
message.type = MESSAGE_DAMAGE_OTHERS;

if (spectatorMessage.empty()) {
ss.str({});
ss << ucfirst(target->getNameDescription()) << " loses " << damageString;
if (attacker) {
ss << " due to ";
if (attacker == target) {
if (targetPlayer) {
ss << (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her own attack" : "his own attack");
} else {
ss << "its own attack";
}
} else {
ss << "an attack by " << attacker->getNameDescription();
}
}
ss << '.';
spectatorMessage = ss.str();
}

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

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

double realManaChange = manaChange;
targetPlayer->changeMana(manaChange);
realManaChange = (realManaChange / (targetPlayer->getMaxMana() / 100.));
if (realManaChange > 0 && !targetPlayer->isInGhostMode()) {
TextMessage message(MESSAGE_HEALED, "You gained " + std::to_string(realManaChange) + "% MP.");
message.position = target->getPosition();
message.primary.value = std::ceil(realManaChange);
message.primary.color = TEXTCOLOR_MAYABLUE;
targetPlayer->sendTextMessage(message);
}
} 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;
}

int64_t manaLoss = std::min<int64_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::stringstream ss;
double manalossP = (manaLoss / (targetPlayer->getMaxMana() / 100.));
std::string damageString = std::to_string(manalossP);

std::string spectatorMessage;

TextMessage message;
message.position = targetPos;
message.primary.value = std::ceil(manalossP);
message.primary.color = TEXTCOLOR_BLUE;

SpectatorHashSet spectators;
map.getSpectators(spectators, targetPos, false, true);
for (Creature* spectator : spectators) {
Player* tmpPlayer = spectator->getPlayer();
if (tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer) {
ss.str({});
ss << ucfirst(target->getNameDescription()) << " loses " << damageString << "% MP due to your attack.";
message.type = MESSAGE_DAMAGE_DEALT;
message.text = ss.str();
} else if (tmpPlayer == targetPlayer) {
ss.str({});
ss << "You lose " << damageString << "% MP";
if (!attacker) {
ss << '.';
} else if (targetPlayer == attackerPlayer) {
ss << " due to your own attack.";
} else {
ss << " MP due to an attack by " << attacker->getNameDescription() << '.';
}
message.type = MESSAGE_DAMAGE_RECEIVED;
message.text = ss.str();
} else {
if (spectatorMessage.empty()) {
ss.str({});
ss << ucfirst(target->getNameDescription()) << " loses " << damageString << "% MP";
if (attacker) {
ss << " due to ";
if (attacker == target) {
ss << (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her own attack" : "his own attack");
} else {
ss << "an attack by " << attacker->getNameDescription();
}
}
ss << '.';
spectatorMessage = ss.str();
}
message.type = MESSAGE_DAMAGE_OTHERS;
message.text = spectatorMessage;
}
tmpPlayer->sendTextMessage(message);
}
}

return true;
}
 
Last edited by a moderator:
Back
Top