TrinityCore
Loading...
Searching...
No Matches
ReputationMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ReputationMgr.h"
19#include "CharacterPackets.h"
20#include "DatabaseEnv.h"
21#include "DB2Stores.h"
22#include "Language.h"
23#include "Log.h"
24#include "MapUtils.h"
25#include "ObjectMgr.h"
26#include "Player.h"
27#include "ReputationPackets.h"
28#include "ScriptMgr.h"
29#include "World.h"
30#include "WorldSession.h"
31
37
38std::set<int32> const ReputationMgr::ReputationRankThresholds =
39{
40 -42000,
41 // Hated
42 -6000,
43 // Hostile
44 -3000,
45 // Unfriendly
46 0,
47 // Neutral
48 3000,
49 // Friendly
50 9000,
51 // Honored
52 21000,
53 // Revered
54 42000
55 // Exalted
56};
57
60
61template<typename T, typename F, typename... Rest>
62static int32 ReputationToRankHelper(std::set<T, Rest...> const& thresholds, int32 standing, F thresholdExtractor)
63{
64 auto itr = thresholds.begin();
65 auto end = thresholds.end();
66 int32 rank = -1;
67 while (itr != end && standing >= thresholdExtractor(*itr))
68 {
69 ++rank;
70 ++itr;
71 }
72
73 return rank;
74}
75
77{
79 if (DB2Manager::FriendshipRepReactionSet const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID))
80 rank = ReputationToRankHelper(*friendshipReactions, standing, [](FriendshipRepReactionEntry const* frr) { return frr->ReactionThreshold; });
81 else
82 rank = ReputationToRankHelper(ReputationRankThresholds, standing, [](int32 threshold) { return threshold; });
83
84 return ReputationRank(rank);
85}
86
87FactionState const* ReputationMgr::GetState(FactionEntry const* factionEntry) const
88{
89 return factionEntry->CanHaveReputation() ? GetState(factionEntry->ReputationIndex) : nullptr;
90}
91
92bool ReputationMgr::IsAtWar(uint32 faction_id) const
93{
94 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
95
96 if (!factionEntry)
97 {
98 TC_LOG_ERROR("misc", "ReputationMgr::IsAtWar: Can't get AtWar flag of {} for unknown faction (faction id) #{}.", _player->GetName(), faction_id);
99 return false;
100 }
101
102 return IsAtWar(factionEntry);
103}
104
105bool ReputationMgr::IsAtWar(FactionEntry const* factionEntry) const
106{
107 if (!factionEntry)
108 return false;
109
110 if (FactionState const* factionState = GetState(factionEntry))
111 return factionState->Flags.HasFlag(ReputationFlags::AtWar);
112 return false;
113}
114
116{
117 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
118
119 if (!factionEntry)
120 {
121 TC_LOG_ERROR("misc", "ReputationMgr::GetReputation: Can't get reputation of {} for unknown faction (faction id) #{}.", _player->GetName(), faction_id);
122 return 0;
123 }
124
125 return GetReputation(factionEntry);
126}
127
129{
130 int32 dataIndex = GetFactionDataIndexForRaceAndClass(factionEntry);
131 if (dataIndex < 0)
132 return 0;
133
134 return factionEntry->ReputationBase[dataIndex];
135}
136
138{
139 if (DB2Manager::FriendshipRepReactionSet const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID))
140 return (*friendshipReactions->begin())->ReactionThreshold;
141
142 return *ReputationRankThresholds.begin();
143}
144
146{
147 if (ParagonReputationEntry const* paragonReputation = sDB2Manager.GetParagonReputation(factionEntry->ID))
148 {
149 // has reward quest, cap is just before threshold for another quest reward
150 // for example: if current reputation is 12345 and quests are given every 10000 and player has unclaimed reward
151 // then cap will be 19999
152
153 // otherwise cap is one theshold level larger
154 // if current reputation is 12345 and questa are given every 10000 and player does NOT have unclaimed reward
155 // then cap will be 29999
156
157 int32 reputation = GetReputation(factionEntry);
158 int32 cap = reputation + paragonReputation->LevelThreshold - reputation % paragonReputation->LevelThreshold - 1;
159
160 if (_player->GetQuestStatus(paragonReputation->QuestID) == QUEST_STATUS_NONE)
161 cap += paragonReputation->LevelThreshold;
162
163 return cap;
164 }
165
166 if (IsRenownReputation(factionEntry))
167 {
168 // Compared to a paragon reputation, DF renown reputations
169 // have a maximum value of 2500 which resets with each level of renown acquired.
170 // We calculate the total reputation necessary to raise the renown to the maximum
171 return GetRenownMaxLevel(factionEntry) * GetRenownLevelThreshold(factionEntry);
172 }
173
174 if (DB2Manager::FriendshipRepReactionSet const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID))
175 return (*friendshipReactions->rbegin())->ReactionThreshold;
176
177 int32 dataIndex = GetFactionDataIndexForRaceAndClass(factionEntry);
178 if (dataIndex >= 0)
179 return factionEntry->ReputationMax[dataIndex];
180
181 return *ReputationRankThresholds.rbegin();
182}
183
185{
186 // Faction without recorded reputation. Just ignore.
187 if (!factionEntry)
188 return 0;
189
190 if (FactionState const* state = GetState(factionEntry))
191 return GetBaseReputation(factionEntry) + state->Standing;
192
193 return 0;
194}
195
197{
198 int32 reputation = GetReputation(factionEntry);
199 return ReputationToRank(factionEntry, reputation);
200}
201
203{
204 int32 reputation = GetBaseReputation(factionEntry);
205 return ReputationToRank(factionEntry, reputation);
206}
207
208std::string ReputationMgr::GetReputationRankName(FactionEntry const* factionEntry) const
209{
210 ReputationRank rank = GetRank(factionEntry);
211 if (!factionEntry->FriendshipRepID)
212 return sObjectMgr->GetTrinityString(ReputationRankStrIndex[rank], _player->GetSession()->GetSessionDbcLocale());
213
214 if (DB2Manager::FriendshipRepReactionSet const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(factionEntry->FriendshipRepID))
215 {
216 auto itr = friendshipReactions->begin();
217 std::advance(itr, uint32(rank));
218 return (*itr)->Reaction[_player->GetSession()->GetSessionDbcLocale()];
219 }
220
221 return "";
222}
223
225{
226 return GetForcedRankIfAny(factionTemplateEntry->Faction);
227}
228
233
235{
236 if (sDB2Manager.GetParagonReputation(factionEntry->ID))
237 return true;
238
239 return false;
240}
241
243{
244 return GetParagonLevel(sFactionStore.LookupEntry(paragonFactionId));
245}
246
247int32 ReputationMgr::GetParagonLevel(FactionEntry const* paragonFactionEntry) const
248{
249 if (!paragonFactionEntry)
250 return 0;
251
252 if (ParagonReputationEntry const* paragonReputation = sDB2Manager.GetParagonReputation(paragonFactionEntry->ID))
253 return GetReputation(paragonFactionEntry) / paragonReputation->LevelThreshold;
254
255 return 0;
256}
257
259{
260 if (!IsRenownReputation(factionEntry))
261 return false;
262
263 return GetRenownLevel(factionEntry) >= GetRenownMaxLevel(factionEntry);
264}
265
266bool ReputationMgr::IsRenownReputation(FactionEntry const* factionEntry) const
267{
268 return factionEntry->RenownCurrencyID > 0;
269}
270
271int32 ReputationMgr::GetRenownLevel(FactionEntry const* renownFactionEntry) const
272{
273 if (!renownFactionEntry)
274 return 0;
275
276 if (CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(renownFactionEntry->RenownCurrencyID))
277 return _player->GetCurrencyQuantity(currency->ID);
278
279 return 0;
280}
281
283{
284 if (!renownFactionEntry || !IsRenownReputation(renownFactionEntry))
285 return 0;
286
287 int32 dataIndex = GetFactionDataIndexForRaceAndClass(renownFactionEntry);
288 if (dataIndex >= 0)
289 return renownFactionEntry->ReputationMax[dataIndex];
290
291 return 0;
292}
293
295{
296 if (!renownFactionEntry)
297 return 0;
298
299 if (CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(renownFactionEntry->RenownCurrencyID))
300 return _player->GetCurrencyMaxQuantity(currency);
301
302 return 0;
303}
304
306{
307 if (apply)
308 {
309 _forcedReactions[faction_id] = rank;
310 _player->SetVisibleForcedReaction(faction_id, rank);
311 }
312 else
313 {
314 _forcedReactions.erase(faction_id);
316 }
317}
318
320{
321 ReputationFlags flags = [&]()
322 {
323 int32 dataIndex = GetFactionDataIndexForRaceAndClass(factionEntry);
324 if (dataIndex < 0)
326
327 return static_cast<ReputationFlags>(factionEntry->ReputationFlags[dataIndex]);
328 }();
329
330 if (sDB2Manager.GetParagonReputation(factionEntry->ID))
332
333 return flags;
334}
335
337{
339 setFactionStanding.BonusFromAchievementSystem = 0.0f;
340
341 auto getStandingForPacket = [](FactionState const* state)
342 {
343 return state->VisualStandingIncrease ? state->VisualStandingIncrease : state->Standing;
344 };
345
346 if (faction)
347 setFactionStanding.Faction.emplace_back(int32(faction->ReputationListID), getStandingForPacket(faction), faction->ID);
348
349 for (auto& [reputationIndex, state] : _factions)
350 {
351 if (state.needSend)
352 {
353 state.needSend = false;
354 if (!faction || state.ReputationListID != faction->ReputationListID)
355 setFactionStanding.Faction.emplace_back(int32(state.ReputationListID), getStandingForPacket(&state), state.ID);
356 }
357 }
358
359 setFactionStanding.ShowVisual = _sendFactionIncreased;
360 _player->SendDirectMessage(setFactionStanding.Write());
361
362 _sendFactionIncreased = false; // Reset
363}
364
366{
368
369 for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr)
370 {
371 WorldPackets::Reputation::FactionData& factionData = initFactions.Factions.emplace_back();
372 factionData.FactionID = itr->second.ID;
373 factionData.Flags = itr->second.Flags.AsUnderlyingType();
374 factionData.Standing = itr->second.Standing;
376 WorldPackets::Reputation::FactionBonusData& bonus = initFactions.Bonuses.emplace_back();
377 bonus.FactionID = itr->second.ID;
378 bonus.FactionHasBonus = false;
379 itr->second.needSend = false;
380 }
381
382 _player->SendDirectMessage(initFactions.Write());
383}
384
385void ReputationMgr::SendVisible(FactionState const* faction, bool visible) const
386{
388 return;
389
390 // make faction visible/not visible in reputation list at client
392 packet.FactionIndex = faction->ReputationListID;
394}
395
397{
398 _factions.clear();
403 _sendFactionIncreased = false;
404
405 for (FactionEntry const* factionEntry : sFactionStore)
406 {
407 if (factionEntry->CanHaveReputation())
408 {
409 FactionState newFaction;
410 newFaction.ID = factionEntry->ID;
411 newFaction.ReputationListID = factionEntry->ReputationIndex;
412 newFaction.Standing = 0;
413 newFaction.VisualStandingIncrease = 0;
414 newFaction.Flags = GetDefaultStateFlags(factionEntry);
415 newFaction.needSend = true;
416 newFaction.needSave = true;
417
418 if (newFaction.Flags.HasFlag(ReputationFlags::Visible))
420
421 if (!factionEntry->FriendshipRepID)
423
424 _factions[newFaction.ReputationListID] = newFaction;
425 }
426 }
427}
428
429bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental, bool spillOverOnly, bool noSpillover)
430{
431 sScriptMgr->OnPlayerReputationChange(_player, factionEntry->ID, standing, incremental);
432 bool res = false;
433 if (!noSpillover)
434 {
435 // if spillover definition exists in DB, override DBC
436 if (RepSpilloverTemplate const* repTemplate = sObjectMgr->GetRepSpilloverTemplate(factionEntry->ID))
437 {
438 for (uint32 i = 0; i < MAX_SPILLOVER_FACTIONS; ++i)
439 {
440 if (repTemplate->faction[i])
441 {
442 if (_player->GetReputationRank(repTemplate->faction[i]) <= ReputationRank(repTemplate->faction_rank[i]))
443 {
444 // bonuses are already given, so just modify standing by rate
445 int32 spilloverRep = int32(standing * repTemplate->faction_rate[i]);
446 SetOneFactionReputation(sFactionStore.AssertEntry(repTemplate->faction[i]), spilloverRep, incremental);
447 }
448 }
449 }
450 }
451 else
452 {
453 float spillOverRepOut = float(standing);
454 // check for sub-factions that receive spillover
455 std::vector<uint32> const* flist = sDB2Manager.GetFactionTeamList(factionEntry->ID);
456 // if has no sub-factions, check for factions with same parent
457 if (!flist && factionEntry->ParentFactionID && factionEntry->ParentFactionMod[1] != 0.0f)
458 {
459 spillOverRepOut *= factionEntry->ParentFactionMod[1];
460 if (FactionEntry const* parent = sFactionStore.LookupEntry(factionEntry->ParentFactionID))
461 {
462 FactionStateList::iterator parentState = _factions.find(parent->ReputationIndex);
463 // some team factions have own reputation standing, in this case do not spill to other sub-factions
464 if (parentState != _factions.end() && parentState->second.Flags.HasFlag(ReputationFlags::HeaderShowsBar))
465 {
466 SetOneFactionReputation(parent, int32(spillOverRepOut), incremental);
467 }
468 else // spill to "sister" factions
469 {
470 flist = sDB2Manager.GetFactionTeamList(factionEntry->ParentFactionID);
471 }
472 }
473 }
474 if (flist)
475 {
476 // Spillover to affiliated factions
477 for (std::vector<uint32>::const_iterator itr = flist->begin(); itr != flist->end(); ++itr)
478 {
479 if (FactionEntry const* factionEntryCalc = sFactionStore.LookupEntry(*itr))
480 {
481 if (factionEntryCalc == factionEntry || GetRank(factionEntryCalc) > ReputationRank(factionEntryCalc->ParentFactionCap[0]))
482 continue;
483 int32 spilloverRep = int32(spillOverRepOut * factionEntryCalc->ParentFactionMod[0]);
484 if (spilloverRep != 0 || !incremental)
485 res = SetOneFactionReputation(factionEntryCalc, spilloverRep, incremental);
486 }
487 }
488 }
489 }
490 }
491
492 // spillover done, update faction itself
493 FactionStateList::iterator faction = _factions.find(factionEntry->ReputationIndex);
494 if (faction != _factions.end())
495 {
496 FactionEntry const* primaryFactionToModify = factionEntry;
497 if (incremental && standing > 0 && CanGainParagonReputationForFaction(factionEntry))
498 {
499 primaryFactionToModify = sFactionStore.AssertEntry(factionEntry->ParagonFactionID);
500 faction = _factions.find(primaryFactionToModify->ReputationIndex);
501 }
502
503 if (faction != _factions.end())
504 {
505 // if we update spillover only, do not update main reputation (rank exceeds creature reward rate)
506 if (!spillOverOnly)
507 res = SetOneFactionReputation(primaryFactionToModify, standing, incremental);
508
509 // only this faction gets reported to client, even if it has no own visible standing
510 SendState(&faction->second);
511 }
512 }
513 return res;
514}
515
516bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
517{
518 FactionStateList::iterator itr = _factions.find(factionEntry->ReputationIndex);
519 if (itr != _factions.end())
520 {
521 // Ignore renown reputation already raised to the maximum level
522 if (HasMaximumRenownReputation(factionEntry) && standing > 0)
523 {
524 itr->second.needSend = false;
525 itr->second.needSave = false;
526 return false;
527 }
528
529 int32 baseRep = GetBaseReputation(factionEntry);
530 int32 oldStanding = itr->second.Standing + baseRep;
531
532 if (incremental || IsRenownReputation(factionEntry))
533 {
534 // int32 *= float cause one point loss?
535 standing = int32(floor((float)standing * sWorld->getRate(RATE_REPUTATION_GAIN) + 0.5f));
536 standing += oldStanding;
537 }
538
539 if (standing > GetMaxReputation(factionEntry))
540 standing = GetMaxReputation(factionEntry);
541 else if (standing < GetMinReputation(factionEntry))
542 standing = GetMinReputation(factionEntry);
543
544 // Ignore rank for paragon or renown reputation
545 if (!IsParagonReputation(factionEntry) && !IsRenownReputation(factionEntry))
546 {
547 ReputationRank oldRank = ReputationToRank(factionEntry, oldStanding);
548 ReputationRank newRank = ReputationToRank(factionEntry, standing);
549
550 if (newRank <= REP_HOSTILE)
551 SetAtWar(&itr->second, true);
552
553 if (newRank > oldRank)
555
556 if (!factionEntry->FriendshipRepID)
557 UpdateRankCounters(oldRank, newRank);
558 }
559 else
560 _sendFactionIncreased = true; // TODO: Check Paragon reputation
561
562 // Calculate new standing and reputation change
563 int32 newStanding = 0;
564 int32 reputationChange = standing - oldStanding;
565
566 if (!IsRenownReputation(factionEntry))
567 newStanding = standing - baseRep;
568 else
569 {
570 if (CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(factionEntry->RenownCurrencyID))
571 {
572 int32 renownLevelThreshold = GetRenownLevelThreshold(factionEntry);
573 int32 oldRenownLevel = GetRenownLevel(factionEntry);
574
575 int32 totalReputation = (oldRenownLevel * renownLevelThreshold) + (standing - baseRep);
576 int32 newRenownLevel = totalReputation / renownLevelThreshold;
577 newStanding = totalReputation % renownLevelThreshold;
578
579 if (newRenownLevel >= GetRenownMaxLevel(factionEntry))
580 {
581 newStanding = 0;
582 reputationChange += (GetRenownMaxLevel(factionEntry) * renownLevelThreshold) - totalReputation;
583 }
584
585 itr->second.VisualStandingIncrease = reputationChange;
586
587 // If the reputation is decreased by command, we will send CurrencyDestroyReason::Cheat
588 if (oldRenownLevel != newRenownLevel)
589 _player->ModifyCurrency(currency->ID, newRenownLevel - oldRenownLevel, CurrencyGainSource::RenownRepGain, CurrencyDestroyReason::Cheat);
590 }
591 }
592
593 _player->ReputationChanged(factionEntry, reputationChange);
594
595 itr->second.Standing = newStanding;
596 itr->second.needSend = true;
597 itr->second.needSave = true;
598
599 SetVisible(&itr->second);
600
601 ParagonReputationEntry const* paragonReputation = sDB2Manager.GetParagonReputation(factionEntry->ID);
602 if (paragonReputation)
603 {
604 int32 oldParagonLevel = oldStanding / paragonReputation->LevelThreshold;
605 int32 newParagonLevel = standing / paragonReputation->LevelThreshold;
606 if (oldParagonLevel != newParagonLevel)
607 if (Quest const* paragonRewardQuest = sObjectMgr->GetQuestTemplate(paragonReputation->QuestID))
608 _player->AddQuestAndCheckCompletion(paragonRewardQuest, nullptr);
609 }
610
616
617 return true;
618 }
619 return false;
620}
621
622void ReputationMgr::SetVisible(FactionTemplateEntry const* factionTemplateEntry)
623{
624 if (!factionTemplateEntry->Faction)
625 return;
626
627 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->Faction))
628 // Never show factions of the opposing team
629 if (!(factionEntry->ReputationRaceMask[1].HasRace(_player->GetRace()) && factionEntry->ReputationBase[1] == Reputation_Bottom))
630 SetVisible(factionEntry);
631}
632
634{
635 if (!factionEntry->CanHaveReputation())
636 return;
637
638 FactionStateList::iterator itr = _factions.find(factionEntry->ReputationIndex);
639 if (itr == _factions.end())
640 return;
641
642 SetVisible(&itr->second);
643}
644
646{
647 // always invisible or hidden faction can't be make visible
649 return;
650
652 return;
653
654 if (sDB2Manager.GetParagonReputation(faction->ID))
655 return;
656
657 // already set
659 return;
660
662 faction->needSend = true;
663 faction->needSave = true;
664
666
667 SendVisible(faction);
668}
669
670void ReputationMgr::SetAtWar(RepListID repListID, bool on)
671{
672 FactionStateList::iterator itr = _factions.find(repListID);
673 if (itr == _factions.end())
674 return;
675
676 // always invisible or hidden faction can't change war state
677 if (itr->second.Flags.HasFlag(ReputationFlags::Hidden | ReputationFlags::Header))
678 return;
679
680 SetAtWar(&itr->second, on);
681}
682
683void ReputationMgr::SetAtWar(FactionState* faction, bool atWar) const
684{
685 // Do not allow to declare war to our own faction. But allow for rival factions (eg Aldor vs Scryer).
686 if (atWar && faction->Flags.HasFlag(ReputationFlags::Peaceful) && GetRank(sFactionStore.AssertEntry(faction->ID)) > REP_HATED)
687 return;
688
689 // already set
690 if (faction->Flags.HasFlag(ReputationFlags::AtWar) == atWar)
691 return;
692
693 if (atWar)
694 faction->Flags |= ReputationFlags::AtWar;
695 else
696 faction->Flags &= ~ReputationFlags::AtWar;
697
698 faction->needSend = true;
699 faction->needSave = true;
700}
701
702void ReputationMgr::SetInactive(RepListID repListID, bool on)
703{
704 FactionStateList::iterator itr = _factions.find(repListID);
705 if (itr == _factions.end())
706 return;
707
708 SetInactive(&itr->second, on);
709}
710
711void ReputationMgr::SetInactive(FactionState* faction, bool inactive) const
712{
713 // always invisible or hidden faction can't be inactive
715 return;
716
717 // already set
718 if (faction->Flags.HasFlag(ReputationFlags::Inactive) == inactive)
719 return;
720
721 if (inactive)
723 else
725
726 faction->needSend = true;
727 faction->needSave = true;
728}
729
731{
732 // Set initial reputations (so everything is nifty before DB data load)
733 Initialize();
734
735 //QueryResult* result = CharacterDatabase.PQuery("SELECT faction, standing, flags FROM character_reputation WHERE guid = '{}'", GetGUIDLow());
736
737 if (result)
738 {
739 do
740 {
741 Field* fields = result->Fetch();
742
743 FactionEntry const* factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt16());
744 if (factionEntry && factionEntry->CanHaveReputation())
745 {
746 FactionState* faction = &_factions[factionEntry->ReputationIndex];
747
748 // update standing to current
749 faction->Standing = fields[1].GetInt32();
750
751 // update counters
752 if (!factionEntry->FriendshipRepID)
753 {
754 int32 BaseRep = GetBaseReputation(factionEntry);
755 ReputationRank old_rank = ReputationToRank(factionEntry, BaseRep);
756 ReputationRank new_rank = ReputationToRank(factionEntry, BaseRep + faction->Standing);
757 UpdateRankCounters(old_rank, new_rank);
758 }
759
760 EnumFlag<ReputationFlags> dbFactionFlags = static_cast<ReputationFlags>(fields[2].GetUInt16());
761
762 if (dbFactionFlags.HasFlag(ReputationFlags::Visible))
763 SetVisible(faction); // have internal checks for forced invisibility
764
765 if (dbFactionFlags.HasFlag(ReputationFlags::Inactive))
766 SetInactive(faction, true); // have internal checks for visibility requirement
767
768 if (dbFactionFlags.HasFlag(ReputationFlags::AtWar)) // DB at war
769 SetAtWar(faction, true); // have internal checks for ReputationFlags::Peaceful
770 else // DB not at war
771 {
772 // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN)
774 SetAtWar(faction, false); // have internal checks for ReputationFlags::Peaceful
775 }
776
777 // set atWar for hostile
778 if (GetRank(factionEntry) <= REP_HOSTILE)
779 SetAtWar(faction, true);
780
781 // reset changed flag if values similar to saved in DB
782 if (faction->Flags == dbFactionFlags)
783 {
784 faction->needSend = false;
785 faction->needSave = false;
786 }
787 }
788 }
789 while (result->NextRow());
790 }
791}
792
794{
795 for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr)
796 {
797 if (itr->second.needSave)
798 {
800 stmt->setUInt64(0, _player->GetGUID().GetCounter());
801 stmt->setUInt16(1, uint16(itr->second.ID));
802 trans->Append(stmt);
803
804 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_REPUTATION_BY_FACTION);
805 stmt->setUInt64(0, _player->GetGUID().GetCounter());
806 stmt->setUInt16(1, uint16(itr->second.ID));
807 stmt->setInt32(2, itr->second.Standing);
808 stmt->setUInt16(3, itr->second.Flags.AsUnderlyingType());
809 trans->Append(stmt);
810
811 itr->second.needSave = false;
812 }
813 }
814}
815
817{
818 if (old_rank >= REP_EXALTED)
820 if (old_rank >= REP_REVERED)
822 if (old_rank >= REP_HONORED)
824
825 if (new_rank >= REP_EXALTED)
827 if (new_rank >= REP_REVERED)
829 if (new_rank >= REP_HONORED)
831}
832
834{
835 if (!factionEntry)
836 return -1;
837
838 uint8 race = _player->GetRace();
839 uint32 classMask = _player->GetClassMask();
840 for (int32 i = 0; i < 4; i++)
841 {
842 if ((factionEntry->ReputationRaceMask[i].HasRace(race) || (factionEntry->ReputationRaceMask[i].IsEmpty() && factionEntry->ReputationClassMask[i] != 0))
843 && (factionEntry->ReputationClassMask[i] & classMask || factionEntry->ReputationClassMask[i] == 0))
844
845 return i;
846 }
847
848 return -1;
849}
850
852{
853 if (!sFactionStore.LookupEntry(factionEntry->ParagonFactionID))
854 return false;
855
856 if (GetRank(factionEntry) != REP_EXALTED && !HasMaximumRenownReputation(factionEntry))
857 return false;
858
859 ParagonReputationEntry const* paragonReputation = sDB2Manager.GetParagonReputation(factionEntry->ParagonFactionID);
860 if (!paragonReputation)
861 return false;
862
863 Quest const* quest = sObjectMgr->GetQuestTemplate(paragonReputation->QuestID);
864 if (!quest)
865 return false;
866
867 return _player->GetLevel() >= _player->GetQuestMinLevel(quest);
868}
@ CHAR_INS_CHAR_REPUTATION_BY_FACTION
@ CHAR_DEL_CHAR_REPUTATION_BY_FACTION
DB2Storage< CurrencyTypesEntry > sCurrencyTypesStore("CurrencyTypes.db2", &CurrencyTypesLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
#define sDB2Manager
Definition DB2Stores.h:569
@ TotalFactionsEncountered
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
uint16 flags
@ LANG_REP_FRIENDLY
Definition Language.h:377
@ LANG_REP_HONORED
Definition Language.h:378
@ LANG_REP_NEUTRAL
Definition Language.h:376
@ LANG_REP_REVERED
Definition Language.h:379
@ LANG_REP_HOSTILE
Definition Language.h:374
@ LANG_REP_HATED
Definition Language.h:373
@ LANG_REP_EXALTED
Definition Language.h:380
@ LANG_REP_UNFRIENDLY
Definition Language.h:375
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define sObjectMgr
Definition ObjectMgr.h:1885
@ QUEST_STATUS_NONE
Definition QuestDef.h:147
uint32 const ReputationRankStrIndex[MAX_REPUTATION_RANK]
static int32 ReputationToRankHelper(std::set< T, Rest... > const &thresholds, int32 standing, F thresholdExtractor)
uint32 RepListID
ReputationFlags
TC_GAME_API uint32 const ReputationRankStrIndex[MAX_REPUTATION_RANK]
#define sScriptMgr
Definition ScriptMgr.h:1449
#define MAX_REPUTATION_RANK
#define MIN_REPUTATION_RANK
ReputationRank
@ REP_HATED
@ REP_EXALTED
@ REP_HONORED
@ REP_REVERED
@ REP_HOSTILE
#define MAX_SPILLOVER_FACTIONS
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
std::set< FriendshipRepReactionEntry const *, FriendshipRepReactionEntryComparator > FriendshipRepReactionSet
Definition DB2Stores.h:439
constexpr bool HasFlag(T flag) const
Definition EnumFlag.h:106
Class used to access individual fields of database query result.
Definition Field.h:94
uint16 GetUInt16() const noexcept
Definition Field.cpp:43
int32 GetInt32() const noexcept
Definition Field.cpp:64
LowType GetCounter() const
Definition ObjectGuid.h:336
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6283
void ReputationChanged(FactionEntry const *factionEntry, int32 change)
Definition Player.cpp:16723
void SetVisibleForcedReaction(uint32 factionId, ReputationRank rank)
Definition Player.cpp:6600
WorldSession * GetSession() const
Definition Player.h:2272
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
void AddQuestAndCheckCompletion(Quest const *quest, Object *questGiver)
Definition Player.cpp:14676
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15962
ReputationRank GetReputationRank(uint32 faction_id) const
Definition Player.cpp:6505
void RemoveVisibleForcedReaction(uint32 factionId)
Definition Player.cpp:6616
int32 GetQuestMinLevel(Quest const *quest) const
Definition Player.cpp:14331
void ModifyCurrency(uint32 id, int32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Modify currency amount.
Definition Player.cpp:7146
uint32 GetCurrencyQuantity(uint32 id) const
Definition Player.cpp:7384
uint32 GetCurrencyMaxQuantity(CurrencyTypesEntry const *currency, bool onLoad=false, bool onUpdateVersion=false) const
Definition Player.cpp:7420
void setUInt16(uint8 index, uint16 value)
void setUInt64(uint8 index, uint64 value)
void setInt32(uint8 index, int32 value)
bool HasMaximumRenownReputation(FactionEntry const *factionEntry) const
bool IsParagonReputation(FactionEntry const *factionEntry) const
std::string GetReputationRankName(FactionEntry const *factionEntry) const
uint8 _honoredFactionCount
ReputationRank GetBaseRank(FactionEntry const *factionEntry) const
int32 GetFactionDataIndexForRaceAndClass(FactionEntry const *factionEntry) const
int32 GetRenownLevelThreshold(FactionEntry const *renownFactionEntry) const
void SetVisible(FactionTemplateEntry const *factionTemplateEntry)
int32 GetBaseReputation(FactionEntry const *factionEntry) const
int32 GetMaxReputation(FactionEntry const *factionEntry) const
uint8 _visibleFactionCount
ReputationFlags GetDefaultStateFlags(FactionEntry const *factionEntry) const
bool CanGainParagonReputationForFaction(FactionEntry const *factionEntry) const
void SetAtWar(RepListID repListID, bool on)
void SendState(FactionState const *faction)
int32 GetReputation(uint32 faction_id) const
bool SetReputation(FactionEntry const *factionEntry, int32 standing)
int32 GetRenownLevel(FactionEntry const *renownFactionEntry) const
void ApplyForceReaction(uint32 faction_id, ReputationRank rank, bool apply)
ReputationRank GetRank(FactionEntry const *factionEntry) const
int32 GetMinReputation(FactionEntry const *factionEntry) const
void SendInitialReputations()
static ReputationRank ReputationToRank(FactionEntry const *factionEntry, int32 standing)
uint8 _exaltedFactionCount
FactionState const * GetState(FactionEntry const *factionEntry) const
uint8 _reveredFactionCount
FactionStateList _factions
ForcedReactions _forcedReactions
static const int32 Reputation_Bottom
void SendVisible(FactionState const *faction, bool visible=true) const
bool IsAtWar(uint32 faction_id) const
bool SetOneFactionReputation(FactionEntry const *factionEntry, int32 standing, bool incremental)
Public for chat command needs.
bool _sendFactionIncreased
Play visual effect on next SMSG_SET_FACTION_STANDING sent.
int32 GetParagonLevel(uint32 paragonFactionId) const
int32 GetRenownMaxLevel(FactionEntry const *renownFactionEntry) const
bool IsRenownReputation(FactionEntry const *factionEntry) const
static std::set< int32 > const ReputationRankThresholds
void UpdateRankCounters(ReputationRank old_rank, ReputationRank new_rank)
static const int32 Reputation_Cap
void LoadFromDB(PreparedQueryResult result)
ReputationRank const * GetForcedRankIfAny(FactionTemplateEntry const *factionTemplateEntry) const
void SetInactive(RepListID repListID, bool on)
void SaveToDB(CharacterDatabaseTransaction trans)
uint32 GetClassMask() const
Definition Unit.h:766
uint8 GetLevel() const
Definition Unit.h:757
uint8 GetRace() const
Definition Unit.h:761
std::string const & GetName() const
Definition Object.h:342
std::vector< FactionBonusData > Bonuses
std::vector< FactionStandingData > Faction
LocaleConstant GetSessionDbcLocale() const
bool PlayerLoading() const
#define sWorld
Definition World.h:916
@ RATE_REPUTATION_GAIN
Definition World.h:482
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
std::array< int32, 4 > ReputationBase
std::array< int32, 4 > ReputationMax
uint16 ParagonFactionID
uint32 FriendshipRepID
uint16 ParentFactionID
std::array< int16, 4 > ReputationClassMask
bool CanHaveReputation() const
std::array< float, 2 > ParentFactionMod
std::array< uint16, 4 > ReputationFlags
int32 RenownCurrencyID
int16 ReputationIndex
std::array< Trinity::RaceMask< int64 >, 4 > ReputationRaceMask
RepListID ReputationListID
EnumFlag< ReputationFlags > Flags
int32 VisualStandingIncrease