diff options
Diffstat (limited to 'src/game/ReputationMgr.cpp')
| -rw-r--r-- | src/game/ReputationMgr.cpp | 473 | 
1 files changed, 473 insertions, 0 deletions
diff --git a/src/game/ReputationMgr.cpp b/src/game/ReputationMgr.cpp new file mode 100644 index 00000000000..62b9504daff --- /dev/null +++ b/src/game/ReputationMgr.cpp @@ -0,0 +1,473 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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" + +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) +            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; +}
\ No newline at end of file  | 
