Skip to content

Instantly share code, notes, and snippets.

@cyberium
Created September 7, 2012 15:30
Show Gist options
  • Save cyberium/3667184 to your computer and use it in GitHub Desktop.
Save cyberium/3667184 to your computer and use it in GitHub Desktop.
Rework map prerequisite check
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index dc7e790..5f2f80b 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -1249,29 +1249,6 @@ void DungeonMap::InitVisibilityDistance()
*/
bool DungeonMap::CanEnter(Player* player)
{
- if (player->GetMapRef().getTarget() == this)
- {
- sLog.outError("DungeonMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode());
- MANGOS_ASSERT(false);
- return false;
- }
-
- // cannot enter if the instance is full (player cap), GMs don't count
- uint32 maxPlayers = GetMaxPlayers();
- if (!player->isGameMaster() && GetPlayersCountExceptGMs() >= maxPlayers)
- {
- DETAIL_LOG("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName());
- player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
- return false;
- }
-
- // cannot enter while an encounter in the instance is in progress
- if (!player->isGameMaster() && GetInstanceData() && GetInstanceData()->IsEncounterInProgress() && player->GetMapId() != GetId())
- {
- player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
- return false;
- }
-
return Map::CanEnter(player);
}
@@ -1549,13 +1526,6 @@ void BattleGroundMap::InitVisibilityDistance()
bool BattleGroundMap::CanEnter(Player* player)
{
- if (player->GetMapRef().getTarget() == this)
- {
- sLog.outError("BGMap::CanEnter - player %u already in map!", player->GetGUIDLow());
- MANGOS_ASSERT(false);
- return false;
- }
-
if (player->GetBattleGroundId() != GetInstanceId())
return false;
@@ -1603,6 +1573,18 @@ void BattleGroundMap::UnloadAll(bool pForce)
Map::UnloadAll(pForce);
}
+bool Map::CanEnter(Player* player)
+{
+ if (player->GetMapRef().getTarget() == this)
+ {
+ sLog.outError("Map::CanEnter - player %u already in map!", player->GetGUIDLow());
+ MANGOS_ASSERT(false);
+ return false;
+ }
+
+ return true;
+}
+
/// Put scripts in the execution queue
bool Map::ScriptsStart(ScriptMapMapName const& scripts, uint32 id, Object* source, Object* target)
{
diff --git a/src/game/Map.h b/src/game/Map.h
index 4e908a4..4761fd0 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -171,7 +171,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
bool CheckGridIntegrity(Creature* c, bool moved) const;
uint32 GetInstanceId() const { return i_InstanceId; }
- virtual bool CanEnter(Player* /*player*/) { return true; }
+ virtual bool CanEnter(Player* /*player*/);
const char* GetMapName() const;
// have meaning only for instanced map (that have set real difficulty), NOT USE its for BaseMap
diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp
index 81e6814..bb6159d 100644
--- a/src/game/MapManager.cpp
+++ b/src/game/MapManager.cpp
@@ -149,62 +149,6 @@ Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const
return iter->second;
}
-/*
- checks that do not require a map to be created
- will send transfer error messages on fail
-*/
-bool MapManager::CanPlayerEnter(uint32 mapid, Player* player)
-{
- const MapEntry* entry = sMapStore.LookupEntry(mapid);
- if (!entry)
- return false;
-
- const char* mapName = entry->name[player->GetSession()->GetSessionDbcLocale()];
-
- if (entry->IsDungeon())
- {
- if (entry->IsRaid())
- {
- // GMs can avoid raid limitations
- if (!player->isGameMaster() && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID))
- {
- // can only enter in a raid group
- Group* group = player->GetGroup();
- if (!group || !group->isRaidGroup())
- {
- // probably there must be special opcode, because client has this string constant in GlobalStrings.lua
- // TODO: this is not a good place to send the message
- player->GetSession()->SendAreaTriggerMessage("You must be in a raid group to enter %s instance", mapName);
- DEBUG_LOG("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player->GetName(), mapName);
- return false;
- }
- }
- }
-
- // The player has a heroic mode and tries to enter into instance which has no a heroic mode
- MapDifficultyEntry const* mapDiff = GetMapDifficultyData(entry->MapID, player->GetDifficulty(entry->map_type == MAP_RAID));
- if (!mapDiff)
- {
- bool isRegularTargetMap = player->GetDifficulty(entry->IsRaid()) == REGULAR_DIFFICULTY;
-
- // Send aborted message
- // FIX ME: what about absent normal/heroic mode with specific players limit...
- player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, isRegularTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC);
- return false;
- }
-
- // TODO: move this to a map dependent location
- /*if(i_data && i_data->IsEncounterInProgress())
- {
- DEBUG_LOG("MAP: Player '%s' can't enter instance '%s' while an encounter is in progress.", player->GetName(), GetMapName());
- player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
- return(false);
- }*/
- }
-
- return true;
-}
-
void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId)
{
Guard _guard(*this);
@@ -223,8 +167,7 @@ void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId)
}
}
-void
-MapManager::Update(uint32 diff)
+void MapManager::Update(uint32 diff)
{
i_timer.Update(diff);
if (!i_timer.Passed())
diff --git a/src/game/MapManager.h b/src/game/MapManager.h
index 2fede2d..f9edc63 100644
--- a/src/game/MapManager.h
+++ b/src/game/MapManager.h
@@ -139,7 +139,6 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::
typedef std::map<uint32, TransportSet> TransportMap;
TransportMap m_TransportsByMap;
- bool CanPlayerEnter(uint32 mapid, Player* player);
void InitializeVisibilityDistanceInfo();
/* statistics */
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index feb0091..2fb4b86 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -801,60 +801,8 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
player->SpawnCorpseBones();
}
- // check trigger requirements
- uint32 miscRequirement = 0;
- AreaLockStatus lockStatus = player->GetAreaTriggerLockStatus(at, player->GetDifficulty(targetMapEntry->IsRaid()), miscRequirement);
- switch (lockStatus)
- {
- case AREA_LOCKSTATUS_OK:
- player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT);
- break;
- case AREA_LOCKSTATUS_TOO_LOW_LEVEL:
- SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), miscRequirement);
- break;
- case AREA_LOCKSTATUS_ZONE_IN_COMBAT:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ZONE_IN_COMBAT);
- break;
- case AREA_LOCKSTATUS_INSTANCE_IS_FULL:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_MAX_PLAYERS);
- break;
- case AREA_LOCKSTATUS_QUEST_NOT_COMPLETED:
- if (at->target_mapId == 269) // Exception for Black Morass
- {
- SendAreaTriggerMessage(GetMangosString(LANG_TELEREQ_QUEST_BLACK_MORASS));
- break;
- }
- else if (targetMapEntry->IsContinent()) // do not report anything for quest areatrigge
- {
- DEBUG_LOG("HandleAreaTriggerOpcode: LockAreaStatus %u, do not teleport, no message sent (trigger %u)", lockStatus, Trigger_ID);
- break;
- }
- // No break here!
- case AREA_LOCKSTATUS_MISSING_ITEM:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, player->GetDifficulty(targetMapEntry->IsRaid()));
- break;
- 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);
- break;
- }
- case AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_INSUF_EXPAN_LVL, miscRequirement);
- break;
- case AREA_LOCKSTATUS_NOT_ALLOWED:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_MAP_NOT_ALLOWED);
- break;
- case AREA_LOCKSTATUS_RAID_LOCKED:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_NEED_GROUP);
- break;
- case AREA_LOCKSTATUS_UNKNOWN_ERROR:
- player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ERROR);
- break;
- default:
- sLog.outError("HandleAreaTriggerOpcode: unhandled LockAreaStatus %u, when %s attempts to use area-trigger %u", lockStatus, player->GetGuidStr().c_str(), Trigger_ID);
- break;
- }
+ // teleport player (trigger requirement will be checked on TeleportTo)
+ player->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/Player.cpp b/src/game/Player.cpp
index 3e8b4cb..9d89f17 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -1641,23 +1641,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if (!InBattleGround() && mEntry->IsBattleGroundOrArena())
return false;
- // client without expansion support
- if (GetSession()->Expansion() < mEntry->Expansion())
- {
- DEBUG_LOG("Player %s using client without required expansion tried teleport to non accessible map %u", GetName(), mapid);
-
- if (GetTransport())
- RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
-
- SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL, mEntry->Expansion());
-
- return false; // normal client can't teleport to this map...
- }
- else
- {
- DEBUG_LOG("Player %s is being teleported to map %u", GetName(), mapid);
- }
-
if (Group* grp = GetGroup())
grp->SetPlayerMap(GetObjectGuid(), mapid);
@@ -1728,9 +1711,13 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// check if we can enter before stopping combat / removing pet / totems / interrupting spells
// Check enter rights before map getting to avoid creating instance copy for player
- // this check not dependent from map instance copy and same for all instance copies of selected map
- if (!sMapMgr.CanPlayerEnter(mapid, this))
+ uint32 miscRequirement = 0;
+ AreaLockStatus lockStatus = GetAreaLockStatus(mapid, this->GetDifficulty(mEntry->IsRaid()), miscRequirement);
+ if (lockStatus != AREA_LOCKSTATUS_OK)
+ {
+ SendTransferAbortedByLockStatus(mEntry, lockStatus, miscRequirement);
return false;
+ }
// If the map is not created, assume it is possible to enter it.
// It will be created in the WorldPortAck.
@@ -20416,20 +20403,70 @@ void Player::SendUpdateToOutOfRangeGroupMembers()
pet->ResetAuraUpdateMask();
}
-void Player::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg)
+void Player::SendTransferAbortedByLockStatus(MapEntry const* mapEntry, AreaLockStatus lockStatus, uint32 miscRequirement)
{
- WorldPacket data(SMSG_TRANSFER_ABORTED, 4 + 2);
- data << uint32(mapid);
- data << uint8(reason); // transfer abort reason
- switch (reason)
+ if (!mapEntry)
+ return;
+
+ switch (lockStatus)
{
- case TRANSFER_ABORT_INSUF_EXPAN_LVL:
- case TRANSFER_ABORT_DIFFICULTY:
- case TRANSFER_ABORT_UNIQUE_MESSAGE:
- data << uint8(arg);
+ case AREA_LOCKSTATUS_TOO_LOW_LEVEL:
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_LEVEL_MINREQUIRED), miscRequirement);
+ break;
+ case AREA_LOCKSTATUS_ZONE_IN_COMBAT:
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_ZONE_IN_COMBAT);
+ break;
+ case AREA_LOCKSTATUS_INSTANCE_IS_FULL:
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_MAX_PLAYERS);
+ break;
+ case AREA_LOCKSTATUS_QUEST_NOT_COMPLETED:
+ if (mapEntry->MapID == 269) // Exception for Black Morass
+ {
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_TELEREQ_QUEST_BLACK_MORASS));
break;
+ }
+ else if (mapEntry->IsContinent()) // do not report anything for quest areatrigge
+ {
+ DEBUG_LOG("SendTransferAbortedByLockStatus: LockAreaStatus %u, do not teleport, no message sent (mapId %u)", lockStatus, mapEntry->MapID);
+ break;
+ }
+ // No break here!
+ case AREA_LOCKSTATUS_MISSING_ITEM:
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_DIFFICULTY, GetDifficulty(mapEntry->IsRaid()));
+ break;
+ case AREA_LOCKSTATUS_MISSING_DIFFICULTY:
+ {
+ Difficulty difficulty = GetDifficulty(mapEntry->IsRaid());
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_DIFFICULTY, difficulty > RAID_DIFFICULTY_10MAN_HEROIC ? RAID_DIFFICULTY_10MAN_HEROIC : difficulty);
+ break;
+ }
+ case AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION:
+ if (GetTransport())
+ RepopAtGraveyard();
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_INSUF_EXPAN_LVL, miscRequirement);
+ break;
+ case AREA_LOCKSTATUS_NOT_ALLOWED:
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_MAP_NOT_ALLOWED);
+ break;
+ case AREA_LOCKSTATUS_RAID_LOCKED:
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_NEED_GROUP);
+ break;
+ case AREA_LOCKSTATUS_UNKNOWN_ERROR:
+ GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_ERROR);
+ break;
+ default:
+ if (lockStatus!=AREA_LOCKSTATUS_OK)
+ sLog.outError("SendTransfertAbortedByLockstatus: unhandled LockAreaStatus %u, when %s attempts to enter in map %u", lockStatus, GetGuidStr().c_str(), mapEntry->MapID);
+ break;
}
- GetSession()->SendPacket(&data);
+}
+
+void Player::SendTransferAbortedByLockStatus(uint32 mapId, AreaLockStatus lockStatus, uint32 miscRequirement)
+{
+ MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
+ if (!mapEntry)
+ return;
+ SendTransferAbortedByLockStatus(mapEntry, lockStatus, miscRequirement);
}
void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time)
diff --git a/src/game/Player.h b/src/game/Player.h
index 8bb267e..3532cd0 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -1047,7 +1047,8 @@ class MANGOS_DLL_SPEC Player : public Unit
void SendInitialPacketsBeforeAddToMap();
void SendInitialPacketsAfterAddToMap();
- void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0);
+ void SendTransferAbortedByLockStatus(uint32 mapId, AreaLockStatus lockStatus, uint32 miscRequirement = 0);
+ void SendTransferAbortedByLockStatus(MapEntry const* mapEntry, AreaLockStatus lockStatus, uint32 miscRequirement = 0);
void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time);
Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask);
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 610637b..b50e8ce 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -792,6 +792,23 @@ void WorldSession::SaveTutorialsData()
m_tutorialState = TUTORIALDATA_UNCHANGED;
}
+// Send chat information about aborted transfer (mostly used by Player::SendTransferAbortedByLockstatus())
+void WorldSession::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg)
+{
+ WorldPacket data(SMSG_TRANSFER_ABORTED, 4 + 2);
+ data << uint32(mapid);
+ data << uint8(reason); // transfer abort reason
+ switch (reason)
+ {
+ case TRANSFER_ABORT_INSUF_EXPAN_LVL:
+ case TRANSFER_ABORT_DIFFICULTY:
+ case TRANSFER_ABORT_UNIQUE_MESSAGE:
+ data << uint8(arg);
+ break;
+ }
+ SendPacket(&data);
+}
+
void WorldSession::ReadAddonsInfo(WorldPacket& data)
{
if (data.rpos() + 4 > data.size())
diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h
index 96586e0..800d140 100644
--- a/src/game/WorldSession.h
+++ b/src/game/WorldSession.h
@@ -251,6 +251,7 @@ class MANGOS_DLL_SPEC WorldSession
void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res);
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 phaseShift);
void SendQueryTimeResponse();
void SendRedirectClient(std::string& ip, uint16 port);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment