/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "RestMgr.h" #include "GameTime.h" #include "Log.h" #include "Player.h" #include "Random.h" #include "World.h" #include "WorldSession.h" RestMgr::RestMgr(Player* player) : _player(player), _restTime(0), _restFlagMask(0) { for (uint8 i = REST_TYPE_XP; i < REST_TYPE_MAX; i++) _restBonus[i] = 0; } void RestMgr::SetRestBonus(RestTypes restType, float restBonus) { int32 next_level_xp; bool affectedByRaF = false; switch (restType) { case REST_TYPE_XP: // Reset restBonus (XP only) for max level players if (_player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) restBonus = 0; next_level_xp = _player->m_activePlayerData->NextLevelXP; affectedByRaF = true; break; case REST_TYPE_HONOR: // Reset restBonus (Honor only) for players with max honor level. if (_player->IsMaxHonorLevel()) restBonus = 0; next_level_xp = _player->m_activePlayerData->HonorNextLevel; break; default: return; } float rest_bonus_max = float(next_level_xp) * 1.5f / 2; if (restBonus < 0) restBonus = 0; if (restBonus > rest_bonus_max) restBonus = rest_bonus_max; uint32 oldBonus = uint32(_restBonus[restType]); _restBonus[restType] = restBonus; PlayerRestState oldRestState = static_cast(*_player->m_activePlayerData->RestInfo[restType].StateID); PlayerRestState newRestState = REST_STATE_NORMAL; if (affectedByRaF && _player->GetsRecruitAFriendBonus(true) && (_player->GetSession()->IsARecruiter() || _player->GetSession()->GetRecruiterId() != 0)) newRestState = REST_STATE_RAF_LINKED; else if (_restBonus[restType] >= 1) newRestState = REST_STATE_RESTED; if (oldBonus == uint32(restBonus) && oldRestState == newRestState) return; // update data for client _player->SetRestThreshold(restType, uint32(_restBonus[restType])); _player->SetRestState(restType, newRestState); } void RestMgr::AddRestBonus(RestTypes restType, float restBonus) { // Don't add extra rest bonus to max level players. Note: Might need different condition in next expansion for honor XP (PLAYER_LEVEL_MIN_HONOR perhaps). if (_player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) restBonus = 0; float totalRestBonus = GetRestBonus(restType) + restBonus; SetRestBonus(restType, totalRestBonus); } void RestMgr::SetRestFlag(RestFlag restFlag) { uint32 oldRestMask = _restFlagMask; _restFlagMask |= restFlag; if (!oldRestMask && _restFlagMask) // only set flag/time on the first rest state { _restTime = GameTime::GetGameTime(); _player->SetPlayerFlag(PLAYER_FLAGS_RESTING); } } void RestMgr::RemoveRestFlag(RestFlag restFlag) { uint32 oldRestMask = _restFlagMask; _restFlagMask &= ~restFlag; if (oldRestMask && !_restFlagMask) // only remove flag/time on the last rest state remove { _restTime = 0; _player->RemovePlayerFlag(PLAYER_FLAGS_RESTING); } } uint32 RestMgr::GetRestBonusFor(RestTypes restType, uint32 xp) { uint32 rested_bonus = uint32(GetRestBonus(restType)); // xp for each rested bonus if (rested_bonus > xp) // max rested_bonus == xp or (r+x) = 200% xp rested_bonus = xp; uint32 rested_loss = rested_bonus; if (restType == REST_TYPE_XP) AddPct(rested_loss, _player->GetTotalAuraModifier(SPELL_AURA_MOD_RESTED_XP_CONSUMPTION)); SetRestBonus(restType, GetRestBonus(restType) - rested_loss); TC_LOG_DEBUG("entities.player", "RestMgr::GetRestBonus: Player '{}' ({}) gain {} xp (+{} Rested Bonus). Rested points={}", _player->GetGUID().ToString(), _player->GetName(), xp + rested_bonus, rested_bonus, GetRestBonus(restType)); return rested_bonus; } void RestMgr::Update(time_t now) { if (roll_chance_i(3) && _restTime > 0) // freeze update { time_t timeDiff = now - _restTime; if (timeDiff >= 10) { _restTime = now; float bubble = 0.125f * sWorld->getRate(RATE_REST_INGAME); AddRestBonus(REST_TYPE_XP, timeDiff * CalcExtraPerSec(REST_TYPE_XP, bubble)); } } } void RestMgr::LoadRestBonus(RestTypes restType, PlayerRestState state, float restBonus) { _restBonus[restType] = restBonus; _player->SetRestState(restType, state); _player->SetRestThreshold(restType, uint32(restBonus)); } float RestMgr::CalcExtraPerSec(RestTypes restType, float bubble) const { switch (restType) { case REST_TYPE_HONOR: return float(_player->m_activePlayerData->HonorNextLevel) / 72000.0f * bubble; case REST_TYPE_XP: return float(_player->m_activePlayerData->NextLevelXP) / 72000.0f * bubble; default: return 0.0f; } }