diff --git a/zone/gm_commands/spawn.cpp b/zone/gm_commands/spawn.cpp index 2dd42ccd6..78ab443af 100755 --- a/zone/gm_commands/spawn.cpp +++ b/zone/gm_commands/spawn.cpp @@ -2,19 +2,36 @@ void command_spawn(Client *c, const Seperator *sep) { - if (sep->arg[1][0] != 0) { - Client *client = entity_list.GetClientByName(sep->arg[1]); - if (client) { - c->Message(Chat::White, "You cannot spawn a mob with the same name as a character!"); - return; - } - } - - NPC *npc = NPC::SpawnNPC(sep->argplus[1], c->GetPosition(), c); - if (!npc) { + const auto arguments = sep->argnum; + if (!arguments) { + c->Message(Chat::White, "Usage: #spawn [Name]"); c->Message( Chat::White, - "Format: #spawn name race level material hp gender class priweapon secweapon merchantid bodytype - spawns a npc those parameters." + "Optional Usage: #spawn [Name] [Race] [Level] [Texture] [Health] [Gender] [Class] [Primary Model] [Secondary Model] [Merchant ID] [Body Type]" + ); + c->Message( + Chat::White, + "Name Format: NPCFirstname_NPCLastname - All numbers in a name are stripped and \"_\" characters become a space." + ); + c->Message( + Chat::White, + "Note: Using \"-\" for gender will autoselect the gender for the race. Using \"-\" for HP will use the calculated maximum HP." + ); + return; + } + + const auto* m = entity_list.GetClientByName(sep->arg[1]); + if (m) { + c->Message(Chat::White, "You cannot spawn a mob with the same name as a character!"); + return; + } + + const auto* n = NPC::SpawnNPC(sep->argplus[1], c->GetPosition(), c); + if (!n) { + c->Message(Chat::White, "Usage: #spawn [Name]"); + c->Message( + Chat::White, + "Optional Usage: #spawn [Name] [Race] [Level] [Texture] [Health] [Gender] [Class] [Primary Model] [Secondary Model] [Merchant ID] [Body Type]" ); c->Message( Chat::White, diff --git a/zone/npc.cpp b/zone/npc.cpp index dc93b12af..94d7175bc 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -1378,7 +1378,7 @@ NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 } NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) { - if(spawncommand == 0 || spawncommand[0] == 0) { + if (spawncommand == 0 || spawncommand[0] == 0) { return 0; } else { @@ -1387,42 +1387,54 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* if (!sep.IsNumber(1)) { sprintf(sep.arg[1], "1"); } + if (!sep.IsNumber(2)) { sprintf(sep.arg[2], "1"); } + if (!sep.IsNumber(3)) { sprintf(sep.arg[3], "0"); } + if (Strings::ToInt(sep.arg[4]) > 2100000000 || Strings::ToInt(sep.arg[4]) <= 0) { sprintf(sep.arg[4], " "); } + if (!strcmp(sep.arg[5], "-")) { sprintf(sep.arg[5], " "); } + if (!sep.IsNumber(5)) { sprintf(sep.arg[5], " "); } + if (!sep.IsNumber(6)) { sprintf(sep.arg[6], "1"); } + if (!sep.IsNumber(8)) { sprintf(sep.arg[8], "0"); } + if (!sep.IsNumber(9)) { sprintf(sep.arg[9], "0"); } + if (!sep.IsNumber(7)) { sprintf(sep.arg[7], "0"); } + if (!strcmp(sep.arg[4], "-")) { sprintf(sep.arg[4], " "); } + if (!sep.IsNumber(10)) { // bodytype sprintf(sep.arg[10], "0"); } + //Calc MaxHP if client neglected to enter it... if (sep.arg[4] && !sep.IsNumber(4)) { - sprintf(sep.arg[4], "0"); + sprintf(sep.arg[4], "1"); } // Autoselect NPC Gender @@ -1435,6 +1447,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* memset(npc_type, 0, sizeof(NPCType)); strncpy(npc_type->name, sep.arg[0], 60); + npc_type->current_hp = Strings::ToInt(sep.arg[4]); npc_type->max_hp = Strings::ToInt(sep.arg[4]); npc_type->race = Strings::ToInt(sep.arg[1]); @@ -1445,8 +1458,8 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* npc_type->npc_id = 0; npc_type->loottable_id = 0; npc_type->texture = Strings::ToInt(sep.arg[3]); - npc_type->light = 0; // spawncommand needs update - npc_type->runspeed = 1.25; + npc_type->light = 0; + npc_type->runspeed = 1.25f; npc_type->d_melee_texture1 = Strings::ToInt(sep.arg[7]); npc_type->d_melee_texture2 = Strings::ToInt(sep.arg[8]); npc_type->merchanttype = Strings::ToInt(sep.arg[9]); @@ -1462,8 +1475,8 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* npc_type->attack_delay = 3000; - npc_type->prim_melee_type = 28; - npc_type->sec_melee_type = 28; + npc_type->prim_melee_type = static_cast(EQ::skills::SkillHandtoHand); + npc_type->sec_melee_type = static_cast(EQ::skills::SkillHandtoHand); auto npc = new NPC(npc_type, nullptr, position, GravityBehavior::Water); npc->GiveNPCTypeData(npc_type); @@ -1472,17 +1485,34 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* if (client) { // Notify client of spawn data - client->Message(Chat::White, "New spawn:"); - client->Message(Chat::White, "Name: %s", npc->name); - client->Message(Chat::White, "Race: %u", npc->race); - client->Message(Chat::White, "Level: %u", npc->level); - client->Message(Chat::White, "Material: %u", npc->texture); - client->Message(Chat::White, "Current/Max HP: %i", npc->max_hp); - client->Message(Chat::White, "Gender: %u", npc->gender); - client->Message(Chat::White, "Class: %u", npc->class_); - client->Message(Chat::White, "Weapon Item Number: %u/%u", npc->d_melee_texture1, npc->d_melee_texture2); - client->Message(Chat::White, "MerchantID: %u", npc->MerchantType); - client->Message(Chat::White, "Bodytype: %u", npc->bodytype); + client->Message(Chat::White, fmt::format("Name | {}", npc->name).c_str()); + client->Message(Chat::White, fmt::format("Level | {}", npc->level).c_str()); + client->Message(Chat::White, fmt::format("Health | {}", npc->max_hp).c_str()); + client->Message(Chat::White, fmt::format("Race | {} ({})", GetRaceIDName(npc->race), npc->race).c_str()); + client->Message(Chat::White, fmt::format("Class | {} ({})", GetClassIDName(npc->class_), npc->class_).c_str()); + client->Message(Chat::White, fmt::format("Gender | {} ({})", GetGenderName(npc->gender), npc->gender).c_str()); + client->Message(Chat::White, fmt::format("Texture | {}", npc->texture).c_str()); + + if (npc->d_melee_texture1 || npc->d_melee_texture2) { + client->Message( + Chat::White, + fmt::format( + "Weapon Item Number | Primary: {} Secondary: {}", + npc->d_melee_texture1, + npc->d_melee_texture2 + ).c_str() + ); + } + + if (npc->MerchantType) { + client->Message(Chat::White, fmt::format("Merchant ID | {}", npc->MerchantType).c_str()); + } + + if (npc->bodytype) { + client->Message(Chat::White, fmt::format("Body Type | {} ({})", EQ::constants::GetBodyTypeName(npc->bodytype), npc->bodytype).c_str()); + } + + client->Message(Chat::White, "New NPC spawned!"); } return npc;