From 0b02ba87fc60d538b78a401604eb8955b895515f Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Sat, 5 Feb 2022 11:37:00 +0100 Subject: [PATCH] =?UTF-8?q?fix(Core/Reputations):=20Faction=20rep=20gained?= =?UTF-8?q?=20by=20killing=20mobs=20is=20now=20prop=E2=80=A6=20(#9737)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(Core/Reputations): Faction rep gained by killing mobs is now properly rounded up. Do not increase reputation rank if exceeds max rank cap. Fixes #8718 --- .../game/Battlegrounds/Battleground.cpp | 2 +- src/server/game/Entities/Player/Player.cpp | 36 ++++++----- src/server/game/Entities/Player/Player.h | 4 +- src/server/game/Handlers/CharacterHandler.cpp | 2 +- src/server/game/Reputation/ReputationMgr.cpp | 59 ++++++++++++++++--- src/server/game/Reputation/ReputationMgr.h | 15 +++-- src/server/game/Spells/SpellEffects.cpp | 3 +- src/server/scripts/Commands/cs_modify.cpp | 2 +- src/server/scripts/Commands/cs_quest.cpp | 4 +- .../scripts/OutdoorPvP/OutdoorPvPSI.cpp | 4 +- src/server/scripts/Spells/spell_generic.cpp | 2 +- 11 files changed, 91 insertions(+), 42 deletions(-) diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index b6387eebc..ed3a7f0c7 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -684,7 +684,7 @@ void Battleground::RewardReputationToTeam(uint32 factionId, uint32 reputation, T { uint32 realFactionId = GetRealRepFactionForPlayer(factionId, itr->second); - uint32 repGain = reputation; + float repGain = static_cast(reputation); AddPct(repGain, itr->second->GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN)); AddPct(repGain, itr->second->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, realFactionId)); if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(realFactionId)) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f3ecccb44..3ecd5b30d 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5736,7 +5736,7 @@ 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) +float Player::CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, float rep, int32 faction, bool noQuestBonus) { float percent = 100.0f; @@ -5746,7 +5746,7 @@ int32 Player::CalculateReputationGain(ReputationSource source, uint32 creatureOr if (source == REPUTATION_SOURCE_KILL) repMod += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, faction); - percent += rep > 0 ? repMod : -repMod; + percent += rep > 0.f ? repMod : -repMod; float rate; switch (source) @@ -5844,24 +5844,26 @@ void Player::RewardReputation(Unit* victim, float rate) if (Rep->RepFaction1 && (!Rep->TeamDependent || teamId == TEAM_ALLIANCE)) { - int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); - donerep1 = int32(donerep1 * rate); + float donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), static_cast(Rep->RepValue1), ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); + donerep1 *= rate; FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); - uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1); if (factionEntry1) - GetReputationMgr().ModifyReputation(factionEntry1, donerep1, bool(current_reputation_rank1 > Rep->ReputationMaxCap1)); + { + GetReputationMgr().ModifyReputation(factionEntry1, donerep1, false, static_cast(Rep->ReputationMaxCap1)); + } } if (Rep->RepFaction2 && (!Rep->TeamDependent || teamId == TEAM_HORDE)) { - int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); - donerep2 = int32(donerep2 * rate); + float donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), static_cast(Rep->RepValue2), ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); + donerep2 *= rate; FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); - uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2); if (factionEntry2) - GetReputationMgr().ModifyReputation(factionEntry2, donerep2, bool(current_reputation_rank2 > Rep->ReputationMaxCap2)); + { + GetReputationMgr().ModifyReputation(factionEntry2, donerep2, false, static_cast(Rep->ReputationMaxCap2)); + } } } @@ -5873,11 +5875,11 @@ void Player::RewardReputation(Quest const* quest) if (!quest->RewardFactionId[i]) continue; - int32 rep = 0; + float rep = 0.f; if (quest->RewardFactionValueIdOverride[i]) { - rep = quest->RewardFactionValueIdOverride[i] / 100; + rep = quest->RewardFactionValueIdOverride[i] / 100.f; } else { @@ -5885,11 +5887,11 @@ void Player::RewardReputation(Quest const* quest) if (QuestFactionRewEntry const* questFactionRewEntry = sQuestFactionRewardStore.LookupEntry(row)) { uint32 field = std::abs(quest->RewardFactionValueId[i]); - rep = questFactionRewEntry->QuestRewFactionValue[field]; + rep = static_cast(questFactionRewEntry->QuestRewFactionValue[field]); } } - if (!rep) + if (rep == 0.f) continue; if (quest->IsDaily()) @@ -5914,7 +5916,9 @@ void Player::RewardReputation(Quest const* quest) } if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i])) - GetReputationMgr().ModifyReputation(factionEntry, rep, false, quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_NO_REP_SPILLOVER)); + { + GetReputationMgr().ModifyReputation(factionEntry, rep, quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_NO_REP_SPILLOVER)); + } } } @@ -14795,7 +14799,7 @@ uint8 Player::GetMostPointsTalentTree() const return maxIndex; } -void Player::SetReputation(uint32 factionentry, uint32 value) +void Player::SetReputation(uint32 factionentry, float value) { GetReputationMgr().SetReputation(sFactionStore.LookupEntry(factionentry), value); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 479633e5b..56ffb5e8c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1645,7 +1645,7 @@ public: void learnQuestRewardedSpells(); void learnQuestRewardedSpells(Quest const* quest); void learnSpellHighRank(uint32 spellid); - void SetReputation(uint32 factionentry, uint32 value); + void SetReputation(uint32 factionentry, float value); [[nodiscard]] uint32 GetReputation(uint32 factionentry) const; std::string const& GetGuildName(); [[nodiscard]] uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } @@ -2056,7 +2056,7 @@ public: void RewardReputation(Unit* victim, float rate); void RewardReputation(Quest const* quest); - int32 CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool noQuestBonus = false); + float CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, float rep, int32 faction, bool noQuestBonus = false); void UpdateSkillsForLevel(); void UpdateSkillsToMaxSkillsForLevel(); // for .levelup diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index fc4d54eac..27e10ceae 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1016,7 +1016,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) { for (auto const& itr : factionsList) { - repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(itr), 42999, false); + repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(itr), 42999.f, false); } }; diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp index 5496a86fc..b749e267f 100644 --- a/src/server/game/Reputation/ReputationMgr.cpp +++ b/src/server/game/Reputation/ReputationMgr.cpp @@ -41,6 +41,17 @@ ReputationRank ReputationMgr::ReputationToRank(int32 standing) return MIN_REPUTATION_RANK; } +int32 ReputationMgr::ReputationRankToStanding(ReputationRank rank) +{ + int32 standing = Reputation_Bottom; + for (uint8 i = MIN_REPUTATION_RANK; i <= rank; ++i) + { + standing += PointsInRank[i]; + } + + return std::max(standing - 1, Reputation_Bottom); +} + bool ReputationMgr::IsAtWar(uint32 faction_id) const { FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); @@ -271,6 +282,7 @@ void ReputationMgr::Initialize() newFaction.Flags = GetDefaultStateFlags(factionEntry); newFaction.needSend = true; newFaction.needSave = true; + newFaction.roundedUp = false; if (newFaction.Flags & FACTION_FLAG_VISIBLE) ++_visibleFactionCount; @@ -282,7 +294,7 @@ void ReputationMgr::Initialize() } } -bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool spillOverOnly, bool noSpillOver) +bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, float standing, bool incremental, bool noSpillOver, Optional repMaxCap) { bool res = false; @@ -298,7 +310,7 @@ bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standi if (_player->GetReputationRank(repTemplate->faction[i]) <= ReputationRank(repTemplate->faction_rank[i])) { // bonuses are already given, so just modify standing by rate - int32 spilloverRep = int32(standing * repTemplate->faction_rate[i]); + float spilloverRep = standing * repTemplate->faction_rate[i]; SetOneFactionReputation(sFactionStore.LookupEntry(repTemplate->faction[i]), spilloverRep, incremental); } } @@ -319,7 +331,7 @@ bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standi // some team factions have own reputation standing, in this case do not spill to other sub-factions if (parentState != _factions.end() && (parentState->second.Flags & FACTION_FLAG_SPECIAL)) { - SetOneFactionReputation(parent, int32(spillOverRepOut), incremental); + SetOneFactionReputation(parent, spillOverRepOut, incremental); } else // spill to "sister" factions { @@ -336,7 +348,7 @@ bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standi { if (factionEntryCalc == factionEntry || GetRank(factionEntryCalc) > ReputationRank(factionEntryCalc->spilloverMaxRankIn)) continue; - int32 spilloverRep = int32(spillOverRepOut * factionEntryCalc->spilloverRateIn); + float spilloverRep = spillOverRepOut * factionEntryCalc->spilloverRateIn; if (spilloverRep != 0 || !incremental) res = SetOneFactionReputation(factionEntryCalc, spilloverRep, incremental); } @@ -345,20 +357,25 @@ bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standi } } + bool spillOverOnly = repMaxCap ? GetRank(factionEntry) > *repMaxCap : false; + // spillover done, update faction itself FactionStateList::iterator faction = _factions.find(factionEntry->reputationListID); if (faction != _factions.end()) { // Xinef: if we update spillover only, do not update main reputation (rank exceeds creature reward rate) if (!spillOverOnly) - res = SetOneFactionReputation(factionEntry, standing, incremental); + { + res = SetOneFactionReputation(factionEntry, standing, incremental, repMaxCap); + } + // only this faction gets reported to client, even if it has no own visible standing SendState(&faction->second); } return res; } -bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental) +bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, float stand, bool incremental, Optional repMaxCap) { FactionStateList::iterator itr = _factions.find(factionEntry->reputationListID); if (itr != _factions.end()) @@ -367,8 +384,27 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in if (incremental) { - // int32 *= float cause one point loss? - standing = int32(floor((float)standing * sWorld->getRate(RATE_REPUTATION_GAIN) + 0.5f)); + stand *= sWorld->getRate(RATE_REPUTATION_GAIN); + } + + int32 standing = 0; + float stand2; + if (fabs(modff(stand, &stand2)) < 1.f) + { + if (itr->second.roundedUp) + { + standing = static_cast(ceil(stand)); + } + else + { + standing = static_cast(stand); + } + + itr->second.roundedUp = !itr->second.roundedUp; + } + + if (incremental) + { standing += itr->second.Standing + BaseRep; } @@ -379,6 +415,11 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in ReputationRank old_rank = ReputationToRank(itr->second.Standing + BaseRep); ReputationRank new_rank = ReputationToRank(standing); + if (repMaxCap && new_rank > *repMaxCap) + { + standing = ReputationRankToStanding(*repMaxCap); + new_rank = *repMaxCap; + } if (sScriptMgr->OnPlayerReputationChange(_player, factionEntry->ID, standing, incremental)) { @@ -574,6 +615,8 @@ void ReputationMgr::LoadFromDB(PreparedQueryResult result) faction->needSend = false; faction->needSave = false; } + + faction->roundedUp = false; } } while (result->NextRow()); } diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h index 40512bd96..57e6f7124 100644 --- a/src/server/game/Reputation/ReputationMgr.h +++ b/src/server/game/Reputation/ReputationMgr.h @@ -46,6 +46,7 @@ struct FactionState uint8 Flags; bool needSend; bool needSave; + bool roundedUp; }; typedef std::map FactionStateList; @@ -68,6 +69,8 @@ public: // statics static const int32 Reputation_Bottom; static ReputationRank ReputationToRank(int32 standing); + static int32 ReputationRankToStanding(ReputationRank rank); + public: // accessors uint8 GetVisibleFactionCount() const { return _visibleFactionCount; } uint8 GetHonoredFactionCount() const { return _honoredFactionCount; } @@ -108,13 +111,13 @@ public: // accessors } public: // modifiers - bool SetReputation(FactionEntry const* factionEntry, int32 standing) + bool SetReputation(FactionEntry const* factionEntry, float standing) { - return SetReputation(factionEntry, standing, false, false, false); + return SetReputation(factionEntry, standing, false); } - bool ModifyReputation(FactionEntry const* factionEntry, int32 standing, bool spillOverOnly = false, bool noSpillOver = false) + bool ModifyReputation(FactionEntry const* factionEntry, float standing, bool noSpillOver = false, Optional repMaxCap = {}) { - return SetReputation(factionEntry, standing, true, spillOverOnly, noSpillOver); + return SetReputation(factionEntry, standing, true, noSpillOver, repMaxCap); } void SetVisible(FactionTemplateEntry const* factionTemplateEntry); @@ -125,7 +128,7 @@ public: // modifiers void ApplyForceReaction(uint32 faction_id, ReputationRank rank, bool apply); //! Public for chat command needs - bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); + bool SetOneFactionReputation(FactionEntry const* factionEntry, float standing, bool incremental, Optional repMaxCap = { }); public: // senders void SendInitialReputations(); @@ -136,7 +139,7 @@ public: // senders private: // internal helper functions void Initialize(); uint32 GetDefaultStateFlags(FactionEntry const* factionEntry) const; - bool SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool spillOverOnly, bool noSpillOver = false); + bool SetReputation(FactionEntry const* factionEntry, float standing, bool incremental, bool noSpillOver = false, Optional repMaxCap = { }); void SetVisible(FactionState* faction); void SetAtWar(FactionState* faction, bool atWar) const; void SetInactive(FactionState* faction, bool inactive) const; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 24629c8a8..f6ac9a0d6 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4879,7 +4879,7 @@ void Spell::EffectReputation(SpellEffIndex effIndex) return; } - int32 repChange = damage; + float repChange = static_cast(damage); uint32 factionId = m_spellInfo->Effects[effIndex].MiscValue; @@ -4888,7 +4888,6 @@ void Spell::EffectReputation(SpellEffIndex effIndex) return; repChange = player->CalculateReputationGain(REPUTATION_SOURCE_SPELL, 0, repChange, factionId); - player->GetReputationMgr().ModifyReputation(factionEntry, repChange); } diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 72ad5acd5..6d1c08c40 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -851,7 +851,7 @@ public: return false; } - target->GetReputationMgr().SetOneFactionReputation(factionEntry, amount, false); + target->GetReputationMgr().SetOneFactionReputation(factionEntry, float(amount), false); target->GetReputationMgr().SendState(target->GetReputationMgr().GetState(factionEntry)); handler->PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[handler->GetSessionDbcLocale()], factionId, diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp index 30d6c5569..5f0d8d911 100644 --- a/src/server/scripts/Commands/cs_quest.cpp +++ b/src/server/scripts/Commands/cs_quest.cpp @@ -317,7 +317,7 @@ public: { if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction)) { - player->GetReputationMgr().SetReputation(factionEntry, repValue); + player->GetReputationMgr().SetReputation(factionEntry, static_cast(repValue)); } } } @@ -331,7 +331,7 @@ public: { if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction)) { - player->GetReputationMgr().SetReputation(factionEntry, repValue2); + player->GetReputationMgr().SetReputation(factionEntry, static_cast(repValue2)); } } } diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index db7b5dfa6..3dc996029 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -113,7 +113,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player* player, uint32 trigger) // add 19 honor player->RewardHonor(nullptr, 1, 19); // add 20 cenarion circle repu - player->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609), 20); + player->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609), 20.f); // complete quest player->KilledMonsterCredit(SI_TURNIN_QUEST_CM_A); } @@ -139,7 +139,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player* player, uint32 trigger) // add 19 honor player->RewardHonor(nullptr, 1, 19); // add 20 cenarion circle repu - player->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609), 20); + player->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609), 20.f); // complete quest player->KilledMonsterCredit(SI_TURNIN_QUEST_CM_H); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index dc9429f6c..c2f08f40d 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -2463,7 +2463,7 @@ class spell_gen_oracle_wolvar_reputation : public SpellScript // Set rep to baserep + basepoints (expecting spillover for oposite faction -> become hated) // Not when player already has equal or higher rep with this faction if (player->GetReputationMgr().GetReputation(factionEntry) <= repChange) - player->GetReputationMgr().SetReputation(factionEntry, repChange); + player->GetReputationMgr().SetReputation(factionEntry, static_cast(repChange)); // EFFECT_INDEX_2 most likely update at war state, we already handle this in SetReputation }