[12195] Improve AreaTrigger teleport requirement checks

Implement AreaLockStatus concept by rsa

Also drop basicly unneeded `areatrigger_teleport`.required_failed_text field.
This concept is still in testing phase, please feedback results of some glitches that might exist!

TODO: Use Player::GetAreaLockStatus or GetAreaTriggerLockStatus for other "CanEnter" checks as well.

Signed-off-by: Schmoozerd <schmoozerd@scriptdev2.com>
This commit is contained in:
cyberium 2012-09-06 16:40:31 +02:00 committed by Antz
parent 7901613472
commit 9022705faf
22 changed files with 304 additions and 162 deletions

View file

@ -16774,7 +16774,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);
@ -16803,7 +16803,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;
@ -23611,3 +23611,123 @@ void Player::SendRatedBGStats()
SendDirectMessage(&data);
}
AreaLockStatus Player::GetAreaTriggerLockStatus(AreaTrigger const* at, Difficulty difficulty, uint32& miscRequirement)
{
miscRequirement = 0;
if (!at)
return AREA_LOCKSTATUS_UNKNOWN_ERROR;
MapEntry const* mapEntry = sMapStore.LookupEntry(at->target_mapId);
if (!mapEntry)
return AREA_LOCKSTATUS_UNKNOWN_ERROR;
bool isRegularTargetMap = !mapEntry->IsDungeon() || GetDifficulty(mapEntry->IsRaid()) == REGULAR_DIFFICULTY;
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(at->target_mapId, difficulty);
if (mapEntry->IsDungeon() && !mapDiff)
return AREA_LOCKSTATUS_MISSING_DIFFICULTY;
// Expansion requirement
if (GetSession()->Expansion() < mapEntry->Expansion())
{
miscRequirement = mapEntry->Expansion();
return AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION;
}
// Gamemaster can always enter
if (isGameMaster())
return AREA_LOCKSTATUS_OK;
// Level Requirements
if (getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL))
{
miscRequirement = at->requiredLevel;
return AREA_LOCKSTATUS_TOO_LOW_LEVEL;
}
if (!isRegularTargetMap && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL) && getLevel() < uint32(maxLevelForExpansion[mapEntry->Expansion()]))
{
miscRequirement = maxLevelForExpansion[mapEntry->Expansion()];
return AREA_LOCKSTATUS_TOO_LOW_LEVEL;
}
// Raid Requirements
if (mapEntry->IsRaid() && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID))
if (!GetGroup() || !GetGroup()->isRaidGroup())
return AREA_LOCKSTATUS_RAID_LOCKED;
// Item Requirements: must have requiredItem OR requiredItem2, report the first one that's missing
if (at->requiredItem)
{
if (!HasItemCount(at->requiredItem, 1) &&
(!at->requiredItem2 || !HasItemCount(at->requiredItem2, 1)))
{
miscRequirement = at->requiredItem;
return AREA_LOCKSTATUS_MISSING_ITEM;
}
}
else if (at->requiredItem2 && !HasItemCount(at->requiredItem2, 1))
{
miscRequirement = at->requiredItem2;
return AREA_LOCKSTATUS_MISSING_ITEM;
}
// Heroic item requirements
if (!isRegularTargetMap && at->heroicKey)
{
if (!HasItemCount(at->heroicKey, 1) && (!at->heroicKey2 || !HasItemCount(at->heroicKey2, 1)))
{
miscRequirement = at->heroicKey;
return AREA_LOCKSTATUS_MISSING_ITEM;
}
}
else if (!isRegularTargetMap && at->heroicKey2 && !HasItemCount(at->heroicKey2, 1))
{
miscRequirement = at->heroicKey2;
return AREA_LOCKSTATUS_MISSING_ITEM;
}
// Quest Requirements
if (isRegularTargetMap && at->requiredQuest && !GetQuestRewardStatus(at->requiredQuest))
{
miscRequirement = at->requiredQuest;
return AREA_LOCKSTATUS_QUEST_NOT_COMPLETED;
}
if (!isRegularTargetMap && at->requiredQuestHeroic && !GetQuestRewardStatus(at->requiredQuestHeroic))
{
miscRequirement = at->requiredQuestHeroic;
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
// Map's state 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;
// In Combat check
if (map && map->GetInstanceData() && map->GetInstanceData()->IsEncounterInProgress())
return AREA_LOCKSTATUS_ZONE_IN_COMBAT;
// Bind Checks
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, uint32& miscRequirement)
{
return GetAreaTriggerLockStatus(sObjectMgr.GetMapEntranceTrigger(mapId), difficulty, miscRequirement);
};