From ab2c78ba5987df828c0abd88cff75fb325a2e8e0 Mon Sep 17 00:00:00 2001 From: Salja Date: Mon, 16 Dec 2013 14:09:19 +0200 Subject: [PATCH] Implemented Phase Definitions, Terrainswap and multiphasing * fixes cataclysm aura effect SPELL_AURA_PHASE without phasemasks defined in miscValueA NOTE: - Need some more test and feedback! Thanks to: - Naios: Main Author - 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 - Zakamurite: For Backporting some to MaNGOS - All other Author --- src/game/CMakeLists.txt | 2 + src/game/Chat.cpp | 2 + src/game/Chat.h | 3 + src/game/DBCStores.cpp | 27 ++++- src/game/DBCStores.h | 3 +- src/game/DBCStructure.h | 2 +- src/game/Formulas.h | 2 +- src/game/Language.h | 8 ++ src/game/Level2.cpp | 37 ++++--- src/game/ObjectMgr.cpp | 189 +++++++++++++++++++++++++-------- src/game/ObjectMgr.h | 45 ++++---- src/game/Player.cpp | 106 ++++++------------ src/game/Player.h | 8 +- src/game/QuestHandler.cpp | 6 ++ src/game/SpellAuras.cpp | 57 ++++++++-- src/game/SpellEffects.cpp | 6 ++ src/game/World.cpp | 20 +++- src/game/World.h | 2 + src/game/WorldSession.cpp | 43 ++++---- src/game/WorldSession.h | 2 +- src/game/debugcmds.cpp | 28 ++++- win/VC100/game.vcxproj | 2 + win/VC100/game.vcxproj.filters | 6 ++ win/VC110/game.vcxproj | 2 + win/VC110/game.vcxproj.filters | 6 ++ win/VC120/bzip2.vcxproj | 4 +- win/VC120/game.vcxproj | 2 + win/VC120/game.vcxproj.filters | 6 ++ win/mangosdVC120.sln | 2 +- 29 files changed, 418 insertions(+), 210 deletions(-) diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index 33fc1cb13..6bb2f3d7b 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -380,6 +380,8 @@ set(SRC_GRP_WORLD_HANDLERS Path.h PetHandler.cpp PetitionsHandler.cpp + PhaseMgr.cpp + PhaseMgr.h PoolManager.cpp PoolManager.h QueryHandler.cpp diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index fb7393113..58a551262 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -227,6 +227,7 @@ ChatCommand* ChatHandler::getCommandTable() { "equiperror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendEquipErrorCommand, "", NULL }, { "largepacket", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendLargePacketCommand, "", NULL }, { "opcode", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendOpcodeCommand, "", NULL }, + { "phase", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugPhaseCommand, "", NULL }, { "poi", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendPoiCommand, "", NULL }, { "qpartymsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestPartyMsgCommand, "", NULL }, { "qinvalidmsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestInvalidMsgCommand, "", NULL }, @@ -575,6 +576,7 @@ ChatCommand* ChatHandler::getCommandTable() { "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL }, { "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL }, { "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL }, + { "phase_definitions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPhaseDefinitionsCommand, "", NULL }, { "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand, "", NULL}, { "points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPointsOfInterestCommand, "", NULL }, { "prospecting_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesProspectingCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index 655bc2e33..0543d7118 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -228,6 +228,7 @@ class MANGOS_DLL_SPEC ChatHandler bool HandleDebugSendQuestInvalidMsgCommand(char* args); bool HandleDebugSendSellErrorCommand(char* args); bool HandleDebugSendSetPhaseShiftCommand(char* args); + bool HandleDebugPhaseCommand(char* args); bool HandleDebugSendSpellFailCommand(char* args); bool HandleEventListCommand(char* args); @@ -611,6 +612,8 @@ class MANGOS_DLL_SPEC ChatHandler bool HandleMmap(char* args); bool HandleMmapTestArea(char* args); + bool HandleReloadPhaseDefinitionsCommand(char* /*args*/); + //! Development Commands bool HandleSaveAllCommand(char* args); diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp index d9eb3ba1c..9a9759ce1 100644 --- a/src/game/DBCStores.cpp +++ b/src/game/DBCStores.cpp @@ -977,12 +977,35 @@ uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId) return mapid; } -ContentLevels GetContentLevelsForMap(uint32 mapid) +ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId) { - MapEntry const* mapEntry = sMapStore.LookupEntry(mapid); + MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); if (!mapEntry) return CONTENT_1_60; + if (mapEntry->rootPhaseMap != -1) + mapId = mapEntry->rootPhaseMap; + + switch (mapId) + { + case 648: // Lost Islands + case 654: // Gilneas + return CONTENT_1_60; + default: + break; + } + + switch (zoneId) + { + case 616: // Mount Hyjal + case 4922: // Twilight Highlands + case 5034: // Uldum + case 5042: // Deepholm + return CONTENT_81_85; + default: + break; + } + switch (mapEntry->Expansion()) { default: return CONTENT_1_60; diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h index b7fd92811..c6d1672f4 100644 --- a/src/game/DBCStores.h +++ b/src/game/DBCStores.h @@ -54,7 +54,8 @@ enum ContentLevels CONTENT_71_80, CONTENT_81_85, }; -ContentLevels GetContentLevelsForMap(uint32 mapid); + +ContentLevels GetContentLevelsForMapAndZone(uint32 mapId, uint32 zoneId); ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id); diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index a8a0a67a3..2dfd78b45 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -1347,7 +1347,7 @@ struct MapEntry uint32 addon; // 16 m_expansionID uint32 unkTime; // 17 m_raidOffset uint32 maxPlayers; // 18 m_maxPlayers - uint32 NextPhaseMap; // 19 - MapId for next phase. + int32 rootPhaseMap; // 19 map with base phasing // Helpers uint32 Expansion() const { return addon; } diff --git a/src/game/Formulas.h b/src/game/Formulas.h index 99ee98e5d..e3d2f6757 100644 --- a/src/game/Formulas.h +++ b/src/game/Formulas.h @@ -116,7 +116,7 @@ namespace MaNGOS (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) return 0; - uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMap(pl->GetMapId())); + uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(), pl->GetZoneId())); if (xp_gain == 0) return 0; diff --git a/src/game/Language.h b/src/game/Language.h index 4db978618..e047a1acd 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -1019,6 +1019,14 @@ enum MangosStrings LANG_VENDOR_WRONG_ITEM_TYPE = 1700, LANG_VENDOR_WRONG_CURRENCY_MAXCOUNT = 1701, + LANG_PHASING_REPORT_STATUS = 1702, + LANG_PHASING_NO_DEFINITIONS = 1703, + LANG_PHASING_SUCCESS = 1704, + LANG_PHASING_FAILED = 1705, + LANG_PHASING_LAST_PHASE = 1706, + LANG_PHASING_LIST = 1707, + LANG_PHASING_PHASEMASK = 1708, + // FREE IDS 1800-9999 // Use for not-in-official-sources patches diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index b6b9ef46b..85ac68d0b 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -42,6 +42,7 @@ #include "GMTicketMgr.h" #include "WaypointManager.h" #include "Util.h" +#include "PhaseMgr.h" #include #include #include @@ -1100,7 +1101,7 @@ bool ChatHandler::HandleGameObjectAddCommand(char* args) } GameObject* pGameObj = new GameObject; - if (!pGameObj->Create(db_lowGUID, gInfo->id, map, plr->GetPhaseMaskForSpawn(), x, y, z, o)) + if (!pGameObj->Create(db_lowGUID, gInfo->id, map, plr->GetPhaseMgr()->GetPhaseMaskForSpawn(), x, y, z, o)) { delete pGameObj; return false; @@ -1110,7 +1111,7 @@ bool ChatHandler::HandleGameObjectAddCommand(char* args) pGameObj->SetRespawnTime(spawntimeSecs); // fill the gameobject data and save to the db - pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), plr->GetPhaseMaskForSpawn()); + pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), plr->GetPhaseMgr()->GetPhaseMaskForSpawn()); // this will generate a new guid if the object is in an instance if (!pGameObj->LoadFromDB(db_lowGUID, map)) @@ -1590,7 +1591,7 @@ bool ChatHandler::HandleNpcAddCommand(char* args) return false; } - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); uint32 db_guid = pCreature->GetGUIDLow(); @@ -2598,7 +2599,10 @@ bool ChatHandler::HandleModifyPhaseCommand(char* args) else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target)) return false; - target->SetPhaseMask(phasemask, true); + if (target->GetTypeId() == TYPEID_PLAYER) + ((Player*)target)->GetPhaseMgr()->SetCustomPhase(phasemask); + else + target->SetPhaseMask(phasemask,true); return true; } @@ -3307,7 +3311,7 @@ bool ChatHandler::HandleWpModifyCommand(char* args) return false; } - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); wpCreature->LoadFromDB(wpCreature->GetGUIDLow(), map); map->Add(wpCreature); @@ -3419,7 +3423,7 @@ bool ChatHandler::HandleWpModifyCommand(char* args) 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(); wpCreature2->LoadFromDB(wpCreature2->GetGUIDLow(), map); map->Add(wpCreature2); @@ -3704,7 +3708,7 @@ bool ChatHandler::HandleWpShowCommand(char* args) Field* fields = result->Fetch(); uint32 point = fields[0].GetUInt32(); - CreatureCreatePos pos(map, fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), chr->GetOrientation(), chr->GetPhaseMaskForSpawn()); + CreatureCreatePos pos(map, fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), chr->GetOrientation(), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); Creature* wpCreature = new Creature; @@ -3721,7 +3725,7 @@ bool ChatHandler::HandleWpShowCommand(char* args) // set "wpguid" column to the visual waypoint WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid=%u WHERE id=%u and point=%u", wpCreature->GetGUIDLow(), lowguid, point); - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); wpCreature->LoadFromDB(wpCreature->GetGUIDLow(), map); map->Add(wpCreature); @@ -3750,7 +3754,7 @@ bool ChatHandler::HandleWpShowCommand(char* args) Map* map = chr->GetMap(); Field* fields = result->Fetch(); - CreatureCreatePos pos(map, fields[0].GetFloat(), fields[1].GetFloat(), fields[2].GetFloat(), chr->GetOrientation(), chr->GetPhaseMaskForSpawn()); + CreatureCreatePos pos(map, fields[0].GetFloat(), fields[1].GetFloat(), fields[2].GetFloat(), chr->GetOrientation(), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); Creature* pCreature = new Creature; @@ -3762,7 +3766,7 @@ bool ChatHandler::HandleWpShowCommand(char* args) return false; } - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); pCreature->LoadFromDB(pCreature->GetGUIDLow(), map); map->Add(pCreature); // player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint"); @@ -3798,7 +3802,7 @@ bool ChatHandler::HandleWpShowCommand(char* args) Map* map = chr->GetMap(); Field* fields = result->Fetch(); - CreatureCreatePos pos(map, fields[0].GetFloat(), fields[1].GetFloat(), fields[2].GetFloat(), chr->GetOrientation(), chr->GetPhaseMaskForSpawn()); + CreatureCreatePos pos(map, fields[0].GetFloat(), fields[1].GetFloat(), fields[2].GetFloat(), chr->GetOrientation(), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); Creature* pCreature = new Creature; @@ -3810,7 +3814,7 @@ bool ChatHandler::HandleWpShowCommand(char* args) return false; } - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr()->GetPhaseMaskForSpawn()); pCreature->LoadFromDB(pCreature->GetGUIDLow(), map); map->Add(pCreature); // player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint"); @@ -3869,6 +3873,15 @@ bool ChatHandler::HandleWpShowCommand(char* args) return true; } // HandleWpShowCommand +bool ChatHandler::HandleReloadPhaseDefinitionsCommand(char* /*args*/) +{ + SendSysMessage("Reloading phase_definitions table..."); + sObjectMgr.LoadPhaseDefinitions(); + sWorld.UpdatePhaseDefinitions(); + SendSysMessage("Phase Definitions reloaded."); + return true; +} + bool ChatHandler::HandleWpExportCommand(char* args) { if (!*args) diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 33ddd50c2..25ce1d302 100755 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -47,6 +47,7 @@ #include "InstanceData.h" #include "DB2Structure.h" #include "DB2Stores.h" +#include "PhaseMgr.h" #include @@ -185,6 +186,15 @@ ObjectMgr::~ObjectMgr() for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) itr->second.Clear(); + + for (PhaseDefinitionStore::iterator itr = _PhaseDefinitionStore.begin(); itr != _PhaseDefinitionStore.end(); ++itr) + { + for (PhaseDefinitionContainer::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + delete *itr2; + } + + for (SpellPhaseStore::iterator itr = _SpellPhaseStore.begin(); itr != _SpellPhaseStore.end(); ++itr) + delete itr->second; } Group* ObjectMgr::GetGroupById(uint32 id) const @@ -6968,50 +6978,6 @@ void ObjectMgr::LoadQuestPOI() sLog.outString(">> Loaded %u quest POI definitions", count); } -void ObjectMgr::LoadQuestPhaseMaps() -{ - mQuestPhaseMap.clear(); // need for reload case - - uint32 count = 0; - - // 0 1 - QueryResult *result = WorldDatabase.Query("SELECT questId, map, phase FROM quest_phase_maps"); - - if (!result) - { - BarGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 quest phase maps definitions. DB table `quest_phase_maps` is empty."); - return; - } - - BarGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 questId = fields[0].GetUInt32(); - uint16 mapId = fields[1].GetUInt16(); - uint32 phase = fields[2].GetUInt32(); - - QuestPhaseMaps QuestPhase(mapId, phase); - - mQuestPhaseMap[questId].push_back(QuestPhase); - - ++count; - } while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u quest phase maps definitions", count); -} - void ObjectMgr::LoadNPCSpellClickSpells() { uint32 count = 0; @@ -7098,6 +7064,27 @@ void ObjectMgr::LoadNPCSpellClickSpells() sLog.outString(">> Loaded %u spellclick definitions", count); } +void ObjectMgr::GetConditions(uint32 conditionId, std::vector& out) const +{ + const PlayerCondition* condition = sConditionStorage.LookupEntry(conditionId); + if (!condition) + return; + + if (condition->m_condition == CONDITION_OR || condition->m_condition == CONDITION_AND) + { + GetConditions(condition->m_value1, out); + GetConditions(condition->m_value2, out); + return; + } + else if (condition->m_condition == CONDITION_NOT) + { + GetConditions(condition->m_value1, out); + return; + } + + out.push_back(condition); +} + void ObjectMgr::LoadWeatherZoneChances() { uint32 count = 0; @@ -7875,7 +7862,8 @@ char const* conditionSourceToStr[] = "vendor's item check", "spell_area check", "npc_spellclick_spells check", - "DBScript engine" + "DBScript engine", + "phase mgr" }; // Checks if player meets the condition @@ -9988,6 +9976,117 @@ bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL* return true; } +void ObjectMgr::LoadPhaseDefinitions() +{ + for (PhaseDefinitionStore::iterator itr = _PhaseDefinitionStore.begin(); itr != _PhaseDefinitionStore.end(); ++itr) + { + for (PhaseDefinitionContainer::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + delete *itr2; + } + + _PhaseDefinitionStore.clear(); + + // 0 1 2 3 4 5 6 + QueryResult* result = WorldDatabase.Query("SELECT zoneId, entry, phasemask, phaseId, terrainswapmap, flags, condition_id FROM `phase_definitions` ORDER BY `entry` ASC"); + + if (!result) + { + sLog.outString(">> Loaded 0 phasing definitions. DB table `phase_definitions` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + PhaseDefinition* phaseDefinition = new 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(); + phaseDefinition->conditionId = fields[6].GetUInt16(); + + // Checks + if ((phaseDefinition->flags & PHASE_FLAG_OVERWRITE_EXISTING) && (phaseDefinition->flags & PHASE_FLAG_NEGATE_PHASE)) + { + sLog.outError("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; + } + + if (!sConditionStorage.LookupEntry(phaseDefinition->conditionId)) + { + sLog.outError("Condition id defined in phase_definitions in zoneId %d and entry %u does not exists. Skipping condition.", phaseDefinition->zoneId, phaseDefinition->entry); + phaseDefinition->conditionId = 0; + } + + _PhaseDefinitionStore[phaseDefinition->zoneId].push_back(phaseDefinition); + + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(">> Loaded %u phasing definitions.", count); +} + +void ObjectMgr::LoadSpellPhaseInfo() +{ + for (SpellPhaseStore::iterator itr = _SpellPhaseStore.begin(); itr != _SpellPhaseStore.end(); ++itr) + delete itr->second; + + _SpellPhaseStore.clear(); + + // 0 1 2 + QueryResult* result = WorldDatabase.Query("SELECT id, phasemask, terrainswapmap FROM `spell_phase`"); + + if (!result) + { + sLog.outString(">> Loaded 0 spell dbc infos. DB table `spell_phase` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + SpellPhaseInfo* spellPhaseInfo = new SpellPhaseInfo(); + spellPhaseInfo->spellId = fields[0].GetUInt32(); + + SpellEntry const* spell = sSpellStore.LookupEntry(spellPhaseInfo->spellId); + if (!spell) + { + sLog.outError("Spell %u defined in `spell_phase` does not exists, skipped.", spellPhaseInfo->spellId); + delete spellPhaseInfo; + continue; + } + + if (!IsSpellHaveAura(spell, SPELL_AURA_PHASE) && !IsSpellHaveAura(spell, SPELL_AURA_PHASE_2)) + { + sLog.outError("Spell %u defined in `spell_phase` does not have aura effect type SPELL_AURA_PHASE or SPELL_AURA_PHASE_2, useless value.", spellPhaseInfo->spellId); + delete spellPhaseInfo; + continue; + } + + spellPhaseInfo->phasemask = fields[1].GetUInt32(); + spellPhaseInfo->terrainswapmap = fields[2].GetUInt32(); + + _SpellPhaseStore[spellPhaseInfo->spellId] = spellPhaseInfo; + + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(">> Loaded %u spell phase dbc infos.", count); +} + CreatureDataPair const* FindCreatureData::GetResult() const { if (i_spawnedData) diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index de723e114..d7b34920d 100755 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -45,6 +45,13 @@ class Group; class ArenaTeam; class Item; class SQLStorage; +struct PhaseDefinition; +struct SpellPhaseInfo; + +typedef std::list PhaseDefinitionContainer; +typedef UNORDERED_MAP PhaseDefinitionStore; + +typedef UNORDERED_MAP SpellPhaseStore; struct GameTele { @@ -320,17 +327,6 @@ struct QuestPOI typedef std::vector QuestPOIVector; typedef UNORDERED_MAP QuestPOIMap; -struct QuestPhaseMaps -{ - uint16 MapId; - uint32 PhaseMask; - - QuestPhaseMaps(uint16 mapId, uint32 phaseMask) : MapId(mapId), PhaseMask(phaseMask) {} -}; - -typedef std::vector QuestPhaseMapsVector; -typedef UNORDERED_MAP QuestPhaseMapsMap; - #define WEATHER_SEASONS 4 struct WeatherSeasonChances { @@ -428,6 +424,7 @@ enum ConditionSource // From where was th CONDITION_FROM_SPELL_AREA = 7, // Used to check a condition from spell_area table CONDITION_FROM_SPELLCLICK = 8, // Used to check a condition from npc_spellclick_spells table CONDITION_FROM_DBSCRIPTS = 9, // Used to check a condition from DB Scripts Engine + CONDITION_FROM_PHASEMGR = 10, // Used to check a condition from phase manager }; class PlayerCondition @@ -451,6 +448,8 @@ class PlayerCondition private: bool CheckParamRequirements(Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const; uint16 m_entry; // entry of the condition + + public: ConditionType m_condition; // additional condition type uint32 m_value1; // data for the condition - see ConditionType definition uint32 m_value2; @@ -673,15 +672,6 @@ class ObjectMgr return NULL; } - QuestPhaseMapsVector const* GetQuestPhaseMapVector(uint32 questId) - { - QuestPhaseMapsMap::const_iterator itr = mQuestPhaseMap.find(questId); - if(itr != mQuestPhaseMap.end()) - return &itr->second; - - return NULL; - } - // Static wrappers for various accessors static GameObjectInfo const* GetGameObjectInfo(uint32 id); ///< Wrapper for sGOStorage.LookupEntry static Player* GetPlayer(const char* name); ///< Wrapper for ObjectAccessor::FindPlayerByName @@ -762,7 +752,6 @@ class ObjectMgr void LoadPointsOfInterest(); void LoadQuestPOI(); - void LoadQuestPhaseMaps(); void LoadNPCSpellClickSpells(); void LoadCreatureTemplateSpells(); @@ -1006,6 +995,8 @@ class ObjectMgr // Check if a player meets condition conditionId bool IsPlayerMeetToCondition(uint16 conditionId, Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const; + void GetConditions(uint32 conditionId, std::vector& out) const; + GameTele const* GetGameTele(uint32 id) const { GameTeleMap::const_iterator itr = m_GameTeleMap.find(id); @@ -1152,6 +1143,12 @@ class ObjectMgr return ret ? ret : uint32(time(NULL)); } + void LoadPhaseDefinitions(); + void LoadSpellPhaseInfo(); + + PhaseDefinitionStore const* GetPhaseDefinitionStore() { return &_PhaseDefinitionStore; } + SpellPhaseStore const* GetSpellPhaseStore() { return &_SpellPhaseStore; } + protected: // first free id for selected id type @@ -1205,7 +1202,6 @@ class ObjectMgr PointOfInterestMap mPointsOfInterest; QuestPOIMap mQuestPOIMap; - QuestPhaseMapsMap mQuestPhaseMap; WeatherZoneMap mWeatherZoneMap; @@ -1290,7 +1286,10 @@ class ObjectMgr CacheTrainerSpellMap m_mCacheTrainerTemplateSpellMap; CacheTrainerSpellMap m_mCacheTrainerSpellMap; - HotfixData m_hotfixData; + HotfixData m_hotfixData; + + PhaseDefinitionStore _PhaseDefinitionStore; + SpellPhaseStore _SpellPhaseStore; }; #define sObjectMgr MaNGOS::Singleton::Instance() diff --git a/src/game/Player.cpp b/src/game/Player.cpp index fe3ea8d8c..568de437c 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -67,6 +67,7 @@ #include "SQLStorages.h" #include "Vehicle.h" #include "Calendar.h" +#include "PhaseMgr.h" #include @@ -558,6 +559,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_ m_cachedGS = 0; m_slot = 255; + + phaseMgr = new PhaseMgr(this); } Player::~Player() @@ -598,6 +601,8 @@ Player::~Player() delete m_declinedname; delete m_runes; + + delete phaseMgr; } void Player::CleanupsBeforeDelete() @@ -839,9 +844,6 @@ bool Player::Create(uint32 guidlow, const std::string& name, uint8 race, uint8 c } // all item positions resolved - if (info->phaseMap != 0) - CharacterDatabase.PExecute("REPLACE INTO `character_phase_data` (`guid`, `map`) VALUES (%u, %u)", guidlow, info->phaseMap); - return true; } @@ -2427,15 +2429,7 @@ void Player::SetGameMaster(bool on) RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); // restore phase - AuraList const& phases = GetAurasByType(SPELL_AURA_PHASE); - AuraList const& phases2 = GetAurasByType(SPELL_AURA_PHASE_2); - - if (!phases.empty()) - SetPhaseMask(phases.front()->GetMiscValue(), false); - else if (!phases2.empty()) - SetPhaseMask(phases2.front()->GetMiscValue(), false); - else - SetPhaseMask(PHASEMASK_NORMAL, false); + SetPhaseMask(phaseMgr->GetCurrentPhasemask(), false); CallForAllControlledUnits(SetGameMasterOffHelper(getFaction()), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); @@ -2447,6 +2441,9 @@ void Player::SetGameMaster(bool on) UpdateArea(m_areaUpdateId); getHostileRefManager().setOnlineOfflineState(true); + + phaseMgr->AddUpdateFlag(PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED); + phaseMgr->Update(); } m_camera.UpdateVisibilityForOwner(); @@ -2675,6 +2672,11 @@ void Player::GiveLevel(uint32 level) MailDraft(mailReward->mailTemplateId).SendMailTo(this, MailSender(MAIL_CREATURE, mailReward->senderEntry)); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL); + + PhaseUpdateData phaseUdateData; + phaseUdateData.AddConditionType(CONDITION_LEVEL); + + phaseMgr->NotifyConditionChanged(phaseUdateData); } void Player::UpdateFreeTalentPoints(bool resetIfNeed) @@ -4137,25 +4139,9 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c } } - SetPhaseAndMap(target); Unit::BuildCreateUpdateBlockForPlayer(data, target); } -void Player::SetPhaseAndMap(Player* target) const -{ - if (QueryResult *result = CharacterDatabase.PQuery("SELECT map, phase FROM character_phase_data WHERE guid = '%u'", target->GetGUIDLow())) - { - Field *fields = result->Fetch(); - - uint16 mapId = fields[0].GetUInt16(); - uint32 phase = fields[1].GetUInt32(); - - target->GetSession()->SendSetPhaseShift(phase, mapId); - - delete result; - } -} - void Player::DestroyForPlayer(Player* target, bool anim) const { Unit::DestroyForPlayer(target, anim); @@ -6860,7 +6846,11 @@ void Player::UpdateArea(uint32 newArea) SetFFAPvP(false); } + phaseMgr->AddUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE); + UpdateAreaDependentAuras(); + + phaseMgr->RemoveUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE); } bool Player::CanUseCapturePoint() @@ -6880,6 +6870,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) if (!zone) return; + phaseMgr->AddUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE); + if (m_zoneUpdateId != newZone) { // handle outdoor pvp zones @@ -6970,6 +6962,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateZoneDependentAuras(); UpdateZoneDependentPets(); + + phaseMgr->RemoveUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE); } // If players are too far way of duel flag... then player loose the duel @@ -14244,6 +14238,11 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, saBounds = sSpellMgr.GetSpellAreaForAreaMapBounds(0); for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) itr->second->ApplyOrRemoveSpellIfCan(this, zone, area, false); + + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr->NotifyConditionChanged(phaseUdateData); } void Player::FailQuest(uint32 questId) @@ -14783,6 +14782,11 @@ void Player::SetQuestStatus(uint32 quest_id, QuestStatus status) q_status.uState = QUEST_CHANGED; } + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr->NotifyConditionChanged(phaseUdateData); + UpdateForQuestWorldObjects(); } @@ -15412,15 +15416,6 @@ void Player::SendQuestReward(Quest const* pQuest, uint32 XP, Object* /*questGive data.WriteBit(1); // unk GetSession()->SendPacket(&data); - - if (QuestPhaseMapsVector const* QuestPhaseVector = sObjectMgr.GetQuestPhaseMapVector(questid)) - { - for (QuestPhaseMapsVector::const_iterator itr = QuestPhaseVector->begin(); itr != QuestPhaseVector->end(); ++itr) - { - GetSession()->SendSetPhaseShift(itr->PhaseMask, itr->MapId); - CharacterDatabase.PExecute("REPLACE INTO character_phase_data` (`guid`, `map`, `phase`) VALUES (%u, %u, %u)", GetSession()->GetPlayer()->GetGUIDLow(), itr->MapId, itr->PhaseMask); - } - } } void Player::SendQuestFailed(uint32 quest_id, InventoryResult reason) @@ -20477,21 +20472,6 @@ template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Corpse* template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, GameObject* target, UpdateData& data, std::set& visibleNow); template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, DynamicObject* target, UpdateData& data, std::set& visibleNow); -void Player::SetPhaseMask(uint32 newPhaseMask, bool update) -{ - // GM-mode have mask PHASEMASK_ANYWHERE always - if (isGameMaster()) - newPhaseMask = PHASEMASK_ANYWHERE; - - // phase auras normally not expected at BG but anyway better check - if (BattleGround* bg = GetBattleGround()) - bg->EventPlayerDroppedFlag(this); - - Unit::SetPhaseMask(newPhaseMask, update); - if (IsInWorld()) - GetSession()->SendSetPhaseShift(GetPhaseMask()); -} - void Player::InitPrimaryProfessions() { uint32 maxProfs = GetSession()->GetSecurity() < AccountTypes(sWorld.getConfig(CONFIG_UINT32_TRADE_SKILL_GMIGNORE_MAX_PRIMARY_COUNT)) @@ -22437,28 +22417,6 @@ void Player::_LoadSkills(QueryResult* result) } } -uint32 Player::GetPhaseMaskForSpawn() const -{ - uint32 phase = PHASEMASK_NORMAL; - if (!isGameMaster()) - phase = GetPhaseMask(); - else - { - AuraList const& phases = GetAurasByType(SPELL_AURA_PHASE); - AuraList const& phases2 = GetAurasByType(SPELL_AURA_PHASE_2); - if (!phases.empty()) - phase = phases.front()->GetMiscValue(); - else if (!phases2.empty()) - phase = phases2.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 { ItemPrototype const* pProto = pItem->GetProto(); diff --git a/src/game/Player.h b/src/game/Player.h index 339cb1783..f027f9cc7 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -53,6 +53,7 @@ class PlayerSocial; class DungeonPersistentState; class Spell; class Item; +class PhaseMgr; struct AreaTrigger; @@ -1135,7 +1136,7 @@ class MANGOS_DLL_SPEC Player : public Unit void RemovePet(PetSaveMode mode); - 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); @@ -1838,7 +1839,6 @@ class MANGOS_DLL_SPEC Player : public Unit void SetSession(WorldSession* s) { m_session = s; } void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override; - void SetPhaseAndMap(Player* target) const; void DestroyForPlayer(Player* target, bool anim = false) const override; void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP); @@ -2262,8 +2262,6 @@ class MANGOS_DLL_SPEC Player : public Unit Camera& GetCamera() { return m_camera; } - virtual void SetPhaseMask(uint32 newPhaseMask, bool update) override;// overwrite Unit::SetPhaseMask - uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } @@ -2687,6 +2685,8 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_timeSyncServer; uint32 m_cachedGS; + + PhaseMgr* phaseMgr; }; void AddItemsSetItem(Player* player, Item* item); diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp index aa4ac8c60..61221e7fb 100644 --- a/src/game/QuestHandler.cpp +++ b/src/game/QuestHandler.cpp @@ -29,6 +29,7 @@ #include "ObjectAccessor.h" #include "ScriptMgr.h" #include "Group.h" +#include "PhaseMgr.h" void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recv_data) { @@ -345,6 +346,11 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data) } _player->SetQuestStatus(quest, QUEST_STATUS_NONE); + + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest); + + _player->GetPhaseMgr()->NotifyConditionChanged(phaseUdateData); } _player->SetQuestSlot(slot, 0); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 238f5022c..ffb44c05d 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -48,6 +48,7 @@ #include "CellImpl.h" #include "Language.h" #include "MapManager.h" +#include "PhaseMgr.h" #define NULL_AURA_SLOT 0xFF @@ -8873,19 +8874,43 @@ void Aura::HandlePhase(bool apply, bool Real) Unit* target = GetTarget(); // always non stackable - if (apply) + if (target->GetTypeId() == TYPEID_PLAYER) { - Unit::AuraList const& phases = target->GetAurasByType(SPELL_AURA_PHASE); - if (!phases.empty()) - target->RemoveAurasDueToSpell(phases.front()->GetId(), GetHolder()); - Unit::AuraList const& phases2 = target->GetAurasByType(SPELL_AURA_PHASE_2); - if (!phases2.empty()) - target->RemoveAurasDueToSpell(phases2.front()->GetId(), GetHolder()); + if (apply) + ((Player*)target)->GetPhaseMgr()->RegisterPhasingAuraEffect(this); + else + ((Player*)target)->GetPhaseMgr()->UnRegisterPhasingAuraEffect(this); + } + else + { + uint32 phaseMask = 0; + if (apply) + { + phaseMask = target->GetPhaseMask(); + if (target->GetAurasByType(SPELL_AURA_PHASE).size() == 1 && target->GetAurasByType(SPELL_AURA_PHASE_2).size() == 1) + phaseMask &= ~PHASEMASK_NORMAL; + + phaseMask |= GetMiscValue(); + } + else + { + Unit::AuraList const& phases = target->GetAurasByType(SPELL_AURA_PHASE); + for (Unit::AuraList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + phaseMask |= (*itr)->GetMiscValue(); + + Unit::AuraList const& phases2 = target->GetAurasByType(SPELL_AURA_PHASE_2); + for (Unit::AuraList::const_iterator itr = phases2.begin(); itr != phases2.end(); ++itr) + phaseMask |= (*itr)->GetMiscValue(); + } + + if (!phaseMask) + phaseMask = PHASEMASK_NORMAL; + + target->SetPhaseMask(phaseMask, true); } - target->SetPhaseMask(apply ? GetMiscValue() : uint32(PHASEMASK_NORMAL), true); // no-phase is also phase state so same code for apply and remove - if (target->GetTypeId() == TYPEID_PLAYER) + if (GetEffIndex() == EFFECT_INDEX_0 && target->GetTypeId() == TYPEID_PLAYER) { SpellAreaForAreaMapBounds saBounds = sSpellMgr.GetSpellAreaForAuraMapBounds(GetId()); if (saBounds.first != saBounds.second) @@ -8893,8 +8918,18 @@ void Aura::HandlePhase(bool apply, bool Real) uint32 zone, area; target->GetZoneAndAreaId(zone, area); - for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) - itr->second->ApplyOrRemoveSpellIfCan((Player*)target, zone, area, false); + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + { + // some auras remove at aura remove + if(!itr->second->IsFitToRequirements((Player*)target, zone, area)) + target->RemoveAurasDueToSpell(itr->second->spellId); + // some auras applied at aura apply + else if(itr->second->autocast) + { + if (!target->HasAura(itr->second->spellId, EFFECT_INDEX_0)) + target->CastSpell(target, itr->second->spellId, true); + } + } } } } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 2f32785a6..a0a7cff06 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -57,6 +57,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "CellImpl.h" +#include "PhaseMgr.h" pEffect SpellEffects[TOTAL_SPELL_EFFECTS] = { @@ -3884,6 +3885,11 @@ void Spell::EffectClearQuest(SpellEffectEntry const* effect) player->SetQuestStatus(quest_id, QUEST_STATUS_NONE); player->getQuestStatusMap()[quest_id].m_rewarded = false; + + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + player->GetPhaseMgr()->NotifyConditionChanged(phaseUdateData); } void Spell::EffectForceCast(SpellEffectEntry const* effect) diff --git a/src/game/World.cpp b/src/game/World.cpp index 3fedc0157..ebce674b0 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -69,6 +69,7 @@ #include "CharacterDatabaseCleaner.h" #include "CreatureLinkingMgr.h" #include "Calendar.h" +#include "PhaseMgr.h" INSTANTIATE_SINGLETON_1(World); @@ -1141,9 +1142,6 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Quest POI"); sObjectMgr.LoadQuestPOI(); - sLog.outString("Loading Quest Phase Maps..."); - sObjectMgr.LoadQuestPhaseMaps(); - sLog.outString("Loading Quests Relations..."); sLog.outString(); sObjectMgr.LoadQuestRelations(); // must be after quest load @@ -1160,6 +1158,12 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Conditions..."); sObjectMgr.LoadConditions(); + sLog.outString("Loading Phase definitions..."); + sObjectMgr.LoadPhaseDefinitions(); + + sLog.outString("Loading Spell Phase Dbc Info..."); + sObjectMgr.LoadSpellPhaseInfo(); + sLog.outString("Creating map persistent states for non-instanceable maps..."); // must be after PackInstances(), LoadCreatures(), sPoolMgr.LoadFromDB(), sGameEventMgr.LoadFromDB(); sMapPersistentStateMgr.InitWorldMaps(); @@ -2541,3 +2545,13 @@ bool World::configNoReload(bool reload, eConfigBoolValues index, char const* fie return false; } + +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(); + } +} \ No newline at end of file diff --git a/src/game/World.h b/src/game/World.h index da14741d6..df635f5f9 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -616,6 +616,8 @@ class World char const* GetDBVersion() { return m_DBVersion.c_str(); } char const* GetCreatureEventAIVersion() { return m_CreatureEventAIVersion.c_str(); } + void UpdatePhaseDefinitions(); + protected: void _UpdateGameTime(); // callback for UpdateRealmCharacters diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 9630b20a2..db8f4b97b 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -575,45 +575,38 @@ void WorldSession::SendNotification(int32 string_id, ...) } } -void WorldSession::SendSetPhaseShift(uint32 phaseMask, uint16 mapId) +void WorldSession::SendSetPhaseShift(std::set const& phaseIds, std::set const& terrainswaps) { + if (PlayerLoading()) + return; + ObjectGuid guid = _player->GetObjectGuid(); - uint32 phaseFlags = 0; - - for (uint32 i = 0; i < sPhaseStore.GetNumRows(); i++) - { - if (PhaseEntry const* phase = sPhaseStore.LookupEntry(i)) - { - if (phase->PhaseShift == phaseMask) - { - phaseFlags = phase->Flags; - break; - } - } - } - - WorldPacket data(SMSG_SET_PHASE_SHIFT, 30); + WorldPacket data(SMSG_SET_PHASE_SHIFT, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2); data.WriteGuidMask<2, 3, 1, 6, 4, 5, 0, 7>(guid); data.WriteGuidBytes<7, 4>(guid); - data << uint32(0); // number of WorldMapArea.dbc entries to control world map shift * 2 + data << uint32(0); + //for (uint8 i = 0; i < worldMapAreaCount; ++i) + // data << uint16(0); // WorldMapArea.dbc id (controls map display) data.WriteGuidBytes<1>(guid); - data << uint32(phaseMask ? phaseFlags : 8); + data << uint32(phaseIds.size() ? 0 : 8); // flags (not phasemask) data.WriteGuidBytes<2, 6>(guid); - data << uint32(0); // number of inactive terrain swaps * 2 + data << uint32(0); // Inactive terrain swaps + //for (uint8 i = 0; i < inactiveSwapsCount; ++i) + // data << uint16(0); - data << uint32(phaseMask ? 2 : 0); // WRONG: number of Phase.dbc ids * 2 - if (phaseMask) - data << uint16(phaseMask); + data << uint32(phaseIds.size() * 2); // Phase.dbc ids + for (std::set::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr) + data << uint16(*itr); data.WriteGuidBytes<3, 0>(guid); - data << uint32(mapId ? 2 : 0); // number of terrains swaps * 2 - if (mapId) - data << uint16(mapId); + data << uint32(terrainswaps.size() * 2); // Active terrain swaps + for (std::set::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr) + data << uint16(*itr); data.WriteGuidBytes<5>(guid); SendPacket(&data); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 797401226..b11d0a429 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -255,7 +255,7 @@ class MANGOS_DLL_SPEC WorldSession void SendGroupInvite(Player* player, bool alreadyInGroup = false); void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2, 3); void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0); - void SendSetPhaseShift(uint32 phaseMask, uint16 mapId = 0); + void SendSetPhaseShift(std::set const& phaseIds, std::set const& terrainswaps); void SendQueryTimeResponse(); void SendRedirectClient(std::string& ip, uint16 port); diff --git a/src/game/debugcmds.cpp b/src/game/debugcmds.cpp index c5798f574..a0cafc491 100644 --- a/src/game/debugcmds.cpp +++ b/src/game/debugcmds.cpp @@ -31,6 +31,7 @@ #include "ObjectMgr.h" #include "ObjectGuid.h" #include "SpellMgr.h" +#include "PhaseMgr.h" bool ChatHandler::HandleDebugSendSpellFailCommand(char* args) { @@ -666,15 +667,34 @@ bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(char* args) if (!*args) return false; - char* m = strtok((char*)args, " "); + char* t = strtok((char*)args, " "); char* p = strtok(NULL, " "); - uint16 MapId = atoi(m); - uint32 PhaseShift = atoi(p); - m_session->SendSetPhaseShift(PhaseShift, MapId); + if (!t) + return false; + + std::set terrainswap; + std::set phaseId; + + terrainswap.insert((uint32)atoi(t)); + + if (p) + phaseId.insert((uint32)atoi(p)); + + m_session->SendSetPhaseShift(phaseId, terrainswap); return true; } +bool ChatHandler::HandleDebugPhaseCommand(char* args) +{ + Player* player = getSelectedPlayer(); + if (!player) + player = m_session->GetPlayer(); + + player->GetPhaseMgr()->SendDebugReportToPlayer(m_session->GetPlayer()); + return true; +} + // show animation bool ChatHandler::HandleDebugAnimCommand(char* args) { diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index 19bda2d22..b11ed5998 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -452,6 +452,7 @@ + @@ -626,6 +627,7 @@ + diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index b3cf5a080..7b8c9b7a6 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -156,6 +156,9 @@ World/Handlers + + World/Handlers + World/Handlers @@ -639,6 +642,9 @@ World/Handlers + + World/Handlers + World/Handlers diff --git a/win/VC110/game.vcxproj b/win/VC110/game.vcxproj index 92b8e2eec..f0d424a80 100644 --- a/win/VC110/game.vcxproj +++ b/win/VC110/game.vcxproj @@ -458,6 +458,7 @@ + @@ -632,6 +633,7 @@ + diff --git a/win/VC110/game.vcxproj.filters b/win/VC110/game.vcxproj.filters index b3cf5a080..7b8c9b7a6 100644 --- a/win/VC110/game.vcxproj.filters +++ b/win/VC110/game.vcxproj.filters @@ -156,6 +156,9 @@ World/Handlers + + World/Handlers + World/Handlers @@ -639,6 +642,9 @@ World/Handlers + + World/Handlers + World/Handlers diff --git a/win/VC120/bzip2.vcxproj b/win/VC120/bzip2.vcxproj index 7bedf4730..7ceea1076 100644 --- a/win/VC120/bzip2.vcxproj +++ b/win/VC120/bzip2.vcxproj @@ -19,12 +19,12 @@ StaticLibrary Unicode true - v110 + v120 StaticLibrary Unicode - v110 + v120 diff --git a/win/VC120/game.vcxproj b/win/VC120/game.vcxproj index 464cf7e7f..04c38e06b 100644 --- a/win/VC120/game.vcxproj +++ b/win/VC120/game.vcxproj @@ -458,6 +458,7 @@ + @@ -632,6 +633,7 @@ + diff --git a/win/VC120/game.vcxproj.filters b/win/VC120/game.vcxproj.filters index b3cf5a080..7b8c9b7a6 100644 --- a/win/VC120/game.vcxproj.filters +++ b/win/VC120/game.vcxproj.filters @@ -156,6 +156,9 @@ World/Handlers + + World/Handlers + World/Handlers @@ -639,6 +642,9 @@ World/Handlers + + World/Handlers + World/Handlers diff --git a/win/mangosdVC120.sln b/win/mangosdVC120.sln index 176b1d27d..a7772c25c 100644 --- a/win/mangosdVC120.sln +++ b/win/mangosdVC120.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio 2013 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "game", "VC120\game.vcxproj", "{1DC6C4DA-A028-41F3-877D-D5400C594F88}" ProjectSection(ProjectDependencies) = postProject {90297C34-F231-4DF4-848E-A74BCC0E40ED} = {90297C34-F231-4DF4-848E-A74BCC0E40ED}