aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp5
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp14
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h9
-rw-r--r--src/server/game/Achievements/CriteriaHandler.cpp14
-rw-r--r--src/server/game/DataStores/DB2LoadInfo.h82
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp48
-rw-r--r--src/server/game/DataStores/DB2Stores.h4
-rw-r--r--src/server/game/DataStores/DB2Structure.h38
-rw-r--r--src/server/game/DataStores/DBCEnums.h7
-rw-r--r--src/server/game/DataStores/GameTables.cpp2
-rw-r--r--src/server/game/DataStores/GameTables.h7
-rw-r--r--src/server/game/Entities/Player/Player.cpp275
-rw-r--r--src/server/game/Entities/Player/Player.h66
-rw-r--r--src/server/game/Entities/Player/RestMgr.cpp171
-rw-r--r--src/server/game/Entities/Player/RestMgr.h89
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp9
-rw-r--r--src/server/game/Server/Packets/MiscPackets.h8
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/game/Server/WorldSession.h4
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp20
-rw-r--r--src/server/game/Spells/SpellInfo.cpp2
22 files changed, 698 insertions, 179 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 8ff6d57fad0..34bef1ea62a 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -83,7 +83,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, "
"resettalents_time, primarySpecialization, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeonDifficulty, "
"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, "
- "health, power1, power2, power3, power4, power5, power6, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, grantableLevels, raidDifficulty, legacyRaidDifficulty, fishingSteps "
+ "health, power1, power2, power3, power4, power5, power6, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, grantableLevels, raidDifficulty, legacyRaidDifficulty, fishingSteps, "
+ "honor, honorLevel, prestigeLevel, honorRestState, honorRestBonus "
"FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH);
@@ -431,7 +432,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,primarySpecialization=?,extra_flags=?,stable_slots=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?,"
"totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?,"
"watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,latency=?,activeTalentGroup=?,lootSpecId=?,exploredZones=?,"
- "equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,online=? WHERE guid=?", CONNECTION_ASYNC);
+ "equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,online=?,honor=?,honorLevel=?,prestigeLevel=?,honorRestState=?,honorRestBonus=? WHERE guid=?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index 99f01a91a5b..fd9415afa16 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -667,9 +667,16 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_POWER_TYPE, "SELECT ID, PowerTypeToken, PowerCostToken, RegenerationPeace, RegenerationCombat, MaxPower, "
"RegenerationDelay, Flags, PowerTypeEnum, RegenerationMin, RegenerationCenter, RegenerationMax, UIModifier FROM power_type ORDER BY ID DESC", CONNECTION_SYNCH);
+ // PrestigeLevelInfo.db2
+ PrepareStatement(HOTFIX_SEL_PRESTIGE_LEVEL_INFO, "SELECT ID, IconID, PrestigeText, PrestigeLevel, Flags FROM prestige_level_info ORDER BY ID DESC", CONNECTION_SYNCH);
+ PREPARE_LOCALE_STMT(HOTFIX_SEL_PRESTIGE_LEVEL_INFO, "SELECT ID, PrestigeText_lang FROM prestige_level_info_locale WHERE locale = ?", CONNECTION_SYNCH);
+
// PvpDifficulty.db2
PrepareStatement(HOTFIX_SEL_PVP_DIFFICULTY, "SELECT ID, MapID, BracketID, MinLevel, MaxLevel FROM pvp_difficulty ORDER BY ID DESC", CONNECTION_SYNCH);
+ // PvpReward.db2
+ PrepareStatement(HOTFIX_SEL_PVP_REWARD, "SELECT ID, HonorLevel, Prestige, RewardPackID FROM pvp_reward ORDER BY ID DESC", CONNECTION_SYNCH);
+
// QuestFactionReward.db2
PrepareStatement(HOTFIX_SEL_QUEST_FACTION_REWARD, "SELECT ID, QuestRewFactionValue1, QuestRewFactionValue2, QuestRewFactionValue3, "
"QuestRewFactionValue4, QuestRewFactionValue5, QuestRewFactionValue6, QuestRewFactionValue7, QuestRewFactionValue8, QuestRewFactionValue9, "
@@ -698,6 +705,13 @@ void HotfixDatabaseConnection::DoPrepareStatements()
"RarePropertiesPoints5, UncommonPropertiesPoints1, UncommonPropertiesPoints2, UncommonPropertiesPoints3, UncommonPropertiesPoints4, "
"UncommonPropertiesPoints5 FROM rand_prop_points ORDER BY ID DESC", CONNECTION_SYNCH);
+ // RewardPack.db2
+ PrepareStatement(HOTFIX_SEL_REWARD_PACK, "SELECT ID, Money, ArtifactXPMultiplier, ArtifactXPDifficulty, ArtifactCategoryID, TitleID, Unused"
+ " FROM reward_pack ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // RewardPackXItem.db2
+ PrepareStatement(HOTFIX_SEL_REWARD_PACK_X_ITEM, "SELECT ID, ItemID, RewardPackID, Amount FROM reward_pack_x_item ORDER BY ID DESC", CONNECTION_SYNCH);
+
// RulesetItemUpgrade.db2
PrepareStatement(HOTFIX_SEL_RULESET_ITEM_UPGRADE, "SELECT ID, ItemID, ItemUpgradeID FROM ruleset_item_upgrade ORDER BY ID DESC", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 06710712818..b5e9f980268 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -358,8 +358,13 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_POWER_TYPE,
+ HOTFIX_SEL_PRESTIGE_LEVEL_INFO,
+ HOTFIX_SEL_PRESTIGE_LEVEL_INFO_LOCALE,
+
HOTFIX_SEL_PVP_DIFFICULTY,
+ HOTFIX_SEL_PVP_REWARD,
+
HOTFIX_SEL_QUEST_FACTION_REWARD,
HOTFIX_SEL_QUEST_MONEY_REWARD,
@@ -375,6 +380,10 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_RAND_PROP_POINTS,
+ HOTFIX_SEL_REWARD_PACK,
+
+ HOTFIX_SEL_REWARD_PACK_X_ITEM,
+
HOTFIX_SEL_RULESET_ITEM_UPGRADE,
HOTFIX_SEL_SCALING_STAT_DISTRIBUTION,
diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp
index eda31175b0b..b90a211e96f 100644
--- a/src/server/game/Achievements/CriteriaHandler.cpp
+++ b/src/server/game/Achievements/CriteriaHandler.cpp
@@ -502,6 +502,8 @@ void CriteriaHandler::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0
case CRITERIA_TYPE_ON_LOGIN:
case CRITERIA_TYPE_PLACE_GARRISON_BUILDING:
case CRITERIA_TYPE_OWN_BATTLE_PET_COUNT:
+ case CRITERIA_TYPE_HONOR_LEVEL_REACHED:
+ case CRITERIA_TYPE_PRESTIGE_REACHED:
SetCriteriaProgress(criteria, 1, referencePlayer, PROGRESS_ACCUMULATE);
break;
// std case: increment at miscValue1
@@ -771,8 +773,6 @@ void CriteriaHandler::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0
case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_WITH_QUALITY:
case CRITERIA_TYPE_ARTIFACT_POWER_EARNED:
case CRITERIA_TYPE_ARTIFACT_TRAITS_UNLOCKED:
- case CRITERIA_TYPE_HONOR_LEVEL_REACHED:
- case CRITERIA_TYPE_PRESTIGE_REACHED:
case CRITERIA_TYPE_ORDER_HALL_TALENT_LEARNED:
case CRITERIA_TYPE_APPEARANCE_UNLOCKED_BY_SLOT:
case CRITERIA_TYPE_ORDER_HALL_RECRUIT_TROOP:
@@ -1142,6 +1142,8 @@ bool CriteriaHandler::IsCompletedCriteria(Criteria const* criteria, uint64 requi
case CRITERIA_TYPE_EXPLORE_AREA:
case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER:
case CRITERIA_TYPE_OWN_BATTLE_PET:
+ case CRITERIA_TYPE_HONOR_LEVEL_REACHED:
+ case CRITERIA_TYPE_PRESTIGE_REACHED:
return progress->Counter >= 1;
case CRITERIA_TYPE_LEARN_SKILL_LEVEL:
return progress->Counter >= (requiredAmount * 75);
@@ -1749,6 +1751,14 @@ bool CriteriaHandler::AdditionalRequirementsSatisfied(ModifierTreeNode const* tr
return false;
break;
}
+ case CRITERIA_ADDITIONAL_CONDITION_HONOR_LEVEL: // 193
+ if (!referencePlayer || referencePlayer->GetHonorLevel() != reqValue)
+ return false;
+ break;
+ case CRITERIA_ADDITIONAL_CONDITION_PRESTIGE_LEVEL: // 194
+ if (!referencePlayer || referencePlayer->GetPrestigeLevel() != reqValue)
+ return false;
+ break;
default:
break;
}
diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h
index 91ea862d1fc..bdc0aa51349 100644
--- a/src/server/game/DataStores/DB2LoadInfo.h
+++ b/src/server/game/DataStores/DB2LoadInfo.h
@@ -824,15 +824,15 @@ struct ConversationLineLoadInfo
{
static DB2FieldMeta const fields[] =
{
- { false, FT_INT, "ID" },
- { false, FT_INT, "BroadcastTextID" },
- { false, FT_INT, "SpellVisualKitID" },
- { false, FT_INT, "Duration" },
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "BroadcastTextID" },
+ { false, FT_INT, "SpellVisualKitID" },
+ { false, FT_INT, "Duration" },
{ false, FT_SHORT, "NextLineID" },
{ false, FT_SHORT, "Unk1" },
- { false, FT_BYTE, "Yell" },
- { false, FT_BYTE, "Unk2" },
- { false, FT_BYTE, "Unk3" },
+ { false, FT_BYTE, "Yell" },
+ { false, FT_BYTE, "Unk2" },
+ { false, FT_BYTE, "Unk3" },
};
static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, ConversationLineMeta::Instance(), HOTFIX_SEL_CONVERSATION_LINE);
return &loadInfo;
@@ -3395,6 +3395,23 @@ struct PowerTypeLoadInfo
}
};
+struct PrestigeLevelInfoLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "IconID" },
+ { false, FT_STRING, "PrestigeText" },
+ { false, FT_BYTE, "PrestigeLevel" },
+ { false, FT_BYTE, "Flags" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, PrestigeLevelInfoMeta::Instance(), HOTFIX_SEL_PRESTIGE_LEVEL_INFO);
+ return &loadInfo;
+ }
+};
+
struct PvpDifficultyLoadInfo
{
static DB2LoadInfo const* Instance()
@@ -3412,6 +3429,22 @@ struct PvpDifficultyLoadInfo
}
};
+struct PvpRewardLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "HonorLevel" },
+ { false, FT_INT, "Prestige" },
+ { false, FT_INT, "RewardPackID" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, PvpRewardMeta::Instance(), HOTFIX_SEL_PVP_REWARD);
+ return &loadInfo;
+ }
+};
+
struct QuestFactionRewardLoadInfo
{
static DB2LoadInfo const* Instance()
@@ -3555,6 +3588,41 @@ struct RandPropPointsLoadInfo
}
};
+struct RewardPackLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "Money" },
+ { false, FT_FLOAT, "ArtifactXPMultiplier" },
+ { false, FT_BYTE, "ArtifactXPDifficulty" },
+ { false, FT_BYTE, "ArtifactCategoryID" },
+ { false, FT_INT, "TitleID" },
+ { false, FT_INT, "Unused" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, RewardPackMeta::Instance(), HOTFIX_SEL_REWARD_PACK);
+ return &loadInfo;
+ }
+};
+
+struct RewardPackXItemLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "ItemID" },
+ { false, FT_INT, "RewardPackID" },
+ { false, FT_INT, "Amount" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, RewardPackXItemMeta::Instance(), HOTFIX_SEL_REWARD_PACK_X_ITEM);
+ return &loadInfo;
+ }
+};
+
struct RulesetItemUpgradeLoadInfo
{
static DB2LoadInfo const* Instance()
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 3f398a9ff40..bbecf711f7a 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -172,7 +172,9 @@ DB2Storage<PhaseXPhaseGroupEntry> sPhaseXPhaseGroupStore("PhaseXPh
DB2Storage<PlayerConditionEntry> sPlayerConditionStore("PlayerCondition.db2", PlayerConditionLoadInfo::Instance());
DB2Storage<PowerDisplayEntry> sPowerDisplayStore("PowerDisplay.db2", PowerDisplayLoadInfo::Instance());
DB2Storage<PowerTypeEntry> sPowerTypeStore("PowerType.db2", PowerTypeLoadInfo::Instance());
+DB2Storage<PrestigeLevelInfoEntry> sPrestigeLevelInfoStore("PrestigeLevelInfo.db2", PrestigeLevelInfoLoadInfo::Instance());
DB2Storage<PvpDifficultyEntry> sPvpDifficultyStore("PvpDifficulty.db2", PvpDifficultyLoadInfo::Instance());
+DB2Storage<PvpRewardEntry> sPvpRewardStore("PvpReward.db2", PvpRewardLoadInfo::Instance());
DB2Storage<QuestFactionRewardEntry> sQuestFactionRewardStore("QuestFactionReward.db2", QuestFactionRewardLoadInfo::Instance());
DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore("QuestMoneyReward.db2", QuestMoneyRewardLoadInfo::Instance());
DB2Storage<QuestPackageItemEntry> sQuestPackageItemStore("QuestPackageItem.db2", QuestPackageItemLoadInfo::Instance());
@@ -180,6 +182,8 @@ DB2Storage<QuestSortEntry> sQuestSortStore("QuestSort.db2",
DB2Storage<QuestV2Entry> sQuestV2Store("QuestV2.db2", QuestV2LoadInfo::Instance());
DB2Storage<QuestXPEntry> sQuestXPStore("QuestXP.db2", QuestXpLoadInfo::Instance());
DB2Storage<RandPropPointsEntry> sRandPropPointsStore("RandPropPoints.db2", RandPropPointsLoadInfo::Instance());
+DB2Storage<RewardPackEntry> sRewardPackStore("RewardPack.db2", RewardPackLoadInfo::Instance());
+DB2Storage<RewardPackXItemEntry> sRewardPackXItemStore("RewardPackXItem.db2", RewardPackXItemLoadInfo::Instance());
DB2Storage<RulesetItemUpgradeEntry> sRulesetItemUpgradeStore("RulesetItemUpgrade.db2", RulesetItemUpgradeLoadInfo::Instance());
DB2Storage<ScalingStatDistributionEntry> sScalingStatDistributionStore("ScalingStatDistribution.db2", ScalingStatDistributionLoadInfo::Instance());
DB2Storage<ScenarioEntry> sScenarioStore("Scenario.db2", ScenarioLoadInfo::Instance());
@@ -294,6 +298,7 @@ typedef std::unordered_set<uint32> ToyItemIdsContainer;
typedef std::tuple<int16, int8, int32> WMOAreaTableKey;
typedef std::map<WMOAreaTableKey, WMOAreaTableEntry const*> WMOAreaTableLookupContainer;
typedef std::unordered_map<uint32, WorldMapAreaEntry const*> WorldMapAreaByAreaIDContainer;
+
namespace
{
StorageMap _stores;
@@ -332,7 +337,9 @@ namespace
NameValidationRegexContainer _nameValidators;
PhaseGroupContainer _phasesByGroup;
PowerTypesContainer _powerTypes;
+ std::unordered_map<std::pair<uint32 /*prestige level*/, uint32 /*honor level*/>, uint32> _pvpRewardPack;
QuestPackageItemContainer _questPackages;
+ std::unordered_map<uint32, std::vector<RewardPackXItemEntry const*>> _rewardPackItems;
RulesetItemUpgradeContainer _rulesetItemUpgrade;
SkillRaceClassInfoContainer _skillRaceClassInfoBySkill;
SpecializationSpellsContainer _specializationSpellsBySpec;
@@ -564,7 +571,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sPlayerConditionStore);
LOAD_DB2(sPowerDisplayStore);
LOAD_DB2(sPowerTypeStore);
+ LOAD_DB2(sPrestigeLevelInfoStore);
LOAD_DB2(sPvpDifficultyStore);
+ LOAD_DB2(sPvpRewardStore);
LOAD_DB2(sQuestFactionRewardStore);
LOAD_DB2(sQuestMoneyRewardStore);
LOAD_DB2(sQuestPackageItemStore);
@@ -572,6 +581,8 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sQuestV2Store);
LOAD_DB2(sQuestXPStore);
LOAD_DB2(sRandPropPointsStore);
+ LOAD_DB2(sRewardPackStore);
+ LOAD_DB2(sRewardPackXItemStore);
LOAD_DB2(sRulesetItemUpgradeStore);
LOAD_DB2(sScalingStatDistributionStore);
LOAD_DB2(sScenarioStore);
@@ -900,6 +911,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
ASSERT(entry->BracketID < MAX_BATTLEGROUND_BRACKETS, "PvpDifficulty bracket (%d) exceeded max allowed value (%d)", entry->BracketID, MAX_BATTLEGROUND_BRACKETS);
}
+ for (PvpRewardEntry const* pvpReward : sPvpRewardStore)
+ _pvpRewardPack[std::make_pair(pvpReward->Prestige, pvpReward->HonorLevel)] = pvpReward->RewardPackID;
+
for (QuestPackageItemEntry const* questPackageItem : sQuestPackageItemStore)
{
if (questPackageItem->FilterType != QUEST_PACKAGE_FILTER_UNMATCHED)
@@ -908,6 +922,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
_questPackages[questPackageItem->QuestPackageID].second.push_back(questPackageItem);
}
+ for (RewardPackXItemEntry const* rewardPackXItem : sRewardPackXItemStore)
+ _rewardPackItems[rewardPackXItem->RewardPackID].push_back(rewardPackXItem);
+
for (RulesetItemUpgradeEntry const* rulesetItemUpgrade : sRulesetItemUpgradeStore)
_rulesetItemUpgrade[rulesetItemUpgrade->ItemID] = rulesetItemUpgrade->ItemUpgradeID;
@@ -1711,6 +1728,16 @@ ResponseCodes DB2Manager::ValidateName(std::wstring const& name, LocaleConstant
return CHAR_NAME_SUCCESS;
}
+uint8 DB2Manager::GetMaxPrestige() const
+{
+ uint8 max = 0;
+ for (PrestigeLevelInfoEntry const* prestigeLevelInfo : sPrestigeLevelInfoStore)
+ if (!prestigeLevelInfo->IsDisabled())
+ max = std::max(prestigeLevelInfo->PrestigeLevel, max);
+
+ return max;
+}
+
PvpDifficultyEntry const* DB2Manager::GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
{
PvpDifficultyEntry const* maxEntry = nullptr; // used for level > max listed level case
@@ -1745,6 +1772,18 @@ PvpDifficultyEntry const* DB2Manager::GetBattlegroundBracketById(uint32 mapid, B
return nullptr;
}
+uint32 DB2Manager::GetRewardPackIDForPvpRewardByHonorLevelAndPrestige(uint8 honorLevel, uint8 prestige) const
+{
+ auto itr = _pvpRewardPack.find({ prestige, honorLevel });
+ if (itr == _pvpRewardPack.end())
+ itr = _pvpRewardPack.find({ 0, honorLevel });
+
+ if (itr == _pvpRewardPack.end())
+ return 0;
+
+ return itr->second;
+}
+
std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItems(uint32 questPackageID) const
{
auto itr = _questPackages.find(questPackageID);
@@ -1787,6 +1826,15 @@ PowerTypeEntry const* DB2Manager::GetPowerTypeEntry(Powers power) const
return _powerTypes[power];
}
+std::vector<RewardPackXItemEntry const*> const* DB2Manager::GetRewardPackItemsByRewardID(uint32 rewardPackID) const
+{
+ auto itr = _rewardPackItems.find(rewardPackID);
+ if (itr != _rewardPackItems.end())
+ return &itr->second;
+
+ return nullptr;
+}
+
uint32 DB2Manager::GetRulesetItemUpgrade(uint32 itemId) const
{
auto itr = _rulesetItemUpgrade.find(itemId);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index ac8d91fe5b6..cafe599f600 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -148,6 +148,7 @@ TC_GAME_API extern DB2Storage<QuestMoneyRewardEntry> sQuestMoneyR
TC_GAME_API extern DB2Storage<QuestSortEntry> sQuestSortStore;
TC_GAME_API extern DB2Storage<QuestXPEntry> sQuestXPStore;
TC_GAME_API extern DB2Storage<RandPropPointsEntry> sRandPropPointsStore;
+TC_GAME_API extern DB2Storage<RewardPackEntry> sRewardPackStore;
TC_GAME_API extern DB2Storage<ScalingStatDistributionEntry> sScalingStatDistributionStore;
TC_GAME_API extern DB2Storage<ScenarioEntry> sScenarioStore;
TC_GAME_API extern DB2Storage<ScenarioStepEntry> sScenarioStepStore;
@@ -306,11 +307,14 @@ public:
ResponseCodes ValidateName(std::wstring const& name, LocaleConstant locale) const;
std::set<uint32> GetPhasesForGroup(uint32 group) const;
PowerTypeEntry const* GetPowerTypeEntry(Powers power) const;
+ uint8 GetMaxPrestige() const;
static PvpDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level);
static PvpDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id);
+ uint32 GetRewardPackIDForPvpRewardByHonorLevelAndPrestige(uint8 honorLevel, uint8 prestige) const;
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const;
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItemsFallback(uint32 questPackageID) const;
uint32 GetQuestUniqueBitFlag(uint32 questId);
+ std::vector<RewardPackXItemEntry const*> const* GetRewardPackItemsByRewardID(uint32 rewardPackID) const;
uint32 GetRulesetItemUpgrade(uint32 itemId) const;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index da5b79e7384..30831a2975f 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -2024,6 +2024,17 @@ struct PowerTypeEntry
uint8 UIModifier;
};
+struct PrestigeLevelInfoEntry
+{
+ uint32 ID;
+ uint32 IconID;
+ LocalizedString* PrestigeText;
+ uint8 PrestigeLevel;
+ uint8 Flags;
+
+ bool IsDisabled() const { return (Flags & PRESTIGE_FLAG_DISABLED) != 0; }
+};
+
struct PvpDifficultyEntry
{
uint32 ID;
@@ -2036,6 +2047,14 @@ struct PvpDifficultyEntry
BattlegroundBracketId GetBracketId() const { return BattlegroundBracketId(BracketID); }
};
+struct PvpRewardEntry
+{
+ uint32 ID;
+ uint32 HonorLevel;
+ uint32 Prestige;
+ uint32 RewardPackID;
+};
+
struct QuestFactionRewardEntry
{
uint32 ID;
@@ -2084,6 +2103,25 @@ struct RandPropPointsEntry
uint32 UncommonPropertiesPoints[5];
};
+struct RewardPackEntry
+{
+ uint32 ID;
+ uint32 Money;
+ float ArtifactXPMultiplier;
+ uint8 ArtifactXPDifficulty;
+ uint8 ArtifactCategoryID;
+ uint32 TitleID;
+ uint32 Unused;
+};
+
+struct RewardPackXItemEntry
+{
+ uint32 ID;
+ uint32 ItemID;
+ uint32 RewardPackID;
+ uint32 Amount;
+};
+
struct RulesetItemUpgradeEntry
{
uint32 ID;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 2f25f9fde47..467494acc6a 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -245,6 +245,8 @@ enum CriteriaAdditionalCondition
CRITERIA_ADDITIONAL_CONDITION_GARRISON_MISSION_TYPE = 167, // NYI
CRITERIA_ADDITIONAL_CONDITION_PLAYER_ITEM_LEVEL = 169, // NYI
CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL = 184,
+ CRITERIA_ADDITIONAL_CONDITION_HONOR_LEVEL = 193,
+ CRITERIA_ADDITIONAL_CONDITION_PRESTIGE_LEVEL = 194
};
enum CriteriaFlags
@@ -769,6 +771,11 @@ enum MountFlags
MOUNT_FLAG_HIDE_IF_UNKNOWN = 0x40
};
+enum PrestigeLevelInfoFlags : uint8
+{
+ PRESTIGE_FLAG_DISABLED = 0x01 // Prestige levels with this flag won't be included to calculate max prestigelevel.
+};
+
enum QuestPackageFilter
{
QUEST_PACKAGE_FILTER_LOOT_SPECIALIZATION = 0, // Players can select this quest reward if it matches their selected loot specialization
diff --git a/src/server/game/DataStores/GameTables.cpp b/src/server/game/DataStores/GameTables.cpp
index ca0d3615f19..9f8b5e603c4 100644
--- a/src/server/game/DataStores/GameTables.cpp
+++ b/src/server/game/DataStores/GameTables.cpp
@@ -29,6 +29,7 @@ GameTable<GtBarberShopCostBaseEntry> sBarberShopCostBaseGameTable;
GameTable<GtBaseMPEntry> sBaseMPGameTable;
GameTable<GtCombatRatingsEntry> sCombatRatingsGameTable;
GameTable<GtCombatRatingsMultByILvl> sCombatRatingsMultByILvlGameTable;
+GameTable<GtHonorLevelEntry> sHonorLevelGameTable;
GameTable<GtHpPerStaEntry> sHpPerStaGameTable;
GameTable<GtItemSocketCostPerLevelEntry> sItemSocketCostPerLevelGameTable;
GameTable<GtNpcDamageByClassEntry> sNpcDamageByClassGameTable[MAX_EXPANSIONS];
@@ -117,6 +118,7 @@ void LoadGameTables(std::string const& dataPath)
LOAD_GT(sCombatRatingsGameTable, "CombatRatings.txt");
LOAD_GT(sCombatRatingsMultByILvlGameTable, "CombatRatingsMultByILvl.txt");
LOAD_GT(sItemSocketCostPerLevelGameTable, "ItemSocketCostPerLevel.txt");
+ LOAD_GT(sHonorLevelGameTable, "HonorLevel.txt");
LOAD_GT(sHpPerStaGameTable, "HpPerSta.txt");
LOAD_GT(sNpcDamageByClassGameTable[0], "NpcDamageByClass.txt");
LOAD_GT(sNpcDamageByClassGameTable[1], "NpcDamageByClassExp1.txt");
diff --git a/src/server/game/DataStores/GameTables.h b/src/server/game/DataStores/GameTables.h
index 93a0fb6b532..21952c515ef 100644
--- a/src/server/game/DataStores/GameTables.h
+++ b/src/server/game/DataStores/GameTables.h
@@ -103,6 +103,12 @@ struct GtCombatRatingsMultByILvl
float JewelryMultiplier = 0.0f;
};
+uint8 constexpr PRESTIGE_COLUMN_COUNT = 16;
+struct GtHonorLevelEntry
+{
+ float Prestige[PRESTIGE_COLUMN_COUNT] = { };
+};
+
struct GtHpPerStaEntry
{
float Health = 0.0f;
@@ -208,6 +214,7 @@ TC_GAME_API extern GameTable<GtBarberShopCostBaseEntry> sBarberShopC
TC_GAME_API extern GameTable<GtBaseMPEntry> sBaseMPGameTable;
TC_GAME_API extern GameTable<GtCombatRatingsEntry> sCombatRatingsGameTable;
TC_GAME_API extern GameTable<GtCombatRatingsMultByILvl> sCombatRatingsMultByILvlGameTable;
+TC_GAME_API extern GameTable<GtHonorLevelEntry> sHonorLevelGameTable;
TC_GAME_API extern GameTable<GtHpPerStaEntry> sHpPerStaGameTable;
TC_GAME_API extern GameTable<GtItemSocketCostPerLevelEntry> sItemSocketCostPerLevelGameTable;
TC_GAME_API extern GameTable<GtNpcDamageByClassEntry> sNpcDamageByClassGameTable[MAX_EXPANSIONS];
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index cbbb0d1cdbc..24e5fb2edba 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -61,6 +61,7 @@
#include "GridNotifiersImpl.h"
#include "Group.h"
#include "GroupMgr.h"
+#include "GameTables.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "InstancePackets.h"
@@ -91,6 +92,7 @@
#include "QuestPackets.h"
#include "Realm.h"
#include "ReputationMgr.h"
+#include "RestMgr.h"
#include "Scenario.h"
#include "SkillDiscovery.h"
#include "SocialMgr.h"
@@ -244,13 +246,6 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this)
m_oldpetspell = 0;
m_lastpetnumber = 0;
- ////////////////////Rest System/////////////////////
- _restTime = 0;
- inn_triggerId = 0;
- m_rest_bonus = 0;
- _restFlagMask = 0;
- ////////////////////Rest System/////////////////////
-
m_mailsLoaded = false;
m_mailsUpdated = false;
unReadMails = 0;
@@ -356,6 +351,8 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this)
_CUFProfiles[i] = nullptr;
_advancedCombatLoggingEnabled = false;
+
+ _restMgr = std::move(Trinity::make_unique<RestMgr>(this));
}
Player::~Player()
@@ -483,6 +480,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
for (uint32 i = 0; i < PLAYER_CUSTOM_DISPLAY_SIZE; ++i)
SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_CUSTOM_DISPLAY_OPTION + i, createInfo->CustomDisplay[i]);
SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_XP, (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED);
+ SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_HONOR, REST_STATE_NOT_RAF_LINKED);
SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER, createInfo->Sex);
SetByteValue(PLAYER_BYTES_4, PLAYER_BYTES_4_OFFSET_ARENA_FACTION, 0);
@@ -1209,24 +1207,7 @@ void Player::Update(uint32 p_time)
}
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
- {
- if (roll_chance_i(3) && _restTime > 0) // freeze update
- {
- time_t currTime = time(nullptr);
- time_t timeDiff = currTime - _restTime;
- if (timeDiff >= 10) // freeze update
- {
- _restTime = currTime;
-
- float bubble = 0.125f * sWorld->getRate(RATE_REST_INGAME);
- float extraPerSec = ((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000.0f) * bubble;
-
- // speed collect rest bonus (section/in hour)
- float currRestBonus = GetRestBonus();
- SetRestBonus(currRestBonus + timeDiff * extraPerSec);
- }
- }
- }
+ _restMgr->Update(now);
if (m_weaponChangeTimer > 0)
{
@@ -1241,11 +1222,11 @@ void Player::Update(uint32 p_time)
if (p_time >= m_zoneUpdateTimer)
{
// On zone update tick check if we are still in an inn if we are supposed to be in one
- if (HasRestFlag(REST_FLAG_IN_TAVERN))
+ if (_restMgr->HasRestFlag(REST_FLAG_IN_TAVERN))
{
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(GetInnTriggerId());
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(_restMgr->GetInnTriggerID());
if (!atEntry || !IsInAreaTriggerRadius(atEntry))
- RemoveRestFlag(REST_FLAG_IN_TAVERN);
+ _restMgr->RemoveRestFlag(REST_FLAG_IN_TAVERN);
}
uint32 newzone, newarea;
@@ -2382,7 +2363,7 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate)
if (recruitAFriend)
bonus_xp = 2 * xp; // xp + bonus_xp must add up to 3 * xp for RaF; calculation for quests done client-side
else
- bonus_xp = victim ? GetXPRestBonus(xp) : 0; // XP resting bonus
+ bonus_xp = victim ? _restMgr->GetRestBonusFor(REST_TYPE_XP, xp) : 0; // XP resting bonus
WorldPackets::Character::LogXPGain packet;
packet.Victim = victim ? victim->GetGUID() : ObjectGuid::Empty;
@@ -6414,6 +6395,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto
// apply honor multiplier from aura (not stacking-get highest)
AddPct(honor_f, GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HONOR_GAIN_PCT));
+ honor_f += _restMgr->GetRestBonusFor(REST_TYPE_HONOR, honor_f);
}
honor_f *= sWorld->getRate(RATE_HONOR);
@@ -6432,7 +6414,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto
GetSession()->SendPacket(data.Write());
- // TODO: add honor xp
+ AddHonorXP(honor);
if (InBattleground() && honor > 0)
{
@@ -6467,6 +6449,116 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto
return true;
}
+void Player::_InitHonorLevelOnLoadFromDB(uint32 honor, uint32 honorLevel, uint32 prestigeLevel)
+{
+ SetUInt32Value(PLAYER_FIELD_HONOR_LEVEL, honorLevel);
+ SetUInt32Value(PLAYER_FIELD_PRESTIGE, prestigeLevel);
+ UpdateHonorNextLevel();
+
+ AddHonorXP(honor);
+ if (CanPrestige())
+ Prestige();
+}
+
+void Player::RewardPlayerWithRewardPack(uint32 rewardPackID)
+{
+ RewardPlayerWithRewardPack(sRewardPackStore.LookupEntry(rewardPackID));
+}
+
+void Player::RewardPlayerWithRewardPack(RewardPackEntry const* rewardPackEntry)
+{
+ if (!rewardPackEntry)
+ return;
+
+ if (CharTitlesEntry const* charTitlesEntry = sCharTitlesStore.LookupEntry(rewardPackEntry->TitleID))
+ SetTitle(charTitlesEntry);
+
+ ModifyMoney(rewardPackEntry->Money);
+ if (std::vector<RewardPackXItemEntry const*> const* rewardPackXItems = sDB2Manager.GetRewardPackItemsByRewardID(rewardPackEntry->ID))
+ for (RewardPackXItemEntry const* rewardPackXItem : *rewardPackXItems)
+ AddItem(rewardPackXItem->ItemID, rewardPackXItem->Amount);
+}
+
+void Player::AddHonorXP(uint32 xp)
+{
+ uint32 currentHonorXP = GetUInt32Value(PLAYER_FIELD_HONOR);
+ uint32 nextHonorLevelXP = GetUInt32Value(PLAYER_FIELD_HONOR_NEXT_LEVEL);
+ uint32 newHonorXP = currentHonorXP + xp;
+ uint32 honorLevel = GetHonorLevel();
+
+ if (xp < 1 || getLevel() < PLAYER_LEVEL_MIN_HONOR || IsMaxHonorLevelAndPrestige())
+ return;
+
+ while (newHonorXP >= nextHonorLevelXP)
+ {
+ newHonorXP -= nextHonorLevelXP;
+
+ if (honorLevel < PLAYER_MAX_HONOR_LEVEL)
+ SetHonorLevel(honorLevel + 1);
+
+ honorLevel = GetHonorLevel();
+ nextHonorLevelXP = GetUInt32Value(PLAYER_FIELD_HONOR_NEXT_LEVEL);
+ }
+
+ SetUInt32Value(PLAYER_FIELD_HONOR, IsMaxHonorLevelAndPrestige() ? 0 : newHonorXP);
+}
+
+void Player::SetHonorLevel(uint8 level)
+{
+ uint8 oldHonorLevel = GetHonorLevel();
+ uint8 prestige = GetPrestigeLevel();
+ if (level == oldHonorLevel)
+ return;
+
+ uint32 rewardPackID = sDB2Manager.GetRewardPackIDForPvpRewardByHonorLevelAndPrestige(level, prestige);
+ RewardPlayerWithRewardPack(rewardPackID);
+
+ SetUInt32Value(PLAYER_FIELD_HONOR_LEVEL, level);
+ UpdateHonorNextLevel();
+
+ UpdateCriteria(CRITERIA_TYPE_HONOR_LEVEL_REACHED);
+
+ // This code is here because no link was found between those items and this reward condition in the db2 files.
+ // Interesting CriteriaTree found: Tree ids: 51140, 51156 (criteria id 31773, modifier tree id 37759)
+ if (level == 50 && prestige == 1)
+ {
+ if (GetTeam() == ALLIANCE)
+ AddItem(138992, 1);
+ else
+ AddItem(138996, 1);
+ }
+
+ if (CanPrestige())
+ Prestige();
+}
+
+void Player::Prestige()
+{
+ SetUInt32Value(PLAYER_FIELD_PRESTIGE, GetPrestigeLevel() + 1);
+ SetUInt32Value(PLAYER_FIELD_HONOR_LEVEL, 1);
+ UpdateHonorNextLevel();
+
+ UpdateCriteria(CRITERIA_TYPE_PRESTIGE_REACHED);
+}
+
+bool Player::CanPrestige() const
+{
+ if (GetSession()->GetExpansion() >= EXPANSION_LEGION && getLevel() >= PLAYER_LEVEL_MIN_HONOR && GetHonorLevel() >= PLAYER_MAX_HONOR_LEVEL && GetPrestigeLevel() < sDB2Manager.GetMaxPrestige())
+ return true;
+
+ return false;
+}
+
+bool Player::IsMaxPrestige() const
+{
+ return GetPrestigeLevel() == sDB2Manager.GetMaxPrestige();
+}
+
+void Player::UpdateHonorNextLevel()
+{
+ uint32 prestige = std::min(static_cast<uint32>(PRESTIGE_COLUMN_COUNT - 1), GetPrestigeLevel());
+ SetUInt32Value(PLAYER_FIELD_HONOR_NEXT_LEVEL, sHonorLevelGameTable.GetRow(GetHonorLevel())->Prestige[prestige]);
+}
void Player::_LoadCurrency(PreparedQueryResult result)
{
@@ -6947,9 +7039,9 @@ void Player::UpdateArea(uint32 newArea)
uint32 const areaRestFlag = (GetTeam() == ALLIANCE) ? AREA_FLAG_REST_ZONE_ALLIANCE : AREA_FLAG_REST_ZONE_HORDE;
if (area && area->Flags[0] & areaRestFlag)
- SetRestFlag(REST_FLAG_IN_FACTION_AREA);
+ _restMgr->SetRestFlag(REST_FLAG_IN_FACTION_AREA);
else
- RemoveRestFlag(REST_FLAG_IN_FACTION_AREA);
+ _restMgr->RemoveRestFlag(REST_FLAG_IN_FACTION_AREA);
}
void Player::UpdateZone(uint32 newZone, uint32 newArea)
@@ -7019,11 +7111,11 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
if (zone->Flags[0] & AREA_FLAG_CAPITAL) // Is in a capital city
{
if (!pvpInfo.IsHostile || zone->IsSanctuary())
- SetRestFlag(REST_FLAG_IN_CITY);
+ _restMgr->SetRestFlag(REST_FLAG_IN_CITY);
pvpInfo.IsInNoPvPArea = true;
}
else
- RemoveRestFlag(REST_FLAG_IN_CITY);
+ _restMgr->RemoveRestFlag(REST_FLAG_IN_CITY);
UpdatePvPState();
@@ -9233,19 +9325,6 @@ void Player::SendBattlefieldWorldStates() const
}
}
-uint32 Player::GetXPRestBonus(uint32 xp)
-{
- uint32 rested_bonus = (uint32)GetRestBonus(); // xp for each rested bonus
-
- if (rested_bonus > xp) // max rested_bonus == xp or (r+x) = 200% xp
- rested_bonus = xp;
-
- SetRestBonus(GetRestBonus() - rested_bonus);
-
- TC_LOG_DEBUG("entities.player", "Player::GetXPRestBonus: Player '%s' (%s) gain %u xp (+%u Rested Bonus). Rested points=%f", GetGUID().ToString().c_str(), GetName().c_str(), xp + rested_bonus, rested_bonus, GetRestBonus());
- return rested_bonus;
-}
-
void Player::SetBindPoint(ObjectGuid guid) const
{
WorldPackets::Misc::BinderConfirm packet(guid);
@@ -17291,6 +17370,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
//"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, "
// 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
//"health, power1, power2, power3, power4, power5, power6, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, grantableLevels, raidDifficulty, legacyRaidDifficulty, fishing_steps "
+ // 72 73 74 75 76
+ //"honor, honorLevel, prestigeLevel, honor_rest_state, honor_rest_bonus "
//
//"FROM characters WHERE guid = ?", CONNECTION_ASYNC);
PreparedQueryResult result = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM);
@@ -17830,21 +17911,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
InitRunes();
// rest bonus can only be calculated after InitStatsForLevel()
- SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_XP, fields[18].GetUInt8());
- m_rest_bonus = fields[30].GetFloat();
-
- if (time_diff > 0)
- {
- //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
- float bubble0 = 0.031f;
- //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
- float bubble1 = 0.125f;
- float bubble = fields[32].GetUInt8() > 0
- ? bubble1*sWorld->getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
- : bubble0*sWorld->getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
-
- SetRestBonus(GetRestBonus() + time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000)*bubble);
- }
+ _restMgr->LoadRestBonus(REST_TYPE_XP, PlayerRestState(fields[18].GetUInt8()), fields[30].GetFloat());
// load skills after InitStatsForLevel because it triggering aura apply also
_LoadSkills(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SKILLS));
@@ -18033,6 +18100,22 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES)))
_garrison = std::move(garrison);
+ _InitHonorLevelOnLoadFromDB(fields[72].GetUInt32(), fields[73].GetUInt32(), fields[74].GetUInt32());
+
+ _restMgr->LoadRestBonus(REST_TYPE_HONOR, PlayerRestState(fields[75].GetUInt8()), fields[76].GetFloat());
+ if (time_diff > 0)
+ {
+ //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
+ float bubble0 = 0.031f;
+ //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
+ float bubble1 = 0.125f;
+ float bubble = fields[31].GetUInt8() > 0
+ ? bubble1 * sWorld->getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
+ : bubble0 * sWorld->getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
+
+ _restMgr->AddRestBonus(REST_TYPE_XP, time_diff * _restMgr->CalcExtraPerSec(REST_TYPE_XP, bubble));
+ }
+
m_achievementMgr->CheckAllAchievementCriteria(this);
return true;
}
@@ -19678,7 +19761,7 @@ void Player::SaveToDB(bool create /*=false*/)
stmt->setUInt8(index++, m_cinematic);
stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_TOTAL]);
stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_LEVEL]);
- stmt->setFloat(index++, finiteAlways(m_rest_bonus));
+ stmt->setFloat(index++, finiteAlways(_restMgr->GetRestBonus(REST_TYPE_XP)));
stmt->setUInt32(index++, uint32(time(nullptr)));
stmt->setUInt8(index++, (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0));
//save, far from tavern/city
@@ -19820,7 +19903,7 @@ void Player::SaveToDB(bool create /*=false*/)
stmt->setUInt8(index++, m_cinematic);
stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_TOTAL]);
stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_LEVEL]);
- stmt->setFloat(index++, finiteAlways(m_rest_bonus));
+ stmt->setFloat(index++, finiteAlways(_restMgr->GetRestBonus(REST_TYPE_XP)));
stmt->setUInt32(index++, uint32(time(nullptr)));
stmt->setUInt8(index++, (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0));
//save, far from tavern/city
@@ -19900,6 +19983,12 @@ void Player::SaveToDB(bool create /*=false*/)
stmt->setUInt32(index++, m_grantableLevels);
stmt->setUInt8(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0);
+ stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_HONOR));
+ stmt->setUInt32(index++, GetHonorLevel());
+ stmt->setUInt32(index++, GetPrestigeLevel());
+ stmt->setUInt8(index++, uint8(GetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_HONOR)));
+ stmt->setFloat(index++, finiteAlways(_restMgr->GetRestBonus(REST_TYPE_HONOR)));
+
// Index
stmt->setUInt64(index, GetGUID().GetCounter());
}
@@ -21804,37 +21893,6 @@ void Player::LeaveAllArenaTeams(ObjectGuid guid)
while (result->NextRow());
}
-void Player::SetRestBonus(float rest_bonus_new)
-{
- // Prevent resting on max level
- if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
- rest_bonus_new = 0;
-
- if (rest_bonus_new < 0)
- rest_bonus_new = 0;
-
- float rest_bonus_max = (float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)*1.5f/2;
-
- if (rest_bonus_new > rest_bonus_max)
- m_rest_bonus = rest_bonus_max;
- else
- m_rest_bonus = rest_bonus_new;
-
- // update data for client
- if ((GetsRecruitAFriendBonus(true) && (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0)))
- SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_XP, REST_STATE_RAF_LINKED);
- else
- {
- if (m_rest_bonus > 10)
- SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_XP, REST_STATE_RESTED);
- else if (m_rest_bonus <= 1)
- SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_STATE_XP, REST_STATE_NOT_RAF_LINKED);
- }
-
- //RestTickUpdate
- SetUInt32Value(PLAYER_FIELD_REST_INFO + REST_RESTED_XP, uint32(m_rest_bonus));
-}
-
bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= nullptr*/, uint32 spellid /*= 0*/, uint32 preferredMountDisplay /*= 0*/)
{
if (nodes.size() < 2)
@@ -27642,33 +27700,6 @@ void Player::SendRaidGroupOnlyMessage(RaidGroupReason reason, int32 delay) const
GetSession()->SendPacket(raidGroupOnly.Write());
}
-void Player::SetRestFlag(RestFlag restFlag, uint32 triggerId /*= 0*/)
-{
- uint32 oldRestMask = _restFlagMask;
- _restFlagMask |= restFlag;
-
- if (!oldRestMask && _restFlagMask) // only set flag/time on the first rest state
- {
- _restTime = time(nullptr);
- SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
- }
-
- if (triggerId)
- inn_triggerId = triggerId;
-}
-
-void Player::RemoveRestFlag(RestFlag restFlag)
-{
- uint32 oldRestMask = _restFlagMask;
- _restFlagMask &= ~restFlag;
-
- if (oldRestMask && !_restFlagMask) // only remove flag/time on the last rest state remove
- {
- _restTime = 0;
- RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
- }
-}
-
uint32 Player::DoRandomRoll(uint32 minimum, uint32 maximum)
{
ASSERT(maximum <= 10000);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 3aafac29b28..140d46758ef 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -53,6 +53,7 @@ struct Loot;
struct Mail;
struct MapEntry;
struct QuestPackageItemEntry;
+struct RewardPackEntry;
struct SkillRaceClassInfoEntry;
struct TalentEntry;
struct TrainerSpell;
@@ -77,6 +78,7 @@ class PlayerAchievementMgr;
class PlayerMenu;
class PlayerSocial;
class ReputationMgr;
+class RestMgr;
class SpellCastTargets;
class TradeData;
@@ -507,16 +509,6 @@ enum PlayerFieldKillsOffsets
PLAYER_FIELD_KILLS_OFFSET_YESTERDAY_KILLS = 1
};
-enum PlayerRestInfoOffsets
-{
- REST_STATE_XP = 0,
- REST_RESTED_XP = 1,
- REST_STATE_HONOR = 2,
- REST_RESTED_HONOR = 3,
-
- MAX_REST_INFO
-};
-
enum MirrorTimerType
{
FATIGUE_TIMER = 0,
@@ -759,13 +751,6 @@ enum ArenaTeamInfoType
class InstanceSave;
-enum RestFlag
-{
- REST_FLAG_IN_TAVERN = 0x1,
- REST_FLAG_IN_CITY = 0x2,
- REST_FLAG_IN_FACTION_AREA = 0x4, // used with AREA_FLAG_REST_ZONE_*
-};
-
enum TeleportToOptions
{
TELE_TO_GM_MODE = 0x01,
@@ -915,13 +900,6 @@ enum ReferAFriendError
ERR_REFER_A_FRIEND_MAP_INCOMING_TRANSFER_NOT_ALLOWED = 15
};
-enum PlayerRestState : uint8
-{
- REST_STATE_RESTED = 0x01,
- REST_STATE_NOT_RAF_LINKED = 0x02,
- REST_STATE_RAF_LINKED = 0x06
-};
-
enum PlayerCommandStates
{
CHEAT_NONE = 0x00,
@@ -1050,10 +1028,14 @@ struct PlayerDynamicFieldSpellModByLabel
};
#pragma pack(pop)
+uint8 const PLAYER_MAX_HONOR_LEVEL = 50;
+uint8 const PLAYER_LEVEL_MIN_HONOR = 110;
+
class TC_GAME_API Player : public Unit, public GridObject<Player>
{
friend class WorldSession;
friend class CinematicMgr;
+ friend class RestMgr;
friend void AddItemToUpdateQueueOf(Item* item, Player* player);
friend void RemoveItemFromUpdateQueueOf(Item* item, Player* player);
public:
@@ -1151,16 +1133,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void setDeathState(DeathState s) override; // overwrite Unit::setDeathState
- float GetRestBonus() const { return m_rest_bonus; }
- void SetRestBonus(float rest_bonus_new);
-
- bool HasRestFlag(RestFlag restFlag) const { return (_restFlagMask & restFlag) != 0; }
- void SetRestFlag(RestFlag restFlag, uint32 triggerId = 0);
- void RemoveRestFlag(RestFlag restFlag);
-
- uint32 GetXPRestBonus(uint32 xp);
- uint32 GetInnTriggerId() const { return inn_triggerId; }
-
Pet* GetPet() const;
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
@@ -1986,8 +1958,21 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void RestoreHealthAfterDuel() { SetHealth(healthBeforeDuel); }
void RestoreManaAfterDuel() { SetPower(POWER_MANA, manaBeforeDuel); }
+ uint32 GetPrestigeLevel() const { return GetUInt32Value(PLAYER_FIELD_PRESTIGE); }
+ uint32 GetHonorLevel() const { return GetUInt32Value(PLAYER_FIELD_HONOR_LEVEL); }
+ void AddHonorXP(uint32 xp);
+ void SetHonorLevel(uint8 honorLevel);
+ void Prestige();
+ bool CanPrestige() const;
+ bool IsMaxPrestige() const;
+ bool IsMaxHonorLevelAndPrestige() const { return IsMaxPrestige() && GetHonorLevel() == PLAYER_MAX_HONOR_LEVEL; }
+ // Updates PLAYER_FIELD_HONOR_NEXT_LEVEL based on PLAYER_FIELD_HONOR_LEVEL and the smallest value of PLAYER_FIELD_PRESTIGE and (PRESTIGE_COLUMN_COUNT - 1)
+ void UpdateHonorNextLevel();
//End of PvP System
+ void RewardPlayerWithRewardPack(uint32 rewardPackID);
+ void RewardPlayerWithRewardPack(RewardPackEntry const* rewardPackEntry);
+
void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0);
uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION); }
static DrunkenState GetDrunkenstateByValue(uint8 value);
@@ -2359,6 +2344,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SetAdvancedCombatLogging(bool enabled) { _advancedCombatLoggingEnabled = enabled; }
SceneMgr& GetSceneMgr() { return m_sceneMgr; }
+ RestMgr& GetRestMgr() const { return *_restMgr; }
protected:
// Gamemaster whisper whitelist
@@ -2591,13 +2577,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 m_titanGripPenaltySpellId;
uint8 m_swingErrorMsg;
- ////////////////////Rest System/////////////////////
- time_t _restTime;
- uint32 inn_triggerId;
- float m_rest_bonus;
- uint32 _restFlagMask;
- ////////////////////Rest System/////////////////////
-
// Social
PlayerSocial* m_social;
@@ -2707,7 +2686,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool _advancedCombatLoggingEnabled;
// variables to save health and mana before duel and restore them after duel
- uint32 healthBeforeDuel;
+ uint64 healthBeforeDuel;
uint32 manaBeforeDuel;
WorldLocation _corpseLocation;
@@ -2715,6 +2694,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
SceneMgr m_sceneMgr;
std::unordered_map<ObjectGuid /*LootObject*/, ObjectGuid /*world object*/> m_AELootView;
+
+ void _InitHonorLevelOnLoadFromDB(uint32 /*honor*/, uint32 /*honorLevel*/, uint32 /*prestigeLevel*/);
+ std::unique_ptr<RestMgr> _restMgr;
};
TC_GAME_API void AddItemsSetItem(Player* player, Item* item);
diff --git a/src/server/game/Entities/Player/RestMgr.cpp b/src/server/game/Entities/Player/RestMgr.cpp
new file mode 100644
index 00000000000..a79e689f132
--- /dev/null
+++ b/src/server/game/Entities/Player/RestMgr.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "RestMgr.h"
+#include "Log.h"
+#include "Player.h"
+#include "Random.h"
+#include "World.h"
+#include "WorldSession.h"
+
+RestMgr::RestMgr(Player* player) : _player(player), _restTime(0), _innAreaTriggerId(0), _restFlagMask(0)
+{
+ for (uint8 i = REST_TYPE_XP; i < REST_TYPE_MAX; i++)
+ _restBonus[i] = 0;
+}
+
+void RestMgr::SetRestBonus(RestTypes restType, float restBonus)
+{
+ uint8 rest_rested_offset;
+ uint8 rest_state_offset;
+ uint16 next_level_xp_field;
+ 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;
+
+ rest_rested_offset = REST_RESTED_XP;
+ rest_state_offset = REST_STATE_XP;
+ next_level_xp_field = PLAYER_NEXT_LEVEL_XP;
+ affectedByRaF = true;
+ break;
+ case REST_TYPE_HONOR:
+ // Reset restBonus (Honor only) for players with max honor level.
+ if (_player->IsMaxHonorLevelAndPrestige())
+ restBonus = 0;
+
+ rest_rested_offset = REST_RESTED_HONOR;
+ rest_state_offset = REST_STATE_HONOR;
+ next_level_xp_field = PLAYER_FIELD_HONOR_NEXT_LEVEL;
+ break;
+ default:
+ return;
+ }
+
+ if (restBonus < 0)
+ restBonus = 0;
+
+ float rest_bonus_max = float(_player->GetUInt32Value(next_level_xp_field)) * 1.5f / 2;
+
+ if (restBonus > rest_bonus_max)
+ _restBonus[restType] = rest_bonus_max;
+ else
+ _restBonus[restType] = restBonus;
+
+ // update data for client
+ if (affectedByRaF && _player->GetsRecruitAFriendBonus(true) && (_player->GetSession()->IsARecruiter() || _player->GetSession()->GetRecruiterId() != 0))
+ _player->SetUInt32Value(PLAYER_FIELD_REST_INFO + rest_state_offset, REST_STATE_RAF_LINKED);
+ else
+ {
+ if (_restBonus[restType] > 10)
+ _player->SetUInt32Value(PLAYER_FIELD_REST_INFO + rest_state_offset, REST_STATE_RESTED);
+ else if (_restBonus[restType] <= 1)
+ _player->SetUInt32Value(PLAYER_FIELD_REST_INFO + rest_state_offset, REST_STATE_NOT_RAF_LINKED);
+ }
+
+ // RestTickUpdate
+ _player->SetUInt32Value(PLAYER_FIELD_REST_INFO + rest_rested_offset, uint32(_restBonus[restType]));
+}
+
+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 triggerID)
+{
+ uint32 oldRestMask = _restFlagMask;
+ _restFlagMask |= restFlag;
+
+ if (!oldRestMask && _restFlagMask) // only set flag/time on the first rest state
+ {
+ _restTime = time(nullptr);
+ _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
+ }
+
+ if (triggerID)
+ _innAreaTriggerId = triggerID;
+}
+
+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->RemoveFlag(PLAYER_FLAGS, 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;
+
+ SetRestBonus(restType, GetRestBonus(restType) - rested_bonus);
+
+ TC_LOG_DEBUG("entities.player", "RestMgr::GetRestBonus: Player '%s' (%s) gain %u xp (+%u Rested Bonus). Rested points=%f", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), 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->SetUInt32Value(PLAYER_FIELD_REST_INFO + restType * 2, state);
+ _player->SetUInt32Value(PLAYER_FIELD_REST_INFO + restType * 2 + 1, uint32(restBonus));
+}
+
+float RestMgr::CalcExtraPerSec(RestTypes restType, float bubble) const
+{
+ switch (restType)
+ {
+ case REST_TYPE_HONOR:
+ return float(_player->GetUInt32Value(PLAYER_FIELD_HONOR_NEXT_LEVEL)) / 72000.0f * bubble;
+ case REST_TYPE_XP:
+ return float(_player->GetUInt32Value(PLAYER_NEXT_LEVEL_XP)) / 72000.0f * bubble;
+ default:
+ return 0.0f;
+ }
+}
diff --git a/src/server/game/Entities/Player/RestMgr.h b/src/server/game/Entities/Player/RestMgr.h
new file mode 100644
index 00000000000..1d12fb765e6
--- /dev/null
+++ b/src/server/game/Entities/Player/RestMgr.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RestMgr_h__
+#define RestMgr_h__
+
+#include "Define.h"
+
+class Player;
+
+enum RestTypes : uint8
+{
+ REST_TYPE_XP = 0,
+ REST_TYPE_HONOR = 1,
+ REST_TYPE_MAX
+};
+
+enum PlayerRestInfoOffsets : uint8
+{
+ REST_STATE_XP = 0,
+ REST_RESTED_XP = 1,
+ REST_STATE_HONOR = 2,
+ REST_RESTED_HONOR = 3,
+
+ MAX_REST_INFO
+};
+
+enum PlayerRestState : uint8
+{
+ REST_STATE_RESTED = 0x01,
+ REST_STATE_NOT_RAF_LINKED = 0x02,
+ REST_STATE_RAF_LINKED = 0x06
+};
+
+enum RestFlag : uint32
+{
+ REST_FLAG_IN_TAVERN = 0x1,
+ REST_FLAG_IN_CITY = 0x2,
+ REST_FLAG_IN_FACTION_AREA = 0x4 // used with AREA_FLAG_REST_ZONE_*
+};
+
+class TC_GAME_API RestMgr
+{
+ friend class Player;
+public:
+ explicit RestMgr(Player* player);
+ ~RestMgr() { }
+
+ float GetRestBonus(RestTypes restType) const { return _restBonus[restType]; }
+
+ void SetRestBonus(RestTypes restType, float restBonus);
+ void AddRestBonus(RestTypes restType, float restBonus);
+
+ bool HasRestFlag(RestFlag restFlag) const { return (_restFlagMask & restFlag) != 0; }
+ void SetRestFlag(RestFlag restFlag, uint32 triggerId = 0);
+ void RemoveRestFlag(RestFlag restFlag);
+
+ uint32 GetRestBonusFor(RestTypes restType, uint32 xp);
+ uint32 GetInnTriggerID() const { return _innAreaTriggerId; }
+
+ void Update(time_t now);
+
+protected:
+ void LoadRestBonus(RestTypes restType, PlayerRestState state, float restBonus);
+ float CalcExtraPerSec(RestTypes restType, float bubble) const;
+
+private:
+ Player* _player;
+ time_t _restTime;
+ uint32 _innAreaTriggerId;
+ float _restBonus[REST_TYPE_MAX];
+ uint32 _restFlagMask;
+};
+
+#endif // RestMgr_h__
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 15543943195..b70dce9a901 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -45,6 +45,7 @@
#include "Opcodes.h"
#include "OutdoorPvP.h"
#include "Player.h"
+#include "RestMgr.h"
#include "ScriptMgr.h"
#include "Spell.h"
#include "SpellPackets.h"
@@ -529,7 +530,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::AreaTrigger::AreaTrigge
if (sObjectMgr->IsTavernAreaTrigger(packet.AreaTriggerID))
{
// set resting flag we are in the inn
- player->SetRestFlag(REST_FLAG_IN_TAVERN, atEntry->ID);
+ player->GetRestMgr().SetRestFlag(REST_FLAG_IN_TAVERN, atEntry->ID);
if (sWorld->IsFFAPvPRealm())
player->RemoveByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_FFA_PVP);
@@ -1180,3 +1181,9 @@ void WorldSession::HandleMountSetFavorite(WorldPackets::Misc::MountSetFavorite&
{
_collectionMgr->MountSetFavorite(mountSetFavorite.MountSpellID, mountSetFavorite.IsFavorite);
}
+
+void WorldSession::HandlePvpPrestigeRankUp(WorldPackets::Misc::PvpPrestigeRankUp& /*pvpPrestigeRankUp*/)
+{
+ if (_player->CanPrestige())
+ _player->Prestige();
+}
diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h
index 8889002f22a..ebd66224b53 100644
--- a/src/server/game/Server/Packets/MiscPackets.h
+++ b/src/server/game/Server/Packets/MiscPackets.h
@@ -880,6 +880,14 @@ namespace WorldPackets
uint32 MountSpellID = 0;
bool IsFavorite = false;
};
+
+ class PvpPrestigeRankUp final : public ClientPacket
+ {
+ public:
+ PvpPrestigeRankUp(WorldPacket&& packet) : ClientPacket(CMSG_PVP_PRESTIGE_RANK_UP, std::move(packet)) { }
+
+ void Read() override { }
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 73c7a32f9f5..71b679f9812 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -634,7 +634,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_PROTOCOL_MISMATCH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_PUSH_QUEST_TO_PARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePushQuestToParty);
DEFINE_HANDLER(CMSG_PVP_LOG_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePVPLogDataOpcode);
- DEFINE_HANDLER(CMSG_PVP_PRESTIGE_RANK_UP, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
+ DEFINE_HANDLER(CMSG_PVP_PRESTIGE_RANK_UP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePvpPrestigeRankUp);
DEFINE_HANDLER(CMSG_QUERY_BATTLE_PET_NAME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_QUERY_CORPSE_LOCATION_FROM_CLIENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryCorpseLocation);
DEFINE_HANDLER(CMSG_QUERY_CORPSE_TRANSPORT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryCorpseTransport);
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index cc0c47af344..3680636ab02 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -450,6 +450,7 @@ namespace WorldPackets
class MountSpecial;
class SetTaxiBenchmarkMode;
class MountSetFavorite;
+ class PvpPrestigeRankUp;
}
namespace Movement
@@ -1705,6 +1706,9 @@ class TC_GAME_API WorldSession
// Scenario
void HandleQueryScenarioPOI(WorldPackets::Scenario::QueryScenarioPOI& queryScenarioPOI);
+ // Honor
+ void HandlePvpPrestigeRankUp(WorldPackets::Misc::PvpPrestigeRankUp& /*pvpPrestigeRankUp*/);
+
union ConnectToKey
{
struct
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 1197dfb73fd..9aaea1b5973 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -476,6 +476,7 @@ class TC_GAME_API Spell
void EffectGiveArtifactPower(SpellEffIndex effIndex);
void EffectGiveArtifactPowerNoBonus(SpellEffIndex effIndex);
void EffectPlayScene(SpellEffIndex effIndex);
+ void EffectGiveHonor(SpellEffIndex effIndex);
typedef std::set<Aura*> UsedSpellMods;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 20b0ae2871d..1a0ea5fb3b0 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -23,6 +23,7 @@
#include "BattlegroundMgr.h"
#include "BattlePetMgr.h"
#include "CombatLogPackets.h"
+#include "CombatPackets.h"
#include "Common.h"
#include "Conversation.h"
#include "Creature.h"
@@ -325,7 +326,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectNULL, //250 SPELL_EFFECT_TAKE_SCREENSHOT
&Spell::EffectNULL, //251 SPELL_EFFECT_SET_GARRISON_CACHE_SIZE
&Spell::EffectTeleportUnits, //252 SPELL_EFFECT_TELEPORT_UNITS
- &Spell::EffectNULL, //253 SPELL_EFFECT_GIVE_HONOR
+ &Spell::EffectGiveHonor, //253 SPELL_EFFECT_GIVE_HONOR
&Spell::EffectNULL, //254 SPELL_EFFECT_254
&Spell::EffectNULL, //255 SPELL_EFFECT_LEARN_TRANSMOG_SET
};
@@ -5890,3 +5891,20 @@ void Spell::EffectPlayScene(SpellEffIndex /*effIndex*/)
m_caster->ToPlayer()->GetSceneMgr().PlayScene(effectInfo->MiscValue, destTarget);
}
+
+void Spell::EffectGiveHonor(SpellEffIndex /*effIndex*/)
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ WorldPackets::Combat::PvPCredit packet;
+ packet.Honor = damage;
+ packet.OriginalHonor = damage;
+
+ Player* playerTarget = unitTarget->ToPlayer();
+ playerTarget->AddHonorXP(damage);
+ playerTarget->SendDirectMessage(packet.Write());
+}
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index a5cfdcdd79c..c99c74278e6 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -979,7 +979,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 250 SPELL_EFFECT_TAKE_SCREENSHOT
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 251 SPELL_EFFECT_SET_GARRISON_CACHE_SIZE
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 252 SPELL_EFFECT_252
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 253 SPELL_EFFECT_253
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 253 SPELL_EFFECT_GIVE_HONOR
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 254 SPELL_EFFECT_254
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 255 SPELL_EFFECT_255
};