mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
334 lines
15 KiB
C++
334 lines
15 KiB
C++
#include "bazaar.h"
|
|
|
|
#include "../../common/item_instance.h"
|
|
#include "repositories/trader_repository.h"
|
|
#include <memory>
|
|
|
|
std::vector<BazaarSearchResultsFromDB_Struct>
|
|
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<uint8, uint32> 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<ItemSearchType> 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<uint32, ItemStatSearch> item_stat_searches_new = {
|
|
{STAT_AC, {" items.ac" , static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_AGI, {" items.aagi", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_CHA, {" items.acha", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_DEX, {" items.adex", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_INT, {" items.aint", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_STA, {" items.asta", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_STR, {" items.astr", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_WIS, {" items.awis", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_COLD, {" items.cr", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_DISEASE, {" items.dr", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_FIRE, {" items.fr", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_MAGIC, {" items.mr", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_POISON, {" items.pr", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HP, {" items.hp", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_MANA, {" items.mana", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_ENDURANCE, {" items.endur", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_ATTACK, {" items.attack", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HP_REGEN, {" items.regen", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_MANA_REGEN, {" items.manaregen", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HASTE, {" items.haste", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_DAMAGE_SHIELD, {" items.damageshield", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_DS_MITIGATION, {" items.dsmitigation", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEAL_AMOUNT, {" items.healamt", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_SPELL_DAMAGE, {" items.spelldmg", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_CLAIRVOYANCE, {" items.clairvoyance", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_AGILITY, {" items.heroic_agi", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_CHARISMA, {" items.heroic_cha", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_DEXTERITY, {" items.heroic_dex", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_INTELLIGENCE, {" items.heroic_int", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_STAMINA, {" items.heroic_sta", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_STRENGTH, {" items.heroic_str", static_cast<EQ::skills::SkillType>(0)} },
|
|
{STAT_HEROIC_WISDOM, {" items.heroic_wis", static_cast<EQ::skills::SkillType>(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<uint32>::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<uint32>::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<uint32>::max()) {
|
|
where_criteria_items.append(
|
|
fmt::format(" AND items.races & {0} = {0}", GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race))));
|
|
}
|
|
|
|
if (search._class != std::numeric_limits<uint32>::max()) {
|
|
where_criteria_items.append(fmt::format(" AND items.classes & {0} = {0}", GetPlayerClassBit(search._class)));
|
|
}
|
|
|
|
if (search.item_stat != std::numeric_limits<uint32>::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<BazaarSearchResultsFromDB_Struct> all_entries;
|
|
std::vector<std::string> 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
|
|
);
|
|
|
|
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;
|
|
}
|