[8483] Implement glyph 43361.
[getmangos.git] / src / game / ReputationMgr.cpp
blobfe72d55441e39043b7e7d8e8df50198232df4e94
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "ReputationMgr.h"
20 #include "DBCStores.h"
21 #include "Player.h"
22 #include "WorldPacket.h"
24 const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000};
26 ReputationRank ReputationMgr::ReputationToRank(int32 standing)
28 int32 limit = Reputation_Cap + 1;
29 for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i)
31 limit -= PointsInRank[i];
32 if (standing >= limit )
33 return ReputationRank(i);
35 return MIN_REPUTATION_RANK;
38 int32 ReputationMgr::GetReputation(uint32 faction_id) const
40 FactionEntry const *factionEntry = sFactionStore.LookupEntry(faction_id);
42 if (!factionEntry)
44 sLog.outError("ReputationMgr::GetReputation: Can't get reputation of %s for unknown faction (faction id) #%u.",m_player->GetName(), faction_id);
45 return 0;
48 return GetReputation(factionEntry);
51 int32 ReputationMgr::GetBaseReputation(FactionEntry const* factionEntry) const
53 if (!factionEntry)
54 return 0;
56 uint32 raceMask = m_player->getRaceMask();
57 uint32 classMask = m_player->getClassMask();
58 for (int i=0; i < 4; i++)
60 if( (factionEntry->BaseRepRaceMask[i] & raceMask) &&
61 (factionEntry->BaseRepClassMask[i]==0 ||
62 (factionEntry->BaseRepClassMask[i] & classMask) ) )
63 return factionEntry->BaseRepValue[i];
66 // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i]==0
67 return 0;
70 int32 ReputationMgr::GetReputation(FactionEntry const* factionEntry) const
72 // Faction without recorded reputation. Just ignore.
73 if(!factionEntry)
74 return 0;
76 if(FactionState const* state = GetState(factionEntry))
77 return GetBaseReputation(factionEntry) + state->Standing;
79 return 0;
82 ReputationRank ReputationMgr::GetRank(FactionEntry const* factionEntry) const
84 int32 reputation = GetReputation(factionEntry);
85 return ReputationToRank(reputation);
88 ReputationRank ReputationMgr::GetBaseRank(FactionEntry const* factionEntry) const
90 int32 reputation = GetBaseReputation(factionEntry);
91 return ReputationToRank(reputation);
94 void ReputationMgr::ApplyForceReaction( uint32 faction_id,ReputationRank rank,bool apply )
96 if(apply)
97 m_forcedReactions[faction_id] = rank;
98 else
99 m_forcedReactions.erase(faction_id);
102 uint32 ReputationMgr::GetDefaultStateFlags(FactionEntry const* factionEntry) const
104 if (!factionEntry)
105 return 0;
107 uint32 raceMask = m_player->getRaceMask();
108 uint32 classMask = m_player->getClassMask();
109 for (int i=0; i < 4; i++)
111 if( (factionEntry->BaseRepRaceMask[i] & raceMask) &&
112 (factionEntry->BaseRepClassMask[i]==0 ||
113 (factionEntry->BaseRepClassMask[i] & classMask) ) )
114 return factionEntry->ReputationFlags[i];
116 return 0;
119 void ReputationMgr::SendForceReactions()
121 WorldPacket data;
122 data.Initialize(SMSG_SET_FORCED_REACTIONS, 4+m_forcedReactions.size()*(4+4));
123 data << uint32(m_forcedReactions.size());
124 for(ForcedReactions::const_iterator itr = m_forcedReactions.begin(); itr != m_forcedReactions.end(); ++itr)
126 data << uint32(itr->first); // faction_id (Faction.dbc)
127 data << uint32(itr->second); // reputation rank
129 m_player->SendDirectMessage(&data);
132 void ReputationMgr::SendState(FactionState const* faction) const
134 if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it
136 WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0
137 data << (float) 0; // unk 2.4.0
138 data << (uint8) 0; // wotlk 8634
139 data << (uint32) 1; // count
140 // for
141 data << (uint32) faction->ReputationListID;
142 data << (uint32) faction->Standing;
143 // end for
144 m_player->SendDirectMessage(&data);
148 void ReputationMgr::SendInitialReputations()
150 WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4+128*5));
151 data << uint32 (0x00000080);
153 RepListID a = 0;
155 for (FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
157 // fill in absent fields
158 for (; a != itr->first; a++)
160 data << uint8 (0x00);
161 data << uint32 (0x00000000);
164 // fill in encountered data
165 data << uint8 (itr->second.Flags);
166 data << uint32 (itr->second.Standing);
168 ++a;
171 // fill in absent fields
172 for (; a != 128; a++)
174 data << uint8 (0x00);
175 data << uint32 (0x00000000);
178 m_player->SendDirectMessage(&data);
181 void ReputationMgr::SendStates() const
183 for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
184 SendState(&(itr->second));
187 void ReputationMgr::SendVisible(FactionState const* faction) const
189 if(m_player->GetSession()->PlayerLoading())
190 return;
192 // make faction visible in reputation list at client
193 WorldPacket data(SMSG_SET_FACTION_VISIBLE, 4);
194 data << faction->ReputationListID;
195 m_player->SendDirectMessage(&data);
198 void ReputationMgr::Initilize()
200 m_factions.clear();
201 m_visibleFactionCount = 0;
202 m_honoredFactionCount = 0;
203 m_reveredFactionCount = 0;
204 m_exaltedFactionCount = 0;
206 for(unsigned int i = 1; i < sFactionStore.GetNumRows(); i++)
208 FactionEntry const *factionEntry = sFactionStore.LookupEntry(i);
210 if( factionEntry && (factionEntry->reputationListID >= 0))
212 FactionState newFaction;
213 newFaction.ID = factionEntry->ID;
214 newFaction.ReputationListID = factionEntry->reputationListID;
215 newFaction.Standing = 0;
216 newFaction.Flags = GetDefaultStateFlags(factionEntry);
217 newFaction.Changed = true;
219 if( newFaction.Flags & FACTION_FLAG_VISIBLE )
220 ++m_visibleFactionCount;
222 UpdateRankCounters(REP_HOSTILE,GetBaseRank(factionEntry));
224 m_factions[newFaction.ReputationListID] = newFaction;
229 bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
231 SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID);
232 if (flist)
234 bool res = false;
235 for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr)
237 FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr);
238 if(factionEntryCalc)
239 res = SetOneFactionReputation(factionEntryCalc, standing, incremental);
241 return res;
243 else
244 return SetOneFactionReputation(factionEntry, standing, incremental);
247 bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
249 FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
250 if (itr != m_factions.end())
252 int32 BaseRep = GetBaseReputation(factionEntry);
254 if(incremental)
255 standing += itr->second.Standing + BaseRep;
257 if (standing > Reputation_Cap)
258 standing = Reputation_Cap;
259 else if (standing < Reputation_Bottom)
260 standing = Reputation_Bottom;
262 ReputationRank old_rank = ReputationToRank(itr->second.Standing + BaseRep);
263 ReputationRank new_rank = ReputationToRank(standing);
265 itr->second.Standing = standing - BaseRep;
266 itr->second.Changed = true;
268 SetVisible(&itr->second);
270 if(new_rank <= REP_HOSTILE)
271 SetAtWar(&itr->second,true);
273 SendState(&itr->second);
275 UpdateRankCounters(old_rank, new_rank);
277 m_player->ReputationChanged(factionEntry);
278 m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS, factionEntry->ID);
279 m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID);
280 m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID);
281 m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION,factionEntry->ID);
282 m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION,factionEntry->ID);
284 return true;
286 return false;
289 void ReputationMgr::SetVisible(FactionTemplateEntry const*factionTemplateEntry)
291 if(!factionTemplateEntry->faction)
292 return;
294 if(FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction))
295 SetVisible(factionEntry);
298 void ReputationMgr::SetVisible(FactionEntry const *factionEntry)
300 if(factionEntry->reputationListID < 0)
301 return;
303 FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
304 if (itr == m_factions.end())
305 return;
307 SetVisible(&itr->second);
310 void ReputationMgr::SetVisible(FactionState* faction)
312 // always invisible or hidden faction can't be make visible
313 if(faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN))
314 return;
316 // already set
317 if(faction->Flags & FACTION_FLAG_VISIBLE)
318 return;
320 faction->Flags |= FACTION_FLAG_VISIBLE;
321 faction->Changed = true;
323 ++m_visibleFactionCount;
325 SendVisible(faction);
328 void ReputationMgr::SetAtWar( RepListID repListID, bool on )
330 FactionStateList::iterator itr = m_factions.find(repListID);
331 if (itr == m_factions.end())
332 return;
334 // always invisible or hidden faction can't change war state
335 if(itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN) )
336 return;
338 SetAtWar(&itr->second,on);
341 void ReputationMgr::SetAtWar(FactionState* faction, bool atWar)
343 // not allow declare war to own faction
344 if(atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) )
345 return;
347 // already set
348 if(((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar)
349 return;
351 if( atWar )
352 faction->Flags |= FACTION_FLAG_AT_WAR;
353 else
354 faction->Flags &= ~FACTION_FLAG_AT_WAR;
356 faction->Changed = true;
359 void ReputationMgr::SetInactive( RepListID repListID, bool on )
361 FactionStateList::iterator itr = m_factions.find(repListID);
362 if (itr == m_factions.end())
363 return;
365 SetInactive(&itr->second,on);
368 void ReputationMgr::SetInactive(FactionState* faction, bool inactive)
370 // always invisible or hidden faction can't be inactive
371 if(inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE) ) )
372 return;
374 // already set
375 if(((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive)
376 return;
378 if(inactive)
379 faction->Flags |= FACTION_FLAG_INACTIVE;
380 else
381 faction->Flags &= ~FACTION_FLAG_INACTIVE;
383 faction->Changed = true;
386 void ReputationMgr::LoadFromDB(QueryResult *result)
388 // Set initial reputations (so everything is nifty before DB data load)
389 Initilize();
391 //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow());
393 if(result)
397 Field *fields = result->Fetch();
399 FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32());
400 if( factionEntry && (factionEntry->reputationListID >= 0))
402 FactionState* faction = &m_factions[factionEntry->reputationListID];
404 // update standing to current
405 faction->Standing = int32(fields[1].GetUInt32());
407 // update counters
408 int32 BaseRep = GetBaseReputation(factionEntry);
409 ReputationRank old_rank = ReputationToRank(BaseRep);
410 ReputationRank new_rank = ReputationToRank(BaseRep + faction->Standing);
411 UpdateRankCounters(old_rank,new_rank);
413 uint32 dbFactionFlags = fields[2].GetUInt32();
415 if( dbFactionFlags & FACTION_FLAG_VISIBLE )
416 SetVisible(faction); // have internal checks for forced invisibility
418 if( dbFactionFlags & FACTION_FLAG_INACTIVE)
419 SetInactive(faction,true); // have internal checks for visibility requirement
421 if( dbFactionFlags & FACTION_FLAG_AT_WAR ) // DB at war
422 SetAtWar(faction,true); // have internal checks for FACTION_FLAG_PEACE_FORCED
423 else // DB not at war
425 // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN)
426 if( faction->Flags & FACTION_FLAG_VISIBLE )
427 SetAtWar(faction,false); // have internal checks for FACTION_FLAG_PEACE_FORCED
430 // set atWar for hostile
431 if(GetRank(factionEntry) <= REP_HOSTILE)
432 SetAtWar(faction,true);
434 // reset changed flag if values similar to saved in DB
435 if(faction->Flags==dbFactionFlags)
436 faction->Changed = false;
439 while( result->NextRow() );
441 delete result;
445 void ReputationMgr::SaveToDB()
447 for(FactionStateList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
449 if (itr->second.Changed)
451 CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", m_player->GetGUIDLow(), itr->second.ID);
452 CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", m_player->GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags);
453 itr->second.Changed = false;
458 void ReputationMgr::UpdateRankCounters( ReputationRank old_rank, ReputationRank new_rank )
460 if(old_rank >= REP_EXALTED)
461 --m_exaltedFactionCount;
462 if(old_rank >= REP_REVERED)
463 --m_reveredFactionCount;
464 if(old_rank >= REP_HONORED)
465 --m_honoredFactionCount;
467 if(new_rank >= REP_EXALTED)
468 ++m_exaltedFactionCount;
469 if(new_rank >= REP_REVERED)
470 ++m_reveredFactionCount;
471 if(new_rank >= REP_HONORED)
472 ++m_honoredFactionCount;