diff options
Diffstat (limited to 'src/server/game/Maps/PhaseMgr.cpp')
-rw-r--r-- | src/server/game/Maps/PhaseMgr.cpp | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/server/game/Maps/PhaseMgr.cpp b/src/server/game/Maps/PhaseMgr.cpp new file mode 100644 index 00000000000..63bdff2d094 --- /dev/null +++ b/src/server/game/Maps/PhaseMgr.cpp @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "PhaseMgr.h" +#include "Chat.h" + +////////////////////////////////////////////////////////////////// +// Updating + +PhaseMgr::PhaseMgr(Player* _player) : player(_player), phaseData(_player), _UpdateFlags(0) +{ + _PhaseDefinitionStore = sObjectMgr->GetPhaseDefinitionStore(); + _SpellPhaseStore = sObjectMgr->GetSpellPhaseStore(); +} + +void PhaseMgr::Update() +{ + if (IsUpdateInProgress()) + return; + + if (_UpdateFlags & PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED) + phaseData.SendPhaseshiftToPlayer(); + + if (_UpdateFlags & PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED) + phaseData.SendPhaseMaskToPlayer(); + + _UpdateFlags = 0; +} + +void PhaseMgr::RemoveUpdateFlag(PhaseUpdateFlag updateFlag) +{ + _UpdateFlags &= ~updateFlag; + + if (updateFlag == PHASE_UPDATE_FLAG_ZONE_UPDATE) + { + // Update zone changes + if (phaseData.HasActiveDefinitions()) + { + phaseData.ResetDefinitions(); + _UpdateFlags |= (PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED | PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED); + } + + if (_PhaseDefinitionStore->find(player->GetZoneId()) != _PhaseDefinitionStore->end()) + Recalculate(); + } + + Update(); +} + +///////////////////////////////////////////////////////////////// +// Notifier + +void PhaseMgr::NotifyConditionChanged(PhaseUpdateData const& updateData) +{ + if (NeedsPhaseUpdateWithData(updateData)) + { + Recalculate(); + Update(); + } +} + +////////////////////////////////////////////////////////////////// +// Phasing Definitions + +void PhaseMgr::Recalculate() +{ + if (phaseData.HasActiveDefinitions()) + { + phaseData.ResetDefinitions(); + _UpdateFlags |= (PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED | PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED); + } + + PhaseDefinitionStore::const_iterator itr = _PhaseDefinitionStore->find(player->GetZoneId()); + if (itr != _PhaseDefinitionStore->end()) + for (PhaseDefinitionContainer::const_iterator phase = itr->second.begin(); phase != itr->second.end(); ++phase) + if (CheckDefinition(&(*phase))) + { + phaseData.AddPhaseDefinition(&(*phase)); + + if (phase->phasemask) + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + + if (phase->phaseId || phase->terrainswapmap) + _UpdateFlags |= PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED; + + if (phase->IsLastDefinition()) + break; + } +} + +inline bool PhaseMgr::CheckDefinition(PhaseDefinition const* phaseDefinition) +{ + return sConditionMgr->IsObjectMeetToConditions(player, sConditionMgr->GetConditionsForPhaseDefinition(phaseDefinition->zoneId, phaseDefinition->entry)); +} + +bool PhaseMgr::NeedsPhaseUpdateWithData(PhaseUpdateData const updateData) const +{ + PhaseDefinitionStore::const_iterator itr = _PhaseDefinitionStore->find(player->GetZoneId()); + if (itr != _PhaseDefinitionStore->end()) + { + for (PhaseDefinitionContainer::const_iterator phase = itr->second.begin(); phase != itr->second.end(); ++phase) + { + ConditionList conditionList = sConditionMgr->GetConditionsForPhaseDefinition(phase->zoneId, phase->entry); + for (ConditionList::const_iterator condition = conditionList.begin(); condition != conditionList.end(); ++condition) + if (updateData.IsConditionRelated(*condition)) + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////// +// Auras + +void PhaseMgr::RegisterPhasingAuraEffect(AuraEffect const* auraEffect) +{ + PhaseInfo phaseInfo; + + if (auraEffect->GetMiscValue()) + { + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + phaseInfo.phasemask = auraEffect->GetMiscValue(); + } + else + { + SpellPhaseStore::const_iterator itr = _SpellPhaseStore->find(auraEffect->GetId()); + if (itr != _SpellPhaseStore->end()) + { + if (itr->second.phasemask) + { + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + phaseInfo.phasemask = itr->second.phasemask; + } + + if (itr->second.terrainswapmap) + phaseInfo.terrainswapmap = itr->second.terrainswapmap; + } + } + + phaseInfo.phaseId = auraEffect->GetMiscValueB(); + + if (phaseInfo.NeedsClientSideUpdate()) + _UpdateFlags |= PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED; + + phaseData.AddAuraInfo(auraEffect->GetId(), phaseInfo); + + Update(); +} + +void PhaseMgr::UnRegisterPhasingAuraEffect(AuraEffect const* auraEffect) +{ + _UpdateFlags |= phaseData.RemoveAuraInfo(auraEffect->GetId()); + + Update(); +} + +////////////////////////////////////////////////////////////////// +// Commands + +void PhaseMgr::SendDebugReportToPlayer(Player* const debugger) +{ + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_REPORT_STATUS, player->GetName(), player->GetZoneId(), player->getLevel(), player->GetTeamId(), _UpdateFlags); + + PhaseDefinitionStore::const_iterator itr = _PhaseDefinitionStore->find(player->GetZoneId()); + if (itr == _PhaseDefinitionStore->end()) + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_NO_DEFINITIONS, player->GetZoneId()); + else + { + for (PhaseDefinitionContainer::const_iterator phase = itr->second.begin(); phase != itr->second.end(); ++phase) + { + if (CheckDefinition(&(*phase))) + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_SUCCESS, phase->entry, phase->IsNegatingPhasemask() ? "negated Phase" : "Phase", phase->phasemask); + else + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_FAILED, phase->phasemask, phase->entry, phase->zoneId); + + if (phase->IsLastDefinition()) + { + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_LAST_PHASE, phase->phasemask, phase->entry, phase->zoneId); + break; + } + } + } + + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_LIST, phaseData._PhasemaskThroughDefinitions, phaseData._PhasemaskThroughAuras, phaseData._CustomPhasemask); + + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_PHASEMASK, phaseData.GetPhaseMaskForSpawn(), player->GetPhaseMask()); +} + +void PhaseMgr::SetCustomPhase(uint32 const phaseMask) +{ + phaseData._CustomPhasemask = phaseMask; + + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + + Update(); +} + +////////////////////////////////////////////////////////////////// +// Phase Data + +uint32 PhaseData::GetCurrentPhasemask() const +{ + if (player->isGameMaster()) + return PHASEMASK_ANYWHERE; + + if (_CustomPhasemask) + return _CustomPhasemask; + + return GetPhaseMaskForSpawn(); +} + +inline uint32 PhaseData::GetPhaseMaskForSpawn() const +{ + uint32 const phase = (_PhasemaskThroughDefinitions | _PhasemaskThroughAuras); + return (phase ? phase : PHASEMASK_NORMAL); +} + +void PhaseData::SendPhaseMaskToPlayer() +{ + // Server side update + uint32 const phasemask = GetCurrentPhasemask(); + if (player->GetPhaseMask() == phasemask) + return; + + player->SetPhaseMask(phasemask, false); + + if (player->IsVisible()) + player->UpdateObjectVisibility(); +} + +void PhaseData::SendPhaseshiftToPlayer() +{ + // Client side update + std::set<uint32> phaseIds; + std::set<uint32> terrainswaps; + + for (PhaseInfoContainer::const_iterator itr = spellPhaseInfo.begin(); itr != spellPhaseInfo.end(); ++itr) + { + if (itr->second.terrainswapmap) + terrainswaps.insert(itr->second.terrainswapmap); + + if (itr->second.phaseId) + phaseIds.insert(itr->second.phaseId); + } + + // Phase Definitions + for (std::list<PhaseDefinition const*>::const_iterator itr = activePhaseDefinitions.begin(); itr != activePhaseDefinitions.end(); ++itr) + { + if ((*itr)->phaseId) + phaseIds.insert((*itr)->phaseId); + + if ((*itr)->terrainswapmap) + terrainswaps.insert((*itr)->terrainswapmap); + } + + player->GetSession()->SendSetPhaseShift(phaseIds, terrainswaps); +} + +void PhaseData::AddPhaseDefinition(PhaseDefinition const* phaseDefinition) +{ + if (phaseDefinition->IsOverwritingExistingPhases()) + { + activePhaseDefinitions.clear(); + _PhasemaskThroughDefinitions = phaseDefinition->phasemask; + } + else + { + if (phaseDefinition->IsNegatingPhasemask()) + _PhasemaskThroughDefinitions &= ~phaseDefinition->phasemask; + else + _PhasemaskThroughDefinitions |= phaseDefinition->phasemask; + } + + activePhaseDefinitions.push_back(phaseDefinition); +} + +void PhaseData::AddAuraInfo(uint32 const spellId, PhaseInfo phaseInfo) +{ + if (phaseInfo.phasemask) + _PhasemaskThroughAuras |= phaseInfo.phasemask; + + spellPhaseInfo[spellId] = phaseInfo; +} + +uint32 PhaseData::RemoveAuraInfo(uint32 const spellId) +{ + PhaseInfoContainer::const_iterator rAura = spellPhaseInfo.find(spellId); + if (rAura != spellPhaseInfo.end()) + { + uint32 updateflag = 0; + + if (rAura->second.NeedsClientSideUpdate()) + updateflag |= PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED; + + if (rAura->second.NeedsServerSideUpdate()) + { + _PhasemaskThroughAuras = 0; + + updateflag |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + + spellPhaseInfo.erase(rAura); + + for (PhaseInfoContainer::const_iterator itr = spellPhaseInfo.begin(); itr != spellPhaseInfo.end(); ++itr) + _PhasemaskThroughAuras |= itr->second.phasemask; + } + + return updateflag; + } + else + return 0; +} + +////////////////////////////////////////////////////////////////// +// Phase Update Data + +void PhaseUpdateData::AddQuestUpdate(uint32 const questId) +{ + AddConditionType(CONDITION_QUESTREWARDED); + AddConditionType(CONDITION_QUESTTAKEN); + AddConditionType(CONDITION_QUEST_COMPLETE); + AddConditionType(CONDITION_QUEST_NONE); + + _questId = questId; +} + +bool PhaseUpdateData::IsConditionRelated(Condition const* condition) const +{ + switch (condition->ConditionType) + { + case CONDITION_QUESTREWARDED: + case CONDITION_QUESTTAKEN: + case CONDITION_QUEST_COMPLETE: + case CONDITION_QUEST_NONE: + return condition->ConditionValue1 == _questId && ((1 << condition->ConditionType) & _conditionTypeFlags); + default: + return (1 << condition->ConditionType) & _conditionTypeFlags; + } +} + +bool PhaseMgr::IsConditionTypeSupported(ConditionTypes const conditionType) +{ + switch (conditionType) + { + case CONDITION_QUESTREWARDED: + case CONDITION_QUESTTAKEN: + case CONDITION_QUEST_COMPLETE: + case CONDITION_QUEST_NONE: + case CONDITION_TEAM: + case CONDITION_CLASS: + case CONDITION_RACE: + case CONDITION_INSTANCE_DATA: + case CONDITION_LEVEL: + return true; + default: + return false; + } +} |