#include "bazaar.h" #include "../../common/item_instance.h" #include "repositories/trader_repository.h" #include std::vector Bazaar::GetSearchResults( Database &db, Database &content_db, BazaarSearchCriteria_Struct search, uint32 char_zone_id, int32 char_zone_instance_id ) { LogTrading( "Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] " "max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] " "search_scope [{}] char_zone_id [{}], char_zone_instance_id [{}]", search.item_name, search.min_cost, search.max_cost, search.min_level, search.max_level, search.max_results, search.prestige, search.augment, search.trader_entity_id, search.trader_id, search.search_scope, char_zone_id, char_zone_instance_id ); static std::map item_slot_searches_new = { {EQ::invslot::slotCharm, 1}, {EQ::invslot::slotEar1, 2}, {EQ::invslot::slotHead, 4}, {EQ::invslot::slotFace, 8}, {EQ::invslot::slotEar2, 16}, {EQ::invslot::slotNeck, 32}, {EQ::invslot::slotShoulders, 64}, {EQ::invslot::slotArms, 128}, {EQ::invslot::slotBack, 256}, {EQ::invslot::slotWrist1, 512}, {EQ::invslot::slotWrist2, 1024}, {EQ::invslot::slotRange, 2048}, {EQ::invslot::slotHands, 4096}, {EQ::invslot::slotPrimary, 8192}, {EQ::invslot::slotSecondary, 16384}, {EQ::invslot::slotFinger1, 32768}, {EQ::invslot::slotFinger2, 65536}, {EQ::invslot::slotChest, 131072}, {EQ::invslot::slotLegs, 262144}, {EQ::invslot::slotFeet, 524288}, {EQ::invslot::slotWaist, 1048576}, {EQ::invslot::slotPowerSource, 2097152}, {EQ::invslot::slotAmmo, 4194304}, }; struct ItemSearchType { EQ::item::ItemType type; std::string condition; }; std::vector item_search_types_new = { {EQ::item::ItemType::ItemTypeBook, " AND (items.itemclass = 2 or items.itemclass = 31)"}, {EQ::item::ItemType::ItemTypeContainer, " AND (items.itemclass = 1 or items.itemclass = 67)"}, {EQ::item::ItemType::ItemTypeAllEffects, " AND (items.scrolleffect > 0 && items.scrolleffect < 65000)"}, {EQ::item::ItemType::ItemTypeUnknown9, " AND items.worneffect = 998"}, {EQ::item::ItemType::ItemTypeUnknown10, " AND (items.worneffect >= 1298 && items.worneffect <= 1307)"}, {EQ::item::ItemType::ItemTypeFocusEffect, " AND items.focuseffect > 0"}, {EQ::item::ItemType::ItemTypeArmor, " AND items.itemtype = 10"}, {EQ::item::ItemType::ItemType1HBlunt, " AND items.itemtype = 3"}, {EQ::item::ItemType::ItemType1HPiercing, " AND items.itemtype = 2"}, {EQ::item::ItemType::ItemType1HSlash, " AND items.itemtype = 0"}, {EQ::item::ItemType::ItemType2HBlunt, " AND items.itemtype = 4"}, {EQ::item::ItemType::ItemType2HSlash, " AND items.itemtype = 1"}, {EQ::item::ItemType::ItemTypeBow, " AND items.itemtype = 5"}, {EQ::item::ItemType::ItemTypeShield, " AND items.itemtype = 8"}, {EQ::item::ItemType::ItemTypeMisc, " AND items.itemtype = 11"}, {EQ::item::ItemType::ItemTypeFood, " AND items.itemtype = 14"}, {EQ::item::ItemType::ItemTypeDrink, " AND items.itemtype = 15"}, {EQ::item::ItemType::ItemTypeLight, " AND items.itemtype = 16"}, {EQ::item::ItemType::ItemTypeCombinable, " AND items.itemtype = 17"}, {EQ::item::ItemType::ItemTypeBandage, " AND items.itemtype = 18"}, {EQ::item::ItemType::ItemTypeSmallThrowing, " AND (items.itemtype = 19 OR items.itemtype = 7)"}, {EQ::item::ItemType::ItemTypeSpell, " AND items.itemtype = 20"}, {EQ::item::ItemType::ItemTypePotion, " AND items.itemtype = 21"}, {EQ::item::ItemType::ItemTypeBrassInstrument, " AND items.itemtype = 25"}, {EQ::item::ItemType::ItemTypeWindInstrument, " AND items.itemtype = 23"}, {EQ::item::ItemType::ItemTypeStringedInstrument, " AND items.itemtype = 24"}, {EQ::item::ItemType::ItemTypePercussionInstrument, " AND items.itemtype = 26"}, {EQ::item::ItemType::ItemTypeArrow, " AND items.itemtype = 27"}, {EQ::item::ItemType::ItemTypeJewelry, " AND items.itemtype = 29"}, {EQ::item::ItemType::ItemTypeNote, " AND items.itemtype = 32"}, {EQ::item::ItemType::ItemTypeKey, " AND items.itemtype = 33"}, {EQ::item::ItemType::ItemType2HPiercing, " AND items.itemtype = 35"}, {EQ::item::ItemType::ItemTypeAlcohol, " AND items.itemtype = 38"}, {EQ::item::ItemType::ItemTypeMartial, " AND items.itemtype = 45"}, {EQ::item::ItemType::ItemTypeAugmentation, " AND items.itemtype = 54"}, {EQ::item::ItemType::ItemTypeAlternateAbility, " AND items.itemtype = 57"}, {EQ::item::ItemType::ItemTypeCount, " AND items.itemtype = 65"}, {EQ::item::ItemType::ItemTypeCollectible, " AND items.itemtype = 66"} }; // item stat searches struct ItemStatSearch { std::string query_string; EQ::skills::SkillType skill_type; }; std::map item_stat_searches_new = { {STAT_AC, {" items.ac" , static_cast(0)} }, {STAT_AGI, {" items.aagi", static_cast(0)} }, {STAT_CHA, {" items.acha", static_cast(0)} }, {STAT_DEX, {" items.adex", static_cast(0)} }, {STAT_INT, {" items.aint", static_cast(0)} }, {STAT_STA, {" items.asta", static_cast(0)} }, {STAT_STR, {" items.astr", static_cast(0)} }, {STAT_WIS, {" items.awis", static_cast(0)} }, {STAT_COLD, {" items.cr", static_cast(0)} }, {STAT_DISEASE, {" items.dr", static_cast(0)} }, {STAT_FIRE, {" items.fr", static_cast(0)} }, {STAT_MAGIC, {" items.mr", static_cast(0)} }, {STAT_POISON, {" items.pr", static_cast(0)} }, {STAT_HP, {" items.hp", static_cast(0)} }, {STAT_MANA, {" items.mana", static_cast(0)} }, {STAT_ENDURANCE, {" items.endur", static_cast(0)} }, {STAT_ATTACK, {" items.attack", static_cast(0)} }, {STAT_HP_REGEN, {" items.regen", static_cast(0)} }, {STAT_MANA_REGEN, {" items.manaregen", static_cast(0)} }, {STAT_HASTE, {" items.haste", static_cast(0)} }, {STAT_DAMAGE_SHIELD, {" items.damageshield", static_cast(0)} }, {STAT_DS_MITIGATION, {" items.dsmitigation", static_cast(0)} }, {STAT_HEAL_AMOUNT, {" items.healamt", static_cast(0)} }, {STAT_SPELL_DAMAGE, {" items.spelldmg", static_cast(0)} }, {STAT_CLAIRVOYANCE, {" items.clairvoyance", static_cast(0)} }, {STAT_HEROIC_AGILITY, {" items.heroic_agi", static_cast(0)} }, {STAT_HEROIC_CHARISMA, {" items.heroic_cha", static_cast(0)} }, {STAT_HEROIC_DEXTERITY, {" items.heroic_dex", static_cast(0)} }, {STAT_HEROIC_INTELLIGENCE, {" items.heroic_int", static_cast(0)} }, {STAT_HEROIC_STAMINA, {" items.heroic_sta", static_cast(0)} }, {STAT_HEROIC_STRENGTH, {" items.heroic_str", static_cast(0)} }, {STAT_HEROIC_WISDOM, {" items.heroic_wis", static_cast(0)} }, {STAT_BASH, {" items.skillmodvalue", EQ::skills::SkillBash} }, {STAT_BACKSTAB, {" items.backstabdmg", EQ::skills::SkillBackstab} }, {STAT_DRAGON_PUNCH, {" items.skillmodvalue", EQ::skills::SkillDragonPunch} }, {STAT_EAGLE_STRIKE, {" items.skillmodvalue", EQ::skills::SkillEagleStrike} }, {STAT_FLYING_KICK, {" items.skillmodvalue", EQ::skills::SkillFlyingKick} }, {STAT_KICK, {" items.skillmodvalue", EQ::skills::SkillKick} }, {STAT_ROUND_KICK, {" items.skillmodvalue", EQ::skills::SkillRoundKick} }, {STAT_TIGER_CLAW, {" items.skillmodvalue", EQ::skills::SkillTigerClaw} }, {STAT_FRENZY, {" items.skillmodvalue", EQ::skills::SkillFrenzy} }, }; bool convert = false; std::string search_criteria_trader("TRUE"); std::string field_criteria_items("FALSE"); std::string where_criteria_items(" TRUE "); if (search.search_scope == NonRoFBazaarSearchScope) { search_criteria_trader.append( fmt::format( " AND trader.char_entity_id = {} AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}", search.trader_entity_id, Zones::BAZAAR, char_zone_instance_id ) ); } else if (search.search_scope == Local_Scope) { search_criteria_trader.append(fmt::format( " AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}", char_zone_id, char_zone_instance_id) ); } else if (search.trader_id > 0) { if (RuleB(Bazaar, UseAlternateBazaarSearch)) { if (search.trader_id >= TraderRepository::TRADER_CONVERT_ID) { convert = true; search_criteria_trader.append(fmt::format( " AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}", Zones::BAZAAR, search.trader_id - TraderRepository::TRADER_CONVERT_ID) ); } else { search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id)); } } else { search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id)); } } if (search.min_cost != 0) { search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000)); } if (search.max_cost != 0) { search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000)); } if (search.slot != std::numeric_limits::max()) { if (item_slot_searches_new.contains(search.slot)) { where_criteria_items.append( fmt::format(" AND items.slots & {0} = {0}", item_slot_searches_new[search.slot])); } } if (search.type != std::numeric_limits::max()) { for (auto const &[type, condition]: item_search_types_new) { if (type == search.type) { where_criteria_items.append(condition); break; } } } if (search.race != std::numeric_limits::max()) { where_criteria_items.append( fmt::format(" AND items.races & {0} = {0}", GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race)))); } if (search._class != std::numeric_limits::max()) { where_criteria_items.append(fmt::format(" AND items.classes & {0} = {0}", GetPlayerClassBit(search._class))); } if (search.item_stat != std::numeric_limits::max()) { if (item_stat_searches_new.contains(search.item_stat)) { field_criteria_items = fmt::format("{}", item_stat_searches_new[search.item_stat].query_string); if (item_stat_searches_new[search.item_stat].skill_type) { where_criteria_items.append( fmt::format(" AND items.skillmodtype = {} ", item_stat_searches_new[search.item_stat].skill_type)); } else { where_criteria_items.append( fmt::format(" AND {} > 0 ", item_stat_searches_new[search.item_stat].query_string)); } } } if (search.augment) { where_criteria_items.append(fmt::format( " AND (items.augslot1type = {0} OR " "items.augslot2type = {0} OR " "items.augslot3type = {0} OR " "items.augslot4type = {0} OR " "items.augslot5type = {0} OR " "items.augslot6type = {0})", search.augment) ); } if (search.min_level != 1) { where_criteria_items.append(fmt::format(" AND items.reclevel >= {}", search.min_level)); } if (search.max_level != 100) { where_criteria_items.append(fmt::format(" AND items.reclevel <= {}", search.max_level)); } std::vector all_entries; std::vector trader_items_ids{}; auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader); if (trader_results.empty()) { LogTradingDetail("Bazaar - No traders found in bazaar search."); return all_entries; } for (auto const &i: trader_results) { trader_items_ids.push_back(std::to_string(i.trader.item_id)); } auto const item_results = ItemsRepository::GetItemsForBazaarSearch( content_db, trader_items_ids, std::string(search.item_name), field_criteria_items, where_criteria_items, search.max_results ); if (item_results.empty()) { LogTradingDetail("Bazaar - No items found in bazaar search."); return all_entries; } all_entries.reserve(trader_results.size()); for (auto const& t:trader_results) { if (!item_results.contains(t.trader.item_id)) { continue; } BazaarSearchResultsFromDB_Struct r{}; r.count = 1; r.trader_id = t.trader.char_id; r.serial_number = t.trader.item_sn; r.cost = t.trader.item_cost; r.slot_id = t.trader.slot_id; r.charges = t.trader.item_charges; r.stackable = item_results.at(t.trader.item_id).stackable; r.icon_id = item_results.at(t.trader.item_id).icon; r.trader_zone_id = t.trader.char_zone_id; r.trader_zone_instance_id = t.trader.char_zone_instance_id; r.trader_entity_id = t.trader.char_entity_id; r.serial_number_RoF = fmt::format("{:016}\0", t.trader.item_sn); r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name); r.trader_name = fmt::format("{:.63}\0", t.trader_name); r.item_stat = item_results.at(t.trader.item_id).stats; if (RuleB(Bazaar, UseAlternateBazaarSearch)) { if (convert || char_zone_id != Zones::BAZAAR || (char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id) ) { r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id; } } all_entries.push_back(r); } if (all_entries.size() > search.max_results) { all_entries.resize(search.max_results); } LogTrading("Returning [{}] items from search results", all_entries.size()); return all_entries; }