mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
[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:
+2
-1
@@ -1352,6 +1352,8 @@ public:
|
||||
void ClearPendingAdventureDoorClick() { safe_delete(adventure_door_timer); }
|
||||
void ClearPendingAdventureData();
|
||||
|
||||
bool CanEnterZone(std::string zone_short_name = "", int16 instance_version = -1);
|
||||
|
||||
int GetAggroCount();
|
||||
void IncrementAggroCount(bool raid_target = false);
|
||||
void DecrementAggroCount();
|
||||
@@ -1861,7 +1863,6 @@ private:
|
||||
void NPCSpawn(const Seperator* sep);
|
||||
uint32 GetEXPForLevel(uint16 level);
|
||||
|
||||
bool CanBeInZone();
|
||||
void SendLogoutPackets();
|
||||
void SendZoneInPackets();
|
||||
bool AddPacket(const EQApplicationPacket *, bool);
|
||||
|
||||
@@ -904,9 +904,9 @@ void Client::CompleteConnect()
|
||||
heroforge_wearchange_timer.Start(250);
|
||||
|
||||
// enforce some rules..
|
||||
if (!CanBeInZone()) {
|
||||
if (!CanEnterZone()) {
|
||||
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
|
||||
GoToSafeCoords(ZoneID("arena"), 0);
|
||||
GoToBind();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,13 +53,6 @@ void command_zone(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
// status checking
|
||||
auto min_status = content_db.GetMinStatus(zone_id, 0);
|
||||
if (c->Admin() < min_status) {
|
||||
c->Message(Chat::White, "Your status is not high enough to go to this zone.");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
// This block is necessary to clean up any bot objects owned by a Client
|
||||
if (zone_id != c->GetZoneID()) {
|
||||
|
||||
@@ -2926,6 +2926,16 @@ uint64 Lua_Client::CalcEXP(uint8 consider_level, bool ignore_modifiers) {
|
||||
return self->CalcEXP(consider_level, ignore_modifiers);
|
||||
}
|
||||
|
||||
bool Lua_Client::CanEnterZone(std::string zone_short_name) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CanEnterZone(zone_short_name);
|
||||
}
|
||||
|
||||
bool Lua_Client::CanEnterZone(std::string zone_short_name, int16 instance_version) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CanEnterZone(zone_short_name, instance_version);
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
int Lua_Client::GetBotRequiredLevel()
|
||||
@@ -3060,6 +3070,8 @@ luabind::scope lua_register_client() {
|
||||
.def("CalcEXP", (uint64(Lua_Client::*)(uint8))&Lua_Client::CalcEXP)
|
||||
.def("CalcEXP", (uint64(Lua_Client::*)(uint8,bool))&Lua_Client::CalcEXP)
|
||||
.def("CalcPriceMod", (float(Lua_Client::*)(Lua_Mob,bool))&Lua_Client::CalcPriceMod)
|
||||
.def("CanEnterZone", (bool(Lua_Client::*)(std::string))&Lua_Client::CanEnterZone)
|
||||
.def("CanEnterZone", (bool(Lua_Client::*)(std::string,int16))&Lua_Client::CanEnterZone)
|
||||
.def("CanHaveSkill", (bool(Lua_Client::*)(int))&Lua_Client::CanHaveSkill)
|
||||
.def("CashReward", &Lua_Client::CashReward)
|
||||
.def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName)
|
||||
|
||||
@@ -459,6 +459,8 @@ public:
|
||||
void SetEXPEnabled(bool is_exp_enabled);
|
||||
uint64 CalcEXP(uint8 consider_level);
|
||||
uint64 CalcEXP(uint8 consider_level, bool ignore_modifiers);
|
||||
bool CanEnterZone(std::string zone_short_name);
|
||||
bool CanEnterZone(std::string zone_short_name, int16 instance_version);
|
||||
|
||||
void ApplySpell(int spell_id);
|
||||
void ApplySpell(int spell_id, int duration);
|
||||
|
||||
@@ -2799,6 +2799,16 @@ void Perl_Client_SetEXPEnabled(Client* self, bool is_exp_enabled)
|
||||
self->SetEXPEnabled(is_exp_enabled);
|
||||
}
|
||||
|
||||
bool Perl_Client_CanEnterZone(Client* self, std::string zone_short_name)
|
||||
{
|
||||
return self->CanEnterZone(zone_short_name);
|
||||
}
|
||||
|
||||
bool Perl_Client_CanEnterZone(Client* self, std::string zone_short_name, int16 instance_version)
|
||||
{
|
||||
return self->CanEnterZone(zone_short_name, instance_version);
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
int Perl_Client_GetBotRequiredLevel(Client* self)
|
||||
@@ -2924,6 +2934,8 @@ void perl_register_client()
|
||||
package.add("CalcPriceMod", (float(*)(Client*))&Perl_Client_CalcPriceMod);
|
||||
package.add("CalcPriceMod", (float(*)(Client*, Mob*))&Perl_Client_CalcPriceMod);
|
||||
package.add("CalcPriceMod", (float(*)(Client*, Mob*, bool))&Perl_Client_CalcPriceMod);
|
||||
package.add("CanEnterZone", (bool(*)(Client*, std::string))&Perl_Client_CanEnterZone);
|
||||
package.add("CanEnterZone", (bool(*)(Client*, std::string, int16))&Perl_Client_CanEnterZone);
|
||||
package.add("CanHaveSkill", &Perl_Client_CanHaveSkill);
|
||||
package.add("CashReward", &Perl_Client_CashReward);
|
||||
package.add("ChangeLastName", &Perl_Client_ChangeLastName);
|
||||
|
||||
@@ -362,7 +362,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
ZoneChange_Struct* zc2 = (ZoneChange_Struct*)outapp->pBuffer;
|
||||
|
||||
if (ztz->response <= 0) {
|
||||
zc2->success = ZONE_ERROR_NOTREADY;
|
||||
zc2->success = ZoningMessage::ZoneNotReady;
|
||||
entity->CastToMob()->SetZone(ztz->current_zone_id, ztz->current_instance_id);
|
||||
entity->CastToClient()->SetZoning(false);
|
||||
entity->CastToClient()->SetLockSavePosition(false);
|
||||
|
||||
+51
-51
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user