/*
* Copyright (C) 2008-2012 TrinityCore
*
* 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 .
*/
#include "PhaseMgr.h"
#include "Chat.h"
#include "ObjectMgr.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 phaseIds;
std::set 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::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;
}
}