Created
September 5, 2012 21:28
-
-
Save cyberium/3645128 to your computer and use it in GitHub Desktop.
AreaLock Rewrite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sql/mangos.sql b/sql/mangos.sql | |
index 6865fd9..5effceb 100644 | |
--- a/sql/mangos.sql | |
+++ b/sql/mangos.sql | |
@@ -141,7 +141,6 @@ CREATE TABLE `areatrigger_teleport` ( | |
`heroic_key2` mediumint(8) unsigned NOT NULL default '0', | |
`required_quest_done` int(11) unsigned NOT NULL default '0', | |
`required_quest_done_heroic` int(11) unsigned NOT NULL default '0', | |
- `required_failed_text` text, | |
`target_map` smallint(5) unsigned NOT NULL default '0', | |
`target_position_x` float NOT NULL default '0', | |
`target_position_y` float NOT NULL default '0', | |
@@ -4107,6 +4106,7 @@ INSERT INTO `mangos_string` VALUES | |
(1634,'|cffffff00Halaa is defenseless!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), | |
(1635,'|cffffff00The Horde has collected 200 silithyst!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), | |
(1636,'|cffffff00The Alliance has collected 200 silithyst!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); | |
+(1700, 'You can\'t enter Black Morass until you rescue Thrall from Durnholde Keep.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); | |
/*!40000 ALTER TABLE `mangos_string` ENABLE KEYS */; | |
UNLOCK TABLES; | |
diff --git a/sql/updates/mangos_areatrigger_teleport.sql b/sql/updates/mangos_areatrigger_teleport.sql | |
new file mode 100644 | |
index 0000000..22e75db | |
--- /dev/null | |
+++ b/sql/updates/mangos_areatrigger_teleport.sql | |
@@ -0,0 +1 @@ | |
+ALTER TABLE areatrigger_teleport DROP COLUMN required_failed_text; | |
diff --git a/sql/updates/mangos_mangos_string.sql b/sql/updates/mangos_mangos_string.sql | |
new file mode 100644 | |
index 0000000..c6941ac | |
--- /dev/null | |
+++ b/sql/updates/mangos_mangos_string.sql | |
@@ -0,0 +1,4 @@ | |
+DELETE FROM mangos_string WHERE entry = 1700; | |
+ | |
+INSERT INTO mangos_string VALUES | |
+(1700, 'You can\'t enter Black Morass until you rescue Thrall from Durnholde Keep.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); | |
diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h | |
index 85657be..fff446c 100644 | |
--- a/src/game/DBCEnums.h | |
+++ b/src/game/DBCEnums.h | |
@@ -511,4 +511,10 @@ enum VehicleSeatFlags | |
SEAT_FLAG_UNK26 = 0x80000000, // "AllowsInteraction" | |
}; | |
+enum MapDifficultyFlags | |
+{ | |
+ MAP_DIFFICULTY_FLAG_NONE = 0x00000001, // Not used in 3.3.5 | |
+ MAP_DIFFICULTY_FLAG_CONDITION = 0x00000002, // This map difficulty has condition | |
+}; | |
+ | |
#endif | |
diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp | |
index 79d29c9..840ba17 100644 | |
--- a/src/game/DBCStores.cpp | |
+++ b/src/game/DBCStores.cpp | |
@@ -463,8 +463,7 @@ void LoadDBCStores(const std::string& dataPath) | |
// fill data | |
for (uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i) | |
if (MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i)) | |
- sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = MapDifficulty(entry->resetTime, entry->maxPlayers); | |
- sMapDifficultyStore.Clear(); | |
+ sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = entry; | |
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sMovieStore, dbcPath, "Movie.dbc"); | |
LoadDBC(availableDbcLocales, bar, bad_dbc_files, sOverrideSpellDataStore, dbcPath, "OverrideSpellData.dbc"); | |
@@ -874,10 +873,10 @@ bool Map2ZoneCoordinates(float& x, float& y, uint32 zone) | |
return true; | |
} | |
-MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty) | |
+MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty) | |
{ | |
MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId, difficulty)); | |
- return itr != sMapDifficultyMap.end() ? &itr->second : NULL; | |
+ return itr != sMapDifficultyMap.end() ? itr->second : NULL; | |
} | |
PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level) | |
diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h | |
index 3e1871f..4f8d3a9 100644 | |
--- a/src/game/DBCStores.h | |
+++ b/src/game/DBCStores.h | |
@@ -61,8 +61,8 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT | |
bool Zone2MapCoordinates(float& x, float& y, uint32 zone); | |
bool Map2ZoneCoordinates(float& x, float& y, uint32 zone); | |
-typedef std::map < uint32/*pair32(map,diff)*/, MapDifficulty > MapDifficultyMap; | |
-MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); | |
+typedef std::map<uint32/*pair32(map,diff)*/, MapDifficultyEntry const*> MapDifficultyMap; | |
+MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); | |
// natural order for difficulties up-down iteration | |
// difficulties for dungeons/battleground ordered in normal way | |
diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h | |
index 23debe1..7fa26ba 100644 | |
--- a/src/game/DBCStructure.h | |
+++ b/src/game/DBCStructure.h | |
@@ -1276,8 +1276,8 @@ struct MapDifficultyEntry | |
// uint32 Id; // 0 m_ID | |
uint32 MapId; // 1 m_mapID | |
uint32 Difficulty; // 2 m_difficulty (for arenas: arena slot) | |
- // char* areaTriggerText[16]; // 3-18 m_message_lang (text showed when transfer to map failed) | |
- // uint32 textFlags; // 19 | |
+// char* areaTriggerText[16]; // 3-18 m_message_lang (text showed when transfer to map failed) | |
+ uint32 mapDifficultyFlags; // 19 | |
uint32 resetTime; // 20 m_raidDuration in secs, 0 if no fixed reset time | |
uint32 maxPlayers; // 21 m_maxPlayers some heroic versions have 0 when expected same amount as in normal version | |
// char* difficultyString; // 22 m_difficultystring | |
@@ -2105,15 +2105,6 @@ typedef std::set<uint32> PetFamilySpellsSet; | |
typedef std::map<uint32, PetFamilySpellsSet > PetFamilySpellsStore; | |
// Structures not used for casting to loaded DBC data and not required then packing | |
-struct MapDifficulty | |
-{ | |
- MapDifficulty() : resetTime(0), maxPlayers(0) {} | |
- MapDifficulty(uint32 _resetTime, uint32 _maxPlayers) : resetTime(_resetTime), maxPlayers(_maxPlayers) {} | |
- | |
- uint32 resetTime; // in secs, 0 if no fixed reset time | |
- uint32 maxPlayers; // some heroic dungeons have 0 when expect same value as in normal dificulty case | |
-}; | |
- | |
struct TalentSpellPos | |
{ | |
TalentSpellPos() : talent_id(0), rank(0) {} | |
diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h | |
index 4df1292..fe88d9f 100644 | |
--- a/src/game/DBCfmt.h | |
+++ b/src/game/DBCfmt.h | |
@@ -77,7 +77,7 @@ const char ItemSetEntryfmt[] = "dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiii | |
const char LockEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; | |
const char MailTemplateEntryfmt[] = "nxxxxxxxxxxxxxxxxxssssssssssssssssx"; | |
const char MapEntryfmt[] = "nxixxssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxixx"; | |
-const char MapDifficultyEntryfmt[] = "diixxxxxxxxxxxxxxxxxiix"; | |
+const char MapDifficultyEntryfmt[] = "diixxxxxxxxxxxxxxxxiiix"; | |
const char MovieEntryfmt[] = "nxx"; | |
const char OverrideSpellDatafmt[] = "niiiiiiiiiix"; | |
const char QuestFactionRewardfmt[] = "niiiiiiiiii"; | |
diff --git a/src/game/Group.cpp b/src/game/Group.cpp | |
index 2385bca..c3cb4a1 100644 | |
--- a/src/game/Group.cpp | |
+++ b/src/game/Group.cpp | |
@@ -1779,7 +1779,7 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, Player* player) | |
Difficulty difficulty = player->GetDifficulty(mapEntry->IsRaid()); | |
// some instances only have one difficulty | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty); | |
if (!mapDiff) | |
difficulty = DUNGEON_DIFFICULTY_NORMAL; | |
@@ -1793,7 +1793,7 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, Player* player) | |
InstanceGroupBind* Group::GetBoundInstance(Map* aMap, Difficulty difficulty) | |
{ | |
// some instances only have one difficulty | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(), difficulty); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(aMap->GetId(), difficulty); | |
if (!mapDiff) | |
return NULL; | |
diff --git a/src/game/Language.h b/src/game/Language.h | |
index a224528..b0fe8cb 100644 | |
--- a/src/game/Language.h | |
+++ b/src/game/Language.h | |
@@ -1011,7 +1011,9 @@ enum MangosStrings | |
LANG_OPVP_SI_CAPTURE_H = 1635, | |
LANG_OPVP_SI_CAPTURE_A = 1636, | |
- // FREE IDS 1700-9999 | |
+ LANG_TELEREQ_QUEST_BLACK_MORASS = 1700, | |
+ | |
+ // FREE IDS 1750-9999 | |
// Use for not-in-official-sources patches | |
// 10000-10999 | |
diff --git a/src/game/Map.cpp b/src/game/Map.cpp | |
index df89695..dc7e790 100644 | |
--- a/src/game/Map.cpp | |
+++ b/src/game/Map.cpp | |
@@ -824,21 +824,21 @@ void Map::UnloadAll(bool pForce) | |
} | |
} | |
-MapDifficulty const* Map::GetMapDifficulty() const | |
+MapDifficultyEntry const* Map::GetMapDifficulty() const | |
{ | |
return GetMapDifficultyData(GetId(), GetDifficulty()); | |
} | |
uint32 Map::GetMaxPlayers() const | |
{ | |
- if (MapDifficulty const* mapDiff = GetMapDifficulty()) | |
+ if (MapDifficultyEntry const* mapDiff = GetMapDifficulty()) | |
{ | |
if (mapDiff->maxPlayers || IsRegularDifficulty()) // Normal case (expect that regular difficulty always have correct maxplayers) | |
return mapDiff->maxPlayers; | |
else // DBC have 0 maxplayers for heroic instances with expansion < 2 | |
{ | |
// The heroic entry exists, so we don't have to check anything, simply return normal max players | |
- MapDifficulty const* normalDiff = GetMapDifficultyData(i_id, REGULAR_DIFFICULTY); | |
+ MapDifficultyEntry const* normalDiff = GetMapDifficultyData(i_id, REGULAR_DIFFICULTY); | |
return normalDiff ? normalDiff->maxPlayers : 0; | |
} | |
} | |
diff --git a/src/game/Map.h b/src/game/Map.h | |
index 133a3e4..895f5f3 100644 | |
--- a/src/game/Map.h | |
+++ b/src/game/Map.h | |
@@ -183,7 +183,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType> | |
bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } | |
uint32 GetMaxPlayers() const; // dependent from map difficulty | |
uint32 GetMaxResetDelay() const; // dependent from map difficulty | |
- MapDifficulty const* GetMapDifficulty() const; // dependent from map difficulty | |
+ MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty | |
bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } | |
// NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable | |
diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp | |
index 306e010..81e6814 100644 | |
--- a/src/game/MapManager.cpp | |
+++ b/src/game/MapManager.cpp | |
@@ -182,7 +182,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) | |
} | |
// The player has a heroic mode and tries to enter into instance which has no a heroic mode | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID, player->GetDifficulty(entry->map_type == MAP_RAID)); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(entry->MapID, player->GetDifficulty(entry->map_type == MAP_RAID)); | |
if (!mapDiff) | |
{ | |
bool isRegularTargetMap = player->GetDifficulty(entry->IsRaid()) == REGULAR_DIFFICULTY; | |
diff --git a/src/game/MapPersistentStateMgr.cpp b/src/game/MapPersistentStateMgr.cpp | |
index 979e506..b01a7ac 100644 | |
--- a/src/game/MapPersistentStateMgr.cpp | |
+++ b/src/game/MapPersistentStateMgr.cpp | |
@@ -319,7 +319,7 @@ bool BattleGroundPersistentState::CanBeUnload() const | |
//== DungeonResetScheduler functions ====================== | |
-uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff) | |
+uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficultyEntry const* mapDiff) | |
{ | |
if (!mapDiff || !mapDiff->resetTime) | |
return 0; | |
@@ -332,7 +332,7 @@ uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff) | |
return delay; | |
} | |
-time_t DungeonResetScheduler::CalculateNextResetTime(MapDifficulty const* mapDiff, time_t prevResetTime) | |
+time_t DungeonResetScheduler::CalculateNextResetTime(MapDifficultyEntry const* mapDiff, time_t prevResetTime) | |
{ | |
uint32 diff = sWorld.getConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR) * HOUR; | |
uint32 period = GetMaxResetTimeFor(mapDiff); | |
@@ -450,7 +450,7 @@ void DungeonResetScheduler::LoadResetTimes() | |
uint32 map_diff_pair = itr->first; | |
uint32 mapid = PAIR32_LOPART(map_diff_pair); | |
Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair)); | |
- MapDifficulty const* mapDiff = &itr->second; | |
+ MapDifficultyEntry const* mapDiff = itr->second; | |
// skip mapDiff without global reset time | |
if (!mapDiff->resetTime) | |
@@ -552,7 +552,7 @@ void DungeonResetScheduler::Update() | |
{ | |
// re-schedule the next/new global reset/warning | |
// calculate the next reset time | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(event.mapid, event.difficulty); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(event.mapid, event.difficulty); | |
MANGOS_ASSERT(mapDiff); | |
time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, resetTime); | |
@@ -857,7 +857,7 @@ void MapPersistentStateManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficu | |
if (!warn) | |
{ | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty); | |
if (!mapDiff || !mapDiff->resetTime) | |
{ | |
sLog.outError("MapPersistentStateManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid); | |
diff --git a/src/game/MapPersistentStateMgr.h b/src/game/MapPersistentStateMgr.h | |
index 5a4f8ca..571d1c4 100644 | |
--- a/src/game/MapPersistentStateMgr.h | |
+++ b/src/game/MapPersistentStateMgr.h | |
@@ -34,7 +34,7 @@ | |
struct InstanceTemplate; | |
struct MapEntry; | |
-struct MapDifficulty; | |
+struct MapDifficultyEntry; | |
struct GameObjectData; | |
struct CreatureData; | |
@@ -304,8 +304,8 @@ class DungeonResetScheduler | |
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0; | |
} | |
- static uint32 GetMaxResetTimeFor(MapDifficulty const* mapDiff); | |
- static time_t CalculateNextResetTime(MapDifficulty const* mapDiff, time_t prevResetTime); | |
+ static uint32 GetMaxResetTimeFor(MapDifficultyEntry const* mapDiff); | |
+ static time_t CalculateNextResetTime(MapDifficultyEntry const* mapDiff, time_t prevResetTime); | |
public: // modifiers | |
void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t) | |
{ | |
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp | |
index 2af78e0..558c24d 100644 | |
--- a/src/game/MiscHandler.cpp | |
+++ b/src/game/MiscHandler.cpp | |
@@ -690,42 +690,42 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) | |
recv_data >> Trigger_ID; | |
DEBUG_LOG("Trigger ID: %u", Trigger_ID); | |
+ Player* player = GetPlayer(); | |
- if (GetPlayer()->IsTaxiFlying()) | |
+ if (player->IsTaxiFlying()) | |
{ | |
- DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID: %u", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), Trigger_ID); | |
+ DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID); | |
return; | |
} | |
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); | |
if (!atEntry) | |
{ | |
- DEBUG_LOG("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID: %u", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), Trigger_ID); | |
+ DEBUG_LOG("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID); | |
return; | |
} | |
// delta is safe radius | |
const float delta = 5.0f; | |
- // check if player in the range of areatrigger | |
- Player* pl = GetPlayer(); | |
- if (!IsPointInAreaTriggerZone(atEntry, pl->GetMapId(), pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), delta)) | |
+ // check if player in the range of areatrigger | |
+ if (!IsPointInAreaTriggerZone(atEntry, player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), delta)) | |
{ | |
- DEBUG_LOG("Player '%s' (GUID: %u) too far, ignore Area Trigger ID: %u", pl->GetName(), pl->GetGUIDLow(), Trigger_ID); | |
+ DEBUG_LOG("Player '%s' (GUID: %u) too far, ignore Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID); | |
return; | |
} | |
- if (sScriptMgr.OnAreaTrigger(pl, atEntry)) | |
+ if (sScriptMgr.OnAreaTrigger(player, atEntry)) | |
return; | |
uint32 quest_id = sObjectMgr.GetQuestForAreaTrigger(Trigger_ID); | |
- if (quest_id && pl->isAlive() && pl->IsActiveQuest(quest_id)) | |
+ if (quest_id && player->isAlive() && player->IsActiveQuest(quest_id)) | |
{ | |
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id); | |
if (pQuest) | |
{ | |
- if (pl->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE) | |
- pl->AreaExploredOrEventHappens(quest_id); | |
+ if (player->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE) | |
+ player->AreaExploredOrEventHappens(quest_id); | |
} | |
} | |
@@ -733,19 +733,19 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) | |
if (sObjectMgr.IsTavernAreaTrigger(Trigger_ID)) | |
{ | |
// set resting flag we are in the inn | |
- if (pl->GetRestType() != REST_TYPE_IN_CITY) | |
- pl->SetRestType(REST_TYPE_IN_TAVERN, Trigger_ID); | |
+ if (player->GetRestType() != REST_TYPE_IN_CITY) | |
+ player->SetRestType(REST_TYPE_IN_TAVERN, Trigger_ID); | |
return; | |
} | |
- if (BattleGround* bg = pl->GetBattleGround()) | |
+ if (BattleGround* bg = player->GetBattleGround()) | |
{ | |
- bg->HandleAreaTrigger(pl, Trigger_ID); | |
+ bg->HandleAreaTrigger(player, Trigger_ID); | |
return; | |
} | |
- else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(pl->GetCachedZoneId())) | |
+ else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(player->GetCachedZoneId())) | |
{ | |
- if (outdoorPvP->HandleAreaTrigger(pl, Trigger_ID)) | |
+ if (outdoorPvP->HandleAreaTrigger(player, Trigger_ID)) | |
return; | |
} | |
@@ -758,111 +758,120 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) | |
if (!targetMapEntry) | |
return; | |
- if (!pl->isGameMaster()) | |
+ // ghost resurrected at enter attempt to dungeon with corpse (including fail enter cases) | |
+ if (!player->isAlive() && targetMapEntry->IsDungeon()) | |
{ | |
- // ghost resurrected at enter attempt to dungeon with corpse (including fail enter cases) | |
- if (!pl->isAlive() && targetMapEntry->IsDungeon()) | |
- { | |
- int32 corpseMapId = 0; | |
- if (Corpse* corpse = pl->GetCorpse()) | |
- corpseMapId = corpse->GetMapId(); | |
+ int32 corpseMapId = 0; | |
+ if (Corpse* corpse = player->GetCorpse()) | |
+ corpseMapId = corpse->GetMapId(); | |
- // check back way from corpse to entrance | |
- uint32 instance_map = corpseMapId; | |
- do | |
- { | |
- // most often fast case | |
- if (instance_map == targetMapEntry->MapID) | |
- break; | |
+ // check back way from corpse to entrance | |
+ uint32 instance_map = corpseMapId; | |
+ do | |
+ { | |
+ // most often fast case | |
+ if (instance_map == targetMapEntry->MapID) | |
+ break; | |
- InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(instance_map); | |
- instance_map = instance ? instance->parent : 0; | |
- } | |
- while (instance_map); | |
+ InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(instance_map); | |
+ instance_map = instance ? instance->parent : 0; | |
+ } | |
+ while (instance_map); | |
- // corpse not in dungeon or some linked deep dungeons | |
- if (!instance_map) | |
- { | |
- WorldPacket data(SMSG_AREA_TRIGGER_NO_CORPSE); | |
- pl->GetSession()->SendPacket(&data); | |
- return; | |
- } | |
+ // corpse not in dungeon or some linked deep dungeons | |
+ if (!instance_map) | |
+ { | |
+ WorldPacket data(SMSG_AREA_TRIGGER_NO_CORPSE); | |
+ player->GetSession()->SendPacket(&data); | |
+ return; | |
+ } | |
- // need find areatrigger to inner dungeon for landing point | |
- if (at->target_mapId != corpseMapId) | |
+ // need find areatrigger to inner dungeon for landing point | |
+ if (at->target_mapId != corpseMapId) | |
+ { | |
+ if (AreaTrigger const* corpseAt = sObjectMgr.GetMapEntranceTrigger(corpseMapId)) | |
{ | |
- if (AreaTrigger const* corpseAt = sObjectMgr.GetMapEntranceTrigger(corpseMapId)) | |
- { | |
- at = corpseAt; | |
- targetMapEntry = sMapStore.LookupEntry(at->target_mapId); | |
- } | |
+ at = corpseAt; | |
+ targetMapEntry = sMapStore.LookupEntry(at->target_mapId); | |
} | |
- | |
- // now we can resurrect player, and then check teleport requirements | |
- pl->ResurrectPlayer(0.5f); | |
- pl->SpawnCorpseBones(); | |
} | |
- // check trigger requirements | |
- bool missingItem = false; | |
- bool missingLevel = false; | |
- bool missingQuest = false; | |
- | |
- if (pl->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL)) | |
- missingLevel = true; | |
+ // now we can resurrect player, and then check teleport requirements | |
+ player->ResurrectPlayer(0.5f); | |
+ player->SpawnCorpseBones(); | |
+ } | |
- // must have one or the other, report the first one that's missing | |
- if (at->requiredItem) | |
+ // check trigger requirements | |
+ switch (player->GetAreaTriggerLockStatus(at, player->GetDifficulty(targetMapEntry->IsRaid()))) | |
+ { | |
+ case AREA_LOCKSTATUS_OK: | |
{ | |
- if (!pl->HasItemCount(at->requiredItem, 1) && | |
- (!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1))) | |
- missingItem = true; | |
+ player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT); | |
+ return; | |
} | |
- else if (at->requiredItem2 && !pl->HasItemCount(at->requiredItem2, 1)) | |
- missingItem = true; | |
- | |
- bool isRegularTargetMap = !targetMapEntry->IsDungeon() || pl->GetDifficulty(targetMapEntry->IsRaid()) == REGULAR_DIFFICULTY; | |
- | |
- if (!isRegularTargetMap) | |
+ case AREA_LOCKSTATUS_TOO_LOW_LEVEL: | |
{ | |
- if (at->heroicKey) | |
- { | |
- if (!pl->HasItemCount(at->heroicKey, 1) && | |
- (!at->heroicKey2 || !pl->HasItemCount(at->heroicKey2, 1))) | |
- missingItem = true; | |
- } | |
- else if (at->heroicKey2 && !pl->HasItemCount(at->heroicKey2, 1)) | |
- missingItem = true; | |
+ SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), at->requiredLevel); | |
+ return; | |
} | |
- | |
- if (!isRegularTargetMap) | |
+ case AREA_LOCKSTATUS_ZONE_IN_COMBAT: | |
{ | |
- if (at->requiredQuestHeroic && !pl->GetQuestRewardStatus(at->requiredQuestHeroic)) | |
- missingQuest = true; | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ZONE_IN_COMBAT); | |
+ return; | |
} | |
- else | |
+ case AREA_LOCKSTATUS_INSTANCE_IS_FULL: | |
{ | |
- if (at->requiredQuest && !pl->GetQuestRewardStatus(at->requiredQuest)) | |
- missingQuest = true; | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_MAX_PLAYERS); | |
+ return; | |
} | |
- | |
- if (missingItem || missingLevel || missingQuest) | |
+ case AREA_LOCKSTATUS_QUEST_NOT_COMPLETED: | |
+ if(at->target_mapId == 269) | |
{ | |
- // hack for "Opening of the Dark Portal" | |
- if (missingQuest && at->target_mapId == 269) | |
- SendAreaTriggerMessage("%s", at->requiredFailedText.c_str()); | |
- else if (missingQuest && targetMapEntry->IsContinent())// do not report anything for quest areatriggers | |
- return; | |
- // hack for TBC heroics | |
- else if (missingLevel && !targetMapEntry->IsRaid() && GetPlayer()->GetDifficulty(false) == DUNGEON_DIFFICULTY_HEROIC && targetMapEntry->addon == 1) | |
- SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), at->requiredLevel); | |
- else | |
- pl->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, pl->GetDifficulty(targetMapEntry->IsRaid())); | |
+ SendAreaTriggerMessage(GetMangosString(LANG_TELEREQ_QUEST_BLACK_MORASS)); | |
+ return; | |
+ } | |
+ // No break here! | |
+ case AREA_LOCKSTATUS_MISSING_ITEM: | |
+ { | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(targetMapEntry->MapID,player->GetDifficulty(targetMapEntry->IsRaid())); | |
+ if (mapDiff && mapDiff->mapDifficultyFlags & MAP_DIFFICULTY_FLAG_CONDITION) | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, mapDiff->Difficulty); | |
+ // do not report anything for quest areatriggers | |
+ DEBUG_LOG("HandleAreaTriggerOpcode: LockAreaStatus %u, do action", uint8(player->GetAreaTriggerLockStatus(at, player->GetDifficulty(targetMapEntry->IsRaid())))); | |
+ return; | |
+ } | |
+ case AREA_LOCKSTATUS_MISSING_DIFFICULTY: | |
+ { | |
+ Difficulty difficulty = player->GetDifficulty(targetMapEntry->IsRaid()); | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, difficulty > RAID_DIFFICULTY_10MAN_HEROIC ? RAID_DIFFICULTY_10MAN_HEROIC : difficulty); | |
+ return; | |
+ } | |
+ case AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION: | |
+ { | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_INSUF_EXPAN_LVL, targetMapEntry->Expansion()); | |
+ return; | |
+ } | |
+ case AREA_LOCKSTATUS_NOT_ALLOWED: | |
+ { | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_MAP_NOT_ALLOWED); | |
+ return; | |
+ } | |
+ case AREA_LOCKSTATUS_RAID_LOCKED: | |
+ { | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_NEED_GROUP); | |
+ return; | |
+ } | |
+ case AREA_LOCKSTATUS_UNKNOWN_ERROR: | |
+ { | |
+ player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ERROR); | |
+ return; | |
+ } | |
+ default: | |
+ { | |
+ DEBUG_LOG("HandleAreaTriggerOpcode: unhandled LockAreaStatus %u, do nothing", uint8(player->GetAreaTriggerLockStatus(at, player->GetDifficulty(targetMapEntry->IsRaid())))); | |
return; | |
} | |
} | |
- | |
- GetPlayer()->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT); | |
} | |
void WorldSession::HandleUpdateAccountData(WorldPacket& recv_data) | |
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp | |
index 265ceec..4687e93 100644 | |
--- a/src/game/MovementHandler.cpp | |
+++ b/src/game/MovementHandler.cpp | |
@@ -172,7 +172,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() | |
if (mInstance) | |
{ | |
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); | |
- if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff)) | |
+ if (MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff)) | |
{ | |
if (mapDiff->resetTime) | |
{ | |
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp | |
index 4ed6d39..b0b8e8e 100755 | |
--- a/src/game/ObjectMgr.cpp | |
+++ b/src/game/ObjectMgr.cpp | |
@@ -5480,8 +5480,8 @@ void ObjectMgr::LoadAreaTriggerTeleports() | |
uint32 count = 0; | |
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 | |
- QueryResult* result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_quest_done_heroic, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); | |
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 | |
+ QueryResult* result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_quest_done_heroic, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); | |
if (!result) | |
{ | |
@@ -5515,12 +5515,11 @@ void ObjectMgr::LoadAreaTriggerTeleports() | |
at.heroicKey2 = fields[5].GetUInt32(); | |
at.requiredQuest = fields[6].GetUInt32(); | |
at.requiredQuestHeroic = fields[7].GetUInt32(); | |
- at.requiredFailedText = fields[8].GetCppString(); | |
- at.target_mapId = fields[9].GetUInt32(); | |
- at.target_X = fields[10].GetFloat(); | |
- at.target_Y = fields[11].GetFloat(); | |
- at.target_Z = fields[12].GetFloat(); | |
- at.target_Orientation = fields[13].GetFloat(); | |
+ at.target_mapId = fields[8].GetUInt32(); | |
+ at.target_X = fields[9].GetFloat(); | |
+ at.target_Y = fields[10].GetFloat(); | |
+ at.target_Z = fields[11].GetFloat(); | |
+ at.target_Orientation = fields[12].GetFloat(); | |
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); | |
if (!atEntry) | |
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h | |
index ef9b3a2..56de465 100755 | |
--- a/src/game/ObjectMgr.h | |
+++ b/src/game/ObjectMgr.h | |
@@ -83,7 +83,6 @@ struct AreaTrigger | |
uint32 heroicKey2; | |
uint32 requiredQuest; | |
uint32 requiredQuestHeroic; | |
- std::string requiredFailedText; | |
uint32 target_mapId; | |
float target_X; | |
float target_Y; | |
diff --git a/src/game/Player.cpp b/src/game/Player.cpp | |
index 56ce8cf..c74f285 100644 | |
--- a/src/game/Player.cpp | |
+++ b/src/game/Player.cpp | |
@@ -17081,7 +17081,7 @@ void Player::_LoadBoundInstances(QueryResult* result) | |
continue; | |
} | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty)); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty)); | |
if (!mapDiff) | |
{ | |
sLog.outError("_LoadBoundInstances: player %s(%d) has bind to nonexistent difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); | |
@@ -17110,7 +17110,7 @@ void Player::_LoadBoundInstances(QueryResult* result) | |
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty) | |
{ | |
// some instances only have one difficulty | |
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty); | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty); | |
if (!mapDiff) | |
return NULL; | |
@@ -23340,3 +23340,86 @@ void Player::_fillGearScoreData(Item* item, GearScoreVec* gearScore, uint32& two | |
break; | |
} | |
} | |
+ | |
+AreaLockStatus Player::GetAreaTriggerLockStatus(AreaTrigger const* at, Difficulty difficulty) | |
+{ | |
+ if (!at) | |
+ return AREA_LOCKSTATUS_UNKNOWN_ERROR; | |
+ | |
+ MapEntry const* mapEntry = sMapStore.LookupEntry(at->target_mapId); | |
+ if (!mapEntry) | |
+ return AREA_LOCKSTATUS_UNKNOWN_ERROR; | |
+ | |
+ MapDifficultyEntry const* mapDiff = GetMapDifficultyData(at->target_mapId,difficulty); | |
+ if (mapEntry->IsDungeon() && !mapDiff) | |
+ return AREA_LOCKSTATUS_MISSING_DIFFICULTY; | |
+ | |
+ if (isGameMaster()) | |
+ return AREA_LOCKSTATUS_OK; | |
+ | |
+ if (GetSession()->Expansion() < mapEntry->Expansion()) | |
+ return AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION; | |
+ | |
+ if (getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL)) | |
+ return AREA_LOCKSTATUS_TOO_LOW_LEVEL; | |
+ | |
+ if (mapEntry->IsRaid() && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID)) | |
+ if (!GetGroup() || !GetGroup()->isRaidGroup()) | |
+ return AREA_LOCKSTATUS_RAID_LOCKED; | |
+ | |
+ // must have one or the other, report the first one that's missing | |
+ if (at->requiredItem) | |
+ { | |
+ if (!HasItemCount(at->requiredItem, 1) && | |
+ (!at->requiredItem2 || !HasItemCount(at->requiredItem2, 1))) | |
+ return AREA_LOCKSTATUS_MISSING_ITEM; | |
+ } | |
+ else if (at->requiredItem2 && !HasItemCount(at->requiredItem2, 1)) | |
+ return AREA_LOCKSTATUS_MISSING_ITEM; | |
+ | |
+ bool isRegularTargetMap = GetDifficulty(mapEntry->IsRaid()) == REGULAR_DIFFICULTY; | |
+ | |
+ if (!isRegularTargetMap) | |
+ { | |
+ if (at->heroicKey) | |
+ { | |
+ if(!HasItemCount(at->heroicKey, 1) && | |
+ (!at->heroicKey2 || !HasItemCount(at->heroicKey2, 1))) | |
+ return AREA_LOCKSTATUS_MISSING_ITEM; | |
+ } | |
+ else if (at->heroicKey2 && !HasItemCount(at->heroicKey2, 1)) | |
+ return AREA_LOCKSTATUS_MISSING_ITEM; | |
+ } | |
+ | |
+ if ((!isRegularTargetMap && | |
+ at->requiredQuest && !GetQuestRewardStatus(at->requiredQuest))) | |
+ return AREA_LOCKSTATUS_QUEST_NOT_COMPLETED; | |
+ | |
+ // If the map is not created, assume it is possible to enter it. | |
+ DungeonPersistentState* state = GetBoundInstanceSaveForSelfOrGroup(at->target_mapId); | |
+ Map* map = sMapMgr.FindMap(at->target_mapId, state ? state->GetInstanceId() : 0); | |
+ | |
+ // ToDo add achievement check | |
+ // ToDo add combat mode check | |
+ | |
+ if (map && map->IsDungeon()) | |
+ { | |
+ // cannot enter if the instance is full (player cap), GMs don't count | |
+ if (((DungeonMap*)map)->GetPlayersCountExceptGMs() >= ((DungeonMap*)map)->GetMaxPlayers()) | |
+ return AREA_LOCKSTATUS_INSTANCE_IS_FULL; | |
+ | |
+ InstancePlayerBind* pBind = GetBoundInstance(at->target_mapId, GetDifficulty(mapEntry->IsRaid())); | |
+ if (pBind && pBind->perm && pBind->state != state) | |
+ return AREA_LOCKSTATUS_HAS_BIND; | |
+ | |
+ if (pBind && pBind->perm && pBind->state != map->GetPersistentState()) | |
+ return AREA_LOCKSTATUS_HAS_BIND; | |
+ } | |
+ | |
+ return AREA_LOCKSTATUS_OK; | |
+}; | |
+ | |
+AreaLockStatus Player::GetAreaLockStatus(uint32 mapId, Difficulty difficulty) | |
+{ | |
+ return GetAreaTriggerLockStatus(sObjectMgr.GetMapEntranceTrigger(mapId), difficulty); | |
+}; | |
diff --git a/src/game/Player.h b/src/game/Player.h | |
index 82dcfdf..8026b4f 100644 | |
--- a/src/game/Player.h | |
+++ b/src/game/Player.h | |
@@ -54,6 +54,8 @@ class DungeonPersistentState; | |
class Spell; | |
class Item; | |
+struct AreaTrigger; | |
+ | |
typedef std::deque<Mail*> PlayerMails; | |
#define PLAYER_MAX_SKILLS 127 | |
@@ -2263,6 +2265,9 @@ class MANGOS_DLL_SPEC Player : public Unit | |
static void ConvertInstancesToGroup(Player* player, Group* group = NULL, ObjectGuid player_guid = ObjectGuid()); | |
DungeonPersistentState* GetBoundInstanceSaveForSelfOrGroup(uint32 mapid); | |
+ AreaLockStatus GetAreaLockStatus(uint32 mapId, Difficulty difficulty); | |
+ AreaLockStatus GetAreaTriggerLockStatus(AreaTrigger const* at, Difficulty difficulty); | |
+ | |
/*********************************************************/ | |
/*** GROUP SYSTEM ***/ | |
/*********************************************************/ | |
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h | |
index fd3ca8c..dcce340 100644 | |
--- a/src/game/SharedDefines.h | |
+++ b/src/game/SharedDefines.h | |
@@ -2984,6 +2984,23 @@ enum ActivateTaxiReply | |
ERR_TAXINOTSTANDING = 12 | |
}; | |
+enum AreaLockStatus | |
+{ | |
+ AREA_LOCKSTATUS_OK = 0, | |
+ AREA_LOCKSTATUS_UNKNOWN_ERROR = 1, | |
+ AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION = 2, | |
+ AREA_LOCKSTATUS_TOO_LOW_LEVEL = 3, | |
+ AREA_LOCKSTATUS_TOO_HIGH_LEVEL = 4, | |
+ AREA_LOCKSTATUS_RAID_LOCKED = 5, | |
+ AREA_LOCKSTATUS_QUEST_NOT_COMPLETED = 6, | |
+ AREA_LOCKSTATUS_MISSING_ITEM = 7, | |
+ AREA_LOCKSTATUS_MISSING_DIFFICULTY = 8, | |
+ AREA_LOCKSTATUS_ZONE_IN_COMBAT = 9, | |
+ AREA_LOCKSTATUS_INSTANCE_IS_FULL = 10, | |
+ AREA_LOCKSTATUS_NOT_ALLOWED = 11, | |
+ AREA_LOCKSTATUS_HAS_BIND = 12, | |
+}; | |
+ | |
// we need to stick to 1 version or half of the stuff will work for someone | |
// others will not and opposite | |
// will only support WoW, WoW:TBC and WoW:WotLK 3.3.5a client build 12340... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment