From c8f6dbb86d1c67ffe9a9ea1a1c3d0be3ebe23d47 Mon Sep 17 00:00:00 2001 From: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com> Date: Sat, 28 May 2022 14:35:05 -0400 Subject: [PATCH] [Commands] Cleanup #npcedit, #lastname, #title, and #titlesuffix Commands. (#2215) * [Commands] Cleanup #lastname, #npcedit, #title, and #titlesuffix Commands. - Cleanup messages and logic. * Update emu_constants.h * Update command.cpp * Update command.cpp * Cleanup of GetXName methods to not define map unnecessarily. * Update emu_constants.cpp * Update npcedit.cpp --- common/emu_constants.cpp | 98 +- common/emu_constants.h | 27 +- zone/command.cpp | 12 +- zone/gm_commands/lastname.cpp | 23 +- zone/gm_commands/npcedit.cpp | 3746 +++++++++++++++++++----------- zone/gm_commands/title.cpp | 16 +- zone/gm_commands/titlesuffix.cpp | 13 +- 7 files changed, 2577 insertions(+), 1358 deletions(-) diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index 4d5c40b64..ad720123c 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -22,7 +22,6 @@ #include "data_verification.h" #include "bodytypes.h" - int16 EQ::invtype::GetInvTypeSize(int16 inv_type) { static const int16 local_array[] = { POSSESSIONS_SIZE, @@ -189,15 +188,16 @@ const std::map& EQ::constants::GetLanguageMap() { LANG_HADAL, "Hadal" }, { LANG_UNKNOWN, "Unknown" } }; + return language_map; } std::string EQ::constants::GetLanguageName(int language_id) { if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) { - auto languages = EQ::constants::GetLanguageMap(); - return languages[language_id]; + return EQ::constants::GetLanguageMap().find(language_id)->second; } + return std::string(); } @@ -211,21 +211,22 @@ const std::map& EQ::constants::GetLDoNThemeMap() { LDoNThemes::RUJ, "Rujarkian Hills" }, { LDoNThemes::TAK, "Takish-Hiz" }, }; + return ldon_theme_map; } std::string EQ::constants::GetLDoNThemeName(uint32 theme_id) { if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) { - auto ldon_themes = EQ::constants::GetLDoNThemeMap(); - return ldon_themes[theme_id]; + return EQ::constants::GetLDoNThemeMap().find(theme_id)->second; } + return std::string(); } -const std::map& EQ::constants::GetFlyModeMap() +const std::map& EQ::constants::GetFlyModeMap() { - static const std::map flymode_map = { + static const std::map flymode_map = { { GravityBehavior::Ground, "Ground" }, { GravityBehavior::Flying, "Flying" }, { GravityBehavior::Levitating, "Levitating" }, @@ -233,15 +234,16 @@ const std::map& EQ::constants::GetFlyModeMap() { GravityBehavior::Floating, "Floating" }, { GravityBehavior::LevitateWhileRunning, "Levitating While Running" }, }; + return flymode_map; } -std::string EQ::constants::GetFlyModeName(uint8 flymode_id) +std::string EQ::constants::GetFlyModeName(int8 flymode_id) { if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) { - auto flymodes = EQ::constants::GetFlyModeMap(); - return flymodes[flymode_id]; + return EQ::constants::GetFlyModeMap().find(flymode_id)->second; } + return std::string(); } @@ -288,15 +290,16 @@ const std::map& EQ::constants::GetBodyTypeMap() { BT_InvisMan, "Invisible Man" }, { BT_Special, "Special" }, }; + return bodytype_map; } std::string EQ::constants::GetBodyTypeName(bodyType bodytype_id) { - auto bodytypes = EQ::constants::GetBodyTypeMap(); - if (!bodytypes[bodytype_id].empty()) { - return bodytypes[bodytype_id]; + if (EQ::constants::GetBodyTypeMap().find(bodytype_id) != EQ::constants::GetBodyTypeMap().end()) { + return EQ::constants::GetBodyTypeMap().find(bodytype_id)->second; } + return std::string(); } @@ -321,21 +324,23 @@ const std::map& EQ::constants::GetAccountStatusMap() { AccountStatus::GMImpossible, "GM Impossible" }, { AccountStatus::Max, "GM Max" } }; + return account_status_map; } std::string EQ::constants::GetAccountStatusName(uint8 account_status) { - auto account_statuses = EQ::constants::GetAccountStatusMap(); - std::string status_name; - for (auto status_level = account_statuses.rbegin(); status_level != account_statuses.rend(); ++status_level) { + for ( + auto status_level = EQ::constants::GetAccountStatusMap().rbegin(); + status_level != EQ::constants::GetAccountStatusMap().rend(); + ++status_level + ) { if (account_status >= status_level->first) { - status_name = status_level->second; - break; + return status_level->second; } } - return status_name; + return std::string(); } const std::map& EQ::constants::GetConsiderLevelMap() @@ -351,15 +356,16 @@ const std::map& EQ::constants::GetConsiderLevelMap() { ConsiderLevel::Threateningly, "Threateningly" }, { ConsiderLevel::Scowls, "Scowls" } }; + return consider_level_map; } std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level) { - auto consider_levels = EQ::constants::GetConsiderLevelMap(); - if (!consider_levels[faction_consider_level].empty()) { - return consider_levels[faction_consider_level]; + if (EQ::constants::GetConsiderLevelMap().find(faction_consider_level) != EQ::constants::GetConsiderLevelMap().end()) { + return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second; } + return std::string(); } @@ -371,14 +377,58 @@ const std::map& EQ::constants::GetEnvironmentalDamageMap() { EnvironmentalDamage::Falling, "Falling" }, { EnvironmentalDamage::Trap, "Trap" } }; + return damage_type_map; } std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type) { if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) { - auto damage_types = EQ::constants::GetEnvironmentalDamageMap(); - return damage_types[damage_type]; + return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second; } + + return std::string(); +} + +const std::map& EQ::constants::GetStuckBehaviorMap() +{ + static const std::map stuck_behavior_map = { + { StuckBehavior::RunToTarget, "Run To Target" }, + { StuckBehavior::WarpToTarget, "Warp To Target" }, + { StuckBehavior::TakeNoAction, "Take No Action" }, + { StuckBehavior::EvadeCombat, "Evade Combat" } + }; + + return stuck_behavior_map; +} + +std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id) +{ + if (EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) { + return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second; + } + + return std::string(); +} + +const std::map& EQ::constants::GetSpawnAnimationMap() +{ + static const std::map spawn_animation_map = { + { SpawnAnimations::Standing, "Standing" }, + { SpawnAnimations::Sitting, "Sitting" }, + { SpawnAnimations::Crouching, "Crouching" }, + { SpawnAnimations::Laying, "Laying" }, + { SpawnAnimations::Looting, "Looting" } + }; + + return spawn_animation_map; +} + +std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id) +{ + if (EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) { + return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second; + } + return std::string(); } diff --git a/common/emu_constants.h b/common/emu_constants.h index 80e7a0b05..941393316 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -221,7 +221,7 @@ namespace EQ stanceBurnAE }; - enum GravityBehavior : uint8 { + enum GravityBehavior : int8 { Ground, Flying, Levitating, @@ -237,6 +237,21 @@ namespace EQ Trap }; + enum StuckBehavior : uint8 { + RunToTarget, + WarpToTarget, + TakeNoAction, + EvadeCombat + }; + + enum SpawnAnimations : uint8 { + Standing, + Sitting, + Crouching, + Laying, + Looting + }; + const char *GetStanceName(StanceType stance_type); int ConvertStanceTypeToIndex(StanceType stance_type); @@ -246,8 +261,8 @@ namespace EQ extern const std::map& GetLDoNThemeMap(); std::string GetLDoNThemeName(uint32 theme_id); - extern const std::map& GetFlyModeMap(); - std::string GetFlyModeName(uint8 flymode_id); + extern const std::map& GetFlyModeMap(); + std::string GetFlyModeName(int8 flymode_id); extern const std::map& GetBodyTypeMap(); std::string GetBodyTypeName(bodyType bodytype_id); @@ -261,6 +276,12 @@ namespace EQ extern const std::map& GetEnvironmentalDamageMap(); std::string GetEnvironmentalDamageName(uint8 damage_type); + extern const std::map& GetStuckBehaviorMap(); + std::string GetStuckBehaviorName(uint8 behavior_id); + + extern const std::map& GetSpawnAnimationMap(); + std::string GetSpawnAnimationName(uint8 animation_id); + const int STANCE_TYPE_FIRST = stancePassive; const int STANCE_TYPE_LAST = stanceBurnAE; const int STANCE_TYPE_COUNT = stanceBurnAE; diff --git a/zone/command.cpp b/zone/command.cpp index 269d6d62e..822d3c98e 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -192,7 +192,7 @@ int command_init(void) command_add("kick", "[Character Name] - Disconnect a player by name", AccountStatus::GMLeadAdmin, command_kick) || command_add("kill", "Kill your target", AccountStatus::GMAdmin, command_kill) || command_add("killallnpcs", "[npc_name] - Kills all npcs by search name, leave blank for all attackable NPC's", AccountStatus::GMMgmt, command_killallnpcs) || - command_add("lastname", "[Last Name] - Set you or your player target's lastname", AccountStatus::Guide, command_lastname) || + command_add("lastname", "[Last Name] - Set your or your player target's last name (use \"-1\" to remove last name)", AccountStatus::Guide, command_lastname) || command_add("level", "[Level] - Set your target's level", AccountStatus::Steward, command_level) || command_add("list", "[npcs|players|corpses|doors|objects] [search] - Search entities", AccountStatus::ApprenticeGuide, command_list) || command_add("listpetition", "List petitions", AccountStatus::Guide, command_listpetition) || @@ -205,7 +205,7 @@ int command_init(void) command_add("memspell", "[Spell ID] [Spell Gem] - Memorize a Spell by ID to the specified Spell Gem for you or your target", AccountStatus::Guide, command_memspell) || command_add("merchant_close_shop", "Closes a merchant shop", AccountStatus::GMAdmin, command_merchantcloseshop) || command_add("merchant_open_shop", "Opens a merchants shop", AccountStatus::GMAdmin, command_merchantopenshop) || - command_add("modifynpcstat", "- Modifys a NPC's stats", AccountStatus::GMLeadAdmin, command_modifynpcstat) || + command_add("modifynpcstat", "Modifies an NPC's stats", AccountStatus::GMLeadAdmin, command_modifynpcstat) || command_add("motd", "[Message of the Day] - Set Message of the Day (leave empty to have no Message of the Day)", AccountStatus::GMLeadAdmin, command_motd) || command_add("movechar", "[Character ID|Character Name] [Zone ID|Zone Short Name] - Move an offline character to the specified zone", AccountStatus::Guide, command_movechar) || command_add("movement", "Various movement commands", AccountStatus::GMMgmt, command_movement) || @@ -230,8 +230,8 @@ int command_init(void) command_add("nukeitem", "[Item ID] - Removes the specified Item ID from you or your player target's inventory", AccountStatus::GMLeadAdmin, command_nukeitem) || command_add("object", "List|Add|Edit|Move|Rotate|Copy|Save|Undo|Delete - Manipulate static and tradeskill objects within the zone", AccountStatus::GMAdmin, command_object) || command_add("oocmute", "[0|1] - Enable or Disable Server OOC", AccountStatus::GMMgmt, command_oocmute) || - command_add("opcode", "- opcode management", AccountStatus::GMImpossible, command_opcode) || - command_add("path", "- view and edit pathing", AccountStatus::GMMgmt, command_path) || + 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", "[Zone ID|Zone Short Name] - Teleports you to the specified zone if you meet the requirements.", AccountStatus::Player, command_peqzone) || command_add("peqzone_flags", "displays the PEQZone Flags of you or your target", AccountStatus::Player, command_peqzone_flags) || @@ -315,8 +315,8 @@ int command_init(void) command_add("time", "[Hour] [Minute] - Set world time to specified time", AccountStatus::EQSupport, command_time) || command_add("timers", "Display persistent timers for target", AccountStatus::GMMgmt, command_timers) || command_add("timezone", "[Hour] [Minutes] - Set timezone (Minutes are optional)", AccountStatus::EQSupport, command_timezone) || - command_add("title", "[Remove|Title] [Save (0 = False, 1 = True)] - Set your or your player target's title (use remove to remove title, Save defaults to false if not used)", AccountStatus::Guide, command_title) || - command_add("titlesuffix", "[Remove|Title Suffix] [Save (0 = False, 1 = True)] - Set your or your player target's title suffix (use remove to remove title suffix, Save defaults to false if not used)", AccountStatus::Guide, command_titlesuffix) || + command_add("title", "[Title] - Set your or your player target's title (use \"-1\" to remove title)", AccountStatus::Guide, command_title) || + command_add("titlesuffix", "[Title Suffix] - Set your or your player target's title suffix (use \"-1\" to remove title suffix)", AccountStatus::Guide, command_titlesuffix) || command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", AccountStatus::GMLeadAdmin, command_traindisc) || command_add("trapinfo", "Gets infomation about the traps currently spawned in the zone.", AccountStatus::QuestTroupe, command_trapinfo) || command_add("tune", "Calculate statistical values related to combat.", AccountStatus::GMAdmin, command_tune) || diff --git a/zone/gm_commands/lastname.cpp b/zone/gm_commands/lastname.cpp index 81b3c2b85..070f5023a 100755 --- a/zone/gm_commands/lastname.cpp +++ b/zone/gm_commands/lastname.cpp @@ -9,20 +9,31 @@ void command_lastname(Client *c, const Seperator *sep) LogInfo("#lastname request from [{}] for [{}]", c->GetCleanName(), target->GetCleanName()); - std::string last_name = sep->arg[1]; + bool is_remove = !strcasecmp(sep->argplus[1], "-1"); + std::string last_name = is_remove ? "" : sep->argplus[1]; + if (last_name.size() > 64) { - c->Message(Chat::White, "Usage: #lastname [Last Name] (Last Name must be 64 characters or less)"); + c->Message(Chat::White, "Last name must be 64 characters or less."); return; } target->ChangeLastName(last_name); + c->Message( Chat::White, fmt::format( - "{} now {} a last name of '{}'.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "have" : "has", - last_name + "Last name has been {}{} for {}{}", + is_remove ? "removed" : "changed", + !is_remove ? " and saved" : "", + c->GetTargetDescription(target), + ( + is_remove ? + "." : + fmt::format( + " to '{}'.", + last_name + ) + ) ).c_str() ); } diff --git a/zone/gm_commands/npcedit.cpp b/zone/gm_commands/npcedit.cpp index 1332a61e6..435155831 100755 --- a/zone/gm_commands/npcedit.cpp +++ b/zone/gm_commands/npcedit.cpp @@ -1,552 +1,847 @@ #include "../client.h" #include "../groups.h" -#include "../mob_movement_manager.h" #include "../raids.h" #include "../raids.h" void command_npcedit(Client *c, const Seperator *sep) { if (!c->GetTarget() || !c->GetTarget()->IsNPC()) { - c->Message(Chat::White, "Error: Must have NPC targeted"); + c->Message(Chat::White, "You must target an NPC to use this command."); return; } - if (strcasecmp(sep->arg[1], "help") == 0) { + int arguments = sep->argnum; - c->Message(Chat::White, "Help File for #npcedit. Syntax for commands are:"); - c->Message(Chat::White, "#npcedit name - Sets an NPC's Name"); - c->Message(Chat::White, "#npcedit lastname - Sets an NPC's Lastname"); - c->Message(Chat::White, "#npcedit level - Sets an NPC's Level"); - c->Message(Chat::White, "#npcedit race - Sets an NPC's Race"); - c->Message(Chat::White, "#npcedit class - Sets an NPC's Class"); - c->Message(Chat::White, "#npcedit bodytype - Sets an NPC's Bodytype"); - c->Message(Chat::White, "#npcedit hp - Sets an NPC's Hitpoints"); - c->Message(Chat::White, "#npcedit mana - Sets an NPC's Mana"); - c->Message(Chat::White, "#npcedit gender - Sets an NPC's Gender"); - c->Message(Chat::White, "#npcedit texture - Sets an NPC's Texture"); - c->Message(Chat::White, "#npcedit helmtexture - Sets an NPC's Helmet Texture"); - c->Message(Chat::White, "#npcedit herosforgemodel - Sets an NPC's Hero's Forge Model"); - c->Message(Chat::White, "#npcedit size - Sets an NPC's Size"); - c->Message(Chat::White, "#npcedit hpregen - Sets an NPC's Hitpoints Regeneration Rate Per Tick"); - c->Message(Chat::White, "#npcedit hp_regen_per_second - Sets an NPC's HP regeneration per second"); - c->Message(Chat::White, "#npcedit manaregen - Sets an NPC's Mana Regeneration Rate Per Tick"); - c->Message(Chat::White, "#npcedit loottable - Sets an NPC's Loottable ID"); - c->Message(Chat::White, "#npcedit merchantid - Sets an NPC's Merchant ID"); - c->Message(Chat::White, "#npcedit alt_currency_id - Sets an NPC's Alternate Currency ID"); - c->Message(Chat::White, "#npcedit spell - Sets an NPC's Spells List ID"); - c->Message(Chat::White, "#npcedit npc_spells_effects_id - Sets an NPC's Spell Effects ID"); - c->Message(Chat::White, "#npcedit faction - Sets an NPC's Faction ID"); - c->Message(Chat::White, "#npcedit adventure_template_id - Sets an NPC's Adventure Template ID"); - c->Message(Chat::White, "#npcedit trap_template - Sets an NPC's Trap Template ID"); - c->Message(Chat::White, "#npcedit damage [minimum] [maximum] - Sets an NPC's Damage"); - c->Message(Chat::White, "#npcedit attackcount - Sets an NPC's Attack Count"); - c->Message(Chat::White, "#npcedit special_attacks - Sets an NPC's Special Attacks"); - c->Message(Chat::White, "#npcedit special_abilities - Sets an NPC's Special Abilities"); - c->Message(Chat::White, "#npcedit aggroradius - Sets an NPC's Aggro Radius"); - c->Message(Chat::White, "#npcedit assistradius - Sets an NPC's Assist Radius"); - c->Message(Chat::White, "#npcedit featuresave - Saves an NPC's current facial features to the database"); - c->Message(Chat::White, "#npcedit armortint_id - Sets an NPC's Armor Tint ID"); - c->Message(Chat::White, "#npcedit color [red] [green] [blue] - Sets an NPC's Red, Green, and Blue armor tint"); - c->Message(Chat::White, "#npcedit ammoidfile - Sets an NPC's Ammo ID File"); + bool is_help = (arguments == 0 || !strcasecmp(sep->arg[1], "help")); + + if (is_help) { + c->Message(Chat::White, "Usage: #npcedit name [Name] - Sets an NPC's Name"); + c->Message(Chat::White, "Usage: #npcedit lastname [Last Name] - Sets an NPC's Last Name"); + c->Message(Chat::White, "Usage: #npcedit level [Level] - Sets an NPC's Level"); + c->Message(Chat::White, "Usage: #npcedit race [Race ID] - Sets an NPC's Race"); + c->Message(Chat::White, "Usage: #npcedit class [Class ID] - Sets an NPC's Class"); + c->Message(Chat::White, "Usage: #npcedit bodytype [Body Type ID] - Sets an NPC's Bodytype"); + c->Message(Chat::White, "Usage: #npcedit hp [HP] - Sets an NPC's HP"); + c->Message(Chat::White, "Usage: #npcedit mana [Mana] - Sets an NPC's Mana"); + c->Message(Chat::White, "Usage: #npcedit gender [Gender ID] - Sets an NPC's Gender"); + c->Message(Chat::White, "Usage: #npcedit texture [Texture] - Sets an NPC's Texture"); + c->Message(Chat::White, "Usage: #npcedit helmtexture [Helmet Texture] - Sets an NPC's Helmet Texture"); + c->Message(Chat::White, "Usage: #npcedit herosforgemodel [Model Number] - Sets an NPC's Hero's Forge Model"); + c->Message(Chat::White, "Usage: #npcedit size [Size] - Sets an NPC's Size"); + c->Message(Chat::White, "Usage: #npcedit hpregen [HP Regen] - Sets an NPC's HP Regen Rate Per Tick"); + c->Message(Chat::White, "Usage: #npcedit hp_regen_per_second [HP Regen] - Sets an NPC's HP Regen Rate Per Second"); + c->Message(Chat::White, "Usage: #npcedit manaregen [Mana Regen] - Sets an NPC's Mana Regen Rate Per Tick"); + c->Message(Chat::White, "Usage: #npcedit loottable [Loottable ID] - Sets an NPC's Loottable ID"); + c->Message(Chat::White, "Usage: #npcedit merchantid [Merchant ID] - Sets an NPC's Merchant ID"); + c->Message(Chat::White, "Usage: #npcedit alt_currency_id [Alternate Currency ID] - Sets an NPC's Alternate Currency ID"); + c->Message(Chat::White, "Usage: #npcedit spell [Spell List ID] - Sets an NPC's Spells List ID"); + c->Message(Chat::White, "Usage: #npcedit npc_spells_effects_id [Spell Effects ID] - Sets an NPC's Spell Effects ID"); + c->Message(Chat::White, "Usage: #npcedit faction [Faction ID] - Sets an NPC's Faction ID"); + c->Message(Chat::White, "Usage: #npcedit adventure_template_id [Template ID] - Sets an NPC's Adventure Template ID"); + c->Message(Chat::White, "Usage: #npcedit trap_template [Template ID] - Sets an NPC's Trap Template ID"); + c->Message(Chat::White, "Usage: #npcedit damage [Minimum] [Maximum] - Sets an NPC's Damage"); + c->Message(Chat::White, "Usage: #npcedit attackcount [Attack Count] - Sets an NPC's Attack Count"); + c->Message(Chat::White, "Usage: #npcedit special_attacks [Special Attacks] - Sets an NPC's Special Attacks"); + c->Message(Chat::White, "Usage: #npcedit special_abilities [Special Abilities] - Sets an NPC's Special Abilities"); + c->Message(Chat::White, "Usage: #npcedit aggroradius [Radius] - Sets an NPC's Aggro Radius"); + c->Message(Chat::White, "Usage: #npcedit assistradius [Radius] - Sets an NPC's Assist Radius"); + c->Message(Chat::White, "Usage: #npcedit featuresave - Saves an NPC's current facial features to the database"); + c->Message(Chat::White, "Usage: #npcedit armortint_id [Armor Tint ID] - Sets an NPC's Armor Tint ID"); + c->Message(Chat::White, "Usage: #npcedit color [Red] [Green] [Blue] - Sets an NPC's Red, Green, and Blue armor tint"); + c->Message(Chat::White, "Usage: #npcedit ammoidfile [ID File] - Sets an NPC's Ammo ID File"); c->Message( Chat::White, - "#npcedit weapon [primary_model] [secondary_model] - Sets an NPC's Primary and Secondary Weapon Model" + "Usage: #npcedit weapon [Primary Model] [Secondary Model] - Sets an NPC's Primary and Secondary Weapon Model" ); - c->Message(Chat::White, "#npcedit meleetype [primary_type] [secondary_type] - Sets an NPC's Melee Types"); - c->Message(Chat::White, "#npcedit rangedtype - Sets an NPC's Ranged Type"); - c->Message(Chat::White, "#npcedit runspeed - Sets an NPC's Run Speed"); - c->Message(Chat::White, "#npcedit mr - Sets an NPC's Magic Resistance"); - c->Message(Chat::White, "#npcedit pr - Sets an NPC's Poison Resistance"); - c->Message(Chat::White, "#npcedit dr - Sets an NPC's Disease Resistance"); - c->Message(Chat::White, "#npcedit fr - Sets an NPC's Fire Resistance"); - c->Message(Chat::White, "#npcedit cr - Sets an NPC's Cold Resistance"); - c->Message(Chat::White, "#npcedit corrup - Sets an NPC's Corruption Resistance"); - c->Message(Chat::White, "#npcedit phr - Sets and NPC's Physical Resistance"); + c->Message(Chat::White, "Usage: #npcedit meleetype [Primary Type] [Secondary Type] - Sets an NPC's Melee Skill Types"); + c->Message(Chat::White, "Usage: #npcedit rangedtype [Type] - Sets an NPC's Ranged Skill Type"); + c->Message(Chat::White, "Usage: #npcedit runspeed [Run Speed] - Sets an NPC's Run Speed"); + c->Message(Chat::White, "Usage: #npcedit mr [Resistance] - Sets an NPC's Magic Resistance"); + c->Message(Chat::White, "Usage: #npcedit pr [Resistance] - Sets an NPC's Poison Resistance"); + c->Message(Chat::White, "Usage: #npcedit dr [Resistance] - Sets an NPC's Disease Resistance"); + c->Message(Chat::White, "Usage: #npcedit fr [Resistance] - Sets an NPC's Fire Resistance"); + c->Message(Chat::White, "Usage: #npcedit cr [Resistance] - Sets an NPC's Cold Resistance"); + c->Message(Chat::White, "Usage: #npcedit corrup [Resistance] - Sets an NPC's Corruption Resistance"); + c->Message(Chat::White, "Usage: #npcedit phr [Resistance] - Sets and NPC's Physical Resistance"); c->Message( Chat::White, - "#npcedit seeinvis - Sets an NPC's See Invisible Flag [0 = Cannot See Invisible, 1 = Can See Invisible]" + "Usage: #npcedit seeinvis [Flag] - Sets an NPC's See Invisible Flag [0 = Cannot See Invisible, 1 = Can See Invisible]" ); c->Message( Chat::White, - "#npcedit seeinvisundead - Sets an NPC's See Invisible vs. Undead Flag [0 = Cannot See Invisible vs. Undead, 1 = Can See Invisible vs. Undead]" + "Usage: #npcedit seeinvisundead [Flag] - Sets an NPC's See Invisible vs. Undead Flag [0 = Cannot See Invisible vs. Undead, 1 = Can See Invisible vs. Undead]" ); c->Message( Chat::White, - "#npcedit qglobal - Sets an NPC's Quest Global Flag [0 = Quest Globals Off, 1 = Quest Globals On]" + "Usage: #npcedit qglobal [Flag] - Sets an NPC's Quest Global Flag [0 = Quest Globals Off, 1 = Quest Globals On]" ); - c->Message(Chat::White, "#npcedit ac - Sets an NPC's Armor Class"); + c->Message(Chat::White, "Usage: #npcedit ac [Armor Class] - Sets an NPC's Armor Class"); c->Message( Chat::White, - "#npcedit npcaggro - Sets an NPC's NPC Aggro Flag [0 = Aggro NPCs Off, 1 = Aggro NPCs On]" + "Usage: #npcedit npcaggro [Flag] - Sets an NPC's NPC Aggro Flag [0 = Aggro NPCs Off, 1 = Aggro NPCs On]" ); - c->Message(Chat::White, "#npcedit spawn_limit - Sets an NPC's Spawn Limit Counter"); - c->Message(Chat::White, "#npcedit attackspeed - Sets an NPC's Attack Speed Modifier"); - c->Message(Chat::White, "#npcedit attackdelay - Sets an NPC's Attack Delay"); - c->Message(Chat::White, "#npcedit findable - Sets an NPC's Findable Flag [0 = Not Findable, 1 = Findable]"); - c->Message(Chat::White, "#npcedit str - Sets an NPC's Strength"); - c->Message(Chat::White, "#npcedit sta - Sets an NPC's Stamina"); - c->Message(Chat::White, "#npcedit dex - Sets an NPC's Dexterity"); - c->Message(Chat::White, "#npcedit agi - Sets an NPC's Agility"); - c->Message(Chat::White, "#npcedit int - Sets an NPC's Intelligence"); - c->Message(Chat::White, "#npcedit wis - Sets an NPC's Wisdom"); - c->Message(Chat::White, "#npcedit cha - Sets an NPC's Charisma"); + c->Message(Chat::White, "Usage: #npcedit spawn_limit [Limit] - Sets an NPC's Spawn Limit Counter"); + c->Message(Chat::White, "Usage: #npcedit attackspeed [Attack Speed] - Sets an NPC's Attack Speed Modifier"); + c->Message(Chat::White, "Usage: #npcedit attackdelay [Attack Delay] - Sets an NPC's Attack Delay"); + c->Message(Chat::White, "Usage: #npcedit findable [Flag] - Sets an NPC's Findable Flag [0 = Not Findable, 1 = Findable]"); + c->Message(Chat::White, "Usage: #npcedit str [Strength] - Sets an NPC's Strength"); + c->Message(Chat::White, "Usage: #npcedit sta [Stamina] - Sets an NPC's Stamina"); + c->Message(Chat::White, "Usage: #npcedit agi [Agility] - Sets an NPC's Agility"); + c->Message(Chat::White, "Usage: #npcedit dex [Dexterity] - Sets an NPC's Dexterity"); + c->Message(Chat::White, "Usage: #npcedit int [Intelligence] - Sets an NPC's Intelligence"); + c->Message(Chat::White, "Usage: #npcedit wis [Wisdom] - Sets an NPC's Wisdom"); + c->Message(Chat::White, "Usage: #npcedit cha [Charisma] - Sets an NPC's Charisma"); c->Message( Chat::White, - "#npcedit seehide - Sets an NPC's See Hide Flag [0 = Cannot See Hide, 1 = Can See Hide]" + "Usage: #npcedit seehide [Flag] - Sets an NPC's See Hide Flag [0 = Cannot See Hide, 1 = Can See Hide]" ); c->Message( Chat::White, - "#npcedit seeimprovedhide - Sets an NPC's See Improved Hide Flag [0 = Cannot See Improved Hide, 1 = Can See Improved Hide]" + "Usage: #npcedit seeimprovedhide [Flag] - Sets an NPC's See Improved Hide Flag [0 = Cannot See Improved Hide, 1 = Can See Improved Hide]" ); - c->Message(Chat::White, "#npcedit trackable - Sets an NPC's Trackable Flag [0 = Not Trackable, 1 = Trackable]"); - c->Message(Chat::White, "#npcedit atk - Sets an NPC's Attack"); - c->Message(Chat::White, "#npcedit accuracy - Sets an NPC's Accuracy"); - c->Message(Chat::White, "#npcedit avoidance - Sets an NPC's Avoidance"); - c->Message(Chat::White, "#npcedit slow_mitigation - Sets an NPC's Slow Mitigation"); - c->Message(Chat::White, "#npcedit version - Sets an NPC's Version"); - c->Message(Chat::White, "#npcedit maxlevel - Sets an NPC's Maximum Level"); - c->Message(Chat::White, "#npcedit scalerate - Sets an NPC's Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); + c->Message(Chat::White, "Usage: #npcedit trackable [Flag] - Sets an NPC's Trackable Flag [0 = Not Trackable, 1 = Trackable]"); + c->Message(Chat::White, "Usage: #npcedit atk [Attack] - Sets an NPC's Attack"); + c->Message(Chat::White, "Usage: #npcedit accuracy [Accuracy] - Sets an NPC's Accuracy"); + c->Message(Chat::White, "Usage: #npcedit avoidance [Avoidance] - Sets an NPC's Avoidance"); + c->Message(Chat::White, "Usage: #npcedit slow_mitigation [Slow Mitigation] - Sets an NPC's Slow Mitigation"); + c->Message(Chat::White, "Usage: #npcedit version [Version] - Sets an NPC's Version"); + c->Message(Chat::White, "Usage: #npcedit maxlevel [Max Level] - Sets an NPC's Maximum Level"); + c->Message(Chat::White, "Usage: #npcedit scalerate [Scale Rate] - Sets an NPC's Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); c->Message( Chat::White, - "#npcedit spellscale - Sets an NPC's Spell Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" + "Usage: #npcedit spellscale [Scale Rate] - Sets an NPC's Spell Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" ); c->Message( Chat::White, - "#npcedit healscale - Sets an NPC's Heal Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" + "Usage: #npcedit healscale [Scale Rate] - Sets an NPC's Heal Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" ); c->Message( Chat::White, - "#npcedit no_target - Sets an NPC's No Target Hotkey Flag [0 = Not Targetable with Target Hotkey, 1 = Targetable with Target Hotkey]" + "Usage: #npcedit no_target [Flag] - Sets an NPC's No Target Hotkey Flag [0 = Not Targetable with Target Hotkey, 1 = Targetable with Target Hotkey]" ); c->Message( Chat::White, - "#npcedit raidtarget - Sets an NPC's Raid Target Flag [0 = Not a Raid Target, 1 = Raid Target]" + "Usage: #npcedit raidtarget [Flag] - Sets an NPC's Raid Target Flag [0 = Not a Raid Target, 1 = Raid Target]" ); - c->Message(Chat::White, "#npcedit armtexture - Sets an NPC's Arm Texture"); - c->Message(Chat::White, "#npcedit bracertexture - Sets an NPC's Bracer Texture"); - c->Message(Chat::White, "#npcedit handtexture - Sets an NPC's Hand Texture"); - c->Message(Chat::White, "#npcedit legtexture - Sets an NPC's Leg Texture"); - c->Message(Chat::White, "#npcedit feettexture - Sets an NPC's Feet Texture"); - c->Message(Chat::White, "#npcedit walkspeed - Sets an NPC's Walk Speed"); - c->Message(Chat::White, "#npcedit show_name - Sets an NPC's Show Name Flag [0 = Hidden, 1 = Shown]"); + c->Message(Chat::White, "Usage: #npcedit armtexture [Texture] - Sets an NPC's Arm Texture"); + c->Message(Chat::White, "Usage: #npcedit bracertexture [Texture] - Sets an NPC's Bracer Texture"); + c->Message(Chat::White, "Usage: #npcedit handtexture [Texture] - Sets an NPC's Hand Texture"); + c->Message(Chat::White, "Usage: #npcedit legtexture [Texture] - Sets an NPC's Leg Texture"); + c->Message(Chat::White, "Usage: #npcedit feettexture [Texture] - Sets an NPC's Feet Texture"); + c->Message(Chat::White, "Usage: #npcedit walkspeed [Walk Speed] - Sets an NPC's Walk Speed"); + c->Message(Chat::White, "Usage: #npcedit show_name [Flag] - Sets an NPC's Show Name Flag [0 = Hidden, 1 = Shown]"); c->Message( Chat::White, - "#npcedit untargetable - Sets an NPC's Untargetable Flag [0 = Targetable, 1 = Untargetable]" + "Usage: #npcedit untargetable [Flag] - Sets an NPC's Untargetable Flag [0 = Targetable, 1 = Untargetable]" ); - c->Message(Chat::White, "#npcedit charm_ac - Sets an NPC's Armor Class while Charmed"); - c->Message(Chat::White, "#npcedit charm_min_dmg - Sets an NPC's Minimum Damage while Charmed"); - c->Message(Chat::White, "#npcedit charm_max_dmg - Sets an NPC's Max Damage while Charmed"); - c->Message(Chat::White, "#npcedit charm_attack_delay - Sets an NPC's Attack Delay while Charmed"); - c->Message(Chat::White, "#npcedit charm_accuracy_rating - Sets an NPC's Accuracy Rating while Charmed"); - c->Message(Chat::White, "#npcedit charm_avoidance_rating - Sets an NPC's Avoidance Rating while Charmed"); - c->Message(Chat::White, "#npcedit charm_atk - Sets an NPC's Attack while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_ac [Armor Class] - Sets an NPC's Armor Class while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_min_dmg [Damage] - Sets an NPC's Minimum Damage while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_max_dmg [Damage] - Sets an NPC's Maximum Damage while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_attack_delay [Attack Delay] - Sets an NPC's Attack Delay while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_accuracy_rating [Accuracy] - Sets an NPC's Accuracy Rating while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_avoidance_rating [Avoidance] - Sets an NPC's Avoidance Rating while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_atk [Attack] - Sets an NPC's Attack while Charmed"); c->Message( Chat::White, - "#npcedit skip_global_loot - Sets an NPC's Skip Global Loot Flag [0 = Don't Skip, 1 = Skip" + "Usage: #npcedit skip_global_loot [Flag] - Sets an NPC's Skip Global Loot Flag [0 = Don't Skip, 1 = Skip" ); c->Message( Chat::White, - "#npcedit rarespawn - Sets an NPC's Rare Spawn Flag [0 = Not a Rare Spawn, 1 = Rare Spawn]" + "Usage: #npcedit rarespawn [Flag] - Sets an NPC's Rare Spawn Flag [0 = Not a Rare Spawn, 1 = Rare Spawn]" ); c->Message( Chat::White, - "#npcedit stuck_behavior - Sets an NPC's Stuck Behavior [0 = Run to Target, 1 = Warp to Target, 2 = Take No Action, 3 = Evade Combat]" + "Usage: #npcedit stuck_behavior [Stuck Behavior] - Sets an NPC's Stuck Behavior [0 = Run to Target, 1 = Warp to Target, 2 = Take No Action, 3 = Evade Combat]" ); c->Message( Chat::White, - "#npcedit flymode - Sets an NPC's Fly Mode [0 = Ground, 1 = Flying, 2 = Levitating, 3 = Water, 4 = Floating, 5 = Levitating While Running]" + "Usage: #npcedit flymode [Fly Mode] - Sets an NPC's Fly Mode [0 = Ground, 1 = Flying, 2 = Levitating, 3 = Water, 4 = Floating, 5 = Levitating While Running]" ); c->Message( Chat::White, - "#npcedit always_aggro - Sets an NPC's Always Aggro Flag [0 = Does not Always Aggro, 1 = Always Aggro]" + "Usage: #npcedit always_aggro [Flag] - Sets an NPC's Always Aggro Flag [0 = Does not Always Aggro, 1 = Always Aggro]" ); c->Message( Chat::White, - "#npcedit exp_mod - Sets an NPC's Experience Modifier [50 = 50%, 100 = 100%, 200 = 200%]" + "Usage: #npcedit exp_mod [Modifier] - Sets an NPC's Experience Modifier [50 = 50%, 100 = 100%, 200 = 200%]" ); - c->Message(Chat::White, "#npcedit setanimation - Sets an NPC's Animation on Spawn (Stored in spawn2 table)"); + c->Message(Chat::White, "Usage: #npcedit setanimation [Animation ID] - Sets an NPC's Animation on Spawn (Stored in spawn2 table)"); c->Message( Chat::White, - "#npcedit respawntime - Sets an NPC's Respawn Timer in Seconds (Stored in spawn2 table)" + "Usage: #npcedit respawntime [Respawn Time] - Sets an NPC's Respawn Timer in Seconds (Stored in spawn2 table)" ); + return; } + std::string sub_command = sep->arg[1]; + uint32 npc_id = c->GetTarget()->CastToNPC()->GetNPCTypeID(); - if (strcasecmp(sep->arg[1], "name") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has the name '{}'.", npc_id, sep->arg[2]).c_str()); - std::string query = fmt::format("UPDATE npc_types SET name = '{}' WHERE id = {}", sep->arg[2], npc_id); - content_db.QueryDatabase(query); - return; - } + auto npc_id_string = fmt::format( + "NPC ID {}", + commify(std::to_string(npc_id)) + ); - if (strcasecmp(sep->arg[1], "lastname") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has the lastname '{}'.", npc_id, sep->arg[2]).c_str()); - std::string query = fmt::format("UPDATE npc_types SET lastname = '{}' WHERE id = {}", sep->arg[2], npc_id); - content_db.QueryDatabase(query); + if (!strcasecmp(sep->arg[1], "name")) { + std::string name = sep->argplus[2]; + if (!name.empty()) { + c->Message( + Chat::Yellow, + fmt::format( + "{} is now named '{}'.", + npc_id_string, + sep->argplus[2] + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET name = '{}' WHERE id = {}", + sep->argplus[2], + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit name [Name] - Sets an NPC's Name"); + } return; - } - - if (strcasecmp(sep->arg[1], "level") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} is now level {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET level = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "lastname")) { + std::string last_name = sep->argplus[2]; + if (!last_name.empty()) { + c->Message( + Chat::Yellow, + fmt::format( + "{} now has the lastname '{}'.", + npc_id_string, + sep->argplus[2] + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET lastname = '{}' WHERE id = {}", + sep->argplus[2], + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit lastname [Last Name] - Sets an NPC's Last Name"); + } return; - } - - if (strcasecmp(sep->arg[1], "race") == 0) { - auto race_id = atoi(sep->arg[2]); - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now a {} ({}).", npc_id, GetRaceIDName(race_id), race_id).c_str()); - std::string query = fmt::format("UPDATE npc_types SET race = {} WHERE id = {}", race_id, npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "level")) { + if (sep->IsNumber(2)) { + auto level = static_cast(std::stoul(sep->arg[2])); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now level {}.", + npc_id_string, + level + ).c_str() + ); + auto query = fmt::format("UPDATE npc_types SET level = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit level [Level] - Sets an NPC's Level"); + } return; - } - - if (strcasecmp(sep->arg[1], "class") == 0) { - auto class_id = atoi(sep->arg[2]); - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now a {} ({}).", npc_id, GetClassIDName(class_id), class_id).c_str()); - std::string query = fmt::format("UPDATE npc_types SET class = {} WHERE id = {}", class_id, npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "race")) { + if (sep->IsNumber(2)) { + auto race_id = static_cast(std::stoul(sep->arg[2])); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now a {} ({}).", + npc_id_string, + GetRaceIDName(race_id), + race_id + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET race = {} WHERE id = {}", + race_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit race [Race ID] - Sets an NPC's Race"); + } return; - } - - if (strcasecmp(sep->arg[1], "bodytype") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is now using Bodytype {} ({}).", - npc_id, - EQ::constants::GetBodyTypeName(static_cast(std::stoul(sep->arg[2]))), - std::stoul(sep->arg[2]) - ).c_str() - ); - std::string query = fmt::format( - "UPDATE npc_types SET bodytype = {} WHERE id = {}", - std::stoul(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "class")) { + if (sep->IsNumber(2)) { + auto class_id = static_cast(std::stoul(sep->arg[2])); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now a {} ({}).", + npc_id_string, + GetClassIDName(class_id), + class_id + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET class = {} WHERE id = {}", + class_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit class [Class ID] - Sets an NPC's Class"); + } return; - } - - if (strcasecmp(sep->arg[1], "hp") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now has {} Health.", - npc_id, - std::strtoll(sep->arg[2], nullptr, 10) - ).c_str() - ); - std::string query = fmt::format("UPDATE npc_types SET hp = {} WHERE id = {}", strtoull(sep->arg[2], nullptr, 10), npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "bodytype")) { + if (sep->IsNumber(2)) { + auto body_type_id = static_cast(std::stoul(sep->arg[2])); + auto body_type_name = EQ::constants::GetBodyTypeName(static_cast(body_type_id)); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Body Type {}.", + npc_id_string, + ( + !body_type_name.empty() ? + fmt::format( + "{} ({})", + body_type_name, + body_type_id + ) : + std::to_string(body_type_id) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET bodytype = {} WHERE id = {}", + body_type_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit bodytype [Body Type ID] - Sets an NPC's Bodytype"); + } return; - } - - if (strcasecmp(sep->arg[1], "mana") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Mana.", npc_id, std::strtoll(sep->arg[2], nullptr, 10)).c_str()); - std::string query = fmt::format("UPDATE npc_types SET mana = {} WHERE id = {}", std::strtoll(sep->arg[2], nullptr, 10), npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "hp")) { + if (sep->IsNumber(2)) { + auto hp = std::stoll(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Health.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET hp = {} WHERE id = {}", + hp, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit hp [HP] - Sets an NPC's HP"); + } return; - } - - if (strcasecmp(sep->arg[1], "gender") == 0) { - auto gender_id = atoi(sep->arg[2]); - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now a {} ({}).", npc_id, gender_id, GetGenderName(gender_id)).c_str()); - std::string query = fmt::format("UPDATE npc_types SET gender = {} WHERE id = {}", gender_id, npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "mana")) { + if (sep->IsNumber(2)) { + auto mana = std::stoll(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Mana.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET mana = {} WHERE id = {}", + mana, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit mana [Mana] - Sets an NPC's Mana"); + } return; - } - - if (strcasecmp(sep->arg[1], "texture") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} is now using Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET texture = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "gender")) { + if (sep->IsNumber(2)) { + auto gender_id = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now a {} ({}).", + npc_id_string, + gender_id, + GetGenderName(gender_id) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET gender = {} WHERE id = {}", + gender_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit gender [Gender ID] - Sets an NPC's Gender"); + } return; - } - - if (strcasecmp(sep->arg[1], "helmtexture") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Helmet Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET helmtexture = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "texture")) { + if (sep->IsNumber(2)) { + auto texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Texture {}.", + npc_id_string, + texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET texture = {} WHERE id = {}", + texture, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit texture [Texture] - Sets an NPC's Texture"); + } return; - } - - if (strcasecmp(sep->arg[1], "herosforgemodel") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Hero's Forge Model {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET herosforgemodel = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "size") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} is now Size {:.2f}.", npc_id, atof(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET size = {:.2f} WHERE id = {}", atof(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "hpregen") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now regenerates {} Health per Tick.", npc_id, std::strtoll(sep->arg[2], nullptr, 10)).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET hp_regen_rate = {} WHERE id = {}", - std::strtoll(sep->arg[2], nullptr, 10), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "hp_regen_per_second") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now regenerates {} HP per second.", - npc_id, - std::strtoll(sep->arg[2], nullptr, 10)).c_str() - ); - std::string query = fmt::format( - "UPDATE npc_types SET hp_regen_per_second = {} WHERE id = {}", - std::strtoll(sep->arg[2], nullptr, 10), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "manaregen") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now regenerates {} Mana per Tick.", npc_id, std::strtoll(sep->arg[2], nullptr, 10)).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET mana_regen_rate = {} WHERE id = {}", - std::strtoll(sep->arg[2], nullptr, 10), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "loottable") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using loottable ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET loottable_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "merchantid") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using merchant ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET merchant_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "alt_currency_id") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Alternate Currency ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET alt_currency_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "spell") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Spell List ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET npc_spells_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "npc_spells_effects_id") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using NPC Spells Effects ID {}.", npc_id, sep->arg[2]).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET npc_spells_effects_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "faction") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Faction ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET npc_faction_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "adventure_template_id") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Adventure Template ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET adventure_template_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "trap_template") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Trap Template ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET trap_template = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "damage") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now hits from {} to {} damage.", - npc_id, + } else if (!strcasecmp(sep->arg[1], "helmtexture")) { + if (sep->IsNumber(2)) { + auto helmet_texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Helmet Texture {}.", + npc_id_string, + helmet_texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET helmtexture = {} WHERE id = {}", atoi(sep->arg[2]), - atoi(sep->arg[3])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET mindmg = {}, maxdmg = {} WHERE id = {}", - atoi(sep->arg[2]), - atoi(sep->arg[3]), - npc_id - ); - content_db.QueryDatabase(query); + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit helmtexture [Helmet Texture] - Sets an NPC's Helmet Texture"); + } return; - } - - if (strcasecmp(sep->arg[1], "attackcount") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has an Attack Count of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET attack_count = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "herosforgemodel")) { + if (sep->IsNumber(2)) { + auto heros_forge_model = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Hero's Forge Model {}.", + npc_id_string, + heros_forge_model + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET herosforgemodel = {} WHERE id = {}", + heros_forge_model, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit herosforgemodel [Model Number] - Sets an NPC's Hero's Forge Model"); + } return; - } - - if (strcasecmp(sep->arg[1], "special_attacks") == 0) { + } else if (!strcasecmp(sep->arg[1], "size")) { + if (sep->IsNumber(2)) { + auto size = std::stof(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now Size {:.2f}.", + npc_id_string, + size + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET size = {:.2f} WHERE id = {}", + size, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit size [Size] - Sets an NPC's Size"); + } + return; + } else if (!strcasecmp(sep->arg[1], "hpregen")) { + if (sep->IsNumber(2)) { + auto hp_regen = std::stoll(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now regenerates {} Health per Tick.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET hp_regen_rate = {} WHERE id = {}", + hp_regen, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit hpregen [HP Regen] - Sets an NPC's HP Regen Rate Per Tick"); + } + return; + } else if (!strcasecmp(sep->arg[1], "hp_regen_per_second")) { + if (sep->IsNumber(2)) { + auto hp_regen_per_second = std::stoll(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now regenerates {} HP per Second.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET hp_regen_per_second = {} WHERE id = {}", + hp_regen_per_second, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit hp_regen_per_second [HP Regen] - Sets an NPC's HP Regen Rate Per Second"); + } + return; + } else if (!strcasecmp(sep->arg[1], "manaregen")) { + if (sep->IsNumber(2)) { + auto mana_regen = std::stoll(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now regenerates {} Mana per Tick.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET mana_regen_rate = {} WHERE id = {}", + mana_regen, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit manaregen [Mana Regen] - Sets an NPC's Mana Regen Rate Per Tick"); + } + return; + } else if (!strcasecmp(sep->arg[1], "loottable")) { + if (sep->IsNumber(2)) { + auto loottable_id = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Loottable ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET loottable_id = {} WHERE id = {}", + loottable_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit loottable [Loottable ID] - Sets an NPC's Loottable ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "merchantid")) { + if (sep->IsNumber(2)) { + auto merchant_id = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Merchant ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET merchant_id = {} WHERE id = {}", + merchant_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit merchantid [Merchant ID] - Sets an NPC's Merchant ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "alt_currency_id")) { + if (sep->IsNumber(2)) { + auto alternate_currency_id = std::stoul(sep->arg[2]); + auto alternate_currency_item_id = zone->GetCurrencyItemID(alternate_currency_id); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Alternate Currency {}.", + npc_id_string, + ( + alternate_currency_item_id ? + fmt::format( + "{} ({})", + database.CreateItemLink(alternate_currency_item_id), + alternate_currency_id + ) : + std::to_string(alternate_currency_id) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET alt_currency_id = {} WHERE id = {}", + alternate_currency_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit alt_currency_id [Alternate Currency ID] - Sets an NPC's Alternate Currency ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "spell")) { + if (sep->IsNumber(2)) { + auto spell_list_id = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Spell List ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET npc_spells_id = {} WHERE id = {}", + spell_list_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit spell [Spell List ID] - Sets an NPC's Spells List ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "npc_spells_effects_id")) { + if (sep->IsNumber(2)) { + auto spell_effects_id = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Spells Effects ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET npc_spells_effects_id = {} WHERE id = {}", + spell_effects_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit npc_spells_effects_id [Spell Effects ID] - Sets an NPC's Spell Effects ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "faction")) { + if (sep->IsNumber(2)) { + auto faction_id = std::stoi(sep->arg[2]); + auto faction_name = content_db.GetFactionName(faction_id); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Faction {}.", + npc_id_string, + ( + !faction_name.empty() ? + fmt::format( + "{} ({})", + faction_name, + faction_id + ) : + commify(sep->arg[2]) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET npc_faction_id = {} WHERE id = {}", + faction_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit faction [Faction ID] - Sets an NPC's Faction ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "adventure_template_id")) { + if (sep->IsNumber(2)) { + auto adventure_template_id = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Adventure Template ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET adventure_template_id = {} WHERE id = {}", + adventure_template_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit adventure_template_id [Template ID] - Sets an NPC's Adventure Template ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "trap_template")) { + if (sep->IsNumber(2)) { + auto trap_template = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Trap Template ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET trap_template = {} WHERE id = {}", + trap_template, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit trap_template [Template ID] - Sets an NPC's Trap Template ID"); + } + return; + } else if (!strcasecmp(sep->arg[1], "damage")) { + if (sep->IsNumber(2) && sep->IsNumber(3)) { + auto minimum_damage = std::stoul(sep->arg[2]); + auto maximum_damage = std::stoul(sep->arg[3]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now hits from {} to {} damage.", + npc_id_string, + commify(sep->arg[2]), + commify(sep->arg[3]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET mindmg = {}, maxdmg = {} WHERE id = {}", + minimum_damage, + maximum_damage, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit damage [Minimum] [Maximum] - Sets an NPC's Damage"); + } + return; + } else if (!strcasecmp(sep->arg[1], "attackcount")) { + if (sep->IsNumber(2)) { + auto attack_count = std::stoi(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has an Attack Count of {}.", + npc_id_string, + attack_count + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET attack_count = {} WHERE id = {}", + attack_count, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit attackcount [Attack Count] - Sets an NPC's Attack Count"); + } + return; + } else if (!strcasecmp(sep->arg[1], "special_attacks")) { + std::string special_attacks = sep->argplus[2]; c->Message( Chat::Yellow, fmt::format( - "NPC ID {} is now using the following Special Attacks '{}'.", - npc_id, - sep->arg[2] - ).c_str()); - std::string query = fmt::format( + "{} is now using the following Special Attacks '{}'.", + npc_id_string, + special_attacks + ).c_str() + ); + auto query = fmt::format( "UPDATE npc_types SET npcspecialattks = '{}' WHERE id = {}", - sep->arg[2], + special_attacks, npc_id ); content_db.QueryDatabase(query); return; - } - - if (strcasecmp(sep->arg[1], "special_abilities") == 0) { + } else if (!strcasecmp(sep->arg[1], "special_abilities")) { + std::string special_abilities = sep->argplus[2]; c->Message( Chat::Yellow, fmt::format( - "NPC ID {} is now using the following Special Abilities '{}'.", - npc_id, - sep->arg[2] - ).c_str()); - std::string query = fmt::format( + "{} is now using the following Special Abilities '{}'.", + npc_id_string, + special_abilities + ).c_str() + ); + auto query = fmt::format( "UPDATE npc_types SET special_abilities = '{}' WHERE id = {}", - sep->arg[2], + special_abilities, npc_id ); content_db.QueryDatabase(query); return; - } - - if (strcasecmp(sep->arg[1], "aggroradius") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has an Aggro Radius of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET aggroradius = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "aggroradius")) { + if (sep->IsNumber(2)) { + auto aggro_radius = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has an Aggro Radius of {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET aggroradius = {} WHERE id = {}", + aggro_radius, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit aggroradius [Radius] - Sets an NPC's Aggro Radius"); + } return; - } - - if (strcasecmp(sep->arg[1], "assistradius") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has an Assist Radius of {}", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET assistradius = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); + } else if (!strcasecmp(sep->arg[1], "assistradius")) { + if (sep->IsNumber(2)) { + auto assist_radius = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has an Assist Radius of {}", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET assistradius = {} WHERE id = {}", + assist_radius, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit assistradius [Radius] - Sets an NPC's Assist Radius"); + } return; - } - - if (strcasecmp(sep->arg[1], "featuresave") == 0) { + } else if (!strcasecmp(sep->arg[1], "featuresave")) { c->Message( Chat::Yellow, - fmt::format("NPC ID {} saved with all current body and facial feature settings.", npc_id).c_str()); - Mob *target = c->GetTarget(); - std::string query = fmt::format( + fmt::format( + "{} saved with all current body and facial feature settings.", + npc_id + ).c_str() + ); + auto target = c->GetTarget(); + auto query = fmt::format( "UPDATE npc_types " "SET luclin_haircolor = {}, luclin_beardcolor = {}, " "luclin_eyecolor = {}, luclin_eyecolor2 = {}, " @@ -574,871 +869,1718 @@ void command_npcedit(Client *c, const Seperator *sep) ); content_db.QueryDatabase(query); return; - } - - if (strcasecmp(sep->arg[1], "armortint_id") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Armor Tint ID {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET armortint_id = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "color") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now has {} Red, {} Green, and {} Blue tinting on their armor.", - npc_id, - atoi(sep->arg[2]), - atoi(sep->arg[3]), - atoi(sep->arg[4])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET armortint_red = {}, armortint_green = {}, armortint_blue = {} WHERE id = {}", - atoi(sep->arg[2]), - atoi(sep->arg[3]), - atoi(sep->arg[4]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "ammoidfile") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Ammo ID File {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET ammo_idfile = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "weapon") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} will have Model {} set to their Primary and Model {} set to their Secondary on repop.", - npc_id, - atoi(sep->arg[2]), - atoi(sep->arg[3])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET d_melee_texture1 = {}, d_melee_texture2 = {} WHERE id = {}", - atoi(sep->arg[2]), - atoi(sep->arg[3]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "meleetype") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now has a Primary Melee Type of {} and a Secondary Melee Type of {}.", - npc_id, - atoi(sep->arg[2]), - atoi(sep->arg[3])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET prim_melee_type = {}, sec_melee_type = {} WHERE id = {}", - atoi(sep->arg[2]), - atoi(sep->arg[3]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "rangedtype") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Ranged Type of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET ranged_type = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "runspeed") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now runs at {:.2f}.", npc_id, atof(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET runspeed = {:.2f} WHERE id = {}", - atof(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "mr") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Magic Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET MR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "pr") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Poison Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET PR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "dr") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Disease Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET DR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "fr") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Fire Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET FR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "cr") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Cold Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET CR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "corrup") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Corruption Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET corrup = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "phr") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Physical Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET PhR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "seeinvis") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} can {} See Invisible.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET see_invis = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "seeinvisundead") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} can {} See Invisible vs. Undead.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET see_invis_undead = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "qglobal") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} can {} use Quest Globals.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET qglobal = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "ac") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Armor Class.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET ac = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "npcaggro") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} will {} aggro other NPCs that have a hostile faction.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET npc_aggro = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "spawn_limit") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Spawn Limit of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET spawn_limit = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "attackspeed") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has an Attack Speed of {:.2f}.", npc_id, atof(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET attack_speed = {:.2f} WHERE id = {}", - atof(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "attackdelay") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has an Attack Delay of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET attack_delay = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "findable") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is {} Findable.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET findable = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "str") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Strength.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET STR = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "sta") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Stamina.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET STA = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "agi") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Agility.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET AGI = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "dex") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Dexterity.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET DEX = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "int") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Intelligence.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET _INT = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "wis") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Magic Resistance of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET WIS = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "cha") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Charisma.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET CHA = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "seehide") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} can {} See Hide.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET see_hide = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "seeimprovedhide") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} can {} See Improved Hide.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET see_improved_hide = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "trackable") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is {} Trackable.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET trackable = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "atk") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Attack.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET atk = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "accuracy") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Accuracy.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET accuracy = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "avoidance") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now has {} Avoidance.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET avoidance = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "slow_mitigation") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has {} Slow Mitigation.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET slow_mitigation = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "version") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} is now using Version {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET version = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "maxlevel") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Maximum Level of {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET maxlevel = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "scalerate") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Scaling Rate of {}%%.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET scalerate = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "spellscale") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Spell Scaling Rate of {}%%.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET spellscale = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "healscale") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has a Heal Scaling Rate of {}%%.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET healscale = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "no_target") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is {} Targetable with Target Hotkey.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET no_target_hotkey = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "raidtarget") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is {} designated as a Raid Target.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET raid_target = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "armtexture") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Arm Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET armtexture = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "bracertexture") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Bracer Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET bracertexture = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "handtexture") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Hand Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET handtexture = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "legtexture") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Leg Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET legtexture = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "feettexture") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} is now using Feet Texture {}.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET feettexture = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "walkspeed") == 0) { - c->Message(Chat::Yellow, fmt::format("NPC ID {} now walks at {:.2f}.", npc_id, atof(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET walkspeed = {:.2f} WHERE id = {}", - atof(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "show_name") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} will {} show their name.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format("UPDATE npc_types SET show_name = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "untargetable") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} will {} be untargetable.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET untargetable = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_ac") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has {} Armor Class while Charmed.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET charm_ac = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_min_dmg") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now does {} Minimum Damage while Charmed.", - npc_id, - atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET charm_min_dmg = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_max_dmg") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now does {} Maximum Damage while Charmed.", - npc_id, - atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET charm_max_dmg = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_attack_delay") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has {} Attack Delay while Charmed.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET charm_attack_delay = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_accuracy_rating") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now has {} Accuracy Rating while Charmed.", - npc_id, - atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET charm_accuracy_rating = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_avoidance_rating") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now has {} Avoidance Rating while Charmed.", - npc_id, - atoi(sep->arg[2])).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET charm_avoidance_rating = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "charm_atk") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has {} Attack while Charmed.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET charm_atk = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "skip_global_loot") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} will {} skip Global Loot.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET skip_global_loot = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "rarespawn") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is {} designated as a Rare Spawn.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET rare_spawn = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "stuck_behavior") == 0) { - auto behavior_id = atoi(sep->arg[2]); - std::string behavior_name = "Unknown"; - if (behavior_id == MobStuckBehavior::RunToTarget) { - behavior_name = "Run To Target"; - } - else if (behavior_id == MobStuckBehavior::WarpToTarget) { - behavior_name = "Warp To Target"; - } - else if (behavior_id == MobStuckBehavior::TakeNoAction) { - behavior_name = "Take No Action"; - } - else if (behavior_id == MobStuckBehavior::EvadeCombat) { - behavior_name = "Evade Combat"; - } - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is now using Stuck Behavior {} ({}).", - npc_id, - behavior_name, - behavior_id - ).c_str()); - std::string query = fmt::format("UPDATE npc_types SET stuck_behavior = {} WHERE id = {}", behavior_id, npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "flymode") == 0) { - auto flymode_id = static_cast(std::stoul(sep->arg[2])); - std::string flymode_name = EQ::constants::GetFlyModeName(flymode_id); - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} is now using Fly Mode {} ({}).", - npc_id, - flymode_name, - flymode_id - ).c_str() - ); - std::string query = fmt::format("UPDATE npc_types SET flymode = {} WHERE id = {}", flymode_id, npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "always_aggro") == 0) { - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} will {} Always Aggro.", - npc_id, - (atoi(sep->arg[2]) == 1 ? "now" : "no longer")).c_str()); - std::string query = fmt::format( - "UPDATE npc_types SET always_aggro = {} WHERE id = {}", - atoi(sep->arg[2]), - npc_id - ); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "exp_mod") == 0) { - c->Message( - Chat::Yellow, - fmt::format("NPC ID {} now has an Experience Modifier of {}%%.", npc_id, atoi(sep->arg[2])).c_str()); - std::string query = fmt::format("UPDATE npc_types SET exp_mod = {} WHERE id = {}", atoi(sep->arg[2]), npc_id); - content_db.QueryDatabase(query); - return; - } - - if (strcasecmp(sep->arg[1], "setanimation") == 0) { - int animation = 0; - std::string animation_name = "Unknown"; - if (sep->arg[2] && atoi(sep->arg[2]) <= 4) { - if (strcasecmp(sep->arg[2], "stand") == 0 || atoi(sep->arg[2]) == 0) { // Stand - animation = 0; - animation_name = "Standing"; - } - else if (strcasecmp(sep->arg[2], "sit") == 0 || atoi(sep->arg[2]) == 1) { // Sit - animation = 1; - animation_name = "Sitting"; - } - else if (strcasecmp(sep->arg[2], "crouch") == 0 || atoi(sep->arg[2]) == 2) { // Crouch - animation = 2; - animation_name = "Crouching"; - } - else if (strcasecmp(sep->arg[2], "dead") == 0 || atoi(sep->arg[2]) == 3) { // Dead - animation = 3; - animation_name = "Dead"; - } - else if (strcasecmp(sep->arg[2], "loot") == 0 || atoi(sep->arg[2]) == 4) { // Looting Animation - animation = 4; - animation_name = "Looting"; - } - } - else { - c->Message( - Chat::White, - "You must specify an Animation (0 = Stand, 1 = Sit, 2 = Crouch, 3 = Dead, 4 = Loot)" - ); - c->Message(Chat::White, "Example: #npcedit setanimation sit"); - c->Message(Chat::White, "Example: #npcedit setanimation 0"); - return; - } - - c->Message( - Chat::Yellow, - fmt::format( - "NPC ID {} now has their Spawn Animation set to {} ({}) on Spawn Group ID {}.", - npc_id, - animation_name, - animation, - c->GetTarget()->CastToNPC()->GetSpawnGroupId() - ).c_str() - ); - std::string query = fmt::format( - "UPDATE spawn2 SET animation = {} WHERE spawngroupID = {}", - animation, - c->GetTarget()->CastToNPC()->GetSpawnGroupId() - ); - content_db.QueryDatabase(query); - - c->GetTarget()->SetAppearance(EmuAppearance(animation)); - return; - } - - if (strcasecmp(sep->arg[1], "respawntime") == 0) { - if (sep->arg[2][0] && sep->IsNumber(sep->arg[2]) && atoi(sep->arg[2]) > 0) { + } else if (!strcasecmp(sep->arg[1], "armortint_id")) { + if (sep->IsNumber(2)) { + auto armor_tint_id = std::stoul(sep->arg[2]); c->Message( Chat::Yellow, fmt::format( - "NPC ID {} now has a Respawn Timer of {} Seconds on Spawn Group ID {}.", - npc_id, - atoi(sep->arg[2]), - c->GetTarget()->CastToNPC()->GetSpawnGroupId()).c_str()); - std::string query = fmt::format( - "UPDATE spawn2 SET respawntime = {} WHERE spawngroupID = {} AND version = {}", - atoi(sep->arg[2]), - c->GetTarget()->CastToNPC()->GetSpawnGroupId(), - zone->GetInstanceVersion()); + "{} is now using Armor Tint ID {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET armortint_id = {} WHERE id = {}", + armor_tint_id, + npc_id + ); content_db.QueryDatabase(query); - return; + } else { + c->Message(Chat::White, "Usage: #npcedit armortint_id [Armor Tint ID] - Sets an NPC's Armor Tint ID"); } - } + return; + } else if (!strcasecmp(sep->arg[1], "color")) { + if (sep->IsNumber(2)) { + auto red = static_cast(std::stoul(sep->arg[2])); + uint8 green = sep->IsNumber(3) ? std::stoul(sep->arg[3]) : 0; + uint8 blue = sep->IsNumber(4) ? std::stoul(sep->arg[4]) : 0; + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Red, {} Green, and {} Blue tinting on their armor.", + npc_id_string, + red, + green, + blue + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET armortint_red = {}, armortint_green = {}, armortint_blue = {} WHERE id = {}", + red, + green, + blue, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit color [Red] [Green] [Blue] - Sets an NPC's Red, Green, and Blue armor tint"); + } + return; + } else if (!strcasecmp(sep->arg[1], "ammoidfile")) { + if (sep->IsNumber(2)) { + auto ammo_id_file = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Ammo ID File {}.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET ammo_idfile = {} WHERE id = {}", + ammo_id_file, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit ammoidfile [ID File] - Sets an NPC's Ammo ID File"); + } + return; + } else if (!strcasecmp(sep->arg[1], "weapon")) { + if (sep->IsNumber(2)) { + auto primary_model = std::stoul(sep->arg[2]); + uint32 secondary_model = sep->IsNumber(3) ? std::stoul(sep->arg[3]) : 0; + c->Message( + Chat::Yellow, + fmt::format( + "{} will have Model {} set to their Primary and Model {} set to their Secondary on repop.", + npc_id_string, + commify(sep->arg[2]), + sep->IsNumber(3) ? commify(sep->arg[3]) : 0 + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET d_melee_texture1 = {}, d_melee_texture2 = {} WHERE id = {}", + primary_model, + secondary_model, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit weapon [Primary Model] [Secondary Model] - Sets an NPC's Primary and Secondary Weapon Model" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "meleetype")) { + if (sep->IsNumber(2)) { + auto primary_type = std::stoul(sep->arg[2]); + uint32 secondary_type = sep->IsNumber(3) ? std::stoul(sep->arg[3]) : 0; - if ((sep->arg[1][0] == 0 || strcasecmp(sep->arg[1], "*") == 0) || - ((c->GetTarget() == 0) || (c->GetTarget()->IsClient()))) { - c->Message(Chat::White, "Type #npcedit help for more info"); - } + auto primary_skill = EQ::skills::GetSkillName(static_cast(primary_type)); + auto secondary_skill = EQ::skills::GetSkillName(static_cast(secondary_type)); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Primary Melee Type of {} and a Secondary Melee Type of {}.", + npc_id_string, + ( + !primary_skill.empty() ? + fmt::format( + "{} ({})", + primary_skill, + primary_type + ) : + std::to_string(primary_type) + ), + ( + !secondary_skill.empty() ? + fmt::format( + "{} ({})", + secondary_skill, + secondary_type + ) : + std::to_string(secondary_type) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET prim_melee_type = {}, sec_melee_type = {} WHERE id = {}", + primary_type, + secondary_type, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit meleetype [Primary Type] [Secondary Type] - Sets an NPC's Melee Skill Types"); + } + return; + } else if (!strcasecmp(sep->arg[1], "rangedtype")) { + if (sep->IsNumber(2)) { + auto ranged_type = std::stoul(sep->arg[2]); + + auto ranged_skill = EQ::skills::GetSkillName(static_cast(ranged_type)); + + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Ranged Type of {}.", + npc_id_string, + ( + !ranged_skill.empty() ? + fmt::format( + "{} ({})", + ranged_skill, + ranged_type + ) : + std::to_string(ranged_type) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET ranged_type = {} WHERE id = {}", + ranged_type, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit rangedtype [Type] - Sets an NPC's Ranged Skill Type"); + } + return; + } else if (!strcasecmp(sep->arg[1], "runspeed")) { + if (sep->IsNumber(2)) { + auto run_speed = std::stof(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now runs at a Run Speed of {:.2f}.", + npc_id_string, + run_speed + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET runspeed = {:.2f} WHERE id = {}", + run_speed, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit runspeed [Run Speed] - Sets an NPC's Run Speed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "mr")) { + if (sep->IsNumber(2)) { + auto magic_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Magic Resistance of {}.", + npc_id_string, + magic_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET MR = {} WHERE id = {}", + magic_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit mr [Resistance] - Sets an NPC's Magic Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "pr")) { + if (sep->IsNumber(2)) { + auto poison_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Poison Resistance of {}.", + npc_id_string, + poison_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET PR = {} WHERE id = {}", + poison_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit pr [Resistance] - Sets an NPC's Poison Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "dr")) { + if (sep->IsNumber(2)) { + auto disease_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Disease Resistance of {}.", + npc_id_string, + disease_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET DR = {} WHERE id = {}", + disease_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit dr [Resistance] - Sets an NPC's Disease Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "fr")) { + if (sep->IsNumber(2)) { + auto fire_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Fire Resistance of {}.", + npc_id_string, + fire_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET FR = {} WHERE id = {}", + fire_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit fr [Resistance] - Sets an NPC's Fire Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "cr")) { + if (sep->IsNumber(2)) { + auto cold_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Cold Resistance of {}.", + npc_id_string, + cold_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET CR = {} WHERE id = {}", + cold_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit cr [Resistance] - Sets an NPC's Cold Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "corrup")) { + if (sep->IsNumber(2)) { + auto corruption_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Corruption Resistance of {}.", + npc_id_string, + corruption_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET corrup = {} WHERE id = {}", + corruption_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit corrup [Resistance] - Sets an NPC's Corruption Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "phr")) { + if (sep->IsNumber(2)) { + auto physical_resist = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Physical Resistance of {}.", + npc_id_string, + physical_resist + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET PhR = {} WHERE id = {}", + physical_resist, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit phr [Resistance] - Sets and NPC's Physical Resistance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "seeinvis")) { + if (sep->IsNumber(2)) { + auto see_invisible = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} can {} See Invisible.", + npc_id_string, + see_invisible ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET see_invis = {} WHERE id = {}", + see_invisible, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit seeinvis [Flag] - Sets an NPC's See Invisible Flag [0 = Cannot See Invisible, 1 = Can See Invisible]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "seeinvisundead")) { + if (sep->IsNumber(2)) { + auto see_invisible_undead = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} can {} See Invisible vs. Undead.", + npc_id_string, + see_invisible_undead ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET see_invis_undead = {} WHERE id = {}", + see_invisible_undead, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit seeinvisundead [Flag] - Sets an NPC's See Invisible vs. Undead Flag [0 = Cannot See Invisible vs. Undead, 1 = Can See Invisible vs. Undead]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "qglobal")) { + if (sep->IsNumber(2)) { + auto use_qglobals = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} can {} use Quest Globals.", + npc_id_string, + use_qglobals ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET qglobal = {} WHERE id = {}", + use_qglobals, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit qglobal [Flag] - Sets an NPC's Quest Global Flag [0 = Quest Globals Off, 1 = Quest Globals On]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "ac")) { + if (sep->IsNumber(2)) { + auto armor_class = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Armor Class.", + npc_id_string, + armor_class + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET ac = {} WHERE id = {}", + armor_class, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit ac [Armor Class] - Sets an NPC's Armor Class"); + } + return; + } else if (!strcasecmp(sep->arg[1], "npcaggro")) { + if (sep->IsNumber(2)) { + auto aggro_npcs = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} will {} aggro other NPCs that have a hostile faction.", + npc_id_string, + aggro_npcs ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET npc_aggro = {} WHERE id = {}", + aggro_npcs, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit npcaggro [Flag] - Sets an NPC's NPC Aggro Flag [0 = Aggro NPCs Off, 1 = Aggro NPCs On]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "spawn_limit")) { + if (sep->IsNumber(2)) { + auto spawn_limit = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Spawn Limit of {}.", + npc_id_string, + spawn_limit + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET spawn_limit = {} WHERE id = {}", + spawn_limit, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit spawn_limit [Limit] - Sets an NPC's Spawn Limit Counter"); + } + return; + } else if (!strcasecmp(sep->arg[1], "attackspeed")) { + if (sep->IsNumber(2)) { + auto attack_speed = std::stof(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has an Attack Speed of {:.2f}.", + npc_id_string, + attack_speed + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET attack_speed = {:.2f} WHERE id = {}", + attack_speed, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit attackspeed [Attack Speed] - Sets an NPC's Attack Speed Modifier"); + } + return; + } else if (!strcasecmp(sep->arg[1], "attackdelay")) { + if (sep->IsNumber(2)) { + auto attack_delay = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has an Attack Delay of {}.", + npc_id_string, + attack_delay + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET attack_delay = {} WHERE id = {}", + attack_delay, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit attackdelay [Attack Delay] - Sets an NPC's Attack Delay"); + } + return; + } else if (!strcasecmp(sep->arg[1], "findable")) { + if (sep->IsNumber(2)) { + auto is_findable = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is {} Findable.", + npc_id_string, + is_findable ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET findable = {} WHERE id = {}", + is_findable, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit findable [Flag] - Sets an NPC's Findable Flag [0 = Not Findable, 1 = Findable]"); + } + return; + } else if (!strcasecmp(sep->arg[1], "str")) { + if (sep->IsNumber(2)) { + auto strength = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Strength.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET STR = {} WHERE id = {}", + strength, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit str [Strength] - Sets an NPC's Strength"); + } + return; + } else if (!strcasecmp(sep->arg[1], "sta")) { + if (sep->IsNumber(2)) { + auto stamina = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Stamina.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET STA = {} WHERE id = {}", + stamina, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit sta [Stamina] - Sets an NPC's Stamina"); + } + return; + } else if (!strcasecmp(sep->arg[1], "agi")) { + if (sep->IsNumber(2)) { + auto agility = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Agility.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET AGI = {} WHERE id = {}", + agility, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit agi [Agility] - Sets an NPC's Agility"); + } + return; + } else if (!strcasecmp(sep->arg[1], "dex")) { + if (sep->IsNumber(2)) { + auto dexterity = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Dexterity.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET DEX = {} WHERE id = {}", + dexterity, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit dex [Dexterity] - Sets an NPC's Dexterity"); + } + return; + } else if (!strcasecmp(sep->arg[1], "int")) { + if (sep->IsNumber(2)) { + auto intelligence = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Intelligence.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET _INT = {} WHERE id = {}", + intelligence, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit int [Intelligence] - Sets an NPC's Intelligence"); + } + return; + } else if (!strcasecmp(sep->arg[1], "wis")) { + if (sep->IsNumber(2)) { + auto wisdom = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Wisdom.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET WIS = {} WHERE id = {}", + wisdom, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit wis [Wisdom] - Sets an NPC's Wisdom"); + } + return; + } else if (!strcasecmp(sep->arg[1], "cha")) { + if (sep->IsNumber(2)) { + auto charisma = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Charisma.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET CHA = {} WHERE id = {}", + charisma, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit cha [Charisma] - Sets an NPC's Charisma"); + } + return; + } else if (!strcasecmp(sep->arg[1], "seehide")) { + if (sep->IsNumber(2)) { + auto see_hide = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} can {} See Hide.", + npc_id_string, + see_hide ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET see_hide = {} WHERE id = {}", + see_hide, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit seehide [Flag] - Sets an NPC's See Hide Flag [0 = Cannot See Hide, 1 = Can See Hide]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "seeimprovedhide")) { + if (sep->IsNumber(2)) { + auto see_improved_hide = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} can {} See Improved Hide.", + npc_id_string, + see_improved_hide ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET see_improved_hide = {} WHERE id = {}", + see_improved_hide, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit seeimprovedhide [Flag] - Sets an NPC's See Improved Hide Flag [0 = Cannot See Improved Hide, 1 = Can See Improved Hide]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "trackable")) { + if (sep->IsNumber(2)) { + auto is_trackable = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is {} Trackable.", + npc_id_string, + is_trackable ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET trackable = {} WHERE id = {}", + is_trackable, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit trackable [Flag] - Sets an NPC's Trackable Flag [0 = Not Trackable, 1 = Trackable]"); + } + return; + } else if (!strcasecmp(sep->arg[1], "atk")) { + if (sep->IsNumber(2)) { + auto attack = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Attack.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET atk = {} WHERE id = {}", + attack, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit atk [Attack] - Sets an NPC's Attack"); + } + return; + } else if (!strcasecmp(sep->arg[1], "accuracy")) { + if (sep->IsNumber(2)) { + auto accuracy = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Accuracy.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET accuracy = {} WHERE id = {}", + accuracy, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit accuracy [Accuracy] - Sets an NPC's Accuracy"); + } + return; + } else if (!strcasecmp(sep->arg[1], "avoidance")) { + if (sep->IsNumber(2)) { + auto avoidance = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Avoidance.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET avoidance = {} WHERE id = {}", + avoidance, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit avoidance [Avoidance] - Sets an NPC's Avoidance"); + } + return; + } else if (!strcasecmp(sep->arg[1], "slow_mitigation")) { + if (sep->IsNumber(2)) { + auto slow_mitigation = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Slow Mitigation.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET slow_mitigation = {} WHERE id = {}", + slow_mitigation, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit slow_mitigation [Slow Mitigation] - Sets an NPC's Slow Mitigation"); + } + return; + } else if (!strcasecmp(sep->arg[1], "version")) { + if (sep->IsNumber(2)) { + auto version = std::stoi(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Version {}.", + npc_id_string, + version + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET version = {} WHERE id = {}", + version, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit version [Version] - Sets an NPC's Version"); + } + return; + } else if (!strcasecmp(sep->arg[1], "maxlevel")) { + if (sep->IsNumber(2)) { + auto max_level = static_cast(std::stoul(sep->arg[2])); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Maximum Level of {}.", + npc_id_string, + max_level + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET maxlevel = {} WHERE id = {}", + max_level, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit maxlevel [Max Level] - Sets an NPC's Maximum Level"); + } + return; + } else if (!strcasecmp(sep->arg[1], "scalerate")) { + if (sep->IsNumber(2)) { + auto scale_rate = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Scaling Rate of {}%%.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET scalerate = {} WHERE id = {}", + scale_rate, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit scalerate [Scale Rate] - Sets an NPC's Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); + } + return; + } else if (!strcasecmp(sep->arg[1], "spellscale")) { + if (sep->IsNumber(2)) { + auto spell_scale = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Spell Scaling Rate of {}%%.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET spellscale = {} WHERE id = {}", + spell_scale, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit spellscale [Scale Rate] - Sets an NPC's Spell Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "healscale")) { + if (sep->IsNumber(2)) { + auto heal_scale = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Heal Scaling Rate of {}%%.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET healscale = {} WHERE id = {}", + heal_scale, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit healscale [Scale Rate] - Sets an NPC's Heal Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "no_target")) { + if (sep->IsNumber(2)) { + auto is_no_target = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is {} Targetable with Target Hotkey.", + npc_id_string, + is_no_target ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET no_target_hotkey = {} WHERE id = {}", + is_no_target, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit no_target [Flag] - Sets an NPC's No Target Hotkey Flag [0 = Not Targetable with Target Hotkey, 1 = Targetable with Target Hotkey]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "raidtarget")) { + if (sep->IsNumber(2)) { + auto is_raid_target = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is {} designated as a Raid Target.", + npc_id_string, + is_raid_target ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET raid_target = {} WHERE id = {}", + is_raid_target, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit raidtarget [Flag] - Sets an NPC's Raid Target Flag [0 = Not a Raid Target, 1 = Raid Target]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "armtexture")) { + if (sep->IsNumber(2)) { + auto arm_texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Arm Texture {}.", + npc_id_string, + arm_texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET armtexture = {} WHERE id = {}", + arm_texture, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit armtexture [Texture] - Sets an NPC's Arm Texture"); + } + return; + } else if (!strcasecmp(sep->arg[1], "bracertexture")) { + if (sep->IsNumber(2)) { + auto bracer_texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Bracer Texture {}.", + npc_id_string, + bracer_texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET bracertexture = {} WHERE id = {}", + bracer_texture, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit bracertexture [Texture] - Sets an NPC's Bracer Texture"); + } + return; + } else if (!strcasecmp(sep->arg[1], "handtexture")) { + if (sep->IsNumber(2)) { + auto hand_texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Hand Texture {}.", + npc_id_string, + hand_texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET handtexture = {} WHERE id = {}", + hand_texture, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit handtexture [Texture] - Sets an NPC's Hand Texture"); + } + return; + } else if (!strcasecmp(sep->arg[1], "legtexture")) { + if (sep->IsNumber(2)) { + auto leg_texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Leg Texture {}.", + npc_id_string, + leg_texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET legtexture = {} WHERE id = {}", + leg_texture, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit legtexture [Texture] - Sets an NPC's Leg Texture"); + } + return; + } else if (!strcasecmp(sep->arg[1], "feettexture")) { + if (sep->IsNumber(2)) { + auto feet_texture = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Feet Texture {}.", + npc_id_string, + feet_texture + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET feettexture = {} WHERE id = {}", + feet_texture, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit feettexture [Texture] - Sets an NPC's Feet Texture"); + } + return; + } else if (!strcasecmp(sep->arg[1], "walkspeed")) { + if (sep->IsNumber(2)) { + auto walk_speed = std::stof(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now walks at a Walk Speed of {:.2f}.", + npc_id_string, + walk_speed + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET walkspeed = {:.2f} WHERE id = {}", + walk_speed, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit walkspeed [Walk Speed] - Sets an NPC's Walk Speed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "show_name")) { + if (sep->IsNumber(2)) { + auto show_name = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} will {} show their name.", + npc_id_string, + show_name ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET show_name = {} WHERE id = {}", + show_name, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit show_name [Flag] - Sets an NPC's Show Name Flag [0 = Hidden, 1 = Shown]"); + } + return; + } else if (!strcasecmp(sep->arg[1], "untargetable")) { + if (sep->IsNumber(2)) { + auto is_untargetable = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} will {} be untargetable.", + npc_id_string, + is_untargetable ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET untargetable = {} WHERE id = {}", + is_untargetable, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit untargetable [Flag] - Sets an NPC's Untargetable Flag [0 = Targetable, 1 = Untargetable]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_ac")) { + if (sep->IsNumber(2)) { + auto charm_armor_class = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Armor Class while Charmed.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_ac = {} WHERE id = {}", + charm_armor_class, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit charm_ac [Armor Class] - Sets an NPC's Armor Class while Charmed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_min_dmg")) { + if (sep->IsNumber(2)) { + auto charm_minimum_damage = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now does {} Minimum Damage while Charmed.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_min_dmg = {} WHERE id = {}", + charm_minimum_damage, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit charm_min_dmg [Damage] - Sets an NPC's Minimum Damage while Charmed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_max_dmg")) { + if (sep->IsNumber(2)) { + auto charm_maximum_damage = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now does {} Maximum Damage while Charmed.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_max_dmg = {} WHERE id = {}", + charm_maximum_damage, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit charm_max_dmg [Damage] - Sets an NPC's Maximum Damage while Charmed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_attack_delay")) { + if (sep->IsNumber(2)) { + auto charm_attack_delay = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Attack Delay while Charmed.", + npc_id_string, + charm_attack_delay + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_attack_delay = {} WHERE id = {}", + charm_attack_delay, + npc_id + ); + content_db.QueryDatabase(query); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_accuracy_rating")) { + if (sep->IsNumber(2)) { + auto charm_accuracy_rating = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Accuracy Rating while Charmed.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_accuracy_rating = {} WHERE id = {}", + charm_accuracy_rating, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit charm_accuracy_rating [Accuracy] - Sets an NPC's Accuracy Rating while Charmed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_avoidance_rating")) { + if (sep->IsNumber(2)) { + auto charm_avoidance_rating = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Avoidance Rating while Charmed.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_avoidance_rating = {} WHERE id = {}", + charm_avoidance_rating, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit charm_avoidance_rating [Avoidance] - Sets an NPC's Avoidance Rating while Charmed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "charm_atk")) { + if (sep->IsNumber(2)) { + auto charm_attack = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has {} Attack while Charmed.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET charm_atk = {} WHERE id = {}", + charm_attack, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Usage: #npcedit charm_atk [Attack] - Sets an NPC's Attack while Charmed"); + } + return; + } else if (!strcasecmp(sep->arg[1], "skip_global_loot")) { + if (sep->IsNumber(2)) { + auto skip_global_loot = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} will {} skip Global Loot.", + npc_id_string, + skip_global_loot ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET skip_global_loot = {} WHERE id = {}", + skip_global_loot, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit skip_global_loot [Flag] - Sets an NPC's Skip Global Loot Flag [0 = Don't Skip, 1 = Skip" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "rarespawn")) { + if (sep->IsNumber(2)) { + auto is_rare_spawn = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} is {} designated as a Rare Spawn.", + npc_id_string, + is_rare_spawn ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET rare_spawn = {} WHERE id = {}", + is_rare_spawn, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit rarespawn [Flag] - Sets an NPC's Rare Spawn Flag [0 = Not a Rare Spawn, 1 = Rare Spawn]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "stuck_behavior")) { + if (sep->IsNumber(2)) { + auto behavior_id = ( + static_cast(std::stoul(sep->arg[2])) > EQ::constants::StuckBehavior::EvadeCombat ? + EQ::constants::StuckBehavior::EvadeCombat : + static_cast(std::stoul(sep->arg[2])) + ); + auto behavior_name = EQ::constants::GetStuckBehaviorName(behavior_id); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Stuck Behavior {}.", + npc_id_string, + ( + !behavior_name.empty() ? + fmt::format( + "{} ({})", + behavior_name, + behavior_id + ) : + std::to_string(behavior_id) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET stuck_behavior = {} WHERE id = {}", + behavior_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit stuck_behavior [Stuck Behavior] - Sets an NPC's Stuck Behavior [0 = Run to Target, 1 = Warp to Target, 2 = Take No Action, 3 = Evade Combat]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "flymode")) { + if (sep->IsNumber(2)) { + auto flymode_id = ( + static_cast(std::stoul(sep->arg[2])) > GravityBehavior::LevitateWhileRunning ? + GravityBehavior::LevitateWhileRunning : + static_cast(std::stoul(sep->arg[2])) + ); + auto flymode_name = EQ::constants::GetFlyModeName(flymode_id); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Fly Mode {}.", + npc_id_string, + ( + !flymode_name.empty() ? + fmt::format( + "{} ({})", + flymode_name, + flymode_id + ) : + std::to_string(flymode_id) + ) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET flymode = {} WHERE id = {}", + flymode_id, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit flymode [Fly Mode] - Sets an NPC's Fly Mode [0 = Ground, 1 = Flying, 2 = Levitating, 3 = Water, 4 = Floating, 5 = Levitating While Running]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "always_aggro")) { + if (sep->IsNumber(2)) { + auto always_aggro = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} will {} Always Aggro.", + npc_id_string, + always_aggro ? "now" : "no longer" + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET always_aggro = {} WHERE id = {}", + always_aggro, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit always_aggro [Flag] - Sets an NPC's Always Aggro Flag [0 = Does not Always Aggro, 1 = Always Aggro]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "exp_mod")) { + if (sep->IsNumber(2)) { + auto experience_modifier = std::stoul(sep->arg[2]); + c->Message( + Chat::Yellow, + fmt::format( + "{} now has an Experience Modifier of {}%%.", + npc_id_string, + commify(sep->arg[2]) + ).c_str() + ); + auto query = fmt::format( + "UPDATE npc_types SET exp_mod = {} WHERE id = {}", + experience_modifier, + npc_id + ); + content_db.QueryDatabase(query); + } else { + c->Message( + Chat::White, + "Usage: #npcedit exp_mod [Modifier] - Sets an NPC's Experience Modifier [50 = 50%, 100 = 100%, 200 = 200%]" + ); + } + return; + } else if (!strcasecmp(sep->arg[1], "setanimation")) { + if (sep->IsNumber(2)) { + auto animation_id = ( + std::stoul(sep->arg[2]) > EQ::constants::SpawnAnimations::Looting ? + EQ::constants::SpawnAnimations::Looting : + std::stoul(sep->arg[2]) + ); + auto animation_name = EQ::constants::GetSpawnAnimationName(animation_id); + c->Message( + Chat::Yellow, + fmt::format( + "{} is now using Spawn Animation {} on Spawn Group ID {}.", + npc_id_string, + ( + !animation_name.empty() ? + fmt::format( + "{} ({})", + animation_name, + animation_id + ) : + std::to_string(animation_id) + ), + commify(std::to_string(c->GetTarget()->CastToNPC()->GetSpawnGroupId())) + ).c_str() + ); + auto query = fmt::format( + "UPDATE spawn2 SET animation = {} WHERE spawngroupID = {}", + animation_id, + c->GetTarget()->CastToNPC()->GetSpawnGroupId() + ); + content_db.QueryDatabase(query); + + c->GetTarget()->SetAppearance(EmuAppearance(animation_id)); + } else { + c->Message(Chat::White, "Usage: #npcedit setanimation [Animation ID] - Sets an NPC's Animation on Spawn (Stored in spawn2 table)"); + } + return; + } else if (!strcasecmp(sep->arg[1], "respawntime")) { + if (sep->IsNumber(2)) { + auto respawn_time = std::stoul(sep->arg[2]); + if (respawn_time) { + c->Message( + Chat::Yellow, + fmt::format( + "{} now has a Respawn Timer of {} ({}) on Spawn Group ID {}.", + npc_id_string, + ConvertSecondsToTime(respawn_time), + respawn_time, + commify(std::to_string(c->GetTarget()->CastToNPC()->GetSpawnGroupId())) + ).c_str() + ); + auto query = fmt::format( + "UPDATE spawn2 SET respawntime = {} WHERE spawngroupID = {} AND version = {}", + respawn_time, + c->GetTarget()->CastToNPC()->GetSpawnGroupId(), + zone->GetInstanceVersion() + ); + content_db.QueryDatabase(query); + } else { + c->Message(Chat::White, "Respawn Timer must be greater than 0 seconds."); + return; + } + } else { + c->Message( + Chat::White, + "Usage: #npcedit respawntime [Respawn Time] - Sets an NPC's Respawn Timer in Seconds (Stored in spawn2 table)" + ); + } + return; + } else { + c->Message(Chat::White, "Usage: #npcedit name [Name] - Sets an NPC's Name"); + c->Message(Chat::White, "Usage: #npcedit lastname [Last Name] - Sets an NPC's Last Name"); + c->Message(Chat::White, "Usage: #npcedit level [Level] - Sets an NPC's Level"); + c->Message(Chat::White, "Usage: #npcedit race [Race ID] - Sets an NPC's Race"); + c->Message(Chat::White, "Usage: #npcedit class [Class ID] - Sets an NPC's Class"); + c->Message(Chat::White, "Usage: #npcedit bodytype [Body Type ID] - Sets an NPC's Bodytype"); + c->Message(Chat::White, "Usage: #npcedit hp [HP] - Sets an NPC's HP"); + c->Message(Chat::White, "Usage: #npcedit mana [Mana] - Sets an NPC's Mana"); + c->Message(Chat::White, "Usage: #npcedit gender [Gender ID] - Sets an NPC's Gender"); + c->Message(Chat::White, "Usage: #npcedit texture [Texture] - Sets an NPC's Texture"); + c->Message(Chat::White, "Usage: #npcedit helmtexture [Helmet Texture] - Sets an NPC's Helmet Texture"); + c->Message(Chat::White, "Usage: #npcedit herosforgemodel [Model Number] - Sets an NPC's Hero's Forge Model"); + c->Message(Chat::White, "Usage: #npcedit size [Size] - Sets an NPC's Size"); + c->Message(Chat::White, "Usage: #npcedit hpregen [HP Regen] - Sets an NPC's HP Regen Rate Per Tick"); + c->Message(Chat::White, "Usage: #npcedit hp_regen_per_second [HP Regen] - Sets an NPC's HP Regen Rate Per Second"); + c->Message(Chat::White, "Usage: #npcedit manaregen [Mana Regen] - Sets an NPC's Mana Regen Rate Per Tick"); + c->Message(Chat::White, "Usage: #npcedit loottable [Loottable ID] - Sets an NPC's Loottable ID"); + c->Message(Chat::White, "Usage: #npcedit merchantid [Merchant ID] - Sets an NPC's Merchant ID"); + c->Message(Chat::White, "Usage: #npcedit alt_currency_id [Alternate Currency ID] - Sets an NPC's Alternate Currency ID"); + c->Message(Chat::White, "Usage: #npcedit spell [Spell List ID] - Sets an NPC's Spells List ID"); + c->Message(Chat::White, "Usage: #npcedit npc_spells_effects_id [Spell Effects ID] - Sets an NPC's Spell Effects ID"); + c->Message(Chat::White, "Usage: #npcedit faction [Faction ID] - Sets an NPC's Faction ID"); + c->Message(Chat::White, "Usage: #npcedit adventure_template_id [Template ID] - Sets an NPC's Adventure Template ID"); + c->Message(Chat::White, "Usage: #npcedit trap_template [Template ID] - Sets an NPC's Trap Template ID"); + c->Message(Chat::White, "Usage: #npcedit damage [Minimum] [Maximum] - Sets an NPC's Damage"); + c->Message(Chat::White, "Usage: #npcedit attackcount [Attack Count] - Sets an NPC's Attack Count"); + c->Message(Chat::White, "Usage: #npcedit special_attacks [Special Attacks] - Sets an NPC's Special Attacks"); + c->Message(Chat::White, "Usage: #npcedit special_abilities [Special Abilities] - Sets an NPC's Special Abilities"); + c->Message(Chat::White, "Usage: #npcedit aggroradius [Radius] - Sets an NPC's Aggro Radius"); + c->Message(Chat::White, "Usage: #npcedit assistradius [Radius] - Sets an NPC's Assist Radius"); + c->Message(Chat::White, "Usage: #npcedit featuresave - Saves an NPC's current facial features to the database"); + c->Message(Chat::White, "Usage: #npcedit armortint_id [Armor Tint ID] - Sets an NPC's Armor Tint ID"); + c->Message(Chat::White, "Usage: #npcedit color [Red] [Green] [Blue] - Sets an NPC's Red, Green, and Blue armor tint"); + c->Message(Chat::White, "Usage: #npcedit ammoidfile [ID File] - Sets an NPC's Ammo ID File"); + c->Message( + Chat::White, + "Usage: #npcedit weapon [Primary Model] [Secondary Model] - Sets an NPC's Primary and Secondary Weapon Model" + ); + c->Message(Chat::White, "Usage: #npcedit meleetype [Primary Type] [Secondary Type] - Sets an NPC's Melee Skill Types"); + c->Message(Chat::White, "Usage: #npcedit rangedtype [Type] - Sets an NPC's Ranged Skill Type"); + c->Message(Chat::White, "Usage: #npcedit runspeed [Run Speed] - Sets an NPC's Run Speed"); + c->Message(Chat::White, "Usage: #npcedit mr [Resistance] - Sets an NPC's Magic Resistance"); + c->Message(Chat::White, "Usage: #npcedit pr [Resistance] - Sets an NPC's Poison Resistance"); + c->Message(Chat::White, "Usage: #npcedit dr [Resistance] - Sets an NPC's Disease Resistance"); + c->Message(Chat::White, "Usage: #npcedit fr [Resistance] - Sets an NPC's Fire Resistance"); + c->Message(Chat::White, "Usage: #npcedit cr [Resistance] - Sets an NPC's Cold Resistance"); + c->Message(Chat::White, "Usage: #npcedit corrup [Resistance] - Sets an NPC's Corruption Resistance"); + c->Message(Chat::White, "Usage: #npcedit phr [Resistance] - Sets and NPC's Physical Resistance"); + c->Message( + Chat::White, + "Usage: #npcedit seeinvis [Flag] - Sets an NPC's See Invisible Flag [0 = Cannot See Invisible, 1 = Can See Invisible]" + ); + c->Message( + Chat::White, + "Usage: #npcedit seeinvisundead [Flag] - Sets an NPC's See Invisible vs. Undead Flag [0 = Cannot See Invisible vs. Undead, 1 = Can See Invisible vs. Undead]" + ); + c->Message( + Chat::White, + "Usage: #npcedit qglobal [Flag] - Sets an NPC's Quest Global Flag [0 = Quest Globals Off, 1 = Quest Globals On]" + ); + c->Message(Chat::White, "Usage: #npcedit ac [Armor Class] - Sets an NPC's Armor Class"); + c->Message( + Chat::White, + "Usage: #npcedit npcaggro [Flag] - Sets an NPC's NPC Aggro Flag [0 = Aggro NPCs Off, 1 = Aggro NPCs On]" + ); + c->Message(Chat::White, "Usage: #npcedit spawn_limit [Limit] - Sets an NPC's Spawn Limit Counter"); + c->Message(Chat::White, "Usage: #npcedit attackspeed [Attack Speed] - Sets an NPC's Attack Speed Modifier"); + c->Message(Chat::White, "Usage: #npcedit attackdelay [Attack Delay] - Sets an NPC's Attack Delay"); + c->Message(Chat::White, "Usage: #npcedit findable [Flag] - Sets an NPC's Findable Flag [0 = Not Findable, 1 = Findable]"); + c->Message(Chat::White, "Usage: #npcedit str [Strength] - Sets an NPC's Strength"); + c->Message(Chat::White, "Usage: #npcedit sta [Stamina] - Sets an NPC's Stamina"); + c->Message(Chat::White, "Usage: #npcedit agi [Agility] - Sets an NPC's Agility"); + c->Message(Chat::White, "Usage: #npcedit dex [Dexterity] - Sets an NPC's Dexterity"); + c->Message(Chat::White, "Usage: #npcedit int [Intelligence] - Sets an NPC's Intelligence"); + c->Message(Chat::White, "Usage: #npcedit wis [Wisdom] - Sets an NPC's Wisdom"); + c->Message(Chat::White, "Usage: #npcedit cha [Charisma] - Sets an NPC's Charisma"); + c->Message( + Chat::White, + "Usage: #npcedit seehide [Flag] - Sets an NPC's See Hide Flag [0 = Cannot See Hide, 1 = Can See Hide]" + ); + c->Message( + Chat::White, + "Usage: #npcedit seeimprovedhide [Flag] - Sets an NPC's See Improved Hide Flag [0 = Cannot See Improved Hide, 1 = Can See Improved Hide]" + ); + c->Message(Chat::White, "Usage: #npcedit trackable [Flag] - Sets an NPC's Trackable Flag [0 = Not Trackable, 1 = Trackable]"); + c->Message(Chat::White, "Usage: #npcedit atk [Attack] - Sets an NPC's Attack"); + c->Message(Chat::White, "Usage: #npcedit accuracy [Accuracy] - Sets an NPC's Accuracy"); + c->Message(Chat::White, "Usage: #npcedit avoidance [Avoidance] - Sets an NPC's Avoidance"); + c->Message(Chat::White, "Usage: #npcedit slow_mitigation [Slow Mitigation] - Sets an NPC's Slow Mitigation"); + c->Message(Chat::White, "Usage: #npcedit version [Version] - Sets an NPC's Version"); + c->Message(Chat::White, "Usage: #npcedit maxlevel [Max Level] - Sets an NPC's Maximum Level"); + c->Message(Chat::White, "Usage: #npcedit scalerate [Scale Rate] - Sets an NPC's Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]"); + c->Message( + Chat::White, + "Usage: #npcedit spellscale [Scale Rate] - Sets an NPC's Spell Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" + ); + c->Message( + Chat::White, + "Usage: #npcedit healscale [Scale Rate] - Sets an NPC's Heal Scaling Rate [50 = 50%, 100 = 100%, 200 = 200%]" + ); + c->Message( + Chat::White, + "Usage: #npcedit no_target [Flag] - Sets an NPC's No Target Hotkey Flag [0 = Not Targetable with Target Hotkey, 1 = Targetable with Target Hotkey]" + ); + c->Message( + Chat::White, + "Usage: #npcedit raidtarget [Flag] - Sets an NPC's Raid Target Flag [0 = Not a Raid Target, 1 = Raid Target]" + ); + c->Message(Chat::White, "Usage: #npcedit armtexture [Texture] - Sets an NPC's Arm Texture"); + c->Message(Chat::White, "Usage: #npcedit bracertexture [Texture] - Sets an NPC's Bracer Texture"); + c->Message(Chat::White, "Usage: #npcedit handtexture [Texture] - Sets an NPC's Hand Texture"); + c->Message(Chat::White, "Usage: #npcedit legtexture [Texture] - Sets an NPC's Leg Texture"); + c->Message(Chat::White, "Usage: #npcedit feettexture [Texture] - Sets an NPC's Feet Texture"); + c->Message(Chat::White, "Usage: #npcedit walkspeed [Walk Speed] - Sets an NPC's Walk Speed"); + c->Message(Chat::White, "Usage: #npcedit show_name [Flag] - Sets an NPC's Show Name Flag [0 = Hidden, 1 = Shown]"); + c->Message( + Chat::White, + "Usage: #npcedit untargetable [Flag] - Sets an NPC's Untargetable Flag [0 = Targetable, 1 = Untargetable]" + ); + c->Message(Chat::White, "Usage: #npcedit charm_ac [Armor Class] - Sets an NPC's Armor Class while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_min_dmg [Damage] - Sets an NPC's Minimum Damage while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_max_dmg [Damage] - Sets an NPC's Maximum Damage while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_attack_delay [Attack Delay] - Sets an NPC's Attack Delay while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_accuracy_rating [Accuracy] - Sets an NPC's Accuracy Rating while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_avoidance_rating [Avoidance] - Sets an NPC's Avoidance Rating while Charmed"); + c->Message(Chat::White, "Usage: #npcedit charm_atk [Attack] - Sets an NPC's Attack while Charmed"); + c->Message( + Chat::White, + "Usage: #npcedit skip_global_loot [Flag] - Sets an NPC's Skip Global Loot Flag [0 = Don't Skip, 1 = Skip" + ); + c->Message( + Chat::White, + "Usage: #npcedit rarespawn [Flag] - Sets an NPC's Rare Spawn Flag [0 = Not a Rare Spawn, 1 = Rare Spawn]" + ); + c->Message( + Chat::White, + "Usage: #npcedit stuck_behavior [Stuck Behavior] - Sets an NPC's Stuck Behavior [0 = Run to Target, 1 = Warp to Target, 2 = Take No Action, 3 = Evade Combat]" + ); + c->Message( + Chat::White, + "Usage: #npcedit flymode [Fly Mode] - Sets an NPC's Fly Mode [0 = Ground, 1 = Flying, 2 = Levitating, 3 = Water, 4 = Floating, 5 = Levitating While Running]" + ); + c->Message( + Chat::White, + "Usage: #npcedit always_aggro [Flag] - Sets an NPC's Always Aggro Flag [0 = Does not Always Aggro, 1 = Always Aggro]" + ); + c->Message( + Chat::White, + "Usage: #npcedit exp_mod [Modifier] - Sets an NPC's Experience Modifier [50 = 50%, 100 = 100%, 200 = 200%]" + ); + c->Message(Chat::White, "Usage: #npcedit setanimation [Animation ID] - Sets an NPC's Animation on Spawn (Stored in spawn2 table)"); + c->Message( + Chat::White, + "Usage: #npcedit respawntime [Respawn Time] - Sets an NPC's Respawn Timer in Seconds (Stored in spawn2 table)" + ); + return; + } } diff --git a/zone/gm_commands/title.cpp b/zone/gm_commands/title.cpp index dff5a3ec4..669cf28b9 100755 --- a/zone/gm_commands/title.cpp +++ b/zone/gm_commands/title.cpp @@ -5,16 +5,12 @@ void command_title(Client *c, const Seperator *sep) { int arguments = sep->argnum; if (!arguments) { - c->Message( - Chat::White, - "Usage: #title [Remove|Title] [Save (0 = False, 1 = True)]" - ); + c->Message(Chat::White, "Usage: #title [Title] (use \"-1\" to remove title)"); return; } - bool is_remove = !strcasecmp(sep->arg[1], "remove"); - std::string title = is_remove ? "" : sep->arg[1]; - bool save_title = sep->IsNumber(2) ? atobool(sep->arg[2]) : false; + bool is_remove = !strcasecmp(sep->argplus[1], "-1"); + std::string title = is_remove ? "" : sep->argplus[1]; auto target = c; if (c->GetTarget() && c->GetTarget()->IsClient()) { @@ -30,9 +26,9 @@ void command_title(Client *c, const Seperator *sep) find_replace(title, "_", " "); } - if (!save_title || is_remove) { + if (is_remove) { target->SetAATitle(title); - } else if (save_title) { + } else { title_manager.CreateNewPlayerTitle(target, title); } @@ -43,7 +39,7 @@ void command_title(Client *c, const Seperator *sep) fmt::format( "Title has been {}{} for {}{}", is_remove ? "removed" : "changed", - !is_remove && save_title ? " and saved" : "", + !is_remove ? " and saved" : "", c->GetTargetDescription(target), ( is_remove ? diff --git a/zone/gm_commands/titlesuffix.cpp b/zone/gm_commands/titlesuffix.cpp index 34c971f64..eefa6614f 100755 --- a/zone/gm_commands/titlesuffix.cpp +++ b/zone/gm_commands/titlesuffix.cpp @@ -7,14 +7,13 @@ void command_titlesuffix(Client *c, const Seperator *sep) if (!arguments) { c->Message( Chat::White, - "Usage: #titlesuffix [Remove|Title] [Save (0 = False, 1 = True)]" + "Usage: #titlesuffix [Title Suffix] (use \"-1\" to remove title suffix)" ); return; } - bool is_remove = !strcasecmp(sep->arg[1], "remove"); - std::string suffix = is_remove ? "" : sep->arg[1]; - bool save_suffix = sep->IsNumber(2) ? atobool(sep->arg[2]) : false; + bool is_remove = !strcasecmp(sep->argplus[1], "-1"); + std::string suffix = is_remove ? "" : sep->argplus[1]; auto target = c; if (c->GetTarget() && c->GetTarget()->IsClient()) { @@ -30,9 +29,9 @@ void command_titlesuffix(Client *c, const Seperator *sep) find_replace(suffix, "_", " "); } - if (!save_suffix || is_remove) { + if (is_remove) { target->SetTitleSuffix(suffix); - } else if (save_suffix) { + } else { title_manager.CreateNewPlayerSuffix(target, suffix); } @@ -43,7 +42,7 @@ void command_titlesuffix(Client *c, const Seperator *sep) fmt::format( "Title suffix has been {}{} for {}{}", is_remove ? "removed" : "changed", - !is_remove && save_suffix ? " and saved" : "", + !is_remove ? " and saved" : "", c->GetTargetDescription(target), ( is_remove ?