diff --git a/common/ruletypes.h b/common/ruletypes.h index 5e62ba960..8b60ddb71 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -263,10 +263,11 @@ RULE_INT(Zone, ClientLinkdeadMS, 90000, "The time a client remains link dead on RULE_INT(Zone, GraveyardTimeMS, 1200000, "Time until a player corpse is moved to a zone's graveyard, if one is specified for the zone (milliseconds)") RULE_BOOL(Zone, EnableShadowrest, 1, "Enables or disables the Shadowrest zone feature for player corpses. Default is turned on") RULE_INT(Zone, AutoShutdownDelay, 5000, "How long a dynamic zone stays loaded while empty (milliseconds)") -RULE_INT(Zone, PEQZoneReuseTime, 900, "Time between two uses of the #peqzone command (seconds)") +RULE_INT(Zone, PEQZoneReuseTime, 900, "Seconds between two uses of the #peqzone command (Set to 0 to disable)") RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is Cursed Keeper's Blight") RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy") RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Setting if the command #peqzone applies the defined debuffs") +RULE_INT(Zone, PEQZoneHPRatio, 75, "Required HP Ratio to use #peqzone") RULE_REAL(Zone, HotZoneBonus, 0.75, "Value which is added to the experience multiplier. This also applies to AA experience.") RULE_INT(Zone, EbonCrystalItemID, 40902, "Item ID for Ebon Crystal") RULE_INT(Zone, RadiantCrystalItemID, 40903, "Item ID for Radiant Crystal") diff --git a/zone/client.cpp b/zone/client.cpp index 3fcd5f443..ed29755ab 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -9459,7 +9459,7 @@ void Client::CheckVirtualZoneLines() LogZonePoints( "Virtual Zone Box Sending player [{}] to [{}]", GetCleanName(), - zone_store.GetZoneLongName(virtual_zone_point.target_zone_id) + ZoneLongName(virtual_zone_point.target_zone_id) ); } } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c2b44842e..ef62a693b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12876,7 +12876,7 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) else zone_id = atoi(row[0]); - std::string zone_long_name = zone_store.GetZoneLongName(zone_id); + std::string zone_long_name = ZoneLongName(zone_id); Message(Chat::Yellow, "%d - %s", zone_id, zone_long_name.c_str()); } diff --git a/zone/command.cpp b/zone/command.cpp index 7da3253d3..858e6c5b8 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -273,7 +273,7 @@ int command_init(void) command_add("opcode", "- opcode management", AccountStatus::GMImpossible, command_opcode) || command_add("path", "- view and edit pathing", AccountStatus::GMMgmt, command_path) || command_add("peekinv", "[equip/gen/cursor/poss/limbo/curlim/trib/bank/shbank/allbank/trade/world/all] - Print out contents of your player target's inventory", AccountStatus::GMAdmin, command_peekinv) || - command_add("peqzone", "[zonename] - Go to specified zone, if you have > 75% health", AccountStatus::Player, command_peqzone) || + command_add("peqzone", "[Zone ID|Zone Short Name] - Teleports you to the specified zone if you meet the requirements.", AccountStatus::Player, command_peqzone) || command_add("permaclass", "[Class ID] - Change your or your player target's class, changed client is disconnected", AccountStatus::QuestTroupe, command_permaclass) || command_add("permagender", "[Gender ID] - Change your or your player target's gender", AccountStatus::QuestTroupe, command_permagender) || command_add("permarace", "[Race ID] - Change your or your player target's race", AccountStatus::QuestTroupe, command_permarace) || diff --git a/zone/gm_commands/peqzone.cpp b/zone/gm_commands/peqzone.cpp index 704e6dd1d..3c94965fc 100755 --- a/zone/gm_commands/peqzone.cpp +++ b/zone/gm_commands/peqzone.cpp @@ -2,74 +2,109 @@ void command_peqzone(Client *c, const Seperator *sep) { - uint32 timeleft = c->GetPTimers().GetRemainingTime(pTimerPeqzoneReuse) / 60; - - if (!c->GetPTimers().Expired(&database, pTimerPeqzoneReuse, false)) { - c->Message(Chat::Red, "You must wait %i minute(s) before using this ability again.", timeleft); + int arguments = sep->argnum; + if (!arguments) { + c->Message(Chat::White, "Usage: #peqzone [Zone ID] or #peqzone [Zone Short Name]"); return; } - if (c->GetHPRatio() < 75) { - c->Message(Chat::White, "You cannot use this command with less than 75 percent health."); + auto reuse_timer = RuleI(Zone, PEQZoneReuseTime); + if (reuse_timer) { + uint32 time_left = c->GetPTimers().GetRemainingTime(pTimerPeqzoneReuse); + if (!c->GetPTimers().Expired(&database, pTimerPeqzoneReuse, false)) { + c->Message( + Chat::White, + fmt::format( + "You must wait {} before using this command again.", + ConvertSecondsToTime(time_left) + ).c_str() + ); + return; + } + } + + auto hp_ratio = RuleI(Zone, PEQZoneHPRatio); + if (c->GetHPRatio() < hp_ratio) { + c->Message( + Chat::White, + fmt::format( + "You cannot use this command with less than {}%% health.", + hp_ratio + ).c_str() + ); return; } - //this isnt perfect, but its better... if ( - c->IsInvisible(c) - || c->IsRooted() - || c->IsStunned() - || c->IsMezzed() - || c->AutoAttackEnabled() - || c->GetInvul() - ) { + c->IsInvisible(c) || + c->IsRooted() || + c->IsStunned() || + c->IsMezzed() || + c->AutoAttackEnabled() || + c->GetInvul() + ) { c->Message(Chat::White, "You cannot use this command in your current state. Settle down and wait."); return; } - uint16 zoneid = 0; - uint8 destzone = 0; - if (sep->IsNumber(1)) { - zoneid = atoi(sep->arg[1]); - destzone = content_db.GetPEQZone(zoneid, 0); - if (destzone == 0) { - c->Message(Chat::Red, "You cannot use this command to enter that zone!"); - return; - } - if (zoneid == zone->GetZoneID()) { - c->Message(Chat::Red, "You cannot use this command on the zone you are in!"); - return; - } - } - else if (sep->arg[1][0] == 0 || sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4) || sep->IsNumber(5)) { - c->Message(Chat::White, "Usage: #peqzone [zonename]"); - c->Message(Chat::White, "Optional Usage: #peqzone [zoneid]"); + auto zone_id = ( + sep->IsNumber(1) ? + static_cast(std::stoul(sep->arg[1])) : + static_cast(ZoneID(sep->arg[1])) + ); + auto zone_short_name = ZoneName(zone_id); + auto zone_long_name = ZoneLongName(zone_id); + if ( + !zone_id || + !zone_short_name + ) { + c->Message( + Chat::White, + fmt::format( + "No zones were found matching '{}'.", + sep->arg[1] + ).c_str() + ); return; } - else { - zoneid = ZoneID(sep->arg[1]); - destzone = content_db.GetPEQZone(zoneid, 0); - if (zoneid == 0) { - c->Message(Chat::White, "Unable to locate zone '%s'", sep->arg[1]); - return; - } - if (destzone == 0) { - c->Message(Chat::Red, "You cannot use this command to enter that zone!"); - return; - } - if (zoneid == zone->GetZoneID()) { - c->Message(Chat::Red, "You cannot use this command on the zone you are in!"); - return; - } + + bool allows_peqzone = ( + content_db.GetPEQZone(zone_id, 0) ? + true : + false + ); + if (!allows_peqzone) { + c->Message( + Chat::White, + fmt::format( + "You cannot use this command to enter {} ({}).", + zone_long_name, + zone_short_name + ).c_str() + ); + return; } - if (RuleB (Zone, UsePEQZoneDebuffs)) { + if (zone_id == zone->GetZoneID()) { + c->Message( + Chat::White, + fmt::format( + "You are already in {} ({}).", + zone->GetLongName(), + zone->GetShortName() + ).c_str() + ); + return; + } + + if (RuleB(Zone, UsePEQZoneDebuffs)) { c->SpellOnTarget(RuleI(Zone, PEQZoneDebuff1), c); c->SpellOnTarget(RuleI(Zone, PEQZoneDebuff2), c); } - //zone to safe coords - c->GetPTimers().Start(pTimerPeqzoneReuse, RuleI(Zone, PEQZoneReuseTime)); - c->MovePC(zoneid, 0.0f, 0.0f, 0.0f, 0.0f, 0, ZoneToSafeCoords); -} + if (reuse_timer) { + c->GetPTimers().Start(pTimerPeqzoneReuse, reuse_timer); + } + c->MoveZone(zone_short_name); +} diff --git a/zone/gm_commands/showzonepoints.cpp b/zone/gm_commands/showzonepoints.cpp index f86dcd29e..d1e8c2428 100755 --- a/zone/gm_commands/showzonepoints.cpp +++ b/zone/gm_commands/showzonepoints.cpp @@ -16,7 +16,7 @@ void command_showzonepoints(Client *c, const Seperator *sep) c->SendChatLineBreak(); for (auto &virtual_zone_point : zone->virtual_zone_point_list) { - std::string zone_long_name = zone_store.GetZoneLongName(virtual_zone_point.target_zone_id); + std::string zone_long_name = ZoneLongName(virtual_zone_point.target_zone_id); c->Message( Chat::White, @@ -112,7 +112,7 @@ void command_showzonepoints(Client *c, const Seperator *sep) iterator.Reset(); while (iterator.MoreElements()) { ZonePoint *zone_point = iterator.GetData(); - std::string zone_long_name = zone_store.GetZoneLongName(zone_point->target_zone_id); + std::string zone_long_name = ZoneLongName(zone_point->target_zone_id); std::string node_name = fmt::format("ZonePoint To [{}]", zone_long_name); NPC::SpawnZonePointNodeNPC( diff --git a/zone/zone_store.cpp b/zone/zone_store.cpp index 467c3af25..67eaeb21e 100644 --- a/zone/zone_store.cpp +++ b/zone/zone_store.cpp @@ -80,6 +80,26 @@ const char *ZoneStore::GetZoneName(uint32 zone_id, bool error_unknown) return nullptr; } +/** + * @param zone_id + * @param error_unknown + * @return + */ +const char *ZoneStore::GetZoneLongName(uint32 zone_id, bool error_unknown) +{ + for (auto &z: zones) { + if (z.zoneidnumber == zone_id) { + return z.long_name.c_str(); + } + } + + if (error_unknown) { + return "UNKNOWN"; + } + + return nullptr; +} + /** * @param zone_id * @return diff --git a/zone/zone_store.h b/zone/zone_store.h index 8513c51fa..521ec63bb 100644 --- a/zone/zone_store.h +++ b/zone/zone_store.h @@ -41,6 +41,7 @@ public: std::string GetZoneName(uint32 zone_id); std::string GetZoneLongName(uint32 zone_id); const char *GetZoneName(uint32 zone_id, bool error_unknown = false); + const char *GetZoneLongName(uint32 zone_id, bool error_unknown = false); static void LoadContentFlags(); static void SetContentFlag(const std::string& content_flag_name, bool enabled); @@ -60,7 +61,13 @@ inline const char *ZoneName(uint32 zone_id, bool error_unknown = false) error_unknown ); } -inline const char *ZoneLongName(uint32 zone_id) { return zone_store.GetZoneLongName(zone_id).c_str(); } +inline const char *ZoneLongName(uint32 zone_id, bool error_unknown = false) +{ + return zone_store.GetZoneLongName( + zone_id, + error_unknown + ); +} inline ZoneRepository::Zone GetZone(uint32 zone_id, int version = 0) { return zone_store.GetZone(zone_id, version); }; inline ZoneRepository::Zone GetZone(const char *in_zone_name) { return zone_store.GetZone(in_zone_name); };