diff --git a/common/string_util.cpp b/common/string_util.cpp index d89bbe39b..d8f5cab9b 100644 --- a/common/string_util.cpp +++ b/common/string_util.cpp @@ -1180,3 +1180,78 @@ std::string ConvertSecondsToTime(int duration, bool is_milliseconds) } return time_string; } + +std::string ConvertMoneyToString(uint32 platinum, uint32 gold, uint32 silver, uint32 copper) +{ + std::string money_string = "Unknown"; + if (copper && silver && gold && platinum) { // CSGP + money_string = fmt::format( + "{} Platinum, {} Gold, {} Silver, and {} Copper", + platinum, + gold, + silver, + copper + ); + } else if (copper && silver && gold && !platinum) { // CSG + money_string = fmt::format( + "{} Gold, {} Silver, and {} Copper", + gold, + silver, + copper + ); + } else if (copper && silver && !gold && !platinum) { // CS + money_string = fmt::format( + "{} Silver and {} Copper", + silver, + copper + ); + } else if (copper && !silver && !gold && !platinum) { // C + money_string = fmt::format( + "{} Copper", + copper + ); + } else if (!copper && silver && gold && platinum) { // SGP + money_string = fmt::format( + "{} Platinum, {} Gold, and {} Silver", + platinum, + gold, + silver + ); + } else if (!copper && silver && gold && !platinum) { // SG + money_string = fmt::format( + "{} Gold and {} Silver", + gold, + silver + ); + } else if (!copper && silver && !gold && !platinum) { // S + money_string = fmt::format( + "{} Silver", + silver + ); + } else if (copper && !silver && gold && platinum) { // CGP + money_string = fmt::format( + "{} Platinum, {} Gold, and {} Copper", + platinum, + gold, + copper + ); + } else if (copper && !silver && gold && !platinum) { // CG + money_string = fmt::format( + "{} Gold and {} Copper", + gold, + copper + ); + } else if (!copper && !silver && gold && platinum) { // GP + money_string = fmt::format( + "{} Platinum and {} Gold", + platinum, + gold + ); + } else if (!copper && !silver && gold && !platinum) { // G + money_string = fmt::format( + "{} Gold", + gold + ); + } + return money_string; +} \ No newline at end of file diff --git a/common/string_util.h b/common/string_util.h index e9c3bfa15..f6b7e35ce 100644 --- a/common/string_util.h +++ b/common/string_util.h @@ -45,9 +45,10 @@ std::vector wrap(std::vector &src, std::string charact std::string implode(std::string glue, std::vector src); std::string convert2digit(int n, std::string suffix); std::string numberToWords(unsigned long long int n); +std::string ConvertMoneyToString(uint32 platinum, uint32 gold = 0, uint32 silver = 0, uint32 copper = 0); std::string ConvertSecondsToTime(int duration, bool is_milliseconds = false); inline std::string ConvertMillisecondsToTime(int duration) { - return ConvertSecondsToTime(duration, true); + return ConvertSecondsToTime(duration, true); } // For converstion of numerics into English diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 6401abb95..654aa4b00 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1456,54 +1456,74 @@ void Corpse::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { } void Corpse::QueryLoot(Client* to) { - int x = 0, y = 0; // x = visible items, y = total items - to->Message(Chat::White, "Coin: %ip, %ig, %is, %ic", platinum, gold, silver, copper); + if (itemlist.size() > 0) { + int player_corpse_limit = to->GetInv().GetLookup()->InventoryTypeSize.Corpse; + to->Message( + Chat::White, + fmt::format( + "Loot | Name: {} ID: {}", + GetName(), + GetNPCTypeID() + ).c_str() + ); - ItemList::iterator cur,end; - cur = itemlist.begin(); - end = itemlist.end(); + int item_count = 0; + for (auto current_item : itemlist) { + int item_number = (item_count + 1); + if (!current_item) { + LogError("Corpse::QueryLoot() - ItemList error, null item."); + continue; + } - int corpselootlimit = to->GetInv().GetLookup()->InventoryTypeSize.Corpse; + if (!current_item->item_id || !database.GetItem(current_item->item_id)) { + LogError("Corpse::QueryLoot() - Database error, invalid item."); + continue; + } - for(; cur != end; ++cur) { - ServerLootItem_Struct* sitem = *cur; + EQ::SayLinkEngine linker; + linker.SetLinkType(EQ::saylink::SayLinkLootItem); + linker.SetLootData(current_item); - if (IsPlayerCorpse()) { - if (sitem->equip_slot >= EQ::invbag::GENERAL_BAGS_BEGIN && sitem->equip_slot <= EQ::invbag::CURSOR_BAG_END) - sitem->lootslot = 0xFFFF; - else - x < corpselootlimit ? sitem->lootslot = x : sitem->lootslot = 0xFFFF; - - const EQ::ItemData* item = database.GetItem(sitem->item_id); - - if (item) - to->Message((sitem->lootslot == 0xFFFF), "LootSlot: %i (EquipSlot: %i) Item: %s (%d), Count: %i", static_cast(sitem->lootslot), sitem->equip_slot, item->Name, item->ID, sitem->charges); - else - to->Message((sitem->lootslot == 0xFFFF), "Error: 0x%04x", sitem->item_id); - - if (sitem->lootslot != 0xFFFF) - x++; - - y++; - } - else { - sitem->lootslot=y; - const EQ::ItemData* item = database.GetItem(sitem->item_id); - - if (item) - to->Message(Chat::White, "LootSlot: %i Item: %s (%d), Count: %i", sitem->lootslot, item->Name, item->ID, sitem->charges); - else - to->Message(Chat::White, "Error: 0x%04x", sitem->item_id); - - y++; + to->Message( + Chat::White, + fmt::format( + "Item {} | Name: {} ({}){}", + item_number, + linker.GenerateLink().c_str(), + current_item->item_id, + ( + current_item->charges > 1 ? + fmt::format( + " Amount: {}", + current_item->charges + ) : + "" + ) + ).c_str() + ); + item_count++; } } - if (IsPlayerCorpse()) { - to->Message(Chat::White, "%i visible %s (%i total) on %s (DBID: %i).", x, x==1?"item":"items", y, this->GetName(), this->GetCorpseDBID()); - } - else { - to->Message(Chat::White, "%i %s on %s.", y, y==1?"item":"items", this->GetName()); + bool has_money = ( + platinum > 0 || + gold > 0 || + silver > 0 || + copper > 0 + ); + if (has_money) { + to->Message( + Chat::White, + fmt::format( + "Money | {}", + ConvertMoneyToString( + platinum, + gold, + silver, + copper + ) + ).c_str() + ); } } diff --git a/zone/entity.cpp b/zone/entity.cpp index 1922ec5f4..944418f29 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3152,50 +3152,75 @@ char *EntityList::RemoveNumbers(char *name) void EntityList::ListNPCCorpses(Client *client) { - uint32 x = 0; - - auto it = corpse_list.begin(); - client->Message(Chat::White, "NPC Corpses in the zone:"); - while (it != corpse_list.end()) { - if (it->second->IsNPCCorpse()) { - client->Message(Chat::White, " %5d: %s", it->first, it->second->GetName()); - x++; + uint32 corpse_count = 0; + for (const auto& corpse : corpse_list) { + uint32 corpse_number = (corpse_count + 1); + if (corpse.second->IsNPCCorpse()) { + client->Message( + Chat::White, + fmt::format( + "Corpse {} | Name: {} ({})", + corpse_number, + corpse.second->GetName(), + corpse.second->GetID() + ).c_str() + ); + corpse_count++; } - ++it; } - client->Message(Chat::White, "%d npc corpses listed.", x); + + if (corpse_count > 0) { + client->Message( + Chat::White, + fmt::format( + "{} NPC corpses listed.", + corpse_count + ).c_str() + ); + } } void EntityList::ListPlayerCorpses(Client *client) { - uint32 x = 0; - - auto it = corpse_list.begin(); - client->Message(Chat::White, "Player Corpses in the zone:"); - while (it != corpse_list.end()) { - if (it->second->IsPlayerCorpse()) { - client->Message(Chat::White, " %5d: %s", it->first, it->second->GetName()); - x++; + uint32 corpse_count = 0; + for (const auto& corpse : corpse_list) { + uint32 corpse_number = (corpse_count + 1); + if (corpse.second->IsPlayerCorpse()) { + client->Message( + Chat::White, + fmt::format( + "Corpse {} | Name: {} ({})", + corpse_number, + corpse.second->GetName(), + corpse.second->GetID() + ).c_str() + ); + corpse_count++; } - ++it; } - client->Message(Chat::White, "%d player corpses listed.", x); + + if (corpse_count > 0) { + client->Message( + Chat::White, + fmt::format( + "{} Player corpses listed.", + corpse_count + ).c_str() + ); + } } // returns the number of corpses deleted. A negative number indicates an error code. -int32 EntityList::DeleteNPCCorpses() +uint32 EntityList::DeleteNPCCorpses() { - int32 x = 0; - - auto it = corpse_list.begin(); - while (it != corpse_list.end()) { - if (it->second->IsNPCCorpse()) { - it->second->DepopNPCCorpse(); - x++; + uint32 corpse_count = 0; + for (const auto& corpse : corpse_list) { + if (corpse.second->IsNPCCorpse()) { + corpse.second->DepopNPCCorpse(); + corpse_count++; } - ++it; } - return x; + return corpse_count; } void EntityList::CorpseFix(Client* c) @@ -3215,19 +3240,16 @@ void EntityList::CorpseFix(Client* c) } // returns the number of corpses deleted. A negative number indicates an error code. -int32 EntityList::DeletePlayerCorpses() +uint32 EntityList::DeletePlayerCorpses() { - int32 x = 0; - - auto it = corpse_list.begin(); - while (it != corpse_list.end()) { - if (it->second->IsPlayerCorpse()) { - it->second->CastToCorpse()->Delete(); - x++; + uint32 corpse_count = 0; + for (const auto& corpse : corpse_list) { + if (corpse.second->IsPlayerCorpse()) { + corpse.second->Delete(); + corpse_count++; } - ++it; } - return x; + return corpse_count; } void EntityList::SendPetitionToAdmins() diff --git a/zone/entity.h b/zone/entity.h index a42165fc6..c264237c9 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -440,8 +440,8 @@ public: void ListNPCCorpses(Client* client); void ListPlayerCorpses(Client* client); - int32 DeleteNPCCorpses(); - int32 DeletePlayerCorpses(); + uint32 DeleteNPCCorpses(); + uint32 DeletePlayerCorpses(); void CorpseFix(Client* c); void WriteEntityIDs(); void HalveAggro(Mob* who); diff --git a/zone/gm_commands/corpse.cpp b/zone/gm_commands/corpse.cpp index 739c3458a..43c760fc4 100755 --- a/zone/gm_commands/corpse.cpp +++ b/zone/gm_commands/corpse.cpp @@ -3,166 +3,354 @@ void command_corpse(Client *c, const Seperator *sep) { + int arguments = sep->argnum; + if (!arguments) { + c->Message(Chat::White, "Usage: #corpse delete - Delete targeted corpse"); + c->Message(Chat::White, "Usage: #corpse deletenpccorpses - Deletes all NPC corpses"); + c->Message(Chat::White, "Usage: #corpse inspectloot - Inspects the loot on a corpse"); + c->Message(Chat::White, "Usage: #corpse listnpc - Lists all NPC corpses"); + c->Message(Chat::White, "Usage: #corpse lock - Locks the corpse, only GMs can loot the corpse when it is locked"); + c->Message(Chat::White, "Usage: #corpse removecash - Removes the cash from a corpse"); + c->Message(Chat::White, "Usage: #corpse unlock - Unlocks the corpses, allowing non-GMs to loot the corpse"); + if (c->Admin() >= commandEditPlayerCorpses) { + c->Message(Chat::White, "Usage: #corpse charid [Character ID] - Change player corpse's owner"); + c->Message(Chat::White, "Usage: #corpse deleteplayercorpses - Deletes all player corpses"); + c->Message(Chat::White, "Usage: #corpse depop [Bury] - Depops single target corpse."); + c->Message(Chat::White, "Usage: #corpse depopall [Bury] - Depops all target player's corpses."); + c->Message(Chat::White, "Usage: #corpse listplayer - Lists all player corpses"); + c->Message(Chat::White, "Usage: #corpse moveallgraveyard - Moves all player corpses to the current zone's graveyard or non-instance"); + c->Message(Chat::White, "Note: Set bury to 0 to skip burying the corpses."); + } + return; + } + Mob *target = c->GetTarget(); + bool is_character_id = !strcasecmp(sep->arg[1], "charid"); + bool is_delete = !strcasecmp(sep->arg[1], "delete"); + bool is_delete_npc_corpses = !strcasecmp(sep->arg[1], "deletenpccorpses"); + bool is_delete_player_corpses = !strcasecmp(sep->arg[1], "deleteplayercorpses"); + bool is_depop = !strcasecmp(sep->arg[1], "depop"); + bool is_depop_all = !strcasecmp(sep->arg[1], "depopall"); + bool is_inspect_loot = !strcasecmp(sep->arg[1], "inspectloot"); + bool is_list_npc = !strcasecmp(sep->arg[1], "listnpc"); + bool is_list_player = !strcasecmp(sep->arg[1], "listplayer"); + bool is_lock = !strcasecmp(sep->arg[1], "lock"); + bool is_move_all_to_graveyard = !strcasecmp(sep->arg[1], "moveallgraveyard"); + bool is_remove_cash = !strcasecmp(sep->arg[1], "removecash"); + bool is_reset_looter = !strcasecmp(sep->arg[1], "resetlooter"); + bool is_unlock = !strcasecmp(sep->arg[1], "unlock"); + if ( + !is_character_id && + !is_delete && + !is_delete_npc_corpses && + !is_delete_player_corpses && + !is_depop && + !is_depop_all && + !is_inspect_loot && + !is_list_npc && + !is_list_player && + !is_lock && + !is_move_all_to_graveyard && + !is_remove_cash && + !is_reset_looter && + !is_unlock + ) { + c->Message(Chat::White, "Usage: #corpse delete - Delete targeted corpse"); + c->Message(Chat::White, "Usage: #corpse deletenpccorpses - Deletes all NPC corpses"); + c->Message(Chat::White, "Usage: #corpse inspectloot - Inspects the loot on a corpse"); + c->Message(Chat::White, "Usage: #corpse listnpc - Lists all NPC corpses"); + c->Message(Chat::White, "Usage: #corpse lock - Locks the corpse, only GMs can loot the corpse when it is locked"); + c->Message(Chat::White, "Usage: #corpse removecash - Removes the cash from a corpse"); + c->Message(Chat::White, "Usage: #corpse unlock - Unlocks the corpses, allowing non-GMs to loot the corpse"); + if (c->Admin() >= commandEditPlayerCorpses) { + c->Message(Chat::White, "Usage: #corpse charid [Character ID] - Change player corpse's owner"); + c->Message(Chat::White, "Usage: #corpse deleteplayercorpses - Deletes all player corpses"); + c->Message(Chat::White, "Usage: #corpse depop [Bury] - Depops single target corpse."); + c->Message(Chat::White, "Usage: #corpse depopall [Bury] - Depops all target player's corpses."); + c->Message(Chat::White, "Usage: #corpse listplayer - Lists all player corpses"); + c->Message(Chat::White, "Usage: #corpse moveallgraveyard - Moves all player corpses to the current zone's graveyard or non-instance"); + c->Message(Chat::White, "Note: Set bury to 0 to skip burying the corpses."); + } + return; + } - if (strcasecmp(sep->arg[1], "DeletePlayerCorpses") == 0 && c->Admin() >= commandEditPlayerCorpses) { - int32 tmp = entity_list.DeletePlayerCorpses(); - if (tmp >= 0) { - c->Message(Chat::White, "%i corpses deleted.", tmp); - } - else { - c->Message(Chat::White, "DeletePlayerCorpses Error #%i", tmp); - } - } - else if (strcasecmp(sep->arg[1], "delete") == 0) { - if (target == 0 || !target->IsCorpse()) { - c->Message(Chat::White, "Error: Target the corpse you wish to delete"); - } - else if (target->IsNPCCorpse()) { - c->Message(Chat::White, "Depoping %s.", target->GetName()); - target->CastToCorpse()->Delete(); + if (is_delete_player_corpses) { + if (c->Admin() >= commandEditPlayerCorpses) { + auto corpses_deleted = entity_list.DeletePlayerCorpses(); + auto deleted_string = ( + corpses_deleted ? + fmt::format( + "{} Player corpse{} deleted.", + corpses_deleted, + corpses_deleted != 1 ? "s" : "" + ) : + "There are no player corpses to delete." + ); + c->Message(Chat::White, deleted_string.c_str()); + } else { + c->Message(Chat::White, "Your status is not high enough to delete player corpses."); + return; } - else if (c->Admin() >= commandEditPlayerCorpses) { - c->Message(Chat::White, "Deleting %s.", target->GetName()); - target->CastToCorpse()->Delete(); + } else if (is_delete) { + if (!target || !target->IsCorpse()) { + c->Message(Chat::White, "You must target a corpse to use this command."); + return; } - else { - c->Message(Chat::White, "Insufficient status to delete player corpse."); + + if (target->IsPlayerCorpse() && c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to delete a player corpse."); + return; } - } - else if (strcasecmp(sep->arg[1], "ListNPC") == 0) { - entity_list.ListNPCCorpses(c); - } - else if (strcasecmp(sep->arg[1], "ListPlayer") == 0) { - entity_list.ListPlayerCorpses(c); - } - else if (strcasecmp(sep->arg[1], "DeleteNPCCorpses") == 0) { - int32 tmp = entity_list.DeleteNPCCorpses(); - if (tmp >= 0) { - c->Message(Chat::White, "%d corpses deleted.", tmp); - } - else { - c->Message(Chat::White, "DeletePlayerCorpses Error #%d", tmp); - } - } - else if (strcasecmp(sep->arg[1], "charid") == 0 && c->Admin() >= commandEditPlayerCorpses) { - if (target == 0 || !target->IsPlayerCorpse()) { - c->Message(Chat::White, "Error: Target must be a player corpse."); - } - else if (!sep->IsNumber(2)) { - c->Message(Chat::White, "Error: charid must be a number."); - } - else { + + if ( + target->IsNPCCorpse() || + c->Admin() >= commandEditPlayerCorpses + ) { c->Message( Chat::White, - "Setting CharID=%u on PlayerCorpse '%s'", - target->CastToCorpse()->SetCharID(atoi(sep->arg[2])), - target->GetName()); - } - } - else if (strcasecmp(sep->arg[1], "ResetLooter") == 0) { - if (target == 0 || !target->IsCorpse()) { - c->Message(Chat::White, "Error: Target the corpse you wish to reset"); - } - else { - target->CastToCorpse()->ResetLooter(); - } - } - else if (strcasecmp(sep->arg[1], "RemoveCash") == 0) { - if (target == 0 || !target->IsCorpse()) { - c->Message(Chat::White, "Error: Target the corpse you wish to remove the cash from"); - } - else if (!target->IsPlayerCorpse() || c->Admin() >= commandEditPlayerCorpses) { - c->Message(Chat::White, "Removing Cash from %s.", target->GetName()); - target->CastToCorpse()->RemoveCash(); - } - else { - c->Message(Chat::White, "Insufficient status to modify player corpse."); - } - } - else if (strcasecmp(sep->arg[1], "InspectLoot") == 0) { - if (target == 0 || !target->IsCorpse()) { - c->Message(Chat::White, "Error: Target must be a corpse."); - } - else { - target->CastToCorpse()->QueryLoot(c); - } - } - else if (strcasecmp(sep->arg[1], "lock") == 0) { - if (target == 0 || !target->IsCorpse()) { - c->Message(Chat::White, "Error: Target must be a corpse."); - } - else { - target->CastToCorpse()->Lock(); - c->Message(Chat::White, "Locking %s...", target->GetName()); - } - } - else if (strcasecmp(sep->arg[1], "unlock") == 0) { - if (target == 0 || !target->IsCorpse()) { - c->Message(Chat::White, "Error: Target must be a corpse."); - } - else { - target->CastToCorpse()->UnLock(); - c->Message(Chat::White, "Unlocking %s...", target->GetName()); - } - } - else if (strcasecmp(sep->arg[1], "depop") == 0) { - if (target == 0 || !target->IsPlayerCorpse()) { - c->Message(Chat::White, "Error: Target must be a player corpse."); - } - else if (c->Admin() >= commandEditPlayerCorpses && target->IsPlayerCorpse()) { - c->Message(Chat::White, "Depoping %s.", target->GetName()); - target->CastToCorpse()->DepopPlayerCorpse(); - if (!sep->arg[2][0] || atoi(sep->arg[2]) != 0) { - target->CastToCorpse()->Bury(); - } - } - else { - c->Message(Chat::White, "Insufficient status to depop player corpse."); - } - } - else if (strcasecmp(sep->arg[1], "depopall") == 0) { - if (target == 0 || !target->IsClient()) { - c->Message(Chat::White, "Error: Target must be a player."); - } - else if (c->Admin() >= commandEditPlayerCorpses && target->IsClient()) { - c->Message(Chat::White, "Depoping %s\'s corpses.", target->GetName()); - target->CastToClient()->DepopAllCorpses(); - if (!sep->arg[2][0] || atoi(sep->arg[2]) != 0) { - target->CastToClient()->BuryPlayerCorpses(); - } - } - else { - c->Message(Chat::White, "Insufficient status to depop player corpse."); + fmt::format( + "Deleting {} corpse {} ({}).", + target->IsNPCCorpse() ? "NPC" : "player", + target->GetName(), + target->GetID() + ).c_str() + ); + target->CastToCorpse()->Delete(); + } + } else if (is_list_npc) { + entity_list.ListNPCCorpses(c); + } else if (is_list_player) { + if (c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to list player corpses."); + return; } - } - else if (strcasecmp(sep->arg[1], "moveallgraveyard") == 0) { - int count = entity_list.MovePlayerCorpsesToGraveyard(true); - c->Message(Chat::White, "Moved [%d] player corpse(s) to zone graveyard", count); - } - else if (sep->arg[1][0] == 0 || strcasecmp(sep->arg[1], "help") == 0) { - c->Message(Chat::White, "#Corpse Sub-Commands:"); - c->Message(Chat::White, " DeleteNPCCorpses"); - c->Message(Chat::White, " Delete - Delete targetted corpse"); - c->Message(Chat::White, " ListNPC"); - c->Message(Chat::White, " ListPlayer"); - c->Message(Chat::White, " Lock - GM locks the corpse - cannot be looted by non-GM"); - c->Message(Chat::White, " MoveAllGraveyard - move all player corpses to zone's graveyard or non-instance"); - c->Message(Chat::White, " UnLock"); - c->Message(Chat::White, " RemoveCash"); - c->Message(Chat::White, " InspectLoot"); - c->Message(Chat::White, " [to remove items from corpses, loot them]"); - c->Message(Chat::White, "Lead-GM status required to delete/modify player corpses"); - c->Message(Chat::White, " DeletePlayerCorpses"); - c->Message(Chat::White, " CharID [charid] - change player corpse's owner"); - c->Message(Chat::White, " Depop [bury] - Depops single target corpse."); - c->Message(Chat::White, " Depopall [bury] - Depops all target player's corpses."); - c->Message(Chat::White, "Set bury to 0 to skip burying the corpses."); - } - else { - c->Message(Chat::White, "Error, #corpse sub-command not found"); + entity_list.ListPlayerCorpses(c); + } else if (is_delete_npc_corpses) { + auto corpses_deleted = entity_list.DeleteNPCCorpses(); + auto deleted_string = ( + corpses_deleted ? + fmt::format( + "{} NPC corpse{} deleted.", + corpses_deleted, + corpses_deleted != 1 ? "s" : "" + ) : + "There are no NPC corpses to delete." + ); + c->Message(Chat::White, deleted_string.c_str()); + } else if (is_character_id) { + if (c->Admin() >= commandEditPlayerCorpses) { + if (!target || !target->IsPlayerCorpse()) { + c->Message(Chat::White, "You must target a player corpse to use this command."); + return; + } + + if (!sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #corpse charid [Character ID] - Change player corpse's owner"); + return; + } + + auto character_id = std::stoi(sep->arg[2]); + c->Message( + Chat::White, + fmt::format( + "Setting the owner to {} ({}) for the player corpse {} ({}).", + database.GetCharNameByID(character_id), + target->CastToCorpse()->SetCharID(character_id), + target->GetName(), + target->GetID() + ).c_str() + ); + } else { + c->Message(Chat::White, "Your status is not high enough to modify a player corpse's owner."); + return; + } + } else if (is_reset_looter) { + if (!target || !target->IsCorpse()) { + c->Message(Chat::White, "You must target a corpse to use this command."); + return; + } + + if (target->IsPlayerCorpse() && c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to reset looter on a player corpse."); + return; + } + + target->CastToCorpse()->ResetLooter(); + c->Message( + Chat::White, + fmt::format( + "Reset looter for {} corpse {} ({}).", + target->IsNPCCorpse() ? "NPC" : "player", + target->GetName(), + target->GetID() + ).c_str() + ); + } else if (is_remove_cash) { + if (!target || !target->IsCorpse()) { + c->Message(Chat::White, "You must target a corpse to use this command."); + return; + } + + if (target->IsPlayerCorpse() && c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to remove cash from a player corpse."); + return; + } + + if ( + target->IsNPCCorpse() || + c->Admin() >= commandEditPlayerCorpses + ) { + target->CastToCorpse()->RemoveCash(); + c->Message( + Chat::White, + fmt::format( + "Removed cash from {} corpse {} ({}).", + target->IsNPCCorpse() ? "NPC" : "player", + target->GetName(), + target->GetID() + ).c_str() + ); + } + } else if (is_inspect_loot) { + if (!target || !target->IsCorpse()) { + c->Message(Chat::White, "You must target a corpse to use this command."); + return; + } + + if (target->IsPlayerCorpse() && c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to inspect the loot of a player corpse."); + return; + } + + target->CastToCorpse()->QueryLoot(c); + } else if (is_lock) { + if (!target || !target->IsCorpse()) { + c->Message(Chat::White, "You must target a corpse to use this command."); + return; + } + + if (target->IsPlayerCorpse() && c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to lock player corpses."); + return; + } + + target->CastToCorpse()->Lock(); + c->Message( + Chat::White, + fmt::format( + "Locking {} corpse {} ({}).", + target->IsNPCCorpse() ? "NPC" : "player", + target->GetName(), + target->GetID() + ).c_str() + ); + } else if (is_unlock) { + if (!target || !target->IsCorpse()) { + c->Message(Chat::White, "You must target a corpse to use this command."); + return; + } + + if (target->IsPlayerCorpse() && c->Admin() < commandEditPlayerCorpses) { + c->Message(Chat::White, "Your status is not high enough to unlock player corpses."); + return; + } + + target->CastToCorpse()->UnLock(); + c->Message( + Chat::White, + fmt::format( + "Unlocking {} corpse {} ({}).", + target->IsNPCCorpse() ? "NPC" : "player", + target->GetName(), + target->GetID() + ).c_str() + ); + } else if (is_depop) { + if (!target || !target->IsPlayerCorpse()) { + c->Message(Chat::White, "You must target a player corpse to use this command."); + return; + } + + if (c->Admin() >= commandEditPlayerCorpses) { + bool bury_corpse = ( + sep->IsNumber(2) ? + ( + std::stoi(sep->arg[2]) != 0 ? + true : + false + ) : + false + ); + c->Message( + Chat::White, + fmt::format( + "Depopping player corpse {} ({}).", + target->GetName(), + target->GetID() + ).c_str() + ); + target->CastToCorpse()->DepopPlayerCorpse(); + if (bury_corpse) { + target->CastToCorpse()->Bury(); + } + } else { + c->Message(Chat::White, "Your status is not high enough to depop a player corpse."); + return; + } + } else if (is_depop_all) { + if (!target || !target->IsClient()) { + c->Message(Chat::White, "You must target a player to use this command."); + return; + } + + if (c->Admin() >= commandEditPlayerCorpses) { + bool bury_corpse = ( + sep->IsNumber(2) ? + ( + std::stoi(sep->arg[2]) != 0 ? + true : + false + ) : + false + ); + c->Message( + Chat::White, + fmt::format( + "Depopping all player corpses for {} ({}).", + target->GetName(), + target->GetID() + ).c_str() + ); + target->CastToClient()->DepopAllCorpses(); + if (bury_corpse) { + target->CastToClient()->BuryPlayerCorpses(); + } + } else { + c->Message(Chat::White, "Your status is not high enough to depop all of a player's corpses."); + return; + } + } else if (is_move_all_to_graveyard) { + int moved_count = entity_list.MovePlayerCorpsesToGraveyard(true); + if (c->Admin() >= commandEditPlayerCorpses) { + if (moved_count) { + c->Message( + Chat::White, + fmt::format( + "Moved {} player corpse{} to graveyard in {} ({}).", + moved_count, + moved_count != 1 ? "s" : "", + ZoneLongName(zone->GetZoneID()), + ZoneName(zone->GetZoneID()) + ).c_str() + ); + } else { + c->Message(Chat::White, "There are no player corpses to move to the graveyard."); + } + } else { + c->Message(Chat::White, "Your status is not high enough to move all player corpses to the graveyard."); + } } } diff --git a/zone/lua_entity_list.cpp b/zone/lua_entity_list.cpp index c7721271e..9ee08ecbf 100644 --- a/zone/lua_entity_list.cpp +++ b/zone/lua_entity_list.cpp @@ -277,12 +277,12 @@ void Lua_EntityList::SignalMobsByNPCID(uint32 npc_id, int signal) { self->SignalMobsByNPCID(npc_id, signal); } -int Lua_EntityList::DeleteNPCCorpses() { +uint32 Lua_EntityList::DeleteNPCCorpses() { Lua_Safe_Call_Int(); return self->DeleteNPCCorpses(); } -int Lua_EntityList::DeletePlayerCorpses() { +uint32 Lua_EntityList::DeletePlayerCorpses() { Lua_Safe_Call_Int(); return self->DeletePlayerCorpses(); } @@ -489,8 +489,8 @@ luabind::scope lua_register_entity_list() { .def("ChannelMessage", (void(Lua_EntityList::*)(Lua_Mob, int, int, const char*))&Lua_EntityList::ChannelMessage) .def("ClearClientPetitionQueue", (void(Lua_EntityList::*)(void))&Lua_EntityList::ClearClientPetitionQueue) .def("ClearFeignAggro", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::ClearFeignAggro) - .def("DeleteNPCCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeleteNPCCorpses) - .def("DeletePlayerCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeletePlayerCorpses) + .def("DeleteNPCCorpses", (uint32(Lua_EntityList::*)(void))&Lua_EntityList::DeleteNPCCorpses) + .def("DeletePlayerCorpses", (uint32(Lua_EntityList::*)(void))&Lua_EntityList::DeletePlayerCorpses) .def("DoubleAggro", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::DoubleAggro) .def("Fighting", (bool(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::Fighting) .def("FilteredMessageClose", &Lua_EntityList::FilteredMessageClose) diff --git a/zone/lua_entity_list.h b/zone/lua_entity_list.h index 4fa7b97b9..ba67971dd 100644 --- a/zone/lua_entity_list.h +++ b/zone/lua_entity_list.h @@ -99,8 +99,8 @@ public: std::string MakeNameUnique(const char *name); std::string RemoveNumbers(const char *name); void SignalMobsByNPCID(uint32 npc_id, int signal); - int DeleteNPCCorpses(); - int DeletePlayerCorpses(); + uint32 DeleteNPCCorpses(); + uint32 DeletePlayerCorpses(); void HalveAggro(Lua_Mob who); void DoubleAggro(Lua_Mob who); void ClearFeignAggro(Lua_Mob who); diff --git a/zone/npc.cpp b/zone/npc.cpp index c11e6beb0..905257a28 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -674,12 +674,18 @@ void NPC::QueryLoot(Client* to) to->Message( Chat::White, fmt::format( - "Item {} | Name: {} ID: {} Min Level: {} Max Level: {}", + "Item {} | Name: {} ({}){}", item_number, linker.GenerateLink().c_str(), current_item->item_id, - current_item->trivial_min_level, - current_item->trivial_max_level + ( + current_item->charges > 1 ? + fmt::format( + " Amount: {}", + current_item->charges + ) : + "" + ) ).c_str() ); item_count++; @@ -696,11 +702,13 @@ void NPC::QueryLoot(Client* to) to->Message( Chat::White, fmt::format( - "Money | Platinum: {} Gold: {} Silver: {} Copper: {}", - platinum, - gold, - silver, - copper + "Money | {}", + ConvertMoneyToString( + platinum, + gold, + silver, + copper + ) ).c_str() ); } diff --git a/zone/perl_entity.cpp b/zone/perl_entity.cpp index 8ae7976eb..7dddf791b 100644 --- a/zone/perl_entity.cpp +++ b/zone/perl_entity.cpp @@ -1040,12 +1040,12 @@ XS(XS_EntityList_DeleteNPCCorpses) { Perl_croak(aTHX_ "Usage: EntityList::DeleteNPCCorpses(THIS)"); // @categories Corpse { EntityList *THIS; - int32 RETVAL; + uint32 RETVAL; dXSTARG; VALIDATE_THIS_IS_ENTITY; RETVAL = THIS->DeleteNPCCorpses(); XSprePUSH; - PUSHi((IV) RETVAL); + PUSHu((UV) RETVAL); } XSRETURN(1); } @@ -1057,12 +1057,12 @@ XS(XS_EntityList_DeletePlayerCorpses) { Perl_croak(aTHX_ "Usage: EntityList::DeletePlayerCorpses(THIS)"); // @categories Account and Character, Corpse { EntityList *THIS; - int32 RETVAL; + uint32 RETVAL; dXSTARG; VALIDATE_THIS_IS_ENTITY; RETVAL = THIS->DeletePlayerCorpses(); XSprePUSH; - PUSHi((IV) RETVAL); + PUSHu((UV) RETVAL); } XSRETURN(1); }