/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * 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 3 of the License, or * 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, see . * */ #include "StdAfx.h" static int32 STANDING_TO_RANK[8] = {-36000, -6000, -3000, 3000, 6000, 12000, 21000, 1000}; //static uint32 INITIALIZE_FACTIONS[128] = { 21, 92, 93, 59, 349, 70, 369, 471, 470, 169, 469, 67, 529, 76, 530, 81, 68, 54, 72, 47, 69, 86, 83, 549, 551, 550, 589, 577, 46, 289, 570, 571, 569, 574, 576, 609, 947, 946, 935, 730, 729, 749, 980, 809, 890, 889, 891, 892, 930, 909, 270, 510, 509, 910, 911, 922, 990, 932, 936, 933, 941, 934, 967, 942, 970, 978, 989, 1005, 1011, 1012, 1015, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define FACTION_FLAG_AT_WAR 2 #define FACTION_FLAG_VISIBLE 1 Standing Player::GetReputationRankFromStanding(int32 Standing_) { uint32 i = 0; for(; i < 8; ) { if(Standing_ > STANDING_TO_RANK[i]) { ++i; } else { return Standing(i); } } return STANDING_EXALTED; } inline void SetFlagAtWar(uint8 & flag) { if(flag & FACTION_FLAG_AT_WAR) return; flag |= FACTION_FLAG_AT_WAR; } inline void UnsetFlagAtWar(uint8 & flag) { if(!(flag & FACTION_FLAG_AT_WAR)) return; flag &= ~FACTION_FLAG_AT_WAR; } inline void SetFlagVisible(uint8 & flag) { if(flag & FACTION_FLAG_VISIBLE) return; flag |= FACTION_FLAG_VISIBLE; } inline void UnsetFlagVisible(uint8 & flag) { if(!(flag & FACTION_FLAG_VISIBLE)) return; flag &= ~FACTION_FLAG_VISIBLE; } inline bool AtWar(uint8 flag) { return flag & FACTION_FLAG_AT_WAR; } inline bool Visible(uint8 flag) { return flag & FACTION_FLAG_VISIBLE; } inline bool RankChanged(int32 Standing, int32 Change) { if(Player::GetReputationRankFromStanding(Standing) != Player::GetReputationRankFromStanding(Standing + Change)) return true; else return false; } inline bool RankChangedFlat(int32 Standing, int32 NewStanding) { if(Player::GetReputationRankFromStanding(Standing) != Player::GetReputationRankFromStanding(NewStanding)) return true; else return false; } void Player::smsg_InitialFactions() { WorldPacket data(SMSG_INITIALIZE_FACTIONS, 644); data << uint32(128); FactionReputation * rep; for(uint32 i = 0; i < 128; ++i) { rep = reputationByListId[i]; if(rep) { /*if(rep->flag & 2 && rep->standing >= 0) { printf("listid %u\n", i); }*/ data << rep->flag << rep->CalcStanding(); } else data << uint8(0) << uint32(0); } m_session->SendPacket(&data); } void Player::_InitialReputation() { // Generate Initial Reputation Values FactionReputation * rep; FactionDBC * f; int32 BaseRep = 0; uint32 j; uint32 RaceMask = getRaceMask(); for(uint32 i = 0; i < sFactionStore.GetNumRows(); ++i) { f = static_cast*>(FactionStore::getSingletonPtr())->LookupRow(i); if(f == 0) continue; // Get Base Reputation for(j = 0; j < 4; ++j) { if(f->baseRepMask[j] & RaceMask) { BaseRep = f->baseRepValue[j]; break; } } if(j != 4 && f->RepListId >= 0) { // This is one we can add. rep = new FactionReputation; rep->standing = BaseRep; rep->flag = 0; rep->baseStanding = BaseRep; if(GetReputationRankFromStanding(BaseRep) <= STANDING_HOSTILE) SetFlagAtWar(rep->flag); // Visible-ness shit. if((f->parentFaction == 469 && GetTeam() == 0) || // Alliance own faction. (f->parentFaction == 67 && GetTeam() == 1) ) // Horde own faction. { SetFlagVisible(rep->flag); } reputationByListId[f->RepListId] = rep; } else { // No default standing. continue; } m_reputation[f->ID] = rep; } } int32 Player::GetStanding(uint32 Faction) { ReputationMap::iterator itr = m_reputation.find(Faction); if(itr == m_reputation.end()) return 0; else return itr->second->standing; } int32 Player::GetBaseStanding(uint32 Faction) { ReputationMap::iterator itr = m_reputation.find(Faction); if(itr == m_reputation.end()) return 0; else return itr->second->baseStanding; } void Player::SetStanding(uint32 Faction, int32 Value) { ReputationMap::iterator itr = m_reputation.find(Faction); FactionDBC * dbc = sFactionStore.LookupEntry(Faction); if(dbc == 0) return; if(itr == m_reputation.end()) { // New faction! FactionReputation * rep = new FactionReputation; rep->flag = 0; rep->standing = Value; rep->baseStanding = 0; m_reputation[dbc->ID] = rep; if(dbc->RepListId >= 0) reputationByListId[dbc->RepListId] = rep; } else { // Increment it. if(RankChangedFlat(itr->second->standing, Value)) { itr->second->standing = Value; UpdateInrangeSetsBasedOnReputation(); } else { itr->second->standing = Value; } // Set visible if invisible. if(!Visible(itr->second->flag)) { SetFlagVisible(itr->second->flag); if(IsInWorld()) m_session->OutPacket(SMSG_SET_FACTION_VISIBLE, 4, &dbc->RepListId); } // Set at war if we're beyond hostile. Standing rank = GetReputationRankFromStanding(itr->second->standing); if(rank <= STANDING_HOSTILE && !AtWar(itr->second->flag)) SetFlagAtWar(itr->second->flag); else if(rank >= STANDING_NEUTRAL && AtWar(itr->second->flag)) UnsetFlagAtWar(itr->second->flag); if(IsInWorld()) { WorldPacket data(SMSG_SET_FACTION_STANDING, 12); data << uint32(itr->second->flag) << dbc->RepListId << itr->second->CalcStanding(); m_session->SendPacket(&data); } } } Standing Player::GetStandingRank(uint32 Faction) { return Standing(GetReputationRankFromStanding(GetStanding(Faction))); } bool Player::IsHostileBasedOnReputation(FactionDBC * dbc) { assert(dbc->RepListId < 128 && dbc->RepListId >= 0); FactionReputation * rep = reputationByListId[dbc->RepListId]; if(!rep) return false; if(rep->flag & FACTION_FLAG_AT_WAR || GetReputationRankFromStanding(rep->standing) <= STANDING_HOSTILE) return true; else return false; /*map::iterator itr = m_reputation.find(Faction); if(itr == m_reputation.end()) return false; if(itr->second.flag & FACTION_FLAG_AT_WAR || GetReputationRankFromStanding(itr->second.standing) <= STANDING_HOSTILE) return true; else return false;*/ } void Player::ModStanding(uint32 Faction, int32 Value) { ReputationMap::iterator itr = m_reputation.find(Faction); FactionDBC * dbc = sFactionStore.LookupEntry(Faction); if(dbc == 0) return; if(itr == m_reputation.end()) { // New faction! FactionReputation * rep = new FactionReputation; rep->flag = 0; rep->standing = Value; rep->baseStanding = 0; m_reputation[dbc->ID] = rep; if(dbc->RepListId >= 0) reputationByListId[dbc->RepListId] = rep; } else { // Bonus if(pctReputationMod > 0) { float d = float(float(pctReputationMod) / 100.0f); Value += FL2UINT( float( float(Value) * d ) ); } // Increment it. if(RankChanged(itr->second->standing, Value)) { itr->second->standing += Value; UpdateInrangeSetsBasedOnReputation(); } else { itr->second->standing += Value; } // Set visible if invisible. if(!Visible(itr->second->flag)) { SetFlagVisible(itr->second->flag); if(IsInWorld()) m_session->OutPacket(SMSG_SET_FACTION_VISIBLE, 4, &dbc->RepListId); } // Set at war if we're beyond hostile. if(GetReputationRankFromStanding(itr->second->standing) <= STANDING_HOSTILE && !AtWar(itr->second->flag)) SetFlagAtWar(itr->second->flag); if(IsInWorld() && Visible(itr->second->flag)) { WorldPacket data(SMSG_SET_FACTION_STANDING, 12); data << uint32(1) << dbc->RepListId << itr->second->CalcStanding(); m_session->SendPacket(&data); } } } void Player::SetAtWar(uint32 Faction, bool Set) { FactionReputation * rep = reputationByListId[Faction]; if(Faction > 128 || !rep) return; if(GetReputationRankFromStanding(rep->standing) <= STANDING_HOSTILE && !Set) // At this point we have to be at war. return; if(Set) { if(!AtWar(rep->flag)) SetFlagAtWar(rep->flag); UpdateInrangeSetsBasedOnReputation(); } else { if(AtWar(rep->flag)) UnsetFlagAtWar(rep->flag); UpdateInrangeSetsBasedOnReputation(); } } void WorldSession::HandleSetAtWarOpcode(WorldPacket& recv_data) { uint32 id; uint8 state; recv_data >> id >> state; /*uint32 faction_id = (id >= 128) ? 0 : INITIALIZE_FACTIONS[id]; if(faction_id == 0) return; if(state & FACTION_FLAG_AT_WAR) _player->SetAtWar(faction_id, true); else _player->SetAtWar(faction_id, false);*/ if(state == 1) _player->SetAtWar(id, true); else _player->SetAtWar(id, false); } void Player::UpdateInrangeSetsBasedOnReputation() { // This function assumes that the opp faction set for player = the opp faction set for the unit. InRangeSet::iterator itr; Unit * pUnit; bool rep_value; bool enemy_current; for(itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr) { if((*itr)->GetTypeId() != TYPEID_UNIT) continue; pUnit = ((Unit*)*itr); if(pUnit->m_factionDBC->RepListId < 0) continue; rep_value = IsHostileBasedOnReputation(pUnit->m_factionDBC); enemy_current = IsInRangeOppFactSet(pUnit); if(rep_value && !enemy_current) // We are now enemies. m_oppFactsInRange.insert(pUnit); else if(!rep_value && enemy_current) m_oppFactsInRange.erase(pUnit); } } void Player::Reputation_OnKilledUnit(Unit * pUnit, bool InnerLoop) { // add rep for on kill if(pUnit->GetTypeId() != TYPEID_UNIT || pUnit->IsPet()) return; if(!InnerLoop && m_Group) { /* loop the rep for group members */ m_Group->getLock().Acquire(); GroupMembersSet::iterator it; for(uint32 i = 0; i < m_Group->GetSubGroupCount(); ++i) { for(it = m_Group->GetSubGroup(i)->GetGroupMembersBegin(); it != m_Group->GetSubGroup(i)->GetGroupMembersEnd(); ++it) { if(it->player) it->player->Reputation_OnKilledUnit(pUnit, true); } } m_Group->getLock().Release(); return; } int team = GetTeam(); ReputationModifier * modifier = objmgr.GetReputationModifier(pUnit->GetEntry(), pUnit->m_factionDBC->ID); if(modifier != 0) { // Apply this data. for(vector::iterator itr = modifier->mods.begin(); itr != modifier->mods.end(); ++itr) { if(!(*itr).faction[team]) continue; /* rep limit? */ if((*itr).replimit) { if(GetStanding((*itr).faction[team]) >= (int32)(*itr).replimit) continue; } int32 value = int32(float(itr->value) * sWorld.getRate(RATE_KILLREPUTATION)); //value *= sWorld.getRate(RATE_KILLREPUTATION); ModStanding(itr->faction[team], value); } } else { if(IS_INSTANCE(GetMapId()) && objmgr.HandleInstanceReputationModifiers(this, pUnit)) return; if(pUnit->m_factionDBC->RepListId < 0) return; // decrease rep by 5. int change = -5; change = int32((float(change) * sWorld.getRate(RATE_KILLREPUTATION))); ModStanding(pUnit->m_factionDBC->ID, change); } } void Player::Reputation_OnTalk(FactionDBC * dbc) { // set faction visible if not visible if(!dbc || dbc->RepListId < 0) return; FactionReputation * rep = reputationByListId[dbc->RepListId]; if(!rep) return; if(!Visible(rep->flag)) { SetFlagVisible(rep->flag); if(IsInWorld()) m_session->OutPacket(SMSG_SET_FACTION_VISIBLE, 4, &dbc->RepListId); } }