#include "sidecar_api.h" #include "../../common/json/json.hpp" #include "../zone.h" extern Zone *zone; void SidecarApi::LootSimulatorController(const httplib::Request &req, httplib::Response &res) { int loottable_id = req.has_param("loottable_id") ? std::stoi(req.get_param_value("loottable_id")) : 4027; int npc_id = req.has_param("npc_id") ? std::stoi(req.get_param_value("npc_id")) : 32040; // lord nagafen auto iterations = 100; auto log_enabled = false; LogSys.log_settings[Logs::Loot].log_to_console = 0; nlohmann::json j; auto npc_type = content_db.LoadNPCTypesData(npc_id); if (npc_type) { auto npc = new NPC( npc_type, nullptr, glm::vec4(0, 0, 0, 0), GravityBehavior::Water ); BenchTimer benchmark; // depop the previous one for (auto &n: entity_list.GetNPCList()) { if (n.second->GetNPCTypeID() == npc_id) { LogInfo("found npc id [{}]", npc_id); n.second->Depop(false); } } entity_list.Process(); entity_list.MobProcess(); npc->SetRecordLootStats(true); for (int i = 0; i < iterations; i++) { npc->AddLootTable(loottable_id); for (auto &id: zone->GetGlobalLootTables(npc)) { npc->AddLootTable(id); } } entity_list.AddNPC(npc); j["data"]["loottable_id"] = loottable_id; j["data"]["npc_id"] = npc_id; j["data"]["npc_name"] = npc->GetCleanName(); j["data"]["rolled_items_count"] = npc->GetRolledItems().size(); j["data"]["iterations"] = iterations; // npc level loot table auto loot_table = zone->GetLootTable(loottable_id); if (!loot_table) { res.status = 400; j["error"] = fmt::format("Loot table not found [{}]", loottable_id); res.set_content(j.dump(), "application/json"); return; } auto le = zone->GetLootTableEntries(loottable_id); // translate above for loop using le for (auto &e: le) { auto loot_drop = zone->GetLootdrop(e.lootdrop_id); if (!loot_drop.id) { continue; } LogLootDetail( "# Lootdrop ID [{}] drop_limit [{}] min_drop [{}] mult [{}] probability [{}]", e.lootdrop_id, e.droplimit, e.mindrop, e.multiplier, e.probability ); nlohmann::json jle; jle["lootdrop_id"] = e.lootdrop_id; jle["droplimit"] = e.droplimit; jle["mindrop"] = e.mindrop; jle["multiplier"] = e.multiplier; jle["probability"] = e.probability; auto loot_drop_entries = zone->GetLootdropEntries(e.lootdrop_id); int slot = 0; for (auto &f: loot_drop_entries) { int rolled_count = npc->GetRolledItemCount(f.item_id); const EQ::ItemData *item = database.GetItem(f.item_id); auto rolled_percentage = (float) ((float) ((float) rolled_count / (float) iterations) * 100); nlohmann::json drop; drop["slot"] = slot; drop["item_id"] = f.item_id; drop["item_name"] = item->Name; drop["chance"] = fmt::format("{:.2f}", f.chance); drop["simulate_rolled_count"] = rolled_count; drop["simulate_rolled_percentage"] = fmt::format("{:.2f}", rolled_percentage); jle["drops"].push_back(drop); slot++; } j["lootdrops"].push_back(jle); } // global loot for (auto &id: zone->GetGlobalLootTables(npc)) { loot_table = zone->GetLootTable(id); if (!loot_table) { LogInfo("Global Loot table not found [{}]", id); continue; } le = zone->GetLootTableEntries(id); // translate above for loop using le for (auto &e: le) { auto loot_drop = zone->GetLootdrop(e.lootdrop_id); if (!loot_drop.id) { continue; } LogLootDetail( "# Lootdrop ID [{}] drop_limit [{}] min_drop [{}] mult [{}] probability [{}]", e.lootdrop_id, e.droplimit, e.mindrop, e.multiplier, e.probability ); nlohmann::json jle; jle["lootdrop_id"] = e.lootdrop_id; jle["droplimit"] = e.droplimit; jle["mindrop"] = e.mindrop; jle["multiplier"] = e.multiplier; jle["probability"] = e.probability; auto loot_drop_entries = zone->GetLootdropEntries(e.lootdrop_id); int slot = 0; for (auto &f: loot_drop_entries) { int rolled_count = npc->GetRolledItemCount(f.item_id); const EQ::ItemData *item = database.GetItem(f.item_id); auto rolled_percentage = (float) ((float) ((float) rolled_count / (float) iterations) * 100); nlohmann::json drop; drop["slot"] = slot; drop["item_id"] = f.item_id; drop["item_name"] = item->Name; drop["chance"] = fmt::format("{:.2f}", f.chance); drop["simulate_rolled_count"] = rolled_count; drop["simulate_rolled_percentage"] = fmt::format("{:.2f}", rolled_percentage); jle["drops"].push_back(drop); slot++; } j["global"]["lootdrops"].push_back(jle); } } j["data"]["time"] = benchmark.elapsed(); res.status = 200; res.set_content(j.dump(), "application/json"); } else { res.status = 400; j["error"] = fmt::format("Failed to spawn NPC ID [{}]", npc_id); res.set_content(j.dump(), "application/json"); } }