void Player::addExperience(Creature* source, uint64_t exp, bool sendText/* = false*/)
{
uint64_t currLevelExp = Player::getExpForLevel(level);
uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
uint64_t rawExp = exp;
if (currLevelExp >= nextLevelExp) {
//player has reached max level
levelPercent = 0;
sendStats();
return;
}
//g_events->eventPlayerOnGainExperience(this, source, exp, rawExp);
//if (exp == 0) {
// return;
//}
if (source != nullptr) {
const Monster* monster = source->getMonster();
if (monster != nullptr) {
int level = monster->getLevel();
if (level > 0) {
exp += (exp * 00.08) * level;
}
}
}
experience += exp;
if (sendText) {
std::string expString = std::to_string(exp) + (exp != 1 ? " experience points." : " experience point.");
TextMessage message(MESSAGE_STATUS_DEFAULT, "You gained " + expString);
sendTextMessage(message);
g_game.addAnimatedText(std::to_string(exp), position, TEXTCOLOR_WHITE);
SpectatorVec spectators;
g_game.map.getSpectators(spectators, position, false, true);
spectators.erase(this);
if (!spectators.empty()) {
message.type = MESSAGE_STATUS_DEFAULT;
message.text = getName() + " gained " + expString;
for (Creature* spectator : spectators) {
spectator->getPlayer()->sendTextMessage(message);
}
}
}
uint32_t prevLevel = level;
while (experience >= nextLevelExp) {
++level;
healthMax += vocation->getHPGain();
health += vocation->getHPGain();
manaMax += vocation->getManaGain();
mana += vocation->getManaGain();
capacity += vocation->getCapGain();
currLevelExp = nextLevelExp;
nextLevelExp = Player::getExpForLevel(level + 1);
if (currLevelExp >= nextLevelExp) {
//player has reached max level
break;
}
}
if (prevLevel != level) {
health = getMaxHealth();
mana = getMaxMana();
updateBaseSpeed();
setBaseSpeed(getBaseSpeed());
g_game.changeSpeed(this, 0);
g_game.addCreatureHealth(this);
const uint32_t protectionLevel = static_cast<uint32_t>(g_config.getNumber(ConfigManager::PROTECTION_LEVEL));
if (prevLevel < protectionLevel && level >= protectionLevel) {
g_game.updateCreatureWalkthrough(this);
}
if (party) {
party->updateSharedExperience();
}
g_creatureEvents->playerAdvance(this, SKILL_LEVEL, prevLevel, level);
sendTextMessage(MESSAGE_EVENT_ADVANCE, fmt::format("You advanced from Level {:d} to Level {:d}.", prevLevel, level));
}
if (nextLevelExp > currLevelExp) {
levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
} else {
levelPercent = 0;
}
sendStats();
}
void Player::removeExperience(uint64_t exp, bool sendText/* = false*/)
{
if (experience == 0 || exp == 0) {
return;
}
g_events->eventPlayerOnLoseExperience(this, exp);
if (exp == 0) {
return;
}
uint64_t lostExp = experience;
experience = std::max<int64_t>(0, experience - exp);
if (sendText) {
lostExp -= experience;
std::string expString = std::to_string(lostExp) + (lostExp != 1 ? " experience points." : " experience point.");
TextMessage message(MESSAGE_STATUS_DEFAULT, "You lost " + expString);
sendTextMessage(message);
g_game.addAnimatedText(std::to_string(lostExp), position, TEXTCOLOR_RED);
SpectatorVec spectators;
g_game.map.getSpectators(spectators, position, false, true);
spectators.erase(this);
if (!spectators.empty()) {
message.type = MESSAGE_STATUS_DEFAULT;
message.text = getName() + " lost " + expString;
for (Creature* spectator : spectators) {
spectator->getPlayer()->sendTextMessage(message);
}
}
}
uint32_t oldLevel = level;
uint64_t currLevelExp = Player::getExpForLevel(level);
while (level > 1 && experience < currLevelExp) {
--level;
healthMax = std::max<int32_t>(0, healthMax - vocation->getHPGain());
manaMax = std::max<int32_t>(0, manaMax - vocation->getManaGain());
capacity = std::max<int32_t>(0, capacity - vocation->getCapGain());
currLevelExp = Player::getExpForLevel(level);
}
if (oldLevel != level) {
health = getMaxHealth();
mana = getMaxMana();
updateBaseSpeed();
setBaseSpeed(getBaseSpeed());
g_game.changeSpeed(this, 0);
g_game.addCreatureHealth(this);
const uint32_t protectionLevel = static_cast<uint32_t>(g_config.getNumber(ConfigManager::PROTECTION_LEVEL));
if (oldLevel >= protectionLevel && level < protectionLevel) {
g_game.updateCreatureWalkthrough(this);
}
if (party) {
party->updateSharedExperience();
}
sendTextMessage(MESSAGE_EVENT_ADVANCE, fmt::format("You were downgraded from Level {:d} to Level {:d}.", oldLevel, level));
}
uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
if (nextLevelExp > currLevelExp) {
levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
} else {
levelPercent = 0;
}
sendStats();
}
uint8_t Player::getPercentLevel(uint64_t count, uint64_t nextLevelCount)
{
if (nextLevelCount == 0) {
return 0;
}
uint8_t result = (count * 100) / nextLevelCount;
if (result > 100) {
return 0;
}
return result;
}
void Player::onBlockHit()
{
if (shieldBlockCount > 0) {
--shieldBlockCount;
if (hasShield()) {
addSkillAdvance(SKILL_SHIELD, 1);
}
}
}