diff options
author | Shauren <shauren.trinity@gmail.com> | 2021-06-04 19:27:26 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-06-04 19:27:26 +0200 |
commit | 80a6347b7a0e8dfbe5e690504ed373f75c4f4c76 (patch) | |
tree | 3642bbd6c7ce37bc212d1811368e3c8cbead80c6 | |
parent | ad683a356a173f47fd9cd1f9860d5ea5d6da868c (diff) |
Core/Reputation: Implemented "friendship reputation"
-rw-r--r-- | sql/updates/hotfixes/master/2021_06_04_00_hotfixes.sql | 88 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 14 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.h | 8 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2LoadInfo.h | 35 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 18 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 4 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 21 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 11 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Reputation/ReputationMgr.cpp | 171 | ||||
-rw-r--r-- | src/server/game/Reputation/ReputationMgr.h | 13 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_character.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_lookup.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_modify.cpp | 78 |
14 files changed, 378 insertions, 95 deletions
diff --git a/sql/updates/hotfixes/master/2021_06_04_00_hotfixes.sql b/sql/updates/hotfixes/master/2021_06_04_00_hotfixes.sql new file mode 100644 index 00000000000..e02eac85190 --- /dev/null +++ b/sql/updates/hotfixes/master/2021_06_04_00_hotfixes.sql @@ -0,0 +1,88 @@ +-- +-- Table structure for table `friendship_rep_reaction` +-- +DROP TABLE IF EXISTS `friendship_rep_reaction`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `friendship_rep_reaction` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `Reaction` text, + `FriendshipRepID` int(10) unsigned NOT NULL DEFAULT '0', + `ReactionThreshold` smallint(5) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `friendship_rep_reaction_locale` +-- +DROP TABLE IF EXISTS `friendship_rep_reaction_locale`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `friendship_rep_reaction_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `Reaction_lang` text, + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +/*!50500 PARTITION BY LIST COLUMNS(locale) +(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB, + PARTITION esES VALUES IN ('esES') ENGINE = InnoDB, + PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB, + PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB, + PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB, + PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB, + PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB, + PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB, + PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB, + PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB) */; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `friendship_reputation` +-- +DROP TABLE IF EXISTS `friendship_reputation`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `friendship_reputation` ( + `Description` text, + `StandingModified` text, + `StandingChanged` text, + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `FactionID` int(11) NOT NULL DEFAULT '0', + `TextureFileID` int(11) NOT NULL DEFAULT '0', + `Flags` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `friendship_reputation_locale` +-- +DROP TABLE IF EXISTS `friendship_reputation_locale`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `friendship_reputation_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `Description_lang` text, + `StandingModified_lang` text, + `StandingChanged_lang` text, + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +/*!50500 PARTITION BY LIST COLUMNS(locale) +(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB, + PARTITION esES VALUES IN ('esES') ENGINE = InnoDB, + PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB, + PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB, + PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB, + PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB, + PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB, + PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB, + PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB, + PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB) */; +/*!40101 SET character_set_client = @saved_cs_client */; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 1eba397e46e..eae49d12b2e 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -566,6 +566,20 @@ void HotfixDatabaseConnection::DoPrepareStatements() "Enemies4, Friend1, Friend2, Friend3, Friend4 FROM faction_template WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_FACTION_TEMPLATE, "SELECT MAX(ID) + 1 FROM faction_template", CONNECTION_SYNCH); + // FriendshipRepReaction.db2 + PrepareStatement(HOTFIX_SEL_FRIENDSHIP_REP_REACTION, "SELECT ID, Reaction, FriendshipRepID, ReactionThreshold FROM friendship_rep_reaction" + " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_FRIENDSHIP_REP_REACTION, "SELECT MAX(ID) + 1 FROM friendship_rep_reaction", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_FRIENDSHIP_REP_REACTION, "SELECT ID, Reaction_lang FROM friendship_rep_reaction_locale" + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH); + + // FriendshipReputation.db2 + PrepareStatement(HOTFIX_SEL_FRIENDSHIP_REPUTATION, "SELECT Description, StandingModified, StandingChanged, ID, FactionID, TextureFileID, Flags" + " FROM friendship_reputation WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_FRIENDSHIP_REPUTATION, "SELECT MAX(ID) + 1 FROM friendship_reputation", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_FRIENDSHIP_REPUTATION, "SELECT ID, Description_lang, StandingModified_lang, StandingChanged_lang" + " FROM friendship_reputation_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH); + // GameobjectDisplayInfo.db2 PrepareStatement(HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO, "SELECT ID, GeoBoxMinX, GeoBoxMinY, GeoBoxMinZ, GeoBoxMaxX, GeoBoxMaxY, GeoBoxMaxZ, " "FileDataID, ObjectEffectPackageID, OverrideLootEffectScale, OverrideNameScale FROM gameobject_display_info WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index 4acb89a35bf..8d88f734343 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -327,6 +327,14 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_FACTION_TEMPLATE, HOTFIX_SEL_FACTION_TEMPLATE_MAX_ID, + HOTFIX_SEL_FRIENDSHIP_REP_REACTION, + HOTFIX_SEL_FRIENDSHIP_REP_REACTION_MAX_ID, + HOTFIX_SEL_FRIENDSHIP_REP_REACTION_LOCALE, + + HOTFIX_SEL_FRIENDSHIP_REPUTATION, + HOTFIX_SEL_FRIENDSHIP_REPUTATION_MAX_ID, + HOTFIX_SEL_FRIENDSHIP_REPUTATION_LOCALE, + HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO, HOTFIX_SEL_GAMEOBJECT_DISPLAY_INFO_MAX_ID, diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index 9f55b36f2fe..516842ab861 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -1998,6 +1998,41 @@ struct FactionTemplateLoadInfo } }; +struct FriendshipRepReactionLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_STRING, "Reaction" }, + { false, FT_INT, "FriendshipRepID" }, + { false, FT_SHORT, "ReactionThreshold" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, FriendshipRepReactionMeta::Instance(), HOTFIX_SEL_FRIENDSHIP_REP_REACTION); + return &loadInfo; + } +}; + +struct FriendshipReputationLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_STRING, "Description" }, + { false, FT_STRING, "StandingModified" }, + { false, FT_STRING, "StandingChanged" }, + { false, FT_INT, "ID" }, + { true, FT_INT, "FactionID" }, + { true, FT_INT, "TextureFileID" }, + { true, FT_INT, "Flags" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, FriendshipReputationMeta::Instance(), HOTFIX_SEL_FRIENDSHIP_REPUTATION); + return &loadInfo; + } +}; + struct GameobjectDisplayInfoLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 865afd679d4..bd8bba408b8 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -130,6 +130,8 @@ DB2Storage<ExpectedStatEntry> sExpectedStatStore("ExpectedStat DB2Storage<ExpectedStatModEntry> sExpectedStatModStore("ExpectedStatMod.db2", ExpectedStatModLoadInfo::Instance()); DB2Storage<FactionEntry> sFactionStore("Faction.db2", FactionLoadInfo::Instance()); DB2Storage<FactionTemplateEntry> sFactionTemplateStore("FactionTemplate.db2", FactionTemplateLoadInfo::Instance()); +DB2Storage<FriendshipRepReactionEntry> sFriendshipRepReactionStore("FriendshipRepReaction.db2", FriendshipRepReactionLoadInfo::Instance()); +DB2Storage<FriendshipReputationEntry> sFriendshipReputationStore("FriendshipReputation.db2", FriendshipReputationLoadInfo::Instance()); DB2Storage<GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore("GameObjectDisplayInfo.db2", GameobjectDisplayInfoLoadInfo::Instance()); DB2Storage<GameObjectsEntry> sGameObjectsStore("GameObjects.db2", GameobjectsLoadInfo::Instance()); DB2Storage<GarrAbilityEntry> sGarrAbilityStore("GarrAbility.db2", GarrAbilityLoadInfo::Instance()); @@ -411,6 +413,7 @@ namespace std::unordered_map<std::pair<uint32 /*level*/, int32 /*expansion*/>, ExpectedStatEntry const*> _expectedStatsByLevel; std::unordered_map<uint32 /*contentTuningId*/, std::vector<ExpectedStatModEntry const*>> _expectedStatModsByContentTuning; FactionTeamContainer _factionTeams; + std::unordered_map<uint32, std::set<FriendshipRepReactionEntry const*>> _friendshipRepReactions; HeirloomItemsContainer _heirlooms; GlyphBindableSpellsContainer _glyphBindableSpells; GlyphRequiredSpecsContainer _glyphRequiredSpecs; @@ -669,6 +672,8 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sExpectedStatModStore); LOAD_DB2(sFactionStore); LOAD_DB2(sFactionTemplateStore); + LOAD_DB2(sFriendshipRepReactionStore); + LOAD_DB2(sFriendshipReputationStore); LOAD_DB2(sGameObjectsStore); LOAD_DB2(sGameObjectDisplayInfoStore); LOAD_DB2(sGarrAbilityStore); @@ -1077,6 +1082,9 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul if (faction->ParentFactionID) _factionTeams[faction->ParentFactionID].push_back(faction->ID); + for (FriendshipRepReactionEntry const* friendshipRepReaction : sFriendshipRepReactionStore) + _friendshipRepReactions[friendshipRepReaction->FriendshipRepID].insert(friendshipRepReaction); + for (GameObjectDisplayInfoEntry const* gameObjectDisplayInfo : sGameObjectDisplayInfoStore) { if (gameObjectDisplayInfo->GeoBoxMax.X < gameObjectDisplayInfo->GeoBoxMin.X) @@ -2219,6 +2227,11 @@ std::vector<uint32> const* DB2Manager::GetFactionTeamList(uint32 faction) const return Trinity::Containers::MapGetValuePtr(_factionTeams, faction); } +std::set<FriendshipRepReactionEntry const*> const* DB2Manager::GetFriendshipRepReactions(uint32 friendshipRepID) const +{ + return Trinity::Containers::MapGetValuePtr(_friendshipRepReactions, friendshipRepID); +} + uint32 DB2Manager::GetGlobalCurveId(GlobalCurve globalCurveType) const { for (GlobalCurveEntry const* globalCurveEntry : sGlobalCurveStore) @@ -3222,6 +3235,11 @@ bool ItemLevelSelectorQualityEntryComparator::Compare(ItemLevelSelectorQualityEn return left->Quality < right->Quality; } +bool DB2Manager::FriendshipRepReactionEntryComparator::Compare(FriendshipRepReactionEntry const* left, FriendshipRepReactionEntry const* right) +{ + return left->ReactionThreshold < right->ReactionThreshold; +} + bool DB2Manager::MountTypeXCapabilityEntryComparator::Compare(MountTypeXCapabilityEntry const* left, MountTypeXCapabilityEntry const* right) { if (left->MountTypeID == right->MountTypeID) diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index c39479ee847..640fe011a3d 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -100,6 +100,8 @@ TC_GAME_API extern DB2Storage<EmotesEntry> sEmotesStore TC_GAME_API extern DB2Storage<EmotesTextEntry> sEmotesTextStore; TC_GAME_API extern DB2Storage<FactionEntry> sFactionStore; TC_GAME_API extern DB2Storage<FactionTemplateEntry> sFactionTemplateStore; +TC_GAME_API extern DB2Storage<FriendshipRepReactionEntry> sFriendshipRepReactionStore; +TC_GAME_API extern DB2Storage<FriendshipReputationEntry> sFriendshipReputationStore; TC_GAME_API extern DB2Storage<GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore; TC_GAME_API extern DB2Storage<GameObjectsEntry> sGameObjectsStore; TC_GAME_API extern DB2Storage<GarrAbilityEntry> sGarrAbilityStore; @@ -278,6 +280,7 @@ TC_GAME_API extern TaxiPathNodesByPath sTaxiPathNod class TC_GAME_API DB2Manager { public: + DEFINE_DB2_SET_COMPARATOR(FriendshipRepReactionEntry) DEFINE_DB2_SET_COMPARATOR(MountTypeXCapabilityEntry) struct HotfixRecord @@ -357,6 +360,7 @@ public: EmotesTextSoundEntry const* GetTextSoundEmoteFor(uint32 emote, uint8 race, uint8 gender, uint8 class_) const; float EvaluateExpectedStat(ExpectedStatType stat, uint32 level, int32 expansion, uint32 contentTuningId, Classes unitClass) const; std::vector<uint32> const* GetFactionTeamList(uint32 faction) const; + std::set<FriendshipRepReactionEntry const*> const* GetFriendshipRepReactions(uint32 friendshipRepID) const; uint32 GetGlobalCurveId(GlobalCurve globalCurveType) const; std::vector<uint32> const* GetGlyphBindableSpells(uint32 glyphPropertiesId) const; std::vector<uint32> const* GetGlyphRequiredSpecs(uint32 glyphPropertiesId) const; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index dcc563884b2..101a5db0656 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -1401,6 +1401,27 @@ struct FactionTemplateEntry bool IsContestedGuardFaction() const { return (Flags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) != 0; } }; +struct FriendshipRepReactionEntry +{ + uint32 ID; + LocalizedString Reaction; + uint32 FriendshipRepID; + uint16 ReactionThreshold; +}; + +struct FriendshipReputationEntry +{ + LocalizedString Description; + LocalizedString StandingModified; + LocalizedString StandingChanged; + uint32 ID; + int32 FactionID; + int32 TextureFileID; + int32 Flags; + + EnumFlag<FriendshipReputationFlags> GetFlags() const { return static_cast<FriendshipReputationFlags>(Flags); } +}; + struct GameObjectDisplayInfoEntry { uint32 ID; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index eae6227809c..875576fe4c5 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -997,6 +997,17 @@ enum FactionMasks // if none flags set then non-aggressive creature }; +enum class FriendshipReputationFlags : int32 +{ + NoFXOnReactionChange = 0x01, + NoLogTextOnRepGain = 0x02, + NoLogTextOnReactionChange = 0x04, + ShowRepGainandReactionChangeForHiddenFaction = 0x08, + NoRepGainModifiers = 0x10 +}; + +DEFINE_ENUM_FLAG(FriendshipReputationFlags); + enum class GlobalCurve : int32 { CritDiminishing = 0, diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 7db8a4f6172..b128fcfd70f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6271,6 +6271,12 @@ ReputationRank Player::GetReputationRank(uint32 faction) const // Calculate total reputation percent player gain with quest/creature level int32 Player::CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool noQuestBonus) { + bool noBonuses = false; + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction)) + if (FriendshipReputationEntry const* friendshipReputation = sFriendshipReputationStore.LookupEntry(factionEntry->FriendshipRepID)) + if (friendshipReputation->GetFlags().HasFlag(FriendshipReputationFlags::NoRepGainModifiers)) + noBonuses = true; + float percent = 100.0f; float repMod = noQuestBonus ? 0.0f : float(GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN)); diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp index ebad1e1b632..5e6baf43bf7 100644 --- a/src/server/game/Reputation/ReputationMgr.cpp +++ b/src/server/game/Reputation/ReputationMgr.cpp @@ -27,21 +27,53 @@ #include "World.h" #include "WorldSession.h" -const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000}; - -const int32 ReputationMgr::Reputation_Cap = 42999; +std::set<int32> const ReputationMgr::ReputationRankThresholds = +{ + -42000, + // Hated + -6000, + // Hostile + -3000, + // Unfriendly + 0, + // Neutral + 3000, + // Friendly + 9000, + // Honored + 21000, + // Revered + 42000 + // Exalted +}; + +const int32 ReputationMgr::Reputation_Cap = 42000; const int32 ReputationMgr::Reputation_Bottom = -42000; -ReputationRank ReputationMgr::ReputationToRank(int32 standing) +template<typename T, typename F> +static int32 ReputationToRankHelper(std::set<T> const& thresholds, int32 standing, F thresholdExtractor) { - int32 limit = Reputation_Cap + 1; - for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i) + auto itr = thresholds.begin(); + auto end = thresholds.end(); + int32 rank = -1; + while (itr != end && standing >= thresholdExtractor(*itr)) { - limit -= PointsInRank[i]; - if (standing >= limit) - return ReputationRank(i); + ++rank; + ++itr; } - return MIN_REPUTATION_RANK; + + return rank; +} + +ReputationRank ReputationMgr::ReputationToRank(FactionEntry const* factionEntry, int32 standing) +{ + int32 rank = MIN_REPUTATION_RANK; + if (std::set<FriendshipRepReactionEntry const*> const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID)) + rank = ReputationToRankHelper(*friendshipReactions, standing, [](FriendshipRepReactionEntry const* frr) { return frr->ReactionThreshold; }); + else + rank = ReputationToRankHelper(ReputationRankThresholds, standing, [](int32 threshold) { return threshold; }); + + return ReputationRank(rank); } FactionState const* ReputationMgr::GetState(FactionEntry const* factionEntry) const @@ -87,24 +119,31 @@ int32 ReputationMgr::GetReputation(uint32 faction_id) const int32 ReputationMgr::GetBaseReputation(FactionEntry const* factionEntry) const { - if (!factionEntry) + int32 dataIndex = GetFactionDataIndexForRaceAndClass(factionEntry); + if (dataIndex < 0) return 0; - uint8 race = _player->getRace(); - uint32 classMask = _player->getClassMask(); - for (int i=0; i < 4; i++) - { - if ((factionEntry->ReputationRaceMask[i].HasRace(race) || - (!factionEntry->ReputationRaceMask[i] && - factionEntry->ReputationClassMask[i] != 0)) && - (factionEntry->ReputationClassMask[i] & classMask || - factionEntry->ReputationClassMask[i] == 0)) + return factionEntry->ReputationBase[dataIndex]; +} - return factionEntry->ReputationBase[i]; - } +int32 ReputationMgr::GetMinReputation(FactionEntry const* factionEntry) const +{ + if (std::set<FriendshipRepReactionEntry const*> const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID)) + return (*friendshipReactions->begin())->ReactionThreshold; - // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i] == 0 - return 0; + return *ReputationRankThresholds.begin(); +} + +int32 ReputationMgr::GetMaxReputation(FactionEntry const* factionEntry) const +{ + if (std::set<FriendshipRepReactionEntry const*> const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID)) + return (*friendshipReactions->rbegin())->ReactionThreshold; + + int32 dataIndex = GetFactionDataIndexForRaceAndClass(factionEntry); + if (dataIndex >= 0 && factionEntry->ReputationMax[dataIndex]) + return factionEntry->ReputationMax[dataIndex]; + + return *ReputationRankThresholds.rbegin(); } int32 ReputationMgr::GetReputation(FactionEntry const* factionEntry) const @@ -122,13 +161,29 @@ int32 ReputationMgr::GetReputation(FactionEntry const* factionEntry) const ReputationRank ReputationMgr::GetRank(FactionEntry const* factionEntry) const { int32 reputation = GetReputation(factionEntry); - return ReputationToRank(reputation); + return ReputationToRank(factionEntry, reputation); } ReputationRank ReputationMgr::GetBaseRank(FactionEntry const* factionEntry) const { int32 reputation = GetBaseReputation(factionEntry); - return ReputationToRank(reputation); + return ReputationToRank(factionEntry, reputation); +} + +std::string ReputationMgr::GetReputationRankName(FactionEntry const* factionEntry) const +{ + ReputationRank rank = GetRank(factionEntry); + if (!factionEntry->FriendshipRepID) + return sObjectMgr->GetTrinityString(ReputationRankStrIndex[GetRank(factionEntry)], _player->GetSession()->GetSessionDbcLocale()); + + if (std::set<FriendshipRepReactionEntry const*> const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID)) + { + auto itr = friendshipReactions->begin(); + std::advance(itr, uint32(rank)); + return (*itr)->Reaction[_player->GetSession()->GetSessionDbcLocale()]; + } + + return ""; } ReputationRank const* ReputationMgr::GetForcedRankIfAny(FactionTemplateEntry const* factionTemplateEntry) const @@ -146,22 +201,11 @@ void ReputationMgr::ApplyForceReaction(uint32 faction_id, ReputationRank rank, b uint32 ReputationMgr::GetDefaultStateFlags(FactionEntry const* factionEntry) const { - if (!factionEntry) + int32 dataIndex = GetFactionDataIndexForRaceAndClass(factionEntry); + if (dataIndex < 0) return 0; - uint8 race = _player->getRace(); - uint32 classMask = _player->getClassMask(); - for (int i=0; i < 4; i++) - { - if ((factionEntry->ReputationRaceMask[i].HasRace(race) || - (!factionEntry->ReputationRaceMask[i] && - factionEntry->ReputationClassMask[i] != 0)) && - (factionEntry->ReputationClassMask[i] & classMask || - factionEntry->ReputationClassMask[i] == 0)) - - return factionEntry->ReputationFlags[i]; - } - return 0; + return factionEntry->ReputationFlags[dataIndex]; } void ReputationMgr::SendForceReactions() @@ -255,7 +299,8 @@ void ReputationMgr::Initialize() if (newFaction.Flags & FACTION_FLAG_VISIBLE) ++_visibleFactionCount; - UpdateRankCounters(REP_HOSTILE, GetBaseRank(factionEntry)); + if (!factionEntry->FriendshipRepID) + UpdateRankCounters(REP_HOSTILE, GetBaseRank(factionEntry)); _factions[newFaction.ReputationListID] = newFaction; } @@ -353,13 +398,13 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in standing += itr->second.Standing + BaseRep; } - if (standing > Reputation_Cap) - standing = Reputation_Cap; - else if (standing < Reputation_Bottom) - standing = Reputation_Bottom; + if (standing > GetMaxReputation(factionEntry)) + standing = GetMaxReputation(factionEntry); + else if (standing < GetMinReputation(factionEntry)) + standing = GetMinReputation(factionEntry); - ReputationRank old_rank = ReputationToRank(itr->second.Standing + BaseRep); - ReputationRank new_rank = ReputationToRank(standing); + ReputationRank old_rank = ReputationToRank(factionEntry, itr->second.Standing + BaseRep); + ReputationRank new_rank = ReputationToRank(factionEntry, standing); int32 newStanding = standing - BaseRep; @@ -377,7 +422,8 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in if (new_rank > old_rank) _sendFactionIncreased = true; - UpdateRankCounters(old_rank, new_rank); + if (!factionEntry->FriendshipRepID) + UpdateRankCounters(old_rank, new_rank); _player->UpdateCriteria(CRITERIA_TYPE_KNOWN_FACTIONS, factionEntry->ID); _player->UpdateCriteria(CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID); @@ -515,10 +561,13 @@ void ReputationMgr::LoadFromDB(PreparedQueryResult result) faction->Standing = fields[1].GetInt32(); // update counters - int32 BaseRep = GetBaseReputation(factionEntry); - ReputationRank old_rank = ReputationToRank(BaseRep); - ReputationRank new_rank = ReputationToRank(BaseRep + faction->Standing); - UpdateRankCounters(old_rank, new_rank); + if (!factionEntry->FriendshipRepID) + { + int32 BaseRep = GetBaseReputation(factionEntry); + ReputationRank old_rank = ReputationToRank(factionEntry, BaseRep); + ReputationRank new_rank = ReputationToRank(factionEntry, BaseRep + faction->Standing); + UpdateRankCounters(old_rank, new_rank); + } uint32 dbFactionFlags = fields[2].GetUInt16(); @@ -592,3 +641,21 @@ void ReputationMgr::UpdateRankCounters(ReputationRank old_rank, ReputationRank n if (new_rank >= REP_HONORED) ++_honoredFactionCount; } + +int32 ReputationMgr::GetFactionDataIndexForRaceAndClass(FactionEntry const* factionEntry) const +{ + if (!factionEntry) + return -1; + + uint8 race = _player->getRace(); + uint32 classMask = _player->getClassMask(); + for (int32 i = 0; i < 4; i++) + { + if ((factionEntry->ReputationRaceMask[i].HasRace(race) || (!factionEntry->ReputationRaceMask[i] && factionEntry->ReputationClassMask[i] != 0)) + && (factionEntry->ReputationClassMask[i] & classMask || factionEntry->ReputationClassMask[i] == 0)) + + return i; + } + + return -1; +} diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h index 92eb851f539..68ca9af0054 100644 --- a/src/server/game/Reputation/ReputationMgr.h +++ b/src/server/game/Reputation/ReputationMgr.h @@ -72,11 +72,11 @@ class TC_GAME_API ReputationMgr void SaveToDB(CharacterDatabaseTransaction& trans); void LoadFromDB(PreparedQueryResult result); public: // statics - static const int32 PointsInRank[MAX_REPUTATION_RANK]; + static std::set<int32> const ReputationRankThresholds; static const int32 Reputation_Cap; static const int32 Reputation_Bottom; - static ReputationRank ReputationToRank(int32 standing); + static ReputationRank ReputationToRank(FactionEntry const* factionEntry, int32 standing); public: // accessors uint8 GetVisibleFactionCount() const { return _visibleFactionCount; } uint8 GetHonoredFactionCount() const { return _honoredFactionCount; } @@ -99,13 +99,12 @@ class TC_GAME_API ReputationMgr int32 GetReputation(uint32 faction_id) const; int32 GetReputation(FactionEntry const* factionEntry) const; int32 GetBaseReputation(FactionEntry const* factionEntry) const; + int32 GetMinReputation(FactionEntry const* factionEntry) const; + int32 GetMaxReputation(FactionEntry const* factionEntry) const; ReputationRank GetRank(FactionEntry const* factionEntry) const; ReputationRank GetBaseRank(FactionEntry const* factionEntry) const; - uint32 GetReputationRankStrIndex(FactionEntry const* factionEntry) const - { - return ReputationRankStrIndex[GetRank(factionEntry)]; - }; + std::string GetReputationRankName(FactionEntry const* factionEntry) const;; ReputationRank const* GetForcedRankIfAny(FactionTemplateEntry const* factionTemplateEntry) const; @@ -149,6 +148,8 @@ class TC_GAME_API ReputationMgr void SetInactive(FactionState* faction, bool inactive) const; void SendVisible(FactionState const* faction, bool visible = true) const; void UpdateRankCounters(ReputationRank old_rank, ReputationRank new_rank); + int32 GetFactionDataIndexForRaceAndClass(FactionEntry const* factionEntry) const; + private: Player* _player; FactionStateList _factions; diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 833eec17be0..480ea9aae00 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -648,8 +648,7 @@ public: FactionState const& faction = itr->second; FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction.ID); char const* factionName = factionEntry ? factionEntry->Name[loc] : "#Not found#"; - ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); - std::string rankName = handler->GetTrinityString(ReputationRankStrIndex[rank]); + std::string rankName = target->GetReputationMgr().GetReputationRankName(factionEntry); std::ostringstream ss; if (handler->GetSession()) ss << faction.ID << " - |cffffffff|Hfaction:" << faction.ID << "|h[" << factionName << ' ' << localeNames[loc] << "]|h|r"; diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 8b45a06e9cc..8b74175c628 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -360,8 +360,7 @@ public: if (factionState) // and then target != NULL also { - uint32 index = target->GetReputationMgr().GetReputationRankStrIndex(factionEntry); - std::string rankName = handler->GetTrinityString(index); + std::string rankName = target->GetReputationMgr().GetReputationRankName(factionEntry); ss << ' ' << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ')'; diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index b7b8a33fa31..a0eaa8aea32 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -684,18 +684,39 @@ public: if (!factionId || !rankTxt) return false; + FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId); + + if (!factionEntry) + { + handler->PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId); + handler->SetSentErrorMessage(true); + return false; + } + + if (factionEntry->ReputationIndex < 0) + { + handler->PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->Name[handler->GetSessionDbcLocale()], factionId); + handler->SetSentErrorMessage(true); + return false; + } + amount = atoi(rankTxt); + // try to find rank by name if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0])) { std::string rankStr = rankTxt; std::wstring wrankStr; if (!Utf8toWStr(rankStr, wrankStr)) return false; + wstrToLower(wrankStr); - int r = 0; - amount = -42000; - for (; r < MAX_REPUTATION_RANK; ++r) + auto rankThresholdItr = ReputationMgr::ReputationRankThresholds.begin(); + auto end = ReputationMgr::ReputationRankThresholds.end(); + + int32 r = 0; + + for (; rankThresholdItr != end; ++rankThresholdItr, ++r) { std::string rank = handler->GetTrinityString(ReputationRankStrIndex[r]); if (rank.empty()) @@ -708,45 +729,36 @@ public: wstrToLower(wrank); if (wrank.substr(0, wrankStr.size()) == wrankStr) - { - char *deltaTxt = strtok(nullptr, " "); - if (deltaTxt) - { - int32 delta = atoi(deltaTxt); - if ((delta < 0) || (delta > ReputationMgr::PointsInRank[r] -1)) - { - handler->PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (ReputationMgr::PointsInRank[r]-1)); - handler->SetSentErrorMessage(true); - return false; - } - amount += delta; - } break; - } - amount += ReputationMgr::PointsInRank[r]; } - if (r >= MAX_REPUTATION_RANK) + + if (rankThresholdItr == end) { handler->PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt); handler->SetSentErrorMessage(true); return false; } - } - FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId); - - if (!factionEntry) - { - handler->PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId); - handler->SetSentErrorMessage(true); - return false; - } + amount = *rankThresholdItr; - if (factionEntry->ReputationIndex < 0) - { - handler->PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->Name[handler->GetSessionDbcLocale()], factionId); - handler->SetSentErrorMessage(true); - return false; + char *deltaTxt = strtok(nullptr, " "); + if (deltaTxt) + { + int32 toNextRank = 0; + auto nextThresholdItr = rankThresholdItr; + ++nextThresholdItr; + if (nextThresholdItr != end) + toNextRank = *nextThresholdItr - *rankThresholdItr; + + int32 delta = atoi(deltaTxt); + if (delta < 0 || delta >= toNextRank) + { + handler->PSendSysMessage(LANG_COMMAND_FACTION_DELTA, std::max(0, toNextRank - 1)); + handler->SetSentErrorMessage(true); + return false; + } + amount += delta; + } } target->GetReputationMgr().SetOneFactionReputation(factionEntry, amount, false); |