Skip to content

Instantly share code, notes, and snippets.

@cyberium
Created September 5, 2012 21:28
Show Gist options
  • Save cyberium/3645128 to your computer and use it in GitHub Desktop.
Save cyberium/3645128 to your computer and use it in GitHub Desktop.
AreaLock Rewrite
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