Skip to content

Commit

Permalink
[12155] Rewrite Checks required when entering a map
Browse files Browse the repository at this point in the history
Expected way from now on is:
- Test if a map can be entered with Player::GetAreaTriggerLockStatus
- IF this doesn't return AREA_LOCKSTATUS_OK, and if wanted,
  send the fail-message with Player::SendTransferAbortedByLockStatus function.

Please feedback any hidden problems!

Signed-off-by: Schmoozerd <schmoozerd@scriptdev2.com>
  • Loading branch information
cyberium authored and Schmoozerd committed Sep 9, 2012
1 parent 6bfcef0 commit 3d95311
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 197 deletions.
1 change: 0 additions & 1 deletion src/game/InstanceData.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class MANGOS_DLL_SPEC InstanceData
// Called every map update
virtual void Update(uint32 /*diff*/) {}

// Used by the map's CanEnter function.
// This is to prevent players from entering during boss encounters.
virtual bool IsEncounterInProgress() const { return false; };

Expand Down
52 changes: 14 additions & 38 deletions src/game/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,37 +1244,6 @@ void DungeonMap::InitVisibilityDistance()
m_VisibleDistance = World::GetMaxVisibleDistanceInInstances();
}

/*
Do map specific checks to see if the player can enter
*/
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);
}

/*
Do map specific checks and add the player to the map if successful.
*/
Expand Down Expand Up @@ -1549,19 +1518,14 @@ 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);
if (!Map::CanEnter(player))
return false;
}

if (player->GetBattleGroundId() != GetInstanceId())
return false;

// player number limit is checked in bgmgr, no need to do it here

return Map::CanEnter(player);
return true;
}

bool BattleGroundMap::Add(Player* player)
Expand Down Expand Up @@ -1603,6 +1567,18 @@ void BattleGroundMap::UnloadAll(bool pForce)
Map::UnloadAll(pForce);
}

bool Map::CanEnter(Player* player)
{
if (player->GetMapRef().getTarget() == this)
{

This comment has been minimized.

Copy link
@rsa

rsa Sep 9, 2012

Contributor

it's wrong. in some cases we give assert while TeleportNear.

This comment has been minimized.

Copy link
@Schmoozerd

Schmoozerd Sep 9, 2012

Member

Do you have any way to reproduce?

I saw such a possible problem and noted the TODO comment.
if ((GetMapId() == mapid) && (!m_transport)) // TODO the !m_transport might have unexpected effects when teleporting from transport to other place on same map

However this possible false assert is identical to old code, and it seems to not have been a problem there

sLog.outError("Map::CanEnter -%s already in map!", player->GetGuidStr().c_str());
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)
{
Expand Down
3 changes: 1 addition & 2 deletions src/game/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -384,7 +384,6 @@ class MANGOS_DLL_SPEC DungeonMap : public Map
bool Reset(InstanceResetMethod method);
void PermBindAllPlayers(Player* player);
void UnloadAll(bool pForce) override;
bool CanEnter(Player* player) override;
void SendResetWarnings(uint32 timeLeft) const;
void SetResetSchedule(bool on);

Expand Down
59 changes: 1 addition & 58 deletions src/game/MapManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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())
Expand Down
1 change: 0 additions & 1 deletion src/game/MapManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
56 changes: 2 additions & 54 deletions src/game/MiscHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, at);
}

void WorldSession::HandleUpdateAccountData(WorldPacket& recv_data)
Expand Down

0 comments on commit 3d95311

Please sign in to comment.