/* * Copyright (C) 2005-2009 MaNGOS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ReputationMgr.h" #include "DBCStores.h" #include "Player.h" #include "WorldPacket.h" #include "World.h" const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000}; ReputationRank ReputationMgr::ReputationToRank(int32 standing) { int32 limit = Reputation_Cap + 1; for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i) { limit -= PointsInRank[i]; if (standing >= limit ) return ReputationRank(i); } return MIN_REPUTATION_RANK; } int32 ReputationMgr::GetReputation(uint32 faction_id) const { FactionEntry const *factionEntry = sFactionStore.LookupEntry(faction_id); if (!factionEntry) { sLog.outError("ReputationMgr::GetReputation: Can't get reputation of %s for unknown faction (faction id) #%u.",m_player->GetName(), faction_id); return 0; } return GetReputation(factionEntry); } int32 ReputationMgr::GetBaseReputation(FactionEntry const* factionEntry) const { if (!factionEntry) return 0; uint32 raceMask = m_player->getRaceMask(); uint32 classMask = m_player->getClassMask(); for (int i=0; i < 4; i++) { if( (factionEntry->BaseRepRaceMask[i] & raceMask) && (factionEntry->BaseRepClassMask[i]==0 || (factionEntry->BaseRepClassMask[i] & classMask) ) ) return factionEntry->BaseRepValue[i]; } // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i]==0 return 0; } int32 ReputationMgr::GetReputation(FactionEntry const* factionEntry) const { // Faction without recorded reputation. Just ignore. if(!factionEntry) return 0; if(FactionState const* state = GetState(factionEntry)) return GetBaseReputation(factionEntry) + state->Standing; return 0; } ReputationRank ReputationMgr::GetRank(FactionEntry const* factionEntry) const { int32 reputation = GetReputation(factionEntry); return ReputationToRank(reputation); } ReputationRank ReputationMgr::GetBaseRank(FactionEntry const* factionEntry) const { int32 reputation = GetBaseReputation(factionEntry); return ReputationToRank(reputation); } void ReputationMgr::ApplyForceReaction( uint32 faction_id,ReputationRank rank,bool apply ) { if(apply) m_forcedReactions[faction_id] = rank; else m_forcedReactions.erase(faction_id); } uint32 ReputationMgr::GetDefaultStateFlags(FactionEntry const* factionEntry) const { if (!factionEntry) return 0; uint32 raceMask = m_player->getRaceMask(); uint32 classMask = m_player->getClassMask(); for (int i=0; i < 4; i++) { if( (factionEntry->BaseRepRaceMask[i] & raceMask) && (factionEntry->BaseRepClassMask[i]==0 || (factionEntry->BaseRepClassMask[i] & classMask) ) ) return factionEntry->ReputationFlags[i]; } return 0; } void ReputationMgr::SendForceReactions() { WorldPacket data; data.Initialize(SMSG_SET_FORCED_REACTIONS, 4+m_forcedReactions.size()*(4+4)); data << uint32(m_forcedReactions.size()); for(ForcedReactions::const_iterator itr = m_forcedReactions.begin(); itr != m_forcedReactions.end(); ++itr) { data << uint32(itr->first); // faction_id (Faction.dbc) data << uint32(itr->second); // reputation rank } m_player->SendDirectMessage(&data); } void ReputationMgr::SendState(FactionState const* faction) const { if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it { WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0 data << (float) 0; // unk 2.4.0 data << (uint8) 0; // wotlk 8634 data << (uint32) 1; // count // for data << (uint32) faction->ReputationListID; data << (uint32) faction->Standing; // end for m_player->SendDirectMessage(&data); } } void ReputationMgr::SendInitialReputations() { WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4+128*5)); data << uint32 (0x00000080); RepListID a = 0; for (FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) { // fill in absent fields for (; a != itr->first; a++) { data << uint8 (0x00); data << uint32 (0x00000000); } // fill in encountered data data << uint8 (itr->second.Flags); data << uint32 (itr->second.Standing); ++a; } // fill in absent fields for (; a != 128; a++) { data << uint8 (0x00); data << uint32 (0x00000000); } m_player->SendDirectMessage(&data); } void ReputationMgr::SendStates() const { for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) SendState(&(itr->second)); } void ReputationMgr::SendVisible(FactionState const* faction) const { if(m_player->GetSession()->PlayerLoading()) return; // make faction visible in reputation list at client WorldPacket data(SMSG_SET_FACTION_VISIBLE, 4); data << faction->ReputationListID; m_player->SendDirectMessage(&data); } void ReputationMgr::Initilize() { m_factions.clear(); m_visibleFactionCount = 0; m_honoredFactionCount = 0; m_reveredFactionCount = 0; m_exaltedFactionCount = 0; for(unsigned int i = 1; i < sFactionStore.GetNumRows(); i++) { FactionEntry const *factionEntry = sFactionStore.LookupEntry(i); if( factionEntry && (factionEntry->reputationListID >= 0)) { FactionState newFaction; newFaction.ID = factionEntry->ID; newFaction.ReputationListID = factionEntry->reputationListID; newFaction.Standing = 0; newFaction.Flags = GetDefaultStateFlags(factionEntry); newFaction.Changed = true; if( newFaction.Flags & FACTION_FLAG_VISIBLE ) ++m_visibleFactionCount; UpdateRankCounters(REP_HOSTILE,GetBaseRank(factionEntry)); m_factions[newFaction.ReputationListID] = newFaction; } } } bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental) { SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID); if (flist) { bool res = false; for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr) { FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr); if(factionEntryCalc) res = SetOneFactionReputation(factionEntryCalc, standing, incremental); } return res; } else return SetOneFactionReputation(factionEntry, standing, incremental); } bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental) { FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); if (itr != m_factions.end()) { int32 BaseRep = GetBaseReputation(factionEntry); if(incremental) { // int32 *= float cause one point loss? standing = floor( (float)standing * sWorld.getRate(RATE_REPUTATION_GAIN) + 0.5 ); standing += itr->second.Standing + BaseRep; } if (standing > Reputation_Cap) standing = Reputation_Cap; else if (standing < Reputation_Bottom) standing = Reputation_Bottom; ReputationRank old_rank = ReputationToRank(itr->second.Standing + BaseRep); ReputationRank new_rank = ReputationToRank(standing); itr->second.Standing = standing - BaseRep; itr->second.Changed = true; SetVisible(&itr->second); if(new_rank <= REP_HOSTILE) SetAtWar(&itr->second,true); SendState(&itr->second); UpdateRankCounters(old_rank, new_rank); m_player->ReputationChanged(factionEntry); m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS, factionEntry->ID); m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID); m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID); m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION,factionEntry->ID); m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION,factionEntry->ID); return true; } return false; } void ReputationMgr::SetVisible(FactionTemplateEntry const*factionTemplateEntry) { if(!factionTemplateEntry->faction) return; if(FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction)) SetVisible(factionEntry); } void ReputationMgr::SetVisible(FactionEntry const *factionEntry) { if(factionEntry->reputationListID < 0) return; FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); if (itr == m_factions.end()) return; SetVisible(&itr->second); } void ReputationMgr::SetVisible(FactionState* faction) { // always invisible or hidden faction can't be make visible if(faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) return; // already set if(faction->Flags & FACTION_FLAG_VISIBLE) return; faction->Flags |= FACTION_FLAG_VISIBLE; faction->Changed = true; ++m_visibleFactionCount; SendVisible(faction); } void ReputationMgr::SetAtWar( RepListID repListID, bool on ) { FactionStateList::iterator itr = m_factions.find(repListID); if (itr == m_factions.end()) return; // always invisible or hidden faction can't change war state if(itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN) ) return; SetAtWar(&itr->second,on); } void ReputationMgr::SetAtWar(FactionState* faction, bool atWar) { // not allow declare war to own faction if(atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) ) return; // already set if(((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar) return; if( atWar ) faction->Flags |= FACTION_FLAG_AT_WAR; else faction->Flags &= ~FACTION_FLAG_AT_WAR; faction->Changed = true; } void ReputationMgr::SetInactive( RepListID repListID, bool on ) { FactionStateList::iterator itr = m_factions.find(repListID); if (itr == m_factions.end()) return; SetInactive(&itr->second,on); } void ReputationMgr::SetInactive(FactionState* faction, bool inactive) { // always invisible or hidden faction can't be inactive if(inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE) ) ) return; // already set if(((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive) return; if(inactive) faction->Flags |= FACTION_FLAG_INACTIVE; else faction->Flags &= ~FACTION_FLAG_INACTIVE; faction->Changed = true; } void ReputationMgr::LoadFromDB(QueryResult *result) { // Set initial reputations (so everything is nifty before DB data load) Initilize(); //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow()); if(result) { do { Field *fields = result->Fetch(); FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32()); if( factionEntry && (factionEntry->reputationListID >= 0)) { FactionState* faction = &m_factions[factionEntry->reputationListID]; // update standing to current faction->Standing = int32(fields[1].GetUInt32()); // update counters int32 BaseRep = GetBaseReputation(factionEntry); ReputationRank old_rank = ReputationToRank(BaseRep); ReputationRank new_rank = ReputationToRank(BaseRep + faction->Standing); UpdateRankCounters(old_rank,new_rank); uint32 dbFactionFlags = fields[2].GetUInt32(); if( dbFactionFlags & FACTION_FLAG_VISIBLE ) SetVisible(faction); // have internal checks for forced invisibility if( dbFactionFlags & FACTION_FLAG_INACTIVE) SetInactive(faction,true); // have internal checks for visibility requirement if( dbFactionFlags & FACTION_FLAG_AT_WAR ) // DB at war SetAtWar(faction,true); // have internal checks for FACTION_FLAG_PEACE_FORCED else // DB not at war { // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN) if( faction->Flags & FACTION_FLAG_VISIBLE ) SetAtWar(faction,false); // have internal checks for FACTION_FLAG_PEACE_FORCED } // set atWar for hostile if(GetRank(factionEntry) <= REP_HOSTILE) SetAtWar(faction,true); // reset changed flag if values similar to saved in DB if(faction->Flags==dbFactionFlags) faction->Changed = false; } } while( result->NextRow() ); delete result; } } void ReputationMgr::SaveToDB() { for(FactionStateList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) { if (itr->second.Changed) { CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", m_player->GetGUIDLow(), itr->second.ID); 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); itr->second.Changed = false; } } } void ReputationMgr::UpdateRankCounters( ReputationRank old_rank, ReputationRank new_rank ) { if(old_rank >= REP_EXALTED) --m_exaltedFactionCount; if(old_rank >= REP_REVERED) --m_reveredFactionCount; if(old_rank >= REP_HONORED) --m_honoredFactionCount; if(new_rank >= REP_EXALTED) ++m_exaltedFactionCount; if(new_rank >= REP_REVERED) ++m_reveredFactionCount; if(new_rank >= REP_HONORED) ++m_honoredFactionCount; }