diff options
Diffstat (limited to 'src')
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 }; |