aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNaios <naios-dev@live.de>2012-09-26 17:46:00 +0200
committerNaios <naios-dev@live.de>2012-10-15 20:31:41 +0200
commit61dce1a02e0092f4ad57dbe05ec74d6dd89df14a (patch)
tree31e510e6b6b2bad4ad03a805dd03b11224e0ffe4 /src
parentc757f811f265752f2e4dfe1921ace9d7aaf80983 (diff)
Core/PhaseMgr: Implemented Phase Definitions, Terrainswap and multiphasing
* fixes cataclysm aura effect SPELL_AURA_PHASE without phasemasks defined in miscValueA * implements CONDITION_SOURCE_TYPE_PHASE_DEFINITION Thanks to: - Cyberbrest: For the hard research work about multiphasing. - Venugh: He helped me with a lot of strange compile Errors. - Shauren: For the 4.3.4 phaseshift packet. - Booksize: He showed me how terrainswap works Signed-off-by: Naios <naios-dev@live.de>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Conditions/ConditionMgr.cpp48
-rwxr-xr-xsrc/server/game/Conditions/ConditionMgr.h6
-rw-r--r--src/server/game/DataStores/DBCStructure.h4
-rw-r--r--src/server/game/Entities/Player/Player.cpp74
-rw-r--r--[-rwxr-xr-x]src/server/game/Entities/Player/Player.h9
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp97
-rwxr-xr-xsrc/server/game/Globals/ObjectMgr.h11
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp47
-rwxr-xr-xsrc/server/game/Instances/InstanceScript.cpp11
-rwxr-xr-xsrc/server/game/Instances/InstanceScript.h3
-rw-r--r--src/server/game/Maps/PhaseMgr.cpp371
-rw-r--r--src/server/game/Maps/PhaseMgr.h173
-rwxr-xr-xsrc/server/game/Miscellaneous/Language.h10
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rwxr-xr-xsrc/server/game/Server/WorldSession.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp26
-rw-r--r--src/server/game/World/World.cpp14
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp29
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp4
-rw-r--r--src/server/scripts/Commands/cs_modify.cpp17
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp4
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp10
-rw-r--r--src/server/scripts/Commands/cs_wp.cpp16
24 files changed, 907 insertions, 83 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 917c4cd7f90..406fb7cb753 100755
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -611,7 +611,8 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const
sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL ||
sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET ||
sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT ||
- sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
+ sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT ||
+ sourceType == CONDITION_SOURCE_TYPE_PHASE_DEFINITION);
}
bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const
@@ -687,6 +688,23 @@ ConditionList ConditionMgr::GetConditionsForSmartEvent(int32 entryOrGuid, uint32
return cond;
}
+ConditionList ConditionMgr::GetConditionsForPhaseDefinition(uint32 zone, uint32 entry)
+{
+ ConditionList cond;
+ PhaseDefinitionConditionContainer::const_iterator itr = PhaseDefinitionsConditionStore.find(zone);
+ if (itr != PhaseDefinitionsConditionStore.end())
+ {
+ ConditionTypeContainer::const_iterator i = (*itr).second.find(entry);
+ if (i != (*itr).second.end())
+ {
+ cond = (*i).second;
+ sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForPhaseDefinition: found conditions for zone %u entry %u spell %u", zone, entry);
+ }
+ }
+
+ return cond;
+}
+
void ConditionMgr::LoadConditions(bool isReload)
{
uint32 oldMSTime = getMSTime();
@@ -898,6 +916,13 @@ void ConditionMgr::LoadConditions(bool isReload)
++count;
continue;
}
+ case CONDITION_SOURCE_TYPE_PHASE_DEFINITION:
+ {
+ PhaseDefinitionsConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
+ valid = true;
+ ++count;
+ continue;
+ }
default:
break;
}
@@ -1389,6 +1414,13 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
return false;
}
break;
+ case CONDITION_SOURCE_TYPE_PHASE_DEFINITION:
+ if (!PhaseMgr::IsConditionTypeSupported(cond->ConditionType))
+ {
+ sLog->outError(LOG_FILTER_SQL, "Condition source type `CONDITION_SOURCE_TYPE_PHASE_DEFINITION` does not support condition type %u, ignoring.", cond->ConditionType);
+ return false;
+ }
+ break;
case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
case CONDITION_SOURCE_TYPE_SMART_EVENT:
@@ -1399,6 +1431,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
return true;
}
+
bool ConditionMgr::isConditionTypeValid(Condition* cond)
{
if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX)
@@ -1940,6 +1973,19 @@ void ConditionMgr::Clean()
SpellClickEventConditionStore.clear();
+ for (PhaseDefinitionConditionContainer::iterator itr = PhaseDefinitionsConditionStore.begin(); itr != PhaseDefinitionsConditionStore.end(); ++itr)
+ {
+ for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
+ {
+ for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
+ delete *i;
+ it->second.clear();
+ }
+ itr->second.clear();
+ }
+
+ PhaseDefinitionsConditionStore.clear();
+
// this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;)
for (std::list<Condition*>::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr)
delete *itr;
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 57af0562dcd..fe7f6a18af8 100755
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -124,7 +124,8 @@ enum ConditionSourceType
CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK = 20,
CONDITION_SOURCE_TYPE_VEHICLE_SPELL = 21,
CONDITION_SOURCE_TYPE_SMART_EVENT = 22,
- CONDITION_SOURCE_TYPE_MAX = 23 //MAX
+ CONDITION_SOURCE_TYPE_PHASE_DEFINITION = 23,
+ CONDITION_SOURCE_TYPE_MAX = 24 //MAX
};
enum ComparisionType
@@ -211,6 +212,7 @@ typedef std::map<uint32, ConditionList> ConditionTypeContainer;
typedef std::map<ConditionSourceType, ConditionTypeContainer> ConditionContainer;
typedef std::map<uint32, ConditionTypeContainer> CreatureSpellConditionContainer;
typedef std::map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionTypeContainer> SmartEventConditionContainer;
+typedef std::map<int32 /*zoneId*/, ConditionTypeContainer> PhaseDefinitionConditionContainer;
typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used for references
@@ -237,6 +239,7 @@ class ConditionMgr
ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId);
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId);
+ ConditionList GetConditionsForPhaseDefinition(uint32 zone, uint32 entry);
private:
bool isSourceTypeValid(Condition* cond);
@@ -254,6 +257,7 @@ class ConditionMgr
CreatureSpellConditionContainer VehicleSpellConditionStore;
CreatureSpellConditionContainer SpellClickEventConditionStore;
SmartEventConditionContainer SmartEventConditionStore;
+ PhaseDefinitionConditionContainer PhaseDefinitionsConditionStore;
};
template <class T> bool CompareValues(ComparisionType type, T val1, T val2)
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 308b9fa1a60..a1a0931dc5a 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1408,8 +1408,8 @@ struct LockEntry
struct PhaseEntry
{
uint32 ID; // 0
- char* Name; // 1
- uint32 phaseShift; // 2
+ char* Name; // 1
+ uint32 flag; // 2
};
struct MailTemplateEntry
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 9a0b21194cd..0582a879d5f 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -649,7 +649,7 @@ void KillRewarder::Reward()
#ifdef _MSC_VER
#pragma warning(disable:4355)
#endif
-Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_reputationMgr(this)
+Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_reputationMgr(this), phaseMgr(this)
{
#ifdef _MSC_VER
#pragma warning(default:4355)
@@ -2938,18 +2938,6 @@ void Player::SetGameMaster(bool on)
}
else
{
- // restore phase
- uint32 newPhase = 0;
- AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
- if (!phases.empty())
- for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
- newPhase |= (*itr)->GetMiscValue();
-
- if (!newPhase)
- newPhase = PHASEMASK_NORMAL;
-
- SetPhaseMask(newPhase, false);
-
m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON;
setFactionForRace(getRace());
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
@@ -2970,6 +2958,9 @@ void Player::SetGameMaster(bool on)
getHostileRefManager().setOnlineOfflineState(true);
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
+
+ phaseMgr.AddUpdateFlag(PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED);
+ phaseMgr.Update();
}
UpdateObjectVisibility();
@@ -3202,6 +3193,11 @@ void Player::GiveLevel(uint8 level)
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddConditionType(CONDITION_LEVEL);
+
+ phaseMgr.NotifyConditionChanged(phaseUdateData);
+
// Refer-A-Friend
if (GetSession()->GetRecruiterId())
if (level < sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL))
@@ -7628,6 +7624,8 @@ void Player::UpdateArea(uint32 newArea)
// so apply them accordingly
m_areaUpdateId = newArea;
+ phaseMgr.AddUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE);
+
AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);
pvpInfo.inFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
UpdatePvPState(true);
@@ -7644,10 +7642,14 @@ void Player::UpdateArea(uint32 newArea)
}
else
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
+
+ phaseMgr.RemoveUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE);
}
void Player::UpdateZone(uint32 newZone, uint32 newArea)
{
+ phaseMgr.AddUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE);
+
if (m_zoneUpdateId != newZone)
{
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
@@ -7757,6 +7759,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
UpdateLocalChannels(newZone);
UpdateZoneDependentAuras(newZone);
+
+ phaseMgr.RemoveUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE);
}
//If players are too far away from the duel flag... they lose the duel
@@ -15010,6 +15014,11 @@ void Player::AddQuest(Quest const* quest, Object* questGiver)
CastSpell(this, itr->second->spellId, true);
}
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddQuestUpdate(quest_id);
+
+ phaseMgr.NotifyConditionChanged(phaseUdateData);
+
UpdateForQuestWorldObjects();
}
@@ -15178,6 +15187,11 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
m_RewardedQuests.insert(quest_id);
m_RewardedQuestsSave[quest_id] = true;
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddQuestUpdate(quest_id);
+
+ phaseMgr.NotifyConditionChanged(phaseUdateData);
+
// StoreNewItem, mail reward, etc. save data directly to the database
// to prevent exploitable data desynchronisation we save the quest status to the database too
// (to prevent rewarding this quest another time while rewards were already given out)
@@ -15767,6 +15781,11 @@ void Player::SetQuestStatus(uint32 quest_id, QuestStatus status)
m_QuestStatusSave[quest_id] = true;
}
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddQuestUpdate(quest_id);
+
+ phaseMgr.NotifyConditionChanged(phaseUdateData);
+
UpdateForQuestWorldObjects();
}
@@ -15777,6 +15796,11 @@ void Player::RemoveActiveQuest(uint32 quest_id)
{
m_QuestStatus.erase(itr);
m_QuestStatusSave[quest_id] = false;
+
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddQuestUpdate(quest_id);
+
+ phaseMgr.NotifyConditionChanged(phaseUdateData);
return;
}
}
@@ -15788,6 +15812,11 @@ void Player::RemoveRewardedQuest(uint32 quest_id)
{
m_RewardedQuests.erase(rewItr);
m_RewardedQuestsSave[quest_id] = false;
+
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddQuestUpdate(quest_id);
+
+ phaseMgr.NotifyConditionChanged(phaseUdateData);
}
}
@@ -24420,25 +24449,6 @@ void Player::_LoadSkills(PreparedQueryResult result)
}
}
-uint32 Player::GetPhaseMaskForSpawn() const
-{
- uint32 phase = PHASEMASK_NORMAL;
- if (!isGameMaster())
- phase = GetPhaseMask();
- else
- {
- AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
- if (!phases.empty())
- phase = phases.front()->GetMiscValue();
- }
-
- // some aura phases include 1 normal map in addition to phase itself
- if (uint32 n_phase = phase & ~PHASEMASK_NORMAL)
- return n_phase;
-
- return PHASEMASK_NORMAL;
-}
-
InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const
{
ItemTemplate const* pProto = pItem->GetTemplate();
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 4d91ac42879..f1f58231bef 100755..100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -37,6 +37,9 @@
#include "Unit.h"
#include "Util.h" // for Tokens typedef
#include "WorldSession.h"
+#include "PhaseMgr.h"
+
+// for template
#include "SpellMgr.h"
#include<string>
@@ -54,6 +57,7 @@ class PlayerMenu;
class PlayerSocial;
class SpellCastTargets;
class UpdateMask;
+class PhaseMgr;
typedef std::deque<Mail*> PlayerMails;
@@ -1342,7 +1346,8 @@ class Player : public Unit, public GridObject<Player>
Pet* GetPet() const;
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
- uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn
+
+ PhaseMgr& GetPhaseMgr() { return phaseMgr; }
void Say(const std::string& text, const uint32 language);
void Yell(const std::string& text, const uint32 language);
@@ -3083,6 +3088,8 @@ class Player : public Unit, public GridObject<Player>
uint32 _pendingBindTimer;
uint32 _activeCheats;
+
+ PhaseMgr phaseMgr;
};
void AddItemsSetItem(Player*player, Item* item);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 3945d3b76fe..dd2afa44a07 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8652,7 +8652,7 @@ void ObjectMgr::LoadFactionChangeTitles()
}
uint32 count = 0;
-
+
do
{
Field* fields = result->Fetch();
@@ -8666,7 +8666,7 @@ void ObjectMgr::LoadFactionChangeTitles()
sLog->outError(LOG_FILTER_SQL, "Title %u referenced in `player_factionchange_title` does not exist, pair skipped!", horde);
else
FactionChange_Titles[alliance] = horde;
-
+
++count;
}
while (result->NextRow());
@@ -8674,6 +8674,99 @@ void ObjectMgr::LoadFactionChangeTitles()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
+void ObjectMgr::LoadPhaseDefinitions()
+{
+ _PhaseDefinitionStore.clear();
+
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2 3 4 5
+ QueryResult result = WorldDatabase.Query("SELECT zoneId, entry, phasemask, phaseId, terrainswapmap, flags FROM `phase_definitions` ORDER BY `entry` ASC");
+
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 phasing definitions. DB table `phase_definitions` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ PhaseDefinition PhaseDefinition;
+
+ PhaseDefinition.zoneId = fields[0].GetUInt32();
+ PhaseDefinition.entry = fields[1].GetUInt32();
+ PhaseDefinition.phasemask = fields[2].GetUInt32();
+ PhaseDefinition.phaseId = fields[3].GetUInt32();
+ PhaseDefinition.terrainswapmap = fields[4].GetUInt32();
+ PhaseDefinition.flags = fields[5].GetUInt32();
+
+ // Checks
+ if ((PhaseDefinition.flags & PHASE_FLAG_OVERWRITE_EXISTING) && (PhaseDefinition.flags & PHASE_FLAG_NEGATE_PHASE))
+ {
+ sLog->outError(LOG_FILTER_SQL, "Flags defined in phase_definitions in zoneId %d and entry %u does contain PHASE_FLAG_OVERWRITE_EXISTING and PHASE_FLAG_NEGATE_PHASE. Setting flags to PHASE_FLAG_OVERWRITE_EXISTING", PhaseDefinition.zoneId, PhaseDefinition.entry);
+ PhaseDefinition.flags &= ~PHASE_FLAG_NEGATE_PHASE;
+ }
+
+ _PhaseDefinitionStore[PhaseDefinition.zoneId].push_back(PhaseDefinition);
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u phasing definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void ObjectMgr::LoadSpellPhaseInfo()
+{
+ _SpellPhaseStore.clear();
+
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT id, phasemask, terrainswapmap FROM `spell_phase`");
+
+ if (!result)
+ {
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spell dbc infos. DB table `spell_phase` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field *fields = result->Fetch();
+
+ SpellPhaseInfo spellPhaseInfo;
+ spellPhaseInfo.spellId = fields[0].GetUInt32();
+
+ SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellPhaseInfo.spellId);
+ if (!spell)
+ {
+ sLog->outError(LOG_FILTER_SQL, "Spell %u defined in `spell_phase` does not exists, skipped.", spellPhaseInfo.spellId);
+ continue;
+ }
+
+ if (!spell->HasAura(SPELL_AURA_PHASE))
+ {
+ sLog->outError(LOG_FILTER_SQL, "Spell %u defined in `spell_phase` does not have aura effect type SPELL_AURA_PHASE, useless value.", spellPhaseInfo.spellId);
+ continue;
+ }
+
+ spellPhaseInfo.phasemask = fields[1].GetUInt32();
+ spellPhaseInfo.terrainswapmap = fields[2].GetUInt32();
+
+ _SpellPhaseStore[spellPhaseInfo.spellId] = spellPhaseInfo;
+
+ ++count;
+ }
+ while (result->NextRow());
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u spell dbc infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry)
{
GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 61094d60c55..496d5ae224f 100755
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -42,8 +42,10 @@
#include <limits>
#include "ConditionMgr.h"
#include <functional>
+#include "PhaseMgr.h"
class Item;
+class PhaseMgr;
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
#if defined(__GNUC__)
@@ -906,6 +908,12 @@ class ObjectMgr
void LoadTrainerSpell();
void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel);
+ void LoadPhaseDefinitions();
+ void LoadSpellPhaseInfo();
+
+ PhaseDefinitionStore const* GetPhaseDefinitionStore() { return &_PhaseDefinitionStore; }
+ SpellPhaseStore const* GetSpellPhaseStore() { return &_SpellPhaseStore; }
+
std::string GeneratePetName(uint32 entry);
uint32 GetBaseXP(uint8 level);
uint32 GetXPForLevel(uint8 level) const;
@@ -1222,6 +1230,9 @@ class ObjectMgr
PageTextContainer _pageTextStore;
InstanceTemplateContainer _instanceTemplateStore;
+ PhaseDefinitionStore _PhaseDefinitionStore;
+ SpellPhaseStore _SpellPhaseStore;
+
private:
void LoadScripts(ScriptsType type);
void CheckScripts(ScriptsType type, std::set<int32>& ids);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 2acc8ffcf7b..1947baa43b6 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1753,10 +1753,51 @@ void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recvData*/)
SendAccountDataTimes(GLOBAL_CACHE_MASK);
}
-void WorldSession::SendSetPhaseShift(uint32 PhaseShift)
+void WorldSession::SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps)
{
- WorldPacket data(SMSG_SET_PHASE_SHIFT, 4);
- data << uint32(PhaseShift);
+ ObjectGuid guid = _player->GetGUID();
+
+ WorldPacket data(SMSG_SET_PHASE_SHIFT, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2);
+ data.WriteBit(guid[2]);
+ data.WriteBit(guid[3]);
+ data.WriteBit(guid[1]);
+ data.WriteBit(guid[6]);
+ data.WriteBit(guid[4]);
+ data.WriteBit(guid[5]);
+ data.WriteBit(guid[0]);
+ data.WriteBit(guid[7]);
+
+ data.WriteByteSeq(guid[7]);
+ data.WriteByteSeq(guid[4]);
+
+ data << uint32(0);
+ //for (uint8 i = 0; i < worldMapAreaCount; ++i)
+ // data << uint16(0); // WorldMapArea.dbc id (controls map display)
+
+ data.WriteByteSeq(guid[1]);
+
+ data << uint32(0); // flags (not phasemask)
+
+ data.WriteByteSeq(guid[2]);
+ data.WriteByteSeq(guid[6]);
+
+ data << uint32(0); // Inactive terrain swaps
+ //for (uint8 i = 0; i < inactiveSwapsCount; ++i)
+ // data << uint16(0);
+
+ data << uint32(phaseIds.size()) * 2; // Phase.dbc ids
+ for (std::set<uint32>::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr)
+ data << uint16(*itr);
+
+ data.WriteByteSeq(guid[3]);
+ data.WriteByteSeq(guid[0]);
+
+ data << uint32(terrainswaps.size()) * 2; // Active terrain swaps
+ for (std::set<uint32>::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr)
+ data << uint16(*itr);
+
+ data.WriteByteSeq(guid[5]);
+
SendPacket(&data);
}
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index d967ece9cf2..f14dc3c8b14 100755
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -450,3 +450,14 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi
}
}
}
+
+void InstanceScript::UpdatePhasing()
+{
+ PhaseUpdateData phaseUdateData;
+ phaseUdateData.AddConditionType(CONDITION_INSTANCE_DATA);
+
+ Map::PlayerList const& players = instance->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ if (Player* player = itr->getSource())
+ player->GetPhaseMgr().NotifyConditionChanged(phaseUdateData);
+}
diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h
index ab37c1ab5e9..291ba3be52f 100755
--- a/src/server/game/Instances/InstanceScript.h
+++ b/src/server/game/Instances/InstanceScript.h
@@ -217,6 +217,9 @@ class InstanceScript : public ZoneScript
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {}
+ // ReCheck PhaseTemplate related conditions
+ void UpdatePhasing();
+
protected:
void SetBossNumber(uint32 number) { bosses.resize(number); }
void LoadDoorData(DoorData const* data);
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;
+ }
+}
diff --git a/src/server/game/Maps/PhaseMgr.h b/src/server/game/Maps/PhaseMgr.h
new file mode 100644
index 00000000000..accb0cd3ea8
--- /dev/null
+++ b/src/server/game/Maps/PhaseMgr.h
@@ -0,0 +1,173 @@
+/*
+ * 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/>.
+ */
+
+#ifndef TRINITY_PHASEMGR_H
+#define TRINITY_PHASEMGR_H
+
+#include "SharedDefines.h"
+#include "SpellAuras.h"
+#include "SpellAuraEffects.h"
+
+class ObjectMgr;
+class Player;
+
+// Phasing (visibility)
+enum PhasingFlags
+{
+ PHASE_FLAG_OVERWRITE_EXISTING = 0x01, // don't stack with existing phases, overwrites existing phases
+ PHASE_FLAG_NO_MORE_PHASES = 0x02, // stop calculating phases after this phase was applied (no more phases will be applied)
+ PHASE_FLAG_NEGATE_PHASE = 0x04 // negate instead to add the phasemask
+};
+
+enum PhaseUpdateFlag
+{
+ PHASE_UPDATE_FLAG_ZONE_UPDATE = 0x01,
+ PHASE_UPDATE_FLAG_AREA_UPDATE = 0x02,
+
+ // Internal flags
+ PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED = 0x08,
+ PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED = 0x10,
+};
+
+struct PhaseDefinition
+{
+ uint32 zoneId;
+ uint32 entry;
+ uint32 phasemask;
+ uint32 phaseId;
+ uint32 terrainswapmap;
+ uint8 flags;
+
+ bool IsOverwritingExistingPhases() const { return flags & PHASE_FLAG_OVERWRITE_EXISTING; }
+ bool IsLastDefinition() const { return flags & PHASE_FLAG_NO_MORE_PHASES; }
+ bool IsNegatingPhasemask() const { return flags & PHASE_FLAG_NEGATE_PHASE; }
+};
+
+typedef std::list<PhaseDefinition> PhaseDefinitionContainer;
+typedef UNORDERED_MAP<uint32 /*zoneId*/, PhaseDefinitionContainer> PhaseDefinitionStore;
+
+struct SpellPhaseInfo
+{
+ uint32 spellId;
+ uint32 phasemask;
+ uint32 terrainswapmap;
+};
+
+typedef UNORDERED_MAP<uint32 /*spellId*/, SpellPhaseInfo> SpellPhaseStore;
+
+struct PhaseInfo
+{
+ PhaseInfo() : phasemask(0), terrainswapmap(0), phaseId(0) {}
+
+ uint32 phasemask;
+ uint32 terrainswapmap;
+ uint32 phaseId;
+
+ bool NeedsServerSideUpdate() const { return phasemask; }
+ bool NeedsClientSideUpdate() const { return terrainswapmap || phaseId; }
+};
+
+typedef UNORDERED_MAP<uint32 /*spellId*/, PhaseInfo> PhaseInfoContainer;
+
+struct PhaseData
+{
+ PhaseData(Player* _player) : player(_player), _PhasemaskThroughDefinitions(0), _PhasemaskThroughAuras(0), _CustomPhasemask(0) {}
+
+ uint32 _PhasemaskThroughDefinitions;
+ uint32 _PhasemaskThroughAuras;
+ uint32 _CustomPhasemask;
+
+ uint32 GetCurrentPhasemask() const;
+ inline uint32 GetPhaseMaskForSpawn() const;
+
+ void ResetDefinitions() { _PhasemaskThroughDefinitions = 0; activePhaseDefinitions.clear(); }
+ void AddPhaseDefinition(PhaseDefinition const* phaseDefinition);
+ bool HasActiveDefinitions() const { return !activePhaseDefinitions.empty(); }
+
+ void AddAuraInfo(uint32 const spellId, PhaseInfo phaseInfo);
+ uint32 RemoveAuraInfo(uint32 const spellId);
+
+ void SendPhaseMaskToPlayer();
+ void SendPhaseshiftToPlayer();
+
+private:
+ Player* player;
+ std::list<PhaseDefinition const*> activePhaseDefinitions;
+ PhaseInfoContainer spellPhaseInfo;
+};
+
+struct PhaseUpdateData
+{
+ void AddConditionType(ConditionTypes const conditionType) { _conditionTypeFlags |= (1 << conditionType); }
+ void AddQuestUpdate(uint32 const questId);
+
+ bool IsConditionRelated(Condition const* condition) const;
+
+private:
+ uint32 _conditionTypeFlags;
+ uint32 _questId;
+};
+
+class PhaseMgr
+{
+public:
+ PhaseMgr(Player* _player);
+ ~PhaseMgr() {}
+
+ uint32 GetCurrentPhasemask() { return phaseData.GetCurrentPhasemask(); };
+ inline uint32 GetPhaseMaskForSpawn() { return phaseData.GetCurrentPhasemask(); }
+
+ // Phase definitions update handling
+ void NotifyConditionChanged(PhaseUpdateData const& updateData);
+ void NotifyStoresReloaded() { Recalculate(); Update(); }
+
+ void Update();
+
+ // Aura phase effects
+ void RegisterPhasingAuraEffect(AuraEffect const* auraEffect);
+ void UnRegisterPhasingAuraEffect(AuraEffect const* auraEffect);
+
+ // Update flags (delayed phasing)
+ void AddUpdateFlag(PhaseUpdateFlag const updateFlag) { _UpdateFlags |= updateFlag; }
+ void RemoveUpdateFlag(PhaseUpdateFlag const updateFlag);
+
+ // Needed for modify phase command
+ void SetCustomPhase(uint32 const phaseMask);
+
+ // Debug
+ void SendDebugReportToPlayer(Player* const debugger);
+
+ static bool IsConditionTypeSupported(ConditionTypes const conditionType);
+
+private:
+ void Recalculate();
+
+ inline bool CheckDefinition(PhaseDefinition const* phaseDefinition);
+
+ bool NeedsPhaseUpdateWithData(PhaseUpdateData const updateData) const;
+
+ inline bool IsUpdateInProgress() const { return (_UpdateFlags & PHASE_UPDATE_FLAG_ZONE_UPDATE) || (_UpdateFlags & PHASE_UPDATE_FLAG_AREA_UPDATE); }
+
+ PhaseDefinitionStore const* _PhaseDefinitionStore;
+ SpellPhaseStore const* _SpellPhaseStore;
+
+ Player* player;
+ PhaseData phaseData;
+ uint8 _UpdateFlags;
+};
+
+#endif
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 5893bbd6564..c55c57481f4 100755
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -174,7 +174,15 @@ enum TrinityStrings
LANG_YOU_CHANGE_RUNIC_POWER = 173,
LANG_YOURS_RUNIC_POWER_CHANGED = 174,
LANG_LIQUID_STATUS = 175,
- // Room for more level 1 176-199 not used
+
+ LANG_PHASING_REPORT_STATUS = 176,
+ LANG_PHASING_NO_DEFINITIONS = 177, // Phasing
+ LANG_PHASING_SUCCESS = 178,
+ LANG_PHASING_FAILED = 179,
+ LANG_PHASING_LAST_PHASE = 180,
+ LANG_PHASING_LIST = 181,
+ LANG_PHASING_PHASEMASK = 182,
+ // Room for more level 1 183-199 not used
// level 2 chat
LANG_NO_SELECTION = 200,
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 5b6af4b2de8..694b2cf2d7f 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -1157,7 +1157,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER(SMSG_SET_FLAT_SPELL_MODIFIER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
DEFINE_OPCODE_HANDLER(SMSG_SET_FORCED_REACTIONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
DEFINE_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
- DEFINE_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
+ DEFINE_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
DEFINE_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
DEFINE_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
DEFINE_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide );
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index e6c13557076..5c61385f537 100755
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -253,7 +253,7 @@ class WorldSession
void SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName);
void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val = 0);
void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2, 3);
- void SendSetPhaseShift(uint32 phaseShift);
+ void SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps);
void SendQueryTimeResponse();
void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 28ddaf05afc..d70c68b9be2 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1808,27 +1808,21 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
Unit* target = aurApp->GetTarget();
- // no-phase is also phase state so same code for apply and remove
- uint32 newPhase = 0;
- Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE);
- if (!phases.empty())
- for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
- newPhase |= (*itr)->GetMiscValue();
-
if (Player* player = target->ToPlayer())
{
- if (!newPhase)
- newPhase = PHASEMASK_NORMAL;
-
- // GM-mode have mask 0xFFFFFFFF
- if (player->isGameMaster())
- newPhase = 0xFFFFFFFF;
-
- player->SetPhaseMask(newPhase, false);
- player->GetSession()->SendSetPhaseShift(newPhase);
+ if (apply)
+ player->GetPhaseMgr().RegisterPhasingAuraEffect(this);
+ else
+ player->GetPhaseMgr().UnRegisterPhasingAuraEffect(this);
}
else
{
+ uint32 newPhase = 0;
+ Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE);
+ if (!phases.empty())
+ for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
+ newPhase |= (*itr)->GetMiscValue();
+
if (!newPhase)
{
newPhase = PHASEMASK_NORMAL;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 94961b7b930..371668e73d9 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1368,6 +1368,9 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Spell Group Stack Rules...");
sSpellMgr->LoadSpellGroupStackRules();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Spell Phase Dbc Info...");
+ sObjectMgr->LoadSpellPhaseInfo();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading NPC Texts...");
sObjectMgr->LoadGossipText();
@@ -1616,6 +1619,9 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions
LoadWorldStates();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Phase definitions...");
+ sObjectMgr->LoadPhaseDefinitions();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Conditions...");
sConditionMgr->LoadConditions();
@@ -3022,3 +3028,11 @@ CharacterNameData const* World::GetCharacterNameData(uint32 guid) const
else
return NULL;
}
+
+void World::UpdatePhaseDefinitions()
+{
+ SessionMap::const_iterator itr;
+ for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ if (itr->second && itr->second->GetPlayer() && itr->second->GetPlayer()->IsInWorld())
+ itr->second->GetPlayer()->GetPhaseMgr().NotifyStoresReloaded();
+}
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 33ec159ec81..e1465f4897d 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -784,6 +784,8 @@ class World
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
void ResetEventSeasonalQuests(uint16 event_id);
+
+ void UpdatePhaseDefinitions();
protected:
void _UpdateGameTime();
// callback for UpdateRealmCharacters
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index 67b4d780942..363258648f6 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -90,6 +90,7 @@ public:
{ "areatriggers", SEC_ADMINISTRATOR, false, &HandleDebugAreaTriggersCommand, "", NULL },
{ "los", SEC_MODERATOR, false, &HandleDebugLoSCommand, "", NULL },
{ "moveflags", SEC_ADMINISTRATOR, false, &HandleDebugMoveflagsCommand, "", NULL },
+ { "phase", SEC_MODERATOR, false, &HandleDebugPhaseCommand, "", NULL },
{ NULL, SEC_PLAYER, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
@@ -948,8 +949,21 @@ public:
if (!*args)
return false;
- uint32 PhaseShift = atoi(args);
- handler->GetSession()->SendSetPhaseShift(PhaseShift);
+ char* t = strtok((char*)args, " ");
+ char* p = strtok(NULL, " ");
+
+ if (!t)
+ return false;
+
+ std::set<uint32> terrainswap;
+ std::set<uint32> phaseId;
+
+ terrainswap.insert((uint32)atoi(t));
+
+ if (p)
+ phaseId.insert((uint32)atoi(p));
+
+ handler->GetSession()->SendSetPhaseShift(phaseId, terrainswap);
return true;
}
@@ -1330,6 +1344,17 @@ public:
handler->PSendSysMessage("Waypoint SQL written to SQL Developer log");
return true;
}
+
+ static bool HandleDebugPhaseCommand(ChatHandler* handler, char const* args)
+ {
+ Unit* unit = handler->getSelectedUnit();
+ Player* player = handler->GetSession()->GetPlayer();
+ if(unit && unit->GetTypeId() == TYPEID_PLAYER)
+ player = unit->ToPlayer();
+
+ player->GetPhaseMgr().SendDebugReportToPlayer(handler->GetSession()->GetPlayer());
+ return true;
+ }
};
void AddSC_debug_commandscript()
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 6803354d29b..fd24e618ef0 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -149,7 +149,7 @@ public:
GameObject* object = new GameObject;
uint32 guidLow = sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT);
- if (!object->Create(guidLow, objectInfo->entry, map, player->GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
+ if (!object->Create(guidLow, objectInfo->entry, map, player->GetPhaseMgr().GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
{
delete object;
return false;
@@ -162,7 +162,7 @@ public:
}
// fill the gameobject data and save to the db
- object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMaskForSpawn());
+ object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMgr().GetPhaseMaskForSpawn());
// this will generate a new guid if the object is in an instance
if (!object->LoadGameObjectFromDB(guidLow, map))
diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp
index c370c70a94a..932a0cbc634 100644
--- a/src/server/scripts/Commands/cs_modify.cpp
+++ b/src/server/scripts/Commands/cs_modify.cpp
@@ -1277,14 +1277,15 @@ public:
uint32 phasemask = (uint32)atoi((char*)args);
Unit* target = handler->getSelectedUnit();
- if (!target)
- target = handler->GetSession()->GetPlayer();
-
- // check online security
- else if (target->GetTypeId() == TYPEID_PLAYER && handler->HasLowerSecurity(target->ToPlayer(), 0))
- return false;
-
- target->SetPhaseMask(phasemask, true);
+ if (target)
+ {
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ target->ToPlayer()->GetPhaseMgr().SetCustomPhase(phasemask);
+ else
+ target->SetPhaseMask(phasemask, true);
+ }
+ else
+ handler->GetSession()->GetPlayer()->GetPhaseMgr().SetCustomPhase(phasemask);
return true;
}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index e43760191df..30713728cf6 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -151,13 +151,13 @@ public:
}
Creature* creature = new Creature();
- if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o))
+ if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o))
{
delete creature;
return false;
}
- creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+ creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn());
uint32 db_guid = creature->GetDBTableGUIDLow();
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index ce0141290ff..14481884ec8 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -115,6 +115,7 @@ public:
{ "npc_trainer", SEC_ADMINISTRATOR, true, &HandleReloadNpcTrainerCommand, "", NULL },
{ "npc_vendor", SEC_ADMINISTRATOR, true, &HandleReloadNpcVendorCommand, "", NULL },
{ "page_text", SEC_ADMINISTRATOR, true, &HandleReloadPageTextsCommand, "", NULL },
+ { "phasedefinitions", SEC_ADMINISTRATOR, true, &HandleReloadPhaseDefinitionsCommand, "", NULL },
{ "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesPickpocketingCommand, "", NULL},
{ "points_of_interest", SEC_ADMINISTRATOR, true, &HandleReloadPointsOfInterestCommand, "", NULL },
{ "prospecting_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesProspectingCommand, "", NULL },
@@ -1250,6 +1251,15 @@ public:
handler->SendGlobalGMSysMessage("Vehicle template accessories reloaded.");
return true;
}
+
+ static bool HandleReloadPhaseDefinitionsCommand(ChatHandler* handler, const char* /*args*/)
+ {
+ sLog->outInfo(LOG_FILTER_GENERAL, "Reloading phase_definitions table...");
+ sObjectMgr->LoadPhaseDefinitions();
+ sWorld->UpdatePhaseDefinitions();
+ handler->SendGlobalGMSysMessage("Phase Definitions reloaded.");
+ return true;
+ }
};
void AddSC_reload_commandscript()
diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp
index e3cd185e4a3..05226fb55aa 100644
--- a/src/server/scripts/Commands/cs_wp.cpp
+++ b/src/server/scripts/Commands/cs_wp.cpp
@@ -688,7 +688,7 @@ public:
}
// re-create
Creature* wpCreature2 = new Creature;
- if (!wpCreature2->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0, 0, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()))
+ if (!wpCreature2->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0, 0, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
delete wpCreature2;
@@ -696,7 +696,7 @@ public:
return false;
}
- wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+ wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
//TODO: Should we first use "Create" then use "LoadFromDB"?
if (!wpCreature2->LoadCreatureFromDB(wpCreature2->GetDBTableGUIDLow(), map))
@@ -912,7 +912,7 @@ public:
float o = chr->GetOrientation();
Creature* wpCreature = new Creature;
- if (!wpCreature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o))
+ if (!wpCreature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
delete wpCreature;
@@ -928,7 +928,7 @@ public:
WorldDatabase.Execute(stmt);
- wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+ wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
if (!wpCreature->LoadCreatureFromDB(wpCreature->GetDBTableGUIDLow(), map))
{
@@ -976,14 +976,14 @@ public:
Map* map = chr->GetMap();
Creature* creature = new Creature;
- if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o))
+ if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
delete creature;
return false;
}
- creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+ creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn());
if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
@@ -1025,14 +1025,14 @@ public:
Map* map = chr->GetMap();
Creature* creature = new Creature;
- if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o))
+ if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o))
{
handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);
delete creature;
return false;
}
- creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+ creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn());
if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map))
{
handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);