OregonCore  revision 3611e8a-git
Your Favourite TBC server
ReputationMgr.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of the OregonCore 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 "DBCStores.h"
20 #include "Player.h"
21 #include "WorldPacket.h"
22 #include "ObjectMgr.h"
23 
24 const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = { 36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000 };
25 
28 
30 {
31  int32 limit = Reputation_Cap + 1;
32  for (int i = MAX_REPUTATION_RANK - 1; i >= MIN_REPUTATION_RANK; --i)
33  {
34  limit -= PointsInRank[i];
35  if (standing >= limit)
36  return ReputationRank(i);
37  }
38  return MIN_REPUTATION_RANK;
39 }
40 
42 {
43  FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
44 
45  if (!factionEntry)
46  {
47  sLog.outError("ReputationMgr::GetReputation: Can't get reputation of %s for unknown faction (faction id) #%u.", _player->GetName(), faction_id);
48  return 0;
49  }
50 
51  return GetReputation(factionEntry);
52 }
53 
55 {
56  if (!factionEntry)
57  return 0;
58 
59  uint32 raceMask = _player->getRaceMask();
60  uint32 classMask = _player->getClassMask();
61 
62 
63  int idx = factionEntry->GetIndexFitTo(raceMask, classMask);
64 
65  return idx >= 0 ? factionEntry->BaseRepValue[idx] : 0;
66 }
67 
69 {
70  // Faction without recorded reputation. Just ignore.
71  if (!factionEntry)
72  return 0;
73 
74  if (FactionState const* state = GetState(factionEntry))
75  return GetBaseReputation(factionEntry) + state->Standing;
76 
77  return 0;
78 }
79 
81 {
82  int32 reputation = GetReputation(factionEntry);
83  return ReputationToRank(reputation);
84 }
85 
87 {
88  int32 reputation = GetBaseReputation(factionEntry);
89  return ReputationToRank(reputation);
90 }
91 
93 {
94  if (apply)
95  _forcedReactions[faction_id] = rank;
96  else
97  _forcedReactions.erase(faction_id);
98 }
99 
101 {
102  if (!factionEntry)
103  return 0;
104 
105  uint32 raceMask = _player->getRaceMask();
106  uint32 classMask = _player->getClassMask();
107 
108  int idx = factionEntry->GetIndexFitTo(raceMask, classMask);
109 
110  return idx >= 0 ? factionEntry->ReputationFlags[idx] : 0;
111 }
112 
114 {
115  WorldPacket data;
116  data.Initialize(SMSG_SET_FORCED_REACTIONS, 4 + _forcedReactions.size()*(4 + 4));
117  data << uint32(_forcedReactions.size());
118  for (ForcedReactions::const_iterator itr = _forcedReactions.begin(); itr != _forcedReactions.end(); ++itr)
119  {
120  data << uint32(itr->first); // faction_id (Faction.dbc)
121  data << uint32(itr->second); // reputation rank
122  }
123  _player->SendDirectMessage(&data);
124 }
125 
127 {
128  uint32 count = 1;
129 
130  WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0
131  data << float(0); // unk 2.4.0
132 
133  size_t p_count = data.wpos();
134  data << uint32(count); // placeholder
135 
136  data << uint32(faction->ReputationListID);
137  data << uint32(faction->Standing);
138 
139  for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr)
140  {
141  if (itr->second.needSend)
142  {
143  itr->second.needSend = false;
144  if (itr->second.ReputationListID != faction->ReputationListID)
145  {
146  data << uint32(itr->second.ReputationListID);
147  data << uint32(itr->second.Standing);
148  ++count;
149  }
150  }
151  }
152 
153  data.put<uint32>(p_count, count);
154  _player->SendDirectMessage(&data);
155 }
156 
158 {
159  uint8 count = 128;
160  WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4 + count * 5));
161  data << uint32(count);
162 
163  RepListID a = 0;
164 
165  for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr)
166  {
167  // fill in absent fields
168  for (; a != itr->first; ++a)
169  {
170  data << uint8(0);
171  data << uint32(0);
172  }
173 
174  // fill in encountered data
175  data << uint8(itr->second.Flags);
176  data << uint32(itr->second.Standing);
177 
178  itr->second.needSend = false;
179 
180  ++a;
181  }
182 
183  // fill in absent fields
184  for (; a != count; ++a)
185  {
186  data << uint8(0);
187  data << uint32(0);
188  }
189 
190  _player->SendDirectMessage(&data);
191 }
192 
193 void ReputationMgr::SendVisible(FactionState const* faction) const
194 {
195  if (_player->GetSession()->PlayerLoading())
196  return;
197 
198  // make faction visible in reputation list at client
200  data << faction->ReputationListID;
201  _player->SendDirectMessage(&data);
202 }
203 
205 {
206  _factions.clear();
207 
208  for (unsigned int i = 1; i < sFactionStore.GetNumRows(); i++)
209  {
210  FactionEntry const* factionEntry = sFactionStore.LookupEntry(i);
211 
212  if (factionEntry && (factionEntry->reputationListID >= 0))
213  {
214  FactionState newFaction;
215  newFaction.ID = factionEntry->ID;
216  newFaction.ReputationListID = factionEntry->reputationListID;
217  newFaction.Standing = 0;
218  newFaction.Flags = GetDefaultStateFlags(factionEntry);
219  newFaction.needSend = true;
220  newFaction.needSave = true;
221 
222  _factions[newFaction.ReputationListID] = newFaction;
223  }
224  }
225 }
226 
227 bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
228 {
229  bool res = false;
230  // if spillover definition exists in DB
231  if (const RepSpilloverTemplate* repTemplate = sObjectMgr.GetRepSpilloverTemplate(factionEntry->ID))
232  {
233  for (uint32 i = 0; i < MAX_SPILLOVER_FACTIONS; ++i)
234  {
235  if (repTemplate->faction[i])
236  {
237  if (_player->GetReputationRank(repTemplate->faction[i]) <= ReputationRank(repTemplate->faction_rank[i]))
238  {
239  // bonuses are already given, so just modify standing by rate
240  int32 spilloverRep = standing * repTemplate->faction_rate[i];
241  SetOneFactionReputation(sFactionStore.LookupEntry(repTemplate->faction[i]), spilloverRep, incremental);
242  }
243  }
244  }
245  }
246  // spillover done, update faction itself
247  FactionStateList::iterator faction = _factions.find(factionEntry->reputationListID);
248  if (faction != _factions.end())
249  {
250  res = SetOneFactionReputation(factionEntry, standing, incremental);
251  // only this faction gets reported to client, even if it has no own visible standing
252  SendState(&faction->second);
253  }
254  return res;
255 }
256 
257 bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
258 {
259  FactionStateList::iterator itr = _factions.find(factionEntry->reputationListID);
260  if (itr != _factions.end())
261  {
262  int32 BaseRep = GetBaseReputation(factionEntry);
263 
264  if (incremental)
265  standing += itr->second.Standing + BaseRep;
266 
267  if (standing > Reputation_Cap)
268  standing = Reputation_Cap;
269  else if (standing < Reputation_Bottom)
270  standing = Reputation_Bottom;
271 
272  itr->second.Standing = standing - BaseRep;
273  itr->second.needSend = true;
274  itr->second.needSave = true;
275 
276  SetVisible(&itr->second);
277 
278  if (ReputationToRank(standing) <= REP_HOSTILE)
279  SetAtWar(&itr->second, true);
280 
281  return true;
282  }
283  return false;
284 }
285 
286 void ReputationMgr::SetVisible(FactionTemplateEntry const*factionTemplateEntry)
287 {
288  if (!factionTemplateEntry->faction)
289  return;
290 
291  if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction))
292  SetVisible(factionEntry);
293 }
294 
295 void ReputationMgr::SetVisible(FactionEntry const* factionEntry)
296 {
297  if (factionEntry->reputationListID < 0)
298  return;
299 
300  FactionStateList::iterator itr = _factions.find(factionEntry->reputationListID);
301  if (itr == _factions.end())
302  return;
303 
304  SetVisible(&itr->second);
305 }
306 
308 {
309  // always invisible or hidden faction can't be make visible
311  return;
312 
313  // already set
314  if (faction->Flags & FACTION_FLAG_VISIBLE)
315  return;
316 
317  faction->Flags |= FACTION_FLAG_VISIBLE;
318  faction->needSend = true;
319  faction->needSave = true;
320 
321  SendVisible(faction);
322 }
323 
324 void ReputationMgr::SetAtWar(RepListID repListID, bool on)
325 {
326  FactionStateList::iterator itr = _factions.find(repListID);
327  if (itr == _factions.end())
328  return;
329 
330  // always invisible or hidden faction can't change war state
331  if (itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED | FACTION_FLAG_HIDDEN))
332  return;
333 
334  SetAtWar(&itr->second, on);
335 }
336 
337 void ReputationMgr::SetAtWar(FactionState* faction, bool atWar)
338 {
339  // not allow declare war to faction unless already hated or less
340  if (atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) && ReputationToRank(faction->Standing) > REP_HATED)
341  return;
342 
343  // already set
344  if (((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar)
345  return;
346 
347  if (atWar)
348  faction->Flags |= FACTION_FLAG_AT_WAR;
349  else
350  faction->Flags &= ~FACTION_FLAG_AT_WAR;
351 
352  faction->needSend = true;
353  faction->needSave = true;
354 }
355 
356 bool ReputationMgr::IsAtWar(uint32 faction_id) const
357 {
358  FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
359 
360  if (!factionEntry)
361  {
362  sLog.outError("ReputationMgr::IsAtWar: Can't get AtWat flag of %s for unknown faction (faction id) #%u.", _player->GetName(), faction_id);
363  return 0;
364  }
365 
366  return IsAtWar(factionEntry);
367 }
368 
369 bool ReputationMgr::IsAtWar(FactionEntry const* factionEntry) const
370 {
371  if (!factionEntry)
372  return false;
373 
374  if (FactionState const* factionState = GetState(factionEntry))
375  return (factionState->Flags & FACTION_FLAG_AT_WAR);
376  return false;
377 }
378 
379 void ReputationMgr::SetInactive(RepListID repListID, bool on)
380 {
381  FactionStateList::iterator itr = _factions.find(repListID);
382  if (itr == _factions.end())
383  return;
384 
385  SetInactive(&itr->second, on);
386 }
387 
388 void ReputationMgr::SetInactive(FactionState* faction, bool inactive)
389 {
390  // always invisible or hidden faction can't be inactive
391  if (inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED | FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE)))
392  return;
393 
394  // already set
395  if (((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive)
396  return;
397 
398  if (inactive)
399  faction->Flags |= FACTION_FLAG_INACTIVE;
400  else
401  faction->Flags &= ~FACTION_FLAG_INACTIVE;
402 
403  faction->needSend = true;
404  faction->needSave = true;
405 }
406 
408 {
409  // Set initial reputations (so everything is nifty before DB data load)
410  Initialize();
411 
412  //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow());
413 
414  if (result)
415  {
416  do
417  {
418  Field *fields = result->Fetch();
419 
420  FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32());
421  if (factionEntry && (factionEntry->reputationListID >= 0))
422  {
423  FactionState* faction = &_factions[factionEntry->reputationListID];
424 
425  // update standing to current
426  faction->Standing = int32(fields[1].GetUInt32());
427 
428  uint32 dbFactionFlags = fields[2].GetUInt32();
429 
430  if (dbFactionFlags & FACTION_FLAG_VISIBLE)
431  SetVisible(faction); // have internal checks for forced invisibility
432 
433  if (dbFactionFlags & FACTION_FLAG_INACTIVE)
434  SetInactive(faction, true); // have internal checks for visibility requirement
435 
436  if (dbFactionFlags & FACTION_FLAG_AT_WAR) // DB at war
437  SetAtWar(faction, true); // have internal checks for FACTION_FLAG_PEACE_FORCED
438  else // DB not at war
439  {
440  // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN)
441  if (faction->Flags & FACTION_FLAG_VISIBLE)
442  SetAtWar(faction, false); // have internal checks for FACTION_FLAG_PEACE_FORCED
443  }
444 
445  // set atWar for hostile
446  ForcedReactions::const_iterator forceItr = _forcedReactions.find(factionEntry->ID);
447  if (forceItr != _forcedReactions.end())
448  {
449  if (forceItr->second <= REP_HOSTILE)
450  SetAtWar(faction, true);
451  }
452  else if (GetRank(factionEntry) <= REP_HOSTILE)
453  SetAtWar(faction, true);
454 
455  // reset changed flag if values similar to saved in DB
456  if (faction->Flags == dbFactionFlags)
457  {
458  faction->needSend = false;
459  faction->needSave = false;
460  }
461  }
462  } while (result->NextRow());
463  }
464 }
465 
467 {
468  for (FactionStateList::iterator itr = _factions.begin(); itr != _factions.end(); ++itr)
469  {
470  if (itr->second.needSave)
471  {
472  CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", _player->GetGUIDLow(), itr->second.ID);
473  CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", _player->GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags);
474  {
475  itr->second.needSave = false;
476  }
477  }
478  }
479 }
static ReputationRank ReputationToRank(int32 standing)
int32 BaseRepValue[4]
Definition: DBCStructure.h:267
int32 GetReputation(uint32 faction_id) const
static const int32 PointsInRank[MAX_REPUTATION_RANK]
Definition: ReputationMgr.h:67
void SendState(FactionState const *faction)
ReputationRank
FactionStateList _factions
Definition: Field.h:24
void ApplyForceReaction(uint32 faction_id, ReputationRank rank, bool apply)
uint32 GetDefaultStateFlags(FactionEntry const *factionEntry) const
bool IsAtWar(uint32 faction_id) const
#define MAX_SPILLOVER_FACTIONS
static const int32 Reputation_Cap
Definition: ReputationMgr.h:68
void SendInitialReputations()
#define sLog
Log class singleton.
Definition: Log.h:187
ACE_INT32 int32
Definition: Define.h:67
void Initialize(uint16 opcode, size_t newres=200)
Definition: WorldPacket.h:37
uint32 RepListID
Definition: ReputationMgr.h:39
void SetAtWar(RepListID repListID, bool on)
int GetIndexFitTo(uint32 raceMask, uint32 classMask) const
Definition: DBCStructure.h:282
uint32 GetGUIDLow() const
Definition: Object.h:160
void SendForceReactions()
int32 GetBaseReputation(FactionEntry const *factionEntry) const
void apply(T *val)
Definition: ByteConverter.h:41
FactionState const * GetState(FactionEntry const *factionEntry) const
Definition: ReputationMgr.h:75
#define sObjectMgr
Definition: ObjectMgr.h:1285
void SetInactive(RepListID repListID, bool on)
#define MAX_REPUTATION_RANK
ForcedReactions _forcedReactions
size_t wpos() const
Definition: ByteBuffer.h:264
#define MIN_REPUTATION_RANK
ACE_UINT8 uint8
Definition: Define.h:73
int32 reputationListID
Definition: DBCStructure.h:264
void put(size_t pos, T value)
Definition: ByteBuffer.h:79
void SendDirectMessage(WorldPacket *data)
Definition: Player.cpp:5782
void SetVisible(FactionTemplateEntry const *factionTemplateEntry)
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
void SendVisible(FactionState const *faction) const
const char * GetName() const
Definition: Object.h:692
uint32 getClassMask() const
Definition: Unit.h:1040
static const int32 Reputation_Bottom
Definition: ReputationMgr.h:69
ACE_Refcounted_Auto_Ptr< QueryResult, ACE_Null_Mutex > QueryResult_AutoPtr
Definition: QueryResult.h:113
DBCStorage< FactionEntry > sFactionStore(FactionEntryfmt)
ReputationRank GetRank(FactionEntry const *factionEntry) const
uint32 getRaceMask() const
Definition: Unit.h:1038
WorldSession * GetSession() const
Definition: Player.h:1959
ReputationRank GetBaseRank(FactionEntry const *factionEntry) const
DatabaseType CharacterDatabase
Accessor to the character database.
Definition: Main.cpp:54
ACE_UINT32 uint32
Definition: Define.h:71
ReputationRank GetReputationRank(uint32 faction_id) const
Definition: Player.cpp:5922
bool SetOneFactionReputation(FactionEntry const *factionEntry, int32 standing, bool incremental)
Player * _player
bool SetReputation(FactionEntry const *factionEntry, int32 standing)
bool PlayerLoading() const
Definition: WorldSession.h:73
void LoadFromDB(QueryResult_AutoPtr result)
RepListID ReputationListID
Definition: ReputationMgr.h:43
uint32 ReputationFlags[4]
Definition: DBCStructure.h:268