[Zones] Add Max Level Check to Zones. (#2714)

* [Zones] Add Max Level Check to Zones.

# Perl
- Add `$client->CanEnterZone(zone_short_name)`.
- Add `$client->CanEnterZone(zone_short_name, instance_version)`.

# Lua
- Add `client:CanEnterZone(zone_short_name)`.
- Add `client:CanEnterZone(zone_short_name, instance_version)`.

# Notes
- Allows operators to limit zones to a maximum level.
- Allows operators to see if a player can enter a zone before sending them.
- Keeps players from entering via `#peqzone` and `#zone` as well if they do not meet the requirements or are not high enough status to bypass the requirements.

* Cleanup.
This commit is contained in:
Alex King
2023-01-10 20:47:37 -05:00
committed by GitHub
parent 4c8b65ecc6
commit 0d23ffe5e5
13 changed files with 458 additions and 420 deletions
+51 -51
View File
@@ -297,30 +297,14 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
break;
};
//OK, now we should know where were going...
auto zoning_message = ZoningMessage::ZoneSuccess;
//Check some rules first.
int8 myerror = 1; //1 is succes
//not sure when we would use ZONE_ERROR_NOTREADY
//enforce min status and level
if (!ignore_restrictions && (Admin() < min_status || GetLevel() < zone_data->min_level)) {
myerror = ZONE_ERROR_NOEXPERIENCE;
}
if (!ignore_restrictions && !zone_data->flag_needed.empty()) {
//the flag needed string is not empty, meaning a flag is required.
if (Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(target_zone_id)) {
LogInfo(
"Client [{}] does not have the proper flag to enter [{}] ({})",
GetCleanName(),
ZoneName(target_zone_id),
target_zone_id
);
Message(Chat::Red, "You do not have the flag to enter %s.", target_zone_name);
myerror = ZONE_ERROR_NOEXPERIENCE;
}
// Check Minimum Status, Minimum Level, Maximum Level, and Zone Flag
if (
!ignore_restrictions &&
!CanEnterZone(ZoneName(target_zone_id), target_instance_version)
) {
zoning_message = ZoningMessage::ZoneNoExperience;
}
//TODO: ADVENTURE ENTRANCE CHECK
@@ -345,7 +329,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
);
if (!meets_zone_expansion_check) {
myerror = ZONE_ERROR_NOEXPANSION;
zoning_message = ZoningMessage::ZoneNoExpansion;
}
}
@@ -353,12 +337,11 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
LogInfo("[{}] Bypassing Expansion zone checks because GM status is set", GetCleanName());
}
if (myerror == 1) {
//we have successfully zoned
if (zoning_message == ZoningMessage::ZoneSuccess) {
DoZoneSuccess(zc, target_zone_id, target_instance_id, target_x, target_y, target_z, target_heading, ignore_restrictions);
} else {
LogError("Zoning [{}]: Rules prevent this char from zoning into [{}]", GetName(), target_zone_name);
SendZoneError(zc, myerror);
SendZoneError(zc, zoning_message);
}
}
@@ -1215,47 +1198,64 @@ void Client::SetPEQZoneFlag(uint32 zone_id) {
}
}
bool Client::CanBeInZone() {
bool Client::CanEnterZone(std::string zone_short_name, int16 instance_version) {
//check some critial rules to see if this char needs to be booted from the zone
//only enforce rules here which are serious enough to warrant being kicked from
//the zone
if (Admin() >= RuleI(GM, MinStatusToZoneAnywhere)) {
return (true);
return true;
}
float safe_x, safe_y, safe_z, safe_heading;
int16 min_status = AccountStatus::Player;
uint8 min_level = 0;
auto z = GetZoneVersionWithFallback(
ZoneID(zone->GetShortName()),
zone->GetInstanceVersion()
zone_short_name.empty() ? ZoneID(zone->GetShortName()) : ZoneID(zone_short_name),
instance_version == -1 ? zone->GetInstanceVersion() : instance_version
);
if (!z) {
return false;
}
safe_x = z->safe_x;
safe_y = z->safe_y;
safe_z = z->safe_z;
safe_heading = z->safe_heading;
min_status = z->min_status;
min_level = z->min_level;
if (GetLevel() < min_level) {
LogDebug("[CLIENT] Character does not meet min level requirement ([{}] < [{}])!", GetLevel(), min_level);
return (false);
if (GetLevel() < z->min_level) {
LogInfo(
"Character [{}] does not meet minimum level requirement ([{}] < [{}])!",
GetCleanName(),
GetLevel(),
z->min_level
);
return false;
}
if (Admin() < min_status) {
LogDebug("[CLIENT] Character does not meet min status requirement ([{}] < [{}])!", Admin(), min_status);
return (false);
if (GetLevel() > z->max_level) {
LogInfo(
"Character [{}] does not meet maximum level requirement ([{}] > [{}])!",
GetCleanName(),
GetLevel(),
z->max_level
);
return false;
}
if (Admin() < z->min_status) {
LogInfo(
"Character [{}] does not meet minimum status requirement ([{}] < [{}])!",
GetCleanName(),
Admin(),
z->min_status
);
return false;
}
if (!z->flag_needed.empty()) {
//the flag needed string is not empty, meaning a flag is required.
if (Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(zone->GetZoneID())) {
LogInfo("Character [{}] does not have the flag to be in this zone [{}]!", GetCleanName(), z->flag_needed);
if (
Admin() < minStatusToIgnoreZoneFlags &&
!HasZoneFlag(zone->GetZoneID())
) {
LogInfo(
"Character [{}] does not have the flag to be in this zone [{}]!",
GetCleanName(),
z->flag_needed
);
return false;
}
}