diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index 9b8fb9076..0a5879458 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -435,3 +435,81 @@ std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id) return std::string(); } + +const std::map& EQ::constants::GetObjectTypeMap() +{ + static const std::map object_type_map = { + { ObjectTypes::SmallBag, "Small Bag" }, + { ObjectTypes::LargeBag, "Large Bag" }, + { ObjectTypes::Quiver, "Quiver" }, + { ObjectTypes::BeltPouch, "Belt Pouch" }, + { ObjectTypes::WristPouch, "Wrist Pouch" }, + { ObjectTypes::Backpack, "Backpack" }, + { ObjectTypes::SmallChest, "Small Chest" }, + { ObjectTypes::LargeChest, "Large Chest" }, + { ObjectTypes::Bandolier, "Bandolier" }, + { ObjectTypes::Medicine, "Medicine" }, + { ObjectTypes::Tinkering, "Tinkering" }, + { ObjectTypes::Lexicon, "Lexicon" }, + { ObjectTypes::PoisonMaking, "Mortar and Pestle" }, + { ObjectTypes::Quest, "Quest" }, + { ObjectTypes::MixingBowl, "Mixing Bowl" }, + { ObjectTypes::Baking, "Baking" }, + { ObjectTypes::Tailoring, "Tailoring" }, + { ObjectTypes::Blacksmithing, "Blacksmithing" }, + { ObjectTypes::Fletching, "Fletching" }, + { ObjectTypes::Brewing, "Brewing" }, + { ObjectTypes::JewelryMaking, "Jewelry Making" }, + { ObjectTypes::Pottery, "Pottery" }, + { ObjectTypes::Kiln, "Kiln" }, + { ObjectTypes::KeyMaker, "Key Maker" }, + { ObjectTypes::ResearchWIZ, "Lexicon" }, + { ObjectTypes::ResearchMAG, "Lexicon" }, + { ObjectTypes::ResearchNEC, "Lexicon" }, + { ObjectTypes::ResearchENC, "Lexicon" }, + { ObjectTypes::Unknown, "Unknown" }, + { ObjectTypes::ResearchPractice, "Lexicon" }, + { ObjectTypes::Alchemy, "Alchemy" }, + { ObjectTypes::HighElfForge, "High Elf Forge" }, + { ObjectTypes::DarkElfForge, "Dark Elf Forge" }, + { ObjectTypes::OgreForge, "Ogre Forge" }, + { ObjectTypes::DwarfForge, "Dwarf Forge" }, + { ObjectTypes::GnomeForge, "Gnome Forge" }, + { ObjectTypes::BarbarianForge, "Barbarian Forge" }, + { ObjectTypes::IksarForge, "Iksar Forge" }, + { ObjectTypes::HumanForgeOne, "Human Forge" }, + { ObjectTypes::HumanForgeTwo, "Human Forge" }, + { ObjectTypes::HalflingTailoringOne, "Halfling Tailoring" }, + { ObjectTypes::HalflingTailoringTwo, "Halfling Tailoring" }, + { ObjectTypes::EruditeTailoring, "Erudite Tailoring" }, + { ObjectTypes::WoodElfTailoring, "Wood Elf Tailoring" }, + { ObjectTypes::WoodElfFletching, "Wood Elf Fletching" }, + { ObjectTypes::IksarPottery, "Iksar Pottery" }, + { ObjectTypes::Fishing, "Fishing" }, + { ObjectTypes::TrollForge, "Troll Forge" }, + { ObjectTypes::WoodElfForge, "Wood Elf Forge" }, + { ObjectTypes::HalflingForge, "Halfling Forge" }, + { ObjectTypes::EruditeForge, "Erudite Forge" }, + { ObjectTypes::Merchant, "Merchant" }, + { ObjectTypes::FroglokForge, "Froglok Forge" }, + { ObjectTypes::Augmenter, "Augmenter" }, + { ObjectTypes::Churn, "Churn" }, + { ObjectTypes::TransformationMold, "Transformation Mold" }, + { ObjectTypes::DetransformationMold, "Detransformation Mold" }, + { ObjectTypes::Unattuner, "Unattuner" }, + { ObjectTypes::TradeskillBag, "Tradeskill Bag" }, + { ObjectTypes::CollectibleBag, "Collectible Bag" }, + { ObjectTypes::NoDeposit, "No Deposit" } + }; + + return object_type_map; +} + +std::string EQ::constants::GetObjectTypeName(int object_type) +{ + if (EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) { + return EQ::constants::GetObjectTypeMap().find(object_type)->second; + } + + return std::string(); +} diff --git a/common/emu_constants.h b/common/emu_constants.h index ba4aaedc5..d723fbed8 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -248,6 +248,70 @@ namespace EQ Looting }; + enum ObjectTypes : int { + SmallBag, + LargeBag, + Quiver, + BeltPouch, + WristPouch, + Backpack, + SmallChest, + LargeChest, + Bandolier, + Medicine, + Tinkering, + Lexicon, + PoisonMaking, + Quest, + MixingBowl, + Baking, + Tailoring, + Blacksmithing, + Fletching, + Brewing, + JewelryMaking, + Pottery, + Kiln, + KeyMaker, + ResearchWIZ, + ResearchMAG, + ResearchNEC, + ResearchENC, + Unknown, + ResearchPractice, + Alchemy, + HighElfForge, + DarkElfForge, + OgreForge, + DwarfForge, + GnomeForge, + BarbarianForge, + IksarForge, + HumanForgeOne, + HumanForgeTwo, + HalflingTailoringOne, + HalflingTailoringTwo, + EruditeTailoring, + WoodElfTailoring, + WoodElfFletching, + IksarPottery, + Fishing, + TrollForge, + WoodElfForge, + HalflingForge, + EruditeForge, + Merchant, + FroglokForge, + Augmenter, + Churn, + TransformationMold, + DetransformationMold, + Unattuner, + TradeskillBag, + CollectibleBag, + NoDeposit + }; + const char *GetStanceName(StanceType stance_type); int ConvertStanceTypeToIndex(StanceType stance_type); @@ -278,6 +342,9 @@ namespace EQ extern const std::map& GetSpawnAnimationMap(); std::string GetSpawnAnimationName(uint8 animation_id); + extern const std::map& GetObjectTypeMap(); + std::string GetObjectTypeName(int object_type); + 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 3558c7358..afefb0f25 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -146,6 +146,7 @@ int command_init(void) command_add("findfaction", "[Search Criteria] - Search for a faction", AccountStatus::Guide, command_findfaction) || command_add("findnpctype", "[Search Criteria] - Search database NPC types", AccountStatus::GMAdmin, command_findnpctype) || command_add("findrace", "[Search Criteria] - Search for a race", AccountStatus::Guide, command_findrace) || + command_add("findrecipe", "[Search Criteria] - Search for a recipe", AccountStatus::Guide, command_findrecipe) || command_add("findskill", "[Search Criteria] - Search for a skill", AccountStatus::Guide, command_findskill) || command_add("findspell", "[Search Criteria] - Search for a spell", AccountStatus::Guide, command_findspell) || command_add("findtask", "[Search Criteria] - Search for a task", AccountStatus::Guide, command_findtask) || @@ -341,6 +342,7 @@ int command_init(void) command_add("viewcurrencies", "View your or your target's currencies", AccountStatus::GMAdmin, command_viewcurrencies) || command_add("viewnpctype", "[NPC ID] - Show stats for an NPC by NPC ID", AccountStatus::GMAdmin, command_viewnpctype) || command_add("viewpetition", "[petition number] - View a petition", AccountStatus::ApprenticeGuide, command_viewpetition) || + command_add("viewrecipe", "[Recipe ID] - Show a recipe's entries", AccountStatus::GMAdmin, command_viewrecipe) || command_add("viewzoneloot", "[item id] - Allows you to search a zone's loot for a specific item ID. (0 shows all loot in the zone)", AccountStatus::QuestTroupe, command_viewzoneloot) || command_add("wc", "[wear slot] [material] - Sends an OP_WearChange for your target", AccountStatus::GMMgmt, command_wc) || command_add("weather", "[0/1/2/3] (Off/Rain/Snow/Manual) - Change the weather", AccountStatus::QuestTroupe, command_weather) || @@ -981,6 +983,7 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/findfaction.cpp" #include "gm_commands/findnpctype.cpp" #include "gm_commands/findrace.cpp" +#include "gm_commands/findrecipe.cpp" #include "gm_commands/findskill.cpp" #include "gm_commands/findspell.cpp" #include "gm_commands/findtask.cpp" @@ -1174,6 +1177,7 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/viewcurrencies.cpp" #include "gm_commands/viewnpctype.cpp" #include "gm_commands/viewpetition.cpp" +#include "gm_commands/viewrecipe.cpp" #include "gm_commands/viewzoneloot.cpp" #include "gm_commands/wc.cpp" #include "gm_commands/weather.cpp" diff --git a/zone/command.h b/zone/command.h index 3a0566973..fe49b69e3 100644 --- a/zone/command.h +++ b/zone/command.h @@ -83,6 +83,7 @@ void command_findclass(Client *c, const Seperator *sep); void command_findfaction(Client *c, const Seperator *sep); void command_findnpctype(Client *c, const Seperator *sep); void command_findrace(Client *c, const Seperator *sep); +void command_findrecipe(Client *c, const Seperator *sep); void command_findskill(Client *c, const Seperator *sep); void command_findspell(Client *c, const Seperator *sep); void command_findtask(Client *c, const Seperator *sep); @@ -291,6 +292,7 @@ void command_version(Client *c, const Seperator *sep); void command_viewcurrencies(Client *c, const Seperator *sep); void command_viewnpctype(Client *c, const Seperator *sep); void command_viewpetition(Client *c, const Seperator *sep); +void command_viewrecipe(Client *c, const Seperator *sep); void command_viewzoneloot(Client *c, const Seperator *sep); void command_wc(Client *c, const Seperator *sep); void command_weather(Client *c, const Seperator *sep); diff --git a/zone/gm_commands/findrecipe.cpp b/zone/gm_commands/findrecipe.cpp new file mode 100755 index 000000000..fdcdb9169 --- /dev/null +++ b/zone/gm_commands/findrecipe.cpp @@ -0,0 +1,96 @@ +#include "../client.h" +#include "../command.h" +#include "../../common/repositories/tradeskill_recipe_repository.h" + +void command_findrecipe(Client *c, const Seperator *sep) +{ + int arguments = sep->argnum; + if (!arguments) { + c->Message(Chat::White, "Command Syntax: #findrecipe [Search Criteria]"); + return; + } + + if (sep->IsNumber(1)) { + auto recipe_id = static_cast(std::stoul(sep->arg[1])); + auto r = TradeskillRecipeRepository::GetWhere( + database, + fmt::format("id = {}", recipe_id) + ); + + if (r.empty() || !r[0].id) { + c->Message( + Chat::White, + fmt::format( + "Recipe ID {} could not be found.", + Strings::Commify(std::to_string(recipe_id)) + ).c_str() + ); + return; + } + + bool can_view_recipes = c->Admin() >= GetCommandStatus(c, "viewrecipe"); + + c->Message( + Chat::White, + fmt::format( + "Recipe {} | {}{}", + Strings::Commify(std::to_string(recipe_id)), + r[0].name, + can_view_recipes ? fmt::format(" | {}", Saylink::Silent(fmt::format("#viewrecipe {}", r[0].id), "View")) : "" + ).c_str() + ); + } else { + auto search_criteria = Strings::ToLower(sep->argplus[1]); + int found_count = 0; + + auto rl = TradeskillRecipeRepository::GetWhere( + database, + fmt::format("`name` LIKE '%{}%' ORDER BY `id` ASC", search_criteria) + ); + + if (rl.empty() || !rl[0].id) { + c->Message( + Chat::White, + fmt::format( + "No recipes were found matching '{}'.", + search_criteria + ).c_str() + ); + return; + } + + bool can_view_recipes = c->Admin() >= GetCommandStatus(c, "viewrecipe"); + + for (const auto& r : rl) { + c->Message( + Chat::White, + fmt::format( + "Recipe {} | {}{}", + Strings::Commify(std::to_string(r.id)), + r.name, + can_view_recipes ? fmt::format(" | {}", Saylink::Silent(fmt::format("#viewrecipe {}", r.id), "View")) : "" + ).c_str() + ); + + if (found_count == 50) { + break; + } + + found_count++; + } + + if (found_count == 50) { + c->Message(Chat::White, "50 Recipes found, max reached."); + } else { + c->Message( + Chat::White, + fmt::format( + "{} Recipe{} found.", + found_count, + found_count != 1 ? "s" : "" + ).c_str() + ); + } + } +} + diff --git a/zone/gm_commands/viewrecipe.cpp b/zone/gm_commands/viewrecipe.cpp new file mode 100755 index 000000000..d8eb820f3 --- /dev/null +++ b/zone/gm_commands/viewrecipe.cpp @@ -0,0 +1,120 @@ +#include "../client.h" +#include "../command.h" +#include "../../common/repositories/tradeskill_recipe_repository.h" +#include "../../common/repositories/tradeskill_recipe_entries_repository.h" + +void command_viewrecipe(Client *c, const Seperator *sep) +{ + int arguments = sep->argnum; + if (!arguments || !sep->IsNumber(1)) { + c->Message(Chat::White, "Command Syntax: #viewrecipe [Recipe ID]"); + return; + } + + auto recipe_id = static_cast(std::stoul(sep->arg[1])); + auto re = TradeskillRecipeEntriesRepository::GetWhere( + database, + fmt::format("recipe_id = {} ORDER BY id ASC", recipe_id) + ); + auto r = TradeskillRecipeRepository::GetWhere( + database, + fmt::format("id = {}", recipe_id) + ); + + if (re.empty() || r.empty() || !re[0].id || !r[0].id) { + c->Message( + Chat::White, + fmt::format( + "Recipe ID {} has no entries or could not be found.", + Strings::Commify(std::to_string(recipe_id)) + ).c_str() + ); + return; + } + + c->Message( + Chat::White, + fmt::format( + "Recipe {} | {}", + Strings::Commify(std::to_string(recipe_id)), + r[0].name + ).c_str() + ); + + auto entry_number = 1; + bool can_summon_items = c->Admin() >= GetCommandStatus(c, "summonitem"); + + for (const auto& e : re) { + c->Message( + Chat::White, + fmt::format( + "Entry {}{} | {}{}", + entry_number, + e.iscontainer > 0 ? " (Container)" : "", + e.item_id > 1000 ? database.CreateItemLink(e.item_id) : EQ::constants::GetObjectTypeName(e.item_id), + can_summon_items && e.item_id > 1000 ? fmt::format(" | {}", Saylink::Silent(fmt::format("#si {}", e.item_id), "Summon")) : "" + ).c_str() + ); + + std::vector emv; + bool has_message = false; + + if (e.componentcount) { + emv.push_back( + fmt::format( + "Component: {}", + e.componentcount + ) + ); + + has_message = true; + } + + if (e.failcount) { + emv.push_back( + fmt::format( + "Fail: {}", + e.failcount + ) + ); + + has_message = true; + } + + if (e.salvagecount) { + emv.push_back( + fmt::format( + "Salvage: {}", + e.salvagecount + ) + ); + + has_message = true; + } + + if (e.successcount) { + emv.push_back( + fmt::format( + "Success: {}", + e.successcount + ) + ); + + has_message = true; + } + + if (has_message) { + c->Message( + Chat::White, + fmt::format( + "Entry {} Counts | {}", + entry_number, + Strings::Implode(" | ", emv) + ).c_str() + ); + } + + entry_number++; + } +} +