mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
[Feature] Add RoF2 Bazaar Support (#4315)
* Add RoF2 Bazaar Support Enable RoF2 bazaar features * Add augments to Trader Items * Cleanup Cleanup of formatting and unused functions * Update PlayerProfile for correct char_id in trader transactions. Further cleanup. * Add parcel delivery price functionality Add parcel delivery price functionality via rules and new delivery cost struct. * Add RoF support for bazaar window outside of bazaar with parcel delivery * Further Testing and ActiveTransaction added Further testing and a few fixes and messages added. Add active transaction check to ensure two clients cannot purchase from the bazaar window at the same time * Cleanup and Formatting updates Cleanup and Formatting updates * Update database manifest for the trader table against default peq trader table * Logs and formatting * Update bazaarsearch to be content_db aware * Fix crash * Simplify search * Search fixes * Push up more search logging * More search fixes * Formatting * Update trader_repository.h * Add Rule for Bazaar Parcel Delivery Add a rule Bazaar:EnableParcelDelivery to enable/disable bazaar parcel delivery. Default is True. * Fix crash * Update Bazaar Search Adds/Tested bazaar search with move to content_db - race, class, money, number of returned items, stats, name, slot, level, traders, local traders, specific trader. Outstanding - type, more stats to add (heroic, etc) * Formatting * Push * Update bazaarsearch to include all stats that are available in RoF2 * Update BazaarSearch Updates the bazaar search for item types. They should be working as per RoF2+ types. * Formatting * Final updates to BazaarSearch Add search by augmentation slots available on the item. This enables all but Prestige, which I believe are not implemented yet. * Add Titanium functionality correct ItemType Search Add Titanium /trader /bazaar functionality. Added itemtype=armor bazaar search. It was missed in the search work * Close off for loops --------- Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
parent
d767217461
commit
fc79614fac
@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
|||||||
|
|
||||||
SET(common_sources
|
SET(common_sources
|
||||||
base_packet.cpp
|
base_packet.cpp
|
||||||
|
bazaar.cpp
|
||||||
classes.cpp
|
classes.cpp
|
||||||
cli/eqemu_command_handler.cpp
|
cli/eqemu_command_handler.cpp
|
||||||
compression.cpp
|
compression.cpp
|
||||||
@ -501,6 +502,7 @@ SET(repositories
|
|||||||
|
|
||||||
SET(common_headers
|
SET(common_headers
|
||||||
additive_lagged_fibonacci_engine.h
|
additive_lagged_fibonacci_engine.h
|
||||||
|
bazaar.h
|
||||||
base_packet.h
|
base_packet.h
|
||||||
bodytypes.h
|
bodytypes.h
|
||||||
classes.h
|
classes.h
|
||||||
|
|||||||
359
common/bazaar.cpp
Normal file
359
common/bazaar.cpp
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
#include "bazaar.h"
|
||||||
|
|
||||||
|
#include "../../common/item_instance.h"
|
||||||
|
#include "repositories/trader_repository.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
std::vector<BazaarSearchResultsFromDB_Struct>
|
||||||
|
Bazaar::GetSearchResults(
|
||||||
|
SharedDatabase &db,
|
||||||
|
BazaarSearchCriteria_Struct search,
|
||||||
|
uint32 char_zone_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 [{}]",
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string search_criteria_trader("TRUE ");
|
||||||
|
|
||||||
|
if (search.search_scope == NonRoFBazaarSearchScope) {
|
||||||
|
search_criteria_trader.append(
|
||||||
|
fmt::format(
|
||||||
|
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}",
|
||||||
|
search.trader_entity_id,
|
||||||
|
Zones::BAZAAR
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (search.search_scope == Local_Scope) {
|
||||||
|
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id));
|
||||||
|
}
|
||||||
|
else if (search.trader_id > 0) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
if (search.max_cost != 0) {
|
||||||
|
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// not yet implemented
|
||||||
|
// if (search.prestige != 0) {
|
||||||
|
// 0xffffffff prestige only, 0xfffffffe non-prestige, 0 all
|
||||||
|
// search_criteria.append(fmt::format(" AND items.type = {} ", search.prestige));
|
||||||
|
// }
|
||||||
|
|
||||||
|
std::string query = fmt::format(
|
||||||
|
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
|
||||||
|
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
|
||||||
|
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6 "
|
||||||
|
"FROM trader, character_data "
|
||||||
|
"WHERE {} AND trader.char_id = character_data.id "
|
||||||
|
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
|
||||||
|
search_criteria_trader.c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(query);
|
||||||
|
|
||||||
|
if (!results.Success()) {
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ItemSearchType {
|
||||||
|
EQ::item::ItemType type;
|
||||||
|
bool condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AddititiveSearchCriteria {
|
||||||
|
bool should_check;
|
||||||
|
bool condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto row: results) {
|
||||||
|
BazaarSearchResultsFromDB_Struct r{};
|
||||||
|
|
||||||
|
r.item_id = Strings::ToInt(row[2]);
|
||||||
|
r.charges = Strings::ToInt(row[4]);
|
||||||
|
|
||||||
|
auto item = db.GetItem(r.item_id);
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 aug_slot_1 = Strings::ToUnsignedInt(row[11]);
|
||||||
|
uint32 aug_slot_2 = Strings::ToUnsignedInt(row[12]);
|
||||||
|
uint32 aug_slot_3 = Strings::ToUnsignedInt(row[13]);
|
||||||
|
uint32 aug_slot_4 = Strings::ToUnsignedInt(row[14]);
|
||||||
|
uint32 aug_slot_5 = Strings::ToUnsignedInt(row[15]);
|
||||||
|
uint32 aug_slot_6 = Strings::ToUnsignedInt(row[16]);
|
||||||
|
|
||||||
|
std::unique_ptr<EQ::ItemInstance> inst(
|
||||||
|
db.CreateItem(
|
||||||
|
item,
|
||||||
|
r.charges,
|
||||||
|
aug_slot_1,
|
||||||
|
aug_slot_2,
|
||||||
|
aug_slot_3,
|
||||||
|
aug_slot_4,
|
||||||
|
aug_slot_5,
|
||||||
|
aug_slot_6
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!inst->GetItem()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r.count = Strings::ToInt(row[0]);
|
||||||
|
r.trader_id = Strings::ToInt(row[1]);
|
||||||
|
r.serial_number = Strings::ToInt(row[3]);
|
||||||
|
r.cost = Strings::ToInt(row[5]);
|
||||||
|
r.slot_id = Strings::ToInt(row[6]);
|
||||||
|
r.sum_charges = Strings::ToInt(row[7]);
|
||||||
|
r.stackable = item->Stackable;
|
||||||
|
r.icon_id = item->Icon;
|
||||||
|
r.trader_zone_id = Strings::ToInt(row[8]);
|
||||||
|
r.trader_entity_id = Strings::ToInt(row[9]);
|
||||||
|
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
|
||||||
|
r.item_name = fmt::format("{:.63}\0", item->Name);
|
||||||
|
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
|
||||||
|
|
||||||
|
LogTradingDetail(
|
||||||
|
"Searching against item [{}] ({}) for trader [{}]",
|
||||||
|
item->Name,
|
||||||
|
item->ID,
|
||||||
|
r.trader_name
|
||||||
|
);
|
||||||
|
|
||||||
|
// item stat searches
|
||||||
|
std::map<uint32, uint32> item_stat_searches = {
|
||||||
|
|
||||||
|
{STAT_AC, inst->GetItemArmorClass(true)},
|
||||||
|
{STAT_AGI, static_cast<uint32>(inst->GetItemAgi(true))},
|
||||||
|
{STAT_CHA, static_cast<uint32>(inst->GetItemCha(true))},
|
||||||
|
{STAT_DEX, static_cast<uint32>(inst->GetItemDex(true))},
|
||||||
|
{STAT_INT, static_cast<uint32>(inst->GetItemInt(true))},
|
||||||
|
{STAT_STA, static_cast<uint32>(inst->GetItemSta(true))},
|
||||||
|
{STAT_STR, static_cast<uint32>(inst->GetItemStr(true))},
|
||||||
|
{STAT_WIS, static_cast<uint32>(inst->GetItemWis(true))},
|
||||||
|
{STAT_COLD, static_cast<uint32>(inst->GetItemCR(true))},
|
||||||
|
{STAT_DISEASE, static_cast<uint32>(inst->GetItemDR(true))},
|
||||||
|
{STAT_FIRE, static_cast<uint32>(inst->GetItemFR(true))},
|
||||||
|
{STAT_MAGIC, static_cast<uint32>(inst->GetItemMR(true))},
|
||||||
|
{STAT_POISON, static_cast<uint32>(inst->GetItemPR(true))},
|
||||||
|
{STAT_HP, static_cast<uint32>(inst->GetItemHP(true))},
|
||||||
|
{STAT_MANA, static_cast<uint32>(inst->GetItemMana(true))},
|
||||||
|
{STAT_ENDURANCE, static_cast<uint32>(inst->GetItemEndur(true))},
|
||||||
|
{STAT_ATTACK, static_cast<uint32>(inst->GetItemAttack(true))},
|
||||||
|
{STAT_HP_REGEN, static_cast<uint32>(inst->GetItemRegen(true))},
|
||||||
|
{STAT_MANA_REGEN, static_cast<uint32>(inst->GetItemManaRegen(true))},
|
||||||
|
{STAT_HASTE, static_cast<uint32>(inst->GetItemHaste(true))},
|
||||||
|
{STAT_DAMAGE_SHIELD, static_cast<uint32>(inst->GetItemDamageShield(true))},
|
||||||
|
{STAT_DS_MITIGATION, static_cast<uint32>(inst->GetItemDSMitigation(true))},
|
||||||
|
{STAT_HEAL_AMOUNT, static_cast<uint32>(inst->GetItemHealAmt(true))},
|
||||||
|
{STAT_SPELL_DAMAGE, static_cast<uint32>(inst->GetItemSpellDamage(true))},
|
||||||
|
{STAT_CLAIRVOYANCE, static_cast<uint32>(inst->GetItemClairvoyance(true))},
|
||||||
|
{STAT_HEROIC_AGILITY, static_cast<uint32>(inst->GetItemHeroicAgi(true))},
|
||||||
|
{STAT_HEROIC_CHARISMA, static_cast<uint32>(inst->GetItemHeroicCha(true))},
|
||||||
|
{STAT_HEROIC_DEXTERITY, static_cast<uint32>(inst->GetItemHeroicDex(true))},
|
||||||
|
{STAT_HEROIC_INTELLIGENCE, static_cast<uint32>(inst->GetItemHeroicInt(true))},
|
||||||
|
{STAT_HEROIC_STAMINA, static_cast<uint32>(inst->GetItemHeroicSta(true))},
|
||||||
|
{STAT_HEROIC_STRENGTH, static_cast<uint32>(inst->GetItemHeroicStr(true))},
|
||||||
|
{STAT_HEROIC_WISDOM, static_cast<uint32>(inst->GetItemHeroicWis(true))},
|
||||||
|
{STAT_BASH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillBash, true))},
|
||||||
|
{STAT_BACKSTAB, static_cast<uint32>(inst->GetItemBackstabDamage(true))},
|
||||||
|
{STAT_DRAGON_PUNCH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillDragonPunch, true))},
|
||||||
|
{STAT_EAGLE_STRIKE, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillEagleStrike, true))},
|
||||||
|
{STAT_FLYING_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFlyingKick, true))},
|
||||||
|
{STAT_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillKick, true))},
|
||||||
|
{STAT_ROUND_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillRoundKick, true))},
|
||||||
|
{STAT_TIGER_CLAW, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillTigerClaw, true))},
|
||||||
|
{STAT_FRENZY, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFrenzy, true))},
|
||||||
|
};
|
||||||
|
|
||||||
|
r.item_stat = item_stat_searches.contains(search.item_stat) ? item_stat_searches[search.item_stat] : 0;
|
||||||
|
if (item_stat_searches.contains(search.item_stat) && item_stat_searches[search.item_stat] <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<uint8, uint32> item_slot_searches = {
|
||||||
|
{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},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto GetEquipmentSlotBit = [&](uint32 slot) -> uint32 {
|
||||||
|
return item_slot_searches.contains(slot) ? item_slot_searches[slot] : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto FindItemAugSlot = [&]() -> bool {
|
||||||
|
for (auto const &s: inst->GetItem()->AugSlotType) {
|
||||||
|
return s == search.augment;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// item type searches
|
||||||
|
std::vector<ItemSearchType> item_search_types = {
|
||||||
|
{EQ::item::ItemType::ItemTypeAll, true},
|
||||||
|
{EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
|
||||||
|
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer},
|
||||||
|
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
|
||||||
|
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
|
||||||
|
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
|
||||||
|
{EQ::item::ItemType::ItemTypeFocusEffect, item->Focus.Effect > 0},
|
||||||
|
{EQ::item::ItemType::ItemTypeArmor, item->ItemType == EQ::item::ItemType::ItemTypeArmor},
|
||||||
|
{EQ::item::ItemType::ItemType1HBlunt, item->ItemType == EQ::item::ItemType::ItemType1HBlunt},
|
||||||
|
{EQ::item::ItemType::ItemType1HPiercing, item->ItemType == EQ::item::ItemType::ItemType1HPiercing},
|
||||||
|
{EQ::item::ItemType::ItemType1HSlash, item->ItemType == EQ::item::ItemType::ItemType1HSlash},
|
||||||
|
{EQ::item::ItemType::ItemType2HBlunt, item->ItemType == EQ::item::ItemType::ItemType2HBlunt},
|
||||||
|
{EQ::item::ItemType::ItemType2HSlash, item->ItemType == EQ::item::ItemType::ItemType2HSlash},
|
||||||
|
{EQ::item::ItemType::ItemTypeBow, item->ItemType == EQ::item::ItemType::ItemTypeBow},
|
||||||
|
{EQ::item::ItemType::ItemTypeShield, item->ItemType == EQ::item::ItemType::ItemTypeShield},
|
||||||
|
{EQ::item::ItemType::ItemTypeMisc, item->ItemType == EQ::item::ItemType::ItemTypeMisc},
|
||||||
|
{EQ::item::ItemType::ItemTypeFood, item->ItemType == EQ::item::ItemType::ItemTypeFood},
|
||||||
|
{EQ::item::ItemType::ItemTypeDrink, item->ItemType == EQ::item::ItemType::ItemTypeDrink},
|
||||||
|
{EQ::item::ItemType::ItemTypeLight, item->ItemType == EQ::item::ItemType::ItemTypeLight},
|
||||||
|
{EQ::item::ItemType::ItemTypeCombinable, item->ItemType == EQ::item::ItemType::ItemTypeCombinable},
|
||||||
|
{EQ::item::ItemType::ItemTypeBandage, item->ItemType == EQ::item::ItemType::ItemTypeBandage},
|
||||||
|
{EQ::item::ItemType::ItemTypeSmallThrowing, item->ItemType == EQ::item::ItemType::ItemTypeSmallThrowing ||
|
||||||
|
item->ItemType == EQ::item::ItemType::ItemTypeLargeThrowing},
|
||||||
|
{EQ::item::ItemType::ItemTypeSpell, item->ItemType == EQ::item::ItemType::ItemTypeSpell},
|
||||||
|
{EQ::item::ItemType::ItemTypePotion, item->ItemType == EQ::item::ItemType::ItemTypePotion},
|
||||||
|
{EQ::item::ItemType::ItemTypeBrassInstrument, item->ItemType == EQ::item::ItemType::ItemTypeBrassInstrument},
|
||||||
|
{EQ::item::ItemType::ItemTypeWindInstrument, item->ItemType == EQ::item::ItemType::ItemTypeWindInstrument},
|
||||||
|
{EQ::item::ItemType::ItemTypeStringedInstrument, item->ItemType == EQ::item::ItemType::ItemTypeStringedInstrument},
|
||||||
|
{EQ::item::ItemType::ItemTypePercussionInstrument, item->ItemType == EQ::item::ItemType::ItemTypePercussionInstrument},
|
||||||
|
{EQ::item::ItemType::ItemTypeArrow, item->ItemType == EQ::item::ItemType::ItemTypeArrow},
|
||||||
|
{EQ::item::ItemType::ItemTypeJewelry, item->ItemType == EQ::item::ItemType::ItemTypeJewelry},
|
||||||
|
{EQ::item::ItemType::ItemTypeNote, item->ItemType == EQ::item::ItemType::ItemTypeNote},
|
||||||
|
{EQ::item::ItemType::ItemTypeKey, item->ItemType == EQ::item::ItemType::ItemTypeKey},
|
||||||
|
{EQ::item::ItemType::ItemType2HPiercing, item->ItemType == EQ::item::ItemType::ItemType2HPiercing},
|
||||||
|
{EQ::item::ItemType::ItemTypeAlcohol, item->ItemType == EQ::item::ItemType::ItemTypeAlcohol},
|
||||||
|
{EQ::item::ItemType::ItemTypeMartial, item->ItemType == EQ::item::ItemType::ItemTypeMartial},
|
||||||
|
{EQ::item::ItemType::ItemTypeAugmentation, item->ItemType == EQ::item::ItemType::ItemTypeAugmentation},
|
||||||
|
{EQ::item::ItemType::ItemTypeAlternateAbility, item->ItemType == EQ::item::ItemType::ItemTypeAlternateAbility},
|
||||||
|
{EQ::item::ItemType::ItemTypeCount, item->ItemType == EQ::item::ItemType::ItemTypeCount},
|
||||||
|
{EQ::item::ItemType::ItemTypeCollectible, item->ItemType == EQ::item::ItemType::ItemTypeCollectible}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool met_filter = false;
|
||||||
|
bool has_filter = false;
|
||||||
|
|
||||||
|
for (auto &i: item_search_types) {
|
||||||
|
if (i.type == search.type) {
|
||||||
|
has_filter = true;
|
||||||
|
if (i.condition) {
|
||||||
|
LogTradingDetail("Item [{}] met search criteria for type [{}]", item->Name, uint8(i.type));
|
||||||
|
met_filter = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_filter && !met_filter) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add catch-all item type filter for specific item types
|
||||||
|
|
||||||
|
// item additive searches
|
||||||
|
std::vector<AddititiveSearchCriteria> item_additive_searches = {
|
||||||
|
{
|
||||||
|
.should_check = search.min_level != 1 && inst->GetItemRequiredLevel(true) > 0,
|
||||||
|
.condition = inst->GetItemRequiredLevel(true) >= search.min_level
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.should_check = search.max_level != 1 && inst->GetItemRequiredLevel(true) > 0,
|
||||||
|
.condition = inst->GetItemRequiredLevel(true) <= search.max_level
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.should_check = !std::string(search.item_name).empty(),
|
||||||
|
.condition = Strings::ContainsLower(item->Name, search.item_name)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.should_check = search._class != 0xFFFFFFFF,
|
||||||
|
.condition = static_cast<bool>(item->Classes & GetPlayerClassBit(search._class))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.should_check = search.race != 0xFFFFFFFF,
|
||||||
|
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(search.race))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.should_check = search.augment != 0,
|
||||||
|
.condition = FindItemAugSlot()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.should_check = search.slot != 0xFFFFFFFF,
|
||||||
|
.condition = static_cast<bool>(item->Slots & GetEquipmentSlotBit(search.slot))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool should_add = true;
|
||||||
|
|
||||||
|
for (auto &i: item_additive_searches) {
|
||||||
|
LogTradingDetail(
|
||||||
|
"Checking item [{}] for search criteria - should_check [{}] condition [{}]",
|
||||||
|
item->Name,
|
||||||
|
i.should_check,
|
||||||
|
i.condition
|
||||||
|
);
|
||||||
|
if (i.should_check && !i.condition) {
|
||||||
|
should_add = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!should_add) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTradingDetail("Found item [{}] meeting search criteria.", r.item_name);
|
||||||
|
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;
|
||||||
|
}
|
||||||
14
common/bazaar.h
Normal file
14
common/bazaar.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef EQEMU_BAZAAR_H
|
||||||
|
#define EQEMU_BAZAAR_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "shareddb.h"
|
||||||
|
|
||||||
|
class Bazaar {
|
||||||
|
public:
|
||||||
|
static std::vector<BazaarSearchResultsFromDB_Struct>
|
||||||
|
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EQEMU_BAZAAR_H
|
||||||
@ -5635,6 +5635,33 @@ ALTER TABLE `npc_spells_entries` ADD `content_flags_disabled` varchar(100) NULL;
|
|||||||
)",
|
)",
|
||||||
.content_schema_update = true
|
.content_schema_update = true
|
||||||
},
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9280,
|
||||||
|
.description = "2024_05_11_update_trader_support.sql",
|
||||||
|
.check = "SHOW COLUMNS FROM `trader` LIKE 'aug_slot_1'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `trader`
|
||||||
|
ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||||
|
CHANGE COLUMN `char_id` `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
|
||||||
|
CHANGE COLUMN `item_id` `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_id`,
|
||||||
|
ADD COLUMN `aug_slot_1` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `item_id`,
|
||||||
|
ADD COLUMN `aug_slot_2` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_1`,
|
||||||
|
ADD COLUMN `aug_slot_3` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_2`,
|
||||||
|
ADD COLUMN `aug_slot_4` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_3`,
|
||||||
|
ADD COLUMN `aug_slot_5` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_4`,
|
||||||
|
ADD COLUMN `aug_slot_6` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_5`,
|
||||||
|
CHANGE COLUMN `serialnumber` `item_sn` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_6`,
|
||||||
|
CHANGE COLUMN `charges` `item_charges` INT(11) NOT NULL DEFAULT '0' AFTER `item_sn`,
|
||||||
|
ADD COLUMN `char_entity_id` INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `slot_id`,
|
||||||
|
ADD COLUMN `char_zone_id` INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `char_entity_id`,
|
||||||
|
ADD COLUMN `active_transaction` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `char_zone_id`,
|
||||||
|
DROP PRIMARY KEY,
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD INDEX `charid_slotid` (`char_id`, `slot_id`);
|
||||||
|
)"
|
||||||
|
}
|
||||||
// -- template; copy/paste this when you need to create a new entry
|
// -- template; copy/paste this when you need to create a new entry
|
||||||
// ManifestEntry{
|
// ManifestEntry{
|
||||||
// .version = 9228,
|
// .version = 9228,
|
||||||
|
|||||||
@ -557,6 +557,7 @@ N(OP_TradeBusy),
|
|||||||
N(OP_TradeCoins),
|
N(OP_TradeCoins),
|
||||||
N(OP_TradeMoneyUpdate),
|
N(OP_TradeMoneyUpdate),
|
||||||
N(OP_Trader),
|
N(OP_Trader),
|
||||||
|
N(OP_TraderBulkSend),
|
||||||
N(OP_TraderBuy),
|
N(OP_TraderBuy),
|
||||||
N(OP_TraderDelItem),
|
N(OP_TraderDelItem),
|
||||||
N(OP_TradeRequest),
|
N(OP_TradeRequest),
|
||||||
|
|||||||
@ -772,27 +772,47 @@ typedef enum {
|
|||||||
FilterShowSelfOnly
|
FilterShowSelfOnly
|
||||||
} eqFilterMode;
|
} eqFilterMode;
|
||||||
|
|
||||||
#define STAT_STR 0
|
#define STAT_STR 0
|
||||||
#define STAT_STA 1
|
#define STAT_STA 1
|
||||||
#define STAT_AGI 2
|
#define STAT_AGI 2
|
||||||
#define STAT_DEX 3
|
#define STAT_DEX 3
|
||||||
#define STAT_INT 4
|
#define STAT_INT 4
|
||||||
#define STAT_WIS 5
|
#define STAT_WIS 5
|
||||||
#define STAT_CHA 6
|
#define STAT_CHA 6
|
||||||
#define STAT_MAGIC 7
|
#define STAT_MAGIC 7
|
||||||
#define STAT_COLD 8
|
#define STAT_COLD 8
|
||||||
#define STAT_FIRE 9
|
#define STAT_FIRE 9
|
||||||
#define STAT_POISON 10
|
#define STAT_POISON 10
|
||||||
#define STAT_DISEASE 11
|
#define STAT_DISEASE 11
|
||||||
#define STAT_MANA 12
|
#define STAT_MANA 12
|
||||||
#define STAT_HP 13
|
#define STAT_HP 13
|
||||||
#define STAT_AC 14
|
#define STAT_AC 14
|
||||||
#define STAT_ENDURANCE 15
|
#define STAT_ENDURANCE 15
|
||||||
#define STAT_ATTACK 16
|
#define STAT_ATTACK 16
|
||||||
#define STAT_HP_REGEN 17
|
#define STAT_HP_REGEN 17
|
||||||
#define STAT_MANA_REGEN 18
|
#define STAT_MANA_REGEN 18
|
||||||
#define STAT_HASTE 19
|
#define STAT_HASTE 19
|
||||||
#define STAT_DAMAGE_SHIELD 20
|
#define STAT_DAMAGE_SHIELD 20
|
||||||
|
#define STAT_DS_MITIGATION 22
|
||||||
|
#define STAT_HEAL_AMOUNT 23
|
||||||
|
#define STAT_SPELL_DAMAGE 24
|
||||||
|
#define STAT_CLAIRVOYANCE 25
|
||||||
|
#define STAT_HEROIC_AGILITY 26
|
||||||
|
#define STAT_HEROIC_CHARISMA 27
|
||||||
|
#define STAT_HEROIC_DEXTERITY 28
|
||||||
|
#define STAT_HEROIC_INTELLIGENCE 29
|
||||||
|
#define STAT_HEROIC_STAMINA 30
|
||||||
|
#define STAT_HEROIC_STRENGTH 31
|
||||||
|
#define STAT_HEROIC_WISDOM 32
|
||||||
|
#define STAT_BASH 33
|
||||||
|
#define STAT_BACKSTAB 34
|
||||||
|
#define STAT_DRAGON_PUNCH 35
|
||||||
|
#define STAT_EAGLE_STRIKE 36
|
||||||
|
#define STAT_FLYING_KICK 37
|
||||||
|
#define STAT_KICK 38
|
||||||
|
#define STAT_ROUND_KICK 39
|
||||||
|
#define STAT_TIGER_CLAW 40
|
||||||
|
#define STAT_FRENZY 41
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Recast timer types. Used as an off set to charProfileStruct timers.
|
** Recast timer types. Used as an off set to charProfileStruct timers.
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
#include "../cereal/include/cereal/types/string.hpp"
|
#include "../cereal/include/cereal/types/string.hpp"
|
||||||
#include "../cereal/include/cereal/types/vector.hpp"
|
#include "../cereal/include/cereal/types/vector.hpp"
|
||||||
|
|
||||||
|
|
||||||
static const uint32 BUFF_COUNT = 42;
|
static const uint32 BUFF_COUNT = 42;
|
||||||
static const uint32 PET_BUFF_COUNT = 30;
|
static const uint32 PET_BUFF_COUNT = 30;
|
||||||
static const uint32 MAX_MERC = 100;
|
static const uint32 MAX_MERC = 100;
|
||||||
@ -323,6 +322,7 @@ union
|
|||||||
bool targetable_with_hotkey;
|
bool targetable_with_hotkey;
|
||||||
bool show_name;
|
bool show_name;
|
||||||
bool guild_show;
|
bool guild_show;
|
||||||
|
bool trader;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerState_Struct {
|
struct PlayerState_Struct {
|
||||||
@ -1119,7 +1119,7 @@ struct PlayerProfile_Struct
|
|||||||
/*19558*/ uint8 guildAutoconsent; // 0=off, 1=on
|
/*19558*/ uint8 guildAutoconsent; // 0=off, 1=on
|
||||||
/*19559*/ uint8 unknown19595[5]; // ***Placeholder (6/29/2005)
|
/*19559*/ uint8 unknown19595[5]; // ***Placeholder (6/29/2005)
|
||||||
/*19564*/ uint32 RestTimer;
|
/*19564*/ uint32 RestTimer;
|
||||||
/*19568*/
|
/*19568*/ uint32 char_id; // Found as part of bazaar revamp (5/15/2024)
|
||||||
|
|
||||||
// All player profile packets are translated and this overhead is ignored in out-bound packets
|
// All player profile packets are translated and this overhead is ignored in out-bound packets
|
||||||
PlayerProfile_Struct() : m_player_profile_version(EQ::versions::MobVersion::Unknown) { }
|
PlayerProfile_Struct() : m_player_profile_version(EQ::versions::MobVersion::Unknown) { }
|
||||||
@ -3002,26 +3002,26 @@ struct EnvDamage2_Struct {
|
|||||||
//
|
//
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarTrader_StartTraderMode = 1,
|
BazaarTrader_StartTraderMode = 1,
|
||||||
BazaarTrader_EndTraderMode = 2,
|
BazaarTrader_EndTraderMode = 2,
|
||||||
BazaarTrader_UpdatePrice = 3,
|
BazaarTrader_UpdatePrice = 3,
|
||||||
BazaarTrader_EndTransaction = 4,
|
BazaarTrader_EndTransaction = 4,
|
||||||
BazaarSearchResults = 7,
|
BazaarSearchResults = 7,
|
||||||
BazaarWelcome = 9,
|
BazaarWelcome = 9,
|
||||||
BazaarBuyItem = 10,
|
BazaarBuyItem = 10,
|
||||||
BazaarTrader_ShowItems = 11,
|
BazaarTrader_ShowItems = 11,
|
||||||
BazaarSearchDone = 12,
|
BazaarSearchDone = 12,
|
||||||
BazaarTrader_CustomerBrowsing = 13,
|
BazaarTrader_CustomerBrowsing = 13,
|
||||||
BazaarInspectItem = 18,
|
BazaarInspectItem = 18,
|
||||||
BazaarSearchDone2 = 19,
|
BazaarSearchDone2 = 19,
|
||||||
BazaarTrader_StartTraderMode2 = 22
|
BazaarTrader_StartTraderMode2 = 22
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarPriceChange_Fail = 0,
|
BazaarPriceChange_Fail = 0,
|
||||||
BazaarPriceChange_UpdatePrice = 1,
|
BazaarPriceChange_UpdatePrice = 1,
|
||||||
BazaarPriceChange_RemoveItem = 2,
|
BazaarPriceChange_RemoveItem = 2,
|
||||||
BazaarPriceChange_AddItem = 3
|
BazaarPriceChange_AddItem = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarWindowStart_Struct {
|
struct BazaarWindowStart_Struct {
|
||||||
@ -3032,31 +3032,41 @@ struct BazaarWindowStart_Struct {
|
|||||||
|
|
||||||
|
|
||||||
struct BazaarWelcome_Struct {
|
struct BazaarWelcome_Struct {
|
||||||
BazaarWindowStart_Struct Beginning;
|
uint32 action;
|
||||||
uint32 Traders;
|
uint32 traders;
|
||||||
uint32 Items;
|
uint32 items;
|
||||||
uint32 Unknown012;
|
uint32 unknown_012;
|
||||||
uint32 Unknown016;
|
uint32 unknown_016;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearch_Struct {
|
struct BazaarSearchCriteria_Struct {
|
||||||
BazaarWindowStart_Struct Beginning;
|
/*000*/ uint32 action{0};
|
||||||
uint32 TraderID;
|
/*004*/ uint32 search_scope{0}; // 1 all traders 0 local traders
|
||||||
uint32 Class_;
|
/*008*/ uint32 unknown_008{0};
|
||||||
uint32 Race;
|
/*012*/ uint32 unknown_012{0};
|
||||||
uint32 ItemStat;
|
/*016*/ uint32 trader_id{0};
|
||||||
uint32 Slot;
|
/*020*/ uint32 _class{0};
|
||||||
uint32 Type;
|
/*024*/ uint32 race{0};
|
||||||
char Name[64];
|
/*028*/ uint32 item_stat{0};
|
||||||
uint32 MinPrice;
|
/*032*/ uint32 slot{0};
|
||||||
uint32 MaxPrice;
|
/*036*/ uint32 type{0};
|
||||||
uint32 Minlevel;
|
/*040*/ char item_name[64]{""};
|
||||||
uint32 MaxLlevel;
|
/*104*/ uint32 min_cost{0};
|
||||||
|
/*108*/ uint32 max_cost{0};
|
||||||
|
/*112*/ uint32 min_level{1};
|
||||||
|
/*116*/ uint32 max_level{0};
|
||||||
|
/*120*/ uint32 max_results{0};
|
||||||
|
/*124*/ uint32 prestige{0};
|
||||||
|
/*128*/ uint32 augment{0};
|
||||||
|
/*132*/ uint32 trader_entity_id{0};
|
||||||
};
|
};
|
||||||
struct BazaarInspect_Struct{
|
|
||||||
uint32 ItemID;
|
struct BazaarInspect_Struct {
|
||||||
uint32 Unknown004;
|
uint32 action;
|
||||||
char Name[64];
|
char player_name[64];
|
||||||
|
uint32 serial_number;
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 trader_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NewBazaarInspect_Struct {
|
struct NewBazaarInspect_Struct {
|
||||||
@ -3076,6 +3086,14 @@ struct BazaarReturnDone_Struct{
|
|||||||
uint32 Unknown012;
|
uint32 Unknown012;
|
||||||
uint32 Unknown016;
|
uint32 Unknown016;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BazaarDeliveryCost_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint16 voucher_delivery_cost;
|
||||||
|
float parcel_deliver_cost; //percentage of item cost
|
||||||
|
uint32 unknown_010;
|
||||||
|
};
|
||||||
|
|
||||||
struct BazaarSearchResults_Struct {
|
struct BazaarSearchResults_Struct {
|
||||||
/*000*/ BazaarWindowStart_Struct Beginning;
|
/*000*/ BazaarWindowStart_Struct Beginning;
|
||||||
/*004*/ uint32 NumItems;
|
/*004*/ uint32 NumItems;
|
||||||
@ -3088,8 +3106,10 @@ struct BazaarSearchResults_Struct {
|
|||||||
// New fields for SoD+, stripped off when encoding for older clients.
|
// New fields for SoD+, stripped off when encoding for older clients.
|
||||||
char SellerName[64];
|
char SellerName[64];
|
||||||
uint32 ItemID;
|
uint32 ItemID;
|
||||||
|
uint32 ItemID2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Barter/Buyer
|
// Barter/Buyer
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@ -3389,32 +3409,31 @@ struct WhoAllReturnStruct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_Struct {
|
struct Trader_Struct {
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 unknown_004;
|
||||||
/*008*/ uint64 Items[80];
|
/*008*/ uint64 items[EQ::invtype::BAZAAR_SIZE];
|
||||||
/*648*/ uint32 ItemCost[80];
|
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClickTrader_Struct {
|
struct ClickTrader_Struct {
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 unknown_004;
|
||||||
/*008*/ int64 SerialNumber[80];
|
/*008*/ int64 serial_number[EQ::invtype::BAZAAR_SIZE] {};
|
||||||
/*648*/ uint32 ItemCost[80];
|
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GetItems_Struct{
|
struct GetItems_Struct{
|
||||||
uint32 Items[80];
|
uint32 items[EQ::invtype::BAZAAR_SIZE];
|
||||||
int32 SerialNumber[80];
|
int32 serial_number[EQ::invtype::BAZAAR_SIZE];
|
||||||
int32 Charges[80];
|
int32 charges[EQ::invtype::BAZAAR_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BecomeTrader_Struct
|
struct BecomeTrader_Struct {
|
||||||
{
|
uint32 action;
|
||||||
/*000*/ uint32 ID;
|
uint32 zone_id;
|
||||||
/*004*/ uint32 Code;
|
uint32 trader_id;
|
||||||
/*008*/ char Name[64];
|
uint32 entity_id;
|
||||||
/*072*/ uint32 Unknown072; // Observed 0x33,0x91 etc on zone-in, 0x00 when sent for a new trader after zone-in
|
char trader_name[64];
|
||||||
/*076*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderStatus_Struct{
|
struct TraderStatus_Struct{
|
||||||
@ -3424,20 +3443,30 @@ struct TraderStatus_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct{
|
struct Trader_ShowItems_Struct{
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 TraderID;
|
/*004*/ uint32 entity_id;
|
||||||
/*008*/ uint32 Unknown08[3];
|
/*008*/ uint32 Unknown08[3];
|
||||||
/*020*/
|
/*020*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct{
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 TraderID;
|
/*004*/ uint32 method;
|
||||||
/*008*/ uint32 ItemID;
|
/*008*/ uint32 sub_action;
|
||||||
/*012*/ uint32 AlreadySold;
|
/*012*/ uint32 unknown_012;
|
||||||
/*016*/ uint32 Price;
|
/*016*/ uint32 trader_id;
|
||||||
/*020*/ uint32 Quantity;
|
/*020*/ char buyer_name[64];
|
||||||
/*024*/ char ItemName[64];
|
/*084*/ char seller_name[64];
|
||||||
|
/*148*/ char unknown_148[32];
|
||||||
|
/*180*/ char item_name[64];
|
||||||
|
/*244*/ char serial_number[17];
|
||||||
|
/*261*/ char unknown_261[3];
|
||||||
|
/*264*/ uint32 item_id;
|
||||||
|
/*268*/ uint32 price;
|
||||||
|
/*272*/ uint32 already_sold;
|
||||||
|
/*276*/ uint32 unknown_276;
|
||||||
|
/*280*/ uint32 quantity;
|
||||||
|
/*284*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemUpdate_Struct{
|
struct TraderItemUpdate_Struct{
|
||||||
@ -3465,15 +3494,15 @@ struct MoneyUpdate_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderDelItem_Struct{
|
struct TraderDelItem_Struct{
|
||||||
uint32 Unknown000;
|
uint32 unknown_000;
|
||||||
uint32 TraderID;
|
uint32 trader_id;
|
||||||
uint32 ItemID;
|
uint32 item_id;
|
||||||
uint32 Unknown012;
|
uint32 unknown_012;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
/*000*/ uint32 TraderID;
|
/*000*/ uint32 Code;
|
||||||
/*004*/ uint32 Code;
|
/*004*/ uint32 TraderID;
|
||||||
/*008*/ uint32 Unknown008;
|
/*008*/ uint32 Unknown008;
|
||||||
/*012*/ uint32 Approval;
|
/*012*/ uint32 Approval;
|
||||||
/*016*/
|
/*016*/
|
||||||
@ -5991,6 +6020,102 @@ struct UnderWorld {
|
|||||||
/* 16 */
|
/* 16 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BazaarTraderBarterActions {
|
||||||
|
TraderOff = 0,
|
||||||
|
TraderOn = 1,
|
||||||
|
PriceUpdate = 3,
|
||||||
|
EndTransaction = 4,
|
||||||
|
BazaarSearch = 7,
|
||||||
|
WelcomeMessage = 9,
|
||||||
|
BuyTraderItem = 10,
|
||||||
|
ListTraderItems = 11,
|
||||||
|
CustomerBrowsing = 13,
|
||||||
|
BazaarInspect = 18,
|
||||||
|
ItemMove = 19,
|
||||||
|
TraderAck2 = 22,
|
||||||
|
AddTraderToBazaarWindow = 24,
|
||||||
|
RemoveTraderFromBazaarWindow = 25,
|
||||||
|
ClickTrader = 28,
|
||||||
|
DeliveryCostUpdate = 29
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BazaarPurchaseActions {
|
||||||
|
ByVendor = 0,
|
||||||
|
ByParcel = 1,
|
||||||
|
ByDirectToInventory = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BazaarPurchaseSubActions {
|
||||||
|
Success = 0,
|
||||||
|
Failed = 1,
|
||||||
|
DataOutDated = 3,
|
||||||
|
TooManyParcels = 5,
|
||||||
|
TransactionInProgress = 6,
|
||||||
|
InsufficientFunds = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BazaarSearchScopes {
|
||||||
|
Local_Scope = 0,
|
||||||
|
AllTraders_Scope = 1,
|
||||||
|
NonRoFBazaarSearchScope = 99
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BazaarSearchResultsFromDB_Struct {
|
||||||
|
uint32 count;
|
||||||
|
uint32 trader_id;
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 serial_number;
|
||||||
|
uint32 charges;
|
||||||
|
uint32 cost;
|
||||||
|
uint32 slot_id;
|
||||||
|
uint32 icon_id;
|
||||||
|
uint32 sum_charges;
|
||||||
|
uint32 trader_zone_id;
|
||||||
|
uint32 trader_entity_id;
|
||||||
|
uint32 item_stat;
|
||||||
|
bool stackable;
|
||||||
|
std::string item_name;
|
||||||
|
std::string serial_number_RoF;
|
||||||
|
std::string trader_name;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(count),
|
||||||
|
CEREAL_NVP(trader_id),
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(serial_number),
|
||||||
|
CEREAL_NVP(charges),
|
||||||
|
CEREAL_NVP(cost),
|
||||||
|
CEREAL_NVP(slot_id),
|
||||||
|
CEREAL_NVP(icon_id),
|
||||||
|
CEREAL_NVP(sum_charges),
|
||||||
|
CEREAL_NVP(trader_zone_id),
|
||||||
|
CEREAL_NVP(trader_entity_id),
|
||||||
|
CEREAL_NVP(item_stat),
|
||||||
|
CEREAL_NVP(stackable),
|
||||||
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(serial_number_RoF),
|
||||||
|
CEREAL_NVP(trader_name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BazaarSearchMessaging_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char payload[];
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(action),
|
||||||
|
CEREAL_NVP(payload)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Restore structure packing to default
|
// Restore structure packing to default
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
|||||||
@ -58,72 +58,75 @@ namespace EQ
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum ItemType : uint8 {
|
enum ItemType : uint8 {
|
||||||
/*9138*/ ItemType1HSlash = 0,
|
/*9138*/ ItemType1HSlash = 0,
|
||||||
/*9141*/ ItemType2HSlash,
|
/*9141*/ ItemType2HSlash,
|
||||||
/*9140*/ ItemType1HPiercing,
|
/*9140*/ ItemType1HPiercing,
|
||||||
/*9139*/ ItemType1HBlunt,
|
/*9139*/ ItemType1HBlunt,
|
||||||
/*9142*/ ItemType2HBlunt,
|
/*9142*/ ItemType2HBlunt,
|
||||||
/*5504*/ ItemTypeBow, // 5
|
/*5504*/ ItemTypeBow, // 5
|
||||||
/*----*/ ItemTypeUnknown1,
|
/*----*/ ItemTypeUnknown1,
|
||||||
/*----*/ ItemTypeLargeThrowing,
|
/*----*/ ItemTypeLargeThrowing,
|
||||||
/*5505*/ ItemTypeShield,
|
/*5505*/ ItemTypeShield,
|
||||||
/*5506*/ ItemTypeScroll,
|
/*5506*/ ItemTypeScroll,
|
||||||
/*5507*/ ItemTypeArmor, // 10
|
/*5507*/ ItemTypeArmor, // 10
|
||||||
/*5508*/ ItemTypeMisc, // a lot of random crap has this item use.
|
/*5508*/ ItemTypeMisc, // a lot of random crap has this item use.
|
||||||
/*7564*/ ItemTypeLockPick,
|
/*7564*/ ItemTypeLockPick,
|
||||||
/*----*/ ItemTypeUnknown2,
|
/*----*/ ItemTypeUnknown2,
|
||||||
/*5509*/ ItemTypeFood,
|
/*5509*/ ItemTypeFood,
|
||||||
/*5510*/ ItemTypeDrink, // 15
|
/*5510*/ ItemTypeDrink, // 15
|
||||||
/*5511*/ ItemTypeLight,
|
/*5511*/ ItemTypeLight,
|
||||||
/*5512*/ ItemTypeCombinable, // not all stackable items are this use...
|
/*5512*/ ItemTypeCombinable, // not all stackable items are this use...
|
||||||
/*5513*/ ItemTypeBandage,
|
/*5513*/ ItemTypeBandage,
|
||||||
/*----*/ ItemTypeSmallThrowing,
|
/*----*/ ItemTypeSmallThrowing,
|
||||||
/*----*/ ItemTypeSpell, // 20 // spells and tomes
|
/*----*/ ItemTypeSpell, // 20 // spells and tomes
|
||||||
/*5514*/ ItemTypePotion,
|
/*5514*/ ItemTypePotion,
|
||||||
/*----*/ ItemTypeUnknown3,
|
/*----*/ ItemTypeUnknown3,
|
||||||
/*0406*/ ItemTypeWindInstrument,
|
/*0406*/ ItemTypeWindInstrument,
|
||||||
/*0407*/ ItemTypeStringedInstrument,
|
/*0407*/ ItemTypeStringedInstrument,
|
||||||
/*0408*/ ItemTypeBrassInstrument, // 25
|
/*0408*/ ItemTypeBrassInstrument, // 25
|
||||||
/*0405*/ ItemTypePercussionInstrument,
|
/*0405*/ ItemTypePercussionInstrument,
|
||||||
/*5515*/ ItemTypeArrow,
|
/*5515*/ ItemTypeArrow,
|
||||||
/*----*/ ItemTypeUnknown4,
|
/*----*/ ItemTypeUnknown4,
|
||||||
/*5521*/ ItemTypeJewelry,
|
/*5521*/ ItemTypeJewelry,
|
||||||
/*----*/ ItemTypeSkull, // 30
|
/*----*/ ItemTypeSkull, // 30
|
||||||
/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...)
|
/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...)
|
||||||
/*5517*/ ItemTypeNote,
|
/*5517*/ ItemTypeNote,
|
||||||
/*5518*/ ItemTypeKey,
|
/*5518*/ ItemTypeKey,
|
||||||
/*----*/ ItemTypeCoin,
|
/*----*/ ItemTypeCoin,
|
||||||
/*5520*/ ItemType2HPiercing, // 35
|
/*5520*/ ItemType2HPiercing, // 35
|
||||||
/*----*/ ItemTypeFishingPole,
|
/*----*/ ItemTypeFishingPole,
|
||||||
/*----*/ ItemTypeFishingBait,
|
/*----*/ ItemTypeFishingBait,
|
||||||
/*5519*/ ItemTypeAlcohol,
|
/*5519*/ ItemTypeAlcohol,
|
||||||
/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?)
|
/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?)
|
||||||
/*----*/ ItemTypeCompass, // 40
|
/*----*/ ItemTypeCompass, // 40
|
||||||
/*----*/ ItemTypeUnknown5,
|
/*----*/ ItemTypeUnknown5,
|
||||||
/*----*/ ItemTypePoison, // might be wrong, but includes poisons
|
/*----*/ ItemTypePoison, // might be wrong, but includes poisons
|
||||||
/*----*/ ItemTypeUnknown6,
|
/*----*/ ItemTypeUnknown6,
|
||||||
/*----*/ ItemTypeUnknown7,
|
/*----*/ ItemTypeUnknown7,
|
||||||
/*5522*/ ItemTypeMartial, // 45
|
/*5522*/ ItemTypeMartial, // 45
|
||||||
/*----*/ ItemTypeUnknown8,
|
/*----*/ ItemTypeAllEffects,
|
||||||
/*----*/ ItemTypeUnknown9,
|
/*----*/ ItemTypeUnknown9,
|
||||||
/*----*/ ItemTypeUnknown10,
|
/*----*/ ItemTypeUnknown10,
|
||||||
/*----*/ ItemTypeUnknown11,
|
/*----*/ ItemTypeFocusEffect,
|
||||||
/*----*/ ItemTypeSinging, // 50
|
/*----*/ ItemTypeSinging, // 50
|
||||||
/*5750*/ ItemTypeAllInstrumentTypes,
|
/*5750*/ ItemTypeAllInstrumentTypes,
|
||||||
/*5776*/ ItemTypeCharm,
|
/*5776*/ ItemTypeCharm,
|
||||||
/*----*/ ItemTypeDye,
|
/*----*/ ItemTypeDye,
|
||||||
/*----*/ ItemTypeAugmentation,
|
/*----*/ ItemTypeAugmentation,
|
||||||
/*----*/ ItemTypeAugmentationSolvent, // 55
|
/*----*/ ItemTypeAugmentationSolvent, // 55
|
||||||
/*----*/ ItemTypeAugmentationDistiller,
|
/*----*/ ItemTypeAugmentationDistiller,
|
||||||
/*----*/ ItemTypeUnknown12,
|
/*----*/ ItemTypeAlternateAbility,
|
||||||
/*----*/ ItemTypeFellowshipKit,
|
/*----*/ ItemTypeFellowshipKit,
|
||||||
/*----*/ ItemTypeUnknown13,
|
/*----*/ ItemTypeUnknown13,
|
||||||
/*----*/ ItemTypeRecipe, // 60
|
/*----*/ ItemTypeRecipe, // 60
|
||||||
/*----*/ ItemTypeAdvancedRecipe,
|
/*----*/ ItemTypeAdvancedRecipe,
|
||||||
/*----*/ ItemTypeJournal, // only one(1) database entry
|
/*----*/ ItemTypeJournal, // only one(1) database entry
|
||||||
/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage)
|
/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage)
|
||||||
/*5881*/ ItemTypePerfectedAugmentationDistiller,
|
/*5881*/ ItemTypePerfectedAugmentationDistiller,
|
||||||
/*----*/ ItemTypeCount
|
/*----*/ ItemTypeCount,
|
||||||
|
/*----*/ ItemTypeCollectible,
|
||||||
|
/*----*/ ItemTypeContainer,
|
||||||
|
/*----*/ ItemTypeAll = 0xFF
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unknowns:
|
Unknowns:
|
||||||
|
|||||||
@ -1812,6 +1812,142 @@ std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
|
|||||||
return augments;
|
return augments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemRegen(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->Regen;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemRegen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemManaRegen(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->ManaRegen;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemManaRegen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemDamageShield(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->DamageShield;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemDamageShield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemDSMitigation(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->DSMitigation;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemDSMitigation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemHealAmt(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->HealAmt;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemHealAmt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemSpellDamage(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->SpellDmg;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemSpellDamage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemClairvoyance(bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->Clairvoyance;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemClairvoyance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augments) const
|
||||||
|
{
|
||||||
|
int stat = 0;
|
||||||
|
const auto item = GetItem();
|
||||||
|
if (item) {
|
||||||
|
stat = item->ExtraDmgSkill == skill ? item->ExtraDmgAmt : 0;
|
||||||
|
if (augments) {
|
||||||
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||||
|
if (GetAugment(i)) {
|
||||||
|
stat += GetAugment(i)->GetItemSkillsStat(skill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// class EvolveInfo
|
// class EvolveInfo
|
||||||
//
|
//
|
||||||
|
|||||||
@ -270,6 +270,7 @@ namespace EQ
|
|||||||
int GetItemMagical(bool augments = false) const;
|
int GetItemMagical(bool augments = false) const;
|
||||||
int GetItemHP(bool augments = false) const;
|
int GetItemHP(bool augments = false) const;
|
||||||
int GetItemMana(bool augments = false) const;
|
int GetItemMana(bool augments = false) const;
|
||||||
|
int GetItemManaRegen(bool augments = false) const;
|
||||||
int GetItemEndur(bool augments = false) const;
|
int GetItemEndur(bool augments = false) const;
|
||||||
int GetItemAttack(bool augments = false) const;
|
int GetItemAttack(bool augments = false) const;
|
||||||
int GetItemStr(bool augments = false) const;
|
int GetItemStr(bool augments = false) const;
|
||||||
@ -299,6 +300,13 @@ namespace EQ
|
|||||||
int GetItemHeroicDR(bool augments = false) const;
|
int GetItemHeroicDR(bool augments = false) const;
|
||||||
int GetItemHeroicCorrup(bool augments = false) const;
|
int GetItemHeroicCorrup(bool augments = false) const;
|
||||||
int GetItemHaste(bool augments = false) const;
|
int GetItemHaste(bool augments = false) const;
|
||||||
|
int GetItemRegen(bool augments = false) const;
|
||||||
|
int GetItemDamageShield(bool augments = false) const;
|
||||||
|
int GetItemDSMitigation(bool augments = false) const;
|
||||||
|
int GetItemHealAmt(bool augments = false) const;
|
||||||
|
int GetItemSpellDamage(bool augments = false) const;
|
||||||
|
int GetItemClairvoyance(bool augments = false) const;
|
||||||
|
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
||||||
uint32 GetItemGuildFavor() const;
|
uint32 GetItemGuildFavor() const;
|
||||||
std::vector<uint32> GetAugmentIDs() const;
|
std::vector<uint32> GetAugmentIDs() const;
|
||||||
|
|
||||||
|
|||||||
@ -3494,14 +3494,13 @@ namespace RoF
|
|||||||
ENCODE_LENGTH_EXACT(ClickTrader_Struct);
|
ENCODE_LENGTH_EXACT(ClickTrader_Struct);
|
||||||
SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||||
|
|
||||||
eq->Code = emu->Code;
|
eq->Code = emu->action;
|
||||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
for (uint32 i = 0; i < RoF::invtype::BAZAAR_SIZE; i++)
|
||||||
for (uint32 i = 0; i < 200; i++)
|
|
||||||
{
|
{
|
||||||
strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber));
|
strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber));
|
||||||
eq->items[i].Unknown18 = 0;
|
eq->items[i].Unknown18 = 0;
|
||||||
if (i < 80) {
|
if (i < 80) {
|
||||||
eq->ItemCost[i] = emu->ItemCost[i];
|
eq->ItemCost[i] = emu->item_cost[i];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
eq->ItemCost[i] = 0;
|
eq->ItemCost[i] = 0;
|
||||||
@ -3515,9 +3514,9 @@ namespace RoF
|
|||||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
|
||||||
eq->Code = emu->Code;
|
eq->Code = emu->action;
|
||||||
strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
||||||
eq->TraderID = emu->TraderID;
|
eq->TraderID = emu->entity_id;
|
||||||
eq->Stacksize = 0;
|
eq->Stacksize = 0;
|
||||||
eq->Price = 0;
|
eq->Price = 0;
|
||||||
|
|
||||||
@ -3543,13 +3542,13 @@ namespace RoF
|
|||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
|
||||||
OUT(Action);
|
OUT(action);
|
||||||
OUT(Price);
|
OUT(price);
|
||||||
OUT(TraderID);
|
OUT(trader_id);
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
OUT(ItemID);
|
OUT(item_id);
|
||||||
OUT(Quantity);
|
OUT(quantity);
|
||||||
OUT(AlreadySold);
|
OUT(already_sold);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -5041,12 +5040,11 @@ namespace RoF
|
|||||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||||
MEMSET_IN(ClickTrader_Struct);
|
MEMSET_IN(ClickTrader_Struct);
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
emu->action = eq->Code;
|
||||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
for (uint32 i = 0; i < RoF::invtype::BAZAAR_SIZE; i++)
|
||||||
for (uint32 i = 0; i < 80; i++)
|
|
||||||
{
|
{
|
||||||
emu->SerialNumber[i] = 0; // eq->SerialNumber[i];
|
emu->serial_number[i] = 0; // eq->SerialNumber[i];
|
||||||
emu->ItemCost[i] = eq->ItemCost[i];
|
emu->item_cost[i] = eq->ItemCost[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
@ -5057,8 +5055,8 @@ namespace RoF
|
|||||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
MEMSET_IN(Trader_ShowItems_Struct);
|
MEMSET_IN(Trader_ShowItems_Struct);
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
emu->action = eq->Code;
|
||||||
emu->TraderID = eq->TraderID;
|
emu->entity_id = eq->TraderID;
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
@ -5080,12 +5078,12 @@ namespace RoF
|
|||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
MEMSET_IN(TraderBuy_Struct);
|
MEMSET_IN(TraderBuy_Struct);
|
||||||
|
|
||||||
IN(Action);
|
IN(action);
|
||||||
IN(Price);
|
IN(price);
|
||||||
IN(TraderID);
|
IN(trader_id);
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||||
IN(ItemID);
|
IN(item_id);
|
||||||
IN(Quantity);
|
IN(quantity);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -398,51 +398,182 @@ namespace RoF2
|
|||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
char *Buffer = (char *)in->pBuffer;
|
uint32 action = *(uint32 *) in->pBuffer;
|
||||||
|
|
||||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
switch (action) {
|
||||||
|
case BazaarSearch: {
|
||||||
|
LogTrading("(RoF2) BazaarSearch action <green>[{}]", action);
|
||||||
|
std::vector<BazaarSearchResultsFromDB_Struct> results{};
|
||||||
|
auto bsms = (BazaarSearchMessaging_Struct *) in->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(bsms->payload),
|
||||||
|
in->size - sizeof(BazaarSearchMessaging_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(results);
|
||||||
|
|
||||||
if (SubAction != BazaarSearchResults)
|
auto name_size = 0;
|
||||||
{
|
for (auto const &i: results) {
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
name_size += i.item_name.length() + 1;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
auto p_size = 41 * results.size() + name_size + 14;
|
||||||
|
auto buffer = std::make_unique<char[]>(p_size);
|
||||||
|
auto bufptr = buffer.get();
|
||||||
|
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, results[0].trader_zone_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results[0].trader_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.size());
|
||||||
|
|
||||||
|
for (auto i: results) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.trader_id); //trader ID
|
||||||
|
VARSTRUCT_ENCODE_STRING(bufptr, i.serial_number_RoF.c_str()); //serial
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.cost); //cost
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.stackable ? i.charges : i.count); //quantity
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_id); //ID
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.icon_id); //icon
|
||||||
|
VARSTRUCT_ENCODE_STRING(bufptr, i.item_name.c_str()); //name
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_stat); //itemstat
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_delete(in->pBuffer);
|
||||||
|
in->size = p_size;
|
||||||
|
in->pBuffer = (uchar *) buffer.get();
|
||||||
|
dest->QueuePacket(in);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarInspect: {
|
||||||
|
LogTrading("(RoF2) BazaarInspect action <green>[{}]", action);
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WelcomeMessage: {
|
||||||
|
auto buffer = std::make_unique<char[]>(sizeof(structs::BazaarWelcome_Struct));
|
||||||
|
auto emu = (BazaarWelcome_Struct *) in->pBuffer;
|
||||||
|
auto eq = (structs::BazaarWelcome_Struct *) buffer.get();
|
||||||
|
|
||||||
|
eq->action = structs::RoF2BazaarTraderBuyerActions::WelcomeMessage;
|
||||||
|
eq->num_of_traders = emu->traders;
|
||||||
|
eq->num_of_items = emu->items;
|
||||||
|
|
||||||
|
safe_delete(in->pBuffer);
|
||||||
|
in->SetOpcode(OP_TraderShop);
|
||||||
|
in->size = sizeof(structs::BazaarWelcome_Struct);
|
||||||
|
in->pBuffer = (uchar *) buffer.get();
|
||||||
|
|
||||||
|
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
||||||
|
dest->QueuePacket(in);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DeliveryCostUpdate: {
|
||||||
|
auto data = (BazaarDeliveryCost_Struct *) in->pBuffer;
|
||||||
|
LogTrading("(RoF2) Delivery costs updated: vouchers <green>[{}] parcel percentage <green>[{}]",
|
||||||
|
data->voucher_delivery_cost,
|
||||||
|
data->parcel_deliver_cost
|
||||||
|
);
|
||||||
|
data->action = 0;
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char *__emu_buffer = in->pBuffer;
|
ENCODE(OP_BecomeTrader)
|
||||||
|
{
|
||||||
|
EQApplicationPacket *inapp = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
unsigned char *__emu_buffer = inapp->pBuffer;
|
||||||
|
auto in = (BecomeTrader_Struct *) __emu_buffer;
|
||||||
|
|
||||||
int EntryCount = in->size / sizeof(BazaarSearchResults_Struct);
|
switch (in->action) {
|
||||||
|
case TraderOff: {
|
||||||
|
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||||
|
|
||||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(structs::BecomeTrader_Struct));
|
||||||
{
|
auto eq = (structs::BecomeTrader_Struct *) outapp->pBuffer;
|
||||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
|
||||||
delete in;
|
eq->action = TraderOff;
|
||||||
return;
|
eq->entity_id = emu->entity_id;
|
||||||
|
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) TraderOff action <green>[{}] for entity_id <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->entity_id
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderOn: {
|
||||||
|
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(structs::BecomeTrader_Struct));
|
||||||
|
auto eq = (structs::BecomeTrader_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
|
eq->action = TraderOn;
|
||||||
|
eq->entity_id = emu->entity_id;
|
||||||
|
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) TraderOn action <green>[{}] for entity_id <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->entity_id
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AddTraderToBazaarWindow: {
|
||||||
|
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||||
|
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
|
||||||
|
auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
|
eq->action = emu->action;
|
||||||
|
eq->entity_id = emu->entity_id;
|
||||||
|
eq->trader_id = emu->trader_id;
|
||||||
|
eq->zone_id = emu->zone_id;
|
||||||
|
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||||
|
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->entity_id,
|
||||||
|
eq->trader_id,
|
||||||
|
eq->zone_id
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RemoveTraderFromBazaarWindow: {
|
||||||
|
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||||
|
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(structs::BazaarWindowRemoveTrader_Struct));
|
||||||
|
auto eq = (structs::BazaarWindowRemoveTrader_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
|
eq->action = emu->action;
|
||||||
|
eq->trader_id = emu->trader_id;
|
||||||
|
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) RemoveTraderFromBazaarWindow action <green>[{}] for entity_id <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) Unhandled action <red>[{}]",
|
||||||
|
in->action
|
||||||
|
);
|
||||||
|
dest->QueuePacket(inapp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
safe_delete(inapp);
|
||||||
in->size = EntryCount * sizeof(structs::BazaarSearchResults_Struct);
|
|
||||||
in->pBuffer = new unsigned char[in->size];
|
|
||||||
|
|
||||||
memset(in->pBuffer, 0, in->size);
|
|
||||||
|
|
||||||
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *)in->pBuffer;
|
|
||||||
|
|
||||||
for (int i = 0; i < EntryCount; ++i, ++emu, ++eq)
|
|
||||||
{
|
|
||||||
OUT(Beginning.Action);
|
|
||||||
OUT(SellerID);
|
|
||||||
memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
|
||||||
OUT(NumItems);
|
|
||||||
OUT(ItemID);
|
|
||||||
OUT(SerialNumber);
|
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
|
||||||
OUT(Cost);
|
|
||||||
OUT(ItemStat);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_BeginCast)
|
ENCODE(OP_BeginCast)
|
||||||
@ -2591,7 +2722,7 @@ namespace RoF2
|
|||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->char_id); // character_id
|
||||||
|
|
||||||
outapp->WriteUInt8(emu->leadAAActive);
|
outapp->WriteUInt8(emu->leadAAActive);
|
||||||
|
|
||||||
@ -3586,54 +3717,146 @@ namespace RoF2
|
|||||||
|
|
||||||
ENCODE(OP_Trader)
|
ENCODE(OP_Trader)
|
||||||
{
|
{
|
||||||
if ((*p)->size == sizeof(ClickTrader_Struct))
|
uint32 action = *(uint32 *) (*p)->pBuffer;
|
||||||
{
|
|
||||||
ENCODE_LENGTH_EXACT(ClickTrader_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
|
||||||
|
|
||||||
eq->Code = emu->Code;
|
switch (action) {
|
||||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
case TraderOn: {
|
||||||
for (uint32 i = 0; i < 200; i++)
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
{
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
eq->items[i].Unknown18 = 0;
|
|
||||||
if (i < 80) {
|
eq->action = structs::RoF2BazaarTraderBuyerActions::BeginTraderMode;
|
||||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016" PRId64, emu->SerialNumber[i]);
|
OUT(entity_id);
|
||||||
eq->ItemCost[i] = emu->ItemCost[i];
|
|
||||||
}
|
LogTrading("(RoF2) TraderOn action <green>[{}] entity_id <green>[{}]", action, eq->entity_id);
|
||||||
else {
|
FINISH_ENCODE();
|
||||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0);
|
break;
|
||||||
eq->ItemCost[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case TraderOff: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
eq->action = structs::RoF2BazaarTraderBuyerActions::EndTraderMode;
|
||||||
}
|
OUT(entity_id);
|
||||||
else if ((*p)->size == sizeof(Trader_ShowItems_Struct))
|
|
||||||
{
|
|
||||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
|
||||||
|
|
||||||
eq->Code = emu->Code;
|
LogTrading("(RoF2) TraderOff action <green>[{}] entity_id <green>[{}]", action, eq->entity_id);
|
||||||
//strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
FINISH_ENCODE();
|
||||||
//snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", 0);
|
break;
|
||||||
eq->TraderID = emu->TraderID;
|
}
|
||||||
//eq->Stacksize = 0;
|
case ListTraderItems: {
|
||||||
//eq->Price = 0;
|
ENCODE_LENGTH_EXACT(Trader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_Struct, structs::ClickTrader_Struct);
|
||||||
|
LogTrading("(RoF2) action <green>[{}]", action);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
eq->action = structs::RoF2BazaarTraderBuyerActions::ListTraderItems;
|
||||||
}
|
std::transform(
|
||||||
else if ((*p)->size == sizeof(TraderStatus_Struct))
|
std::begin(emu->items),
|
||||||
{
|
std::end(emu->items),
|
||||||
ENCODE_LENGTH_EXACT(TraderStatus_Struct);
|
std::begin(eq->items),
|
||||||
SETUP_DIRECT_ENCODE(TraderStatus_Struct, structs::TraderStatus_Struct);
|
[&](const uint32 x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
std::copy_n(
|
||||||
|
std::begin(emu->item_cost),
|
||||||
|
EQ::invtype::BAZAAR_SIZE,
|
||||||
|
std::begin(eq->item_cost)
|
||||||
|
);
|
||||||
|
|
||||||
eq->Code = emu->Code;
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderAck2: {
|
||||||
|
LogTrading("(RoF2) TraderAck2 action");
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
FINISH_ENCODE();
|
dest->FastQueuePacket(&in);
|
||||||
}
|
break;
|
||||||
else if ((*p)->size == sizeof(TraderBuy_Struct))
|
}
|
||||||
{
|
case PriceUpdate: {
|
||||||
ENCODE_FORWARD(OP_TraderBuy);
|
SETUP_DIRECT_ENCODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
||||||
|
switch (emu->SubAction) {
|
||||||
|
case BazaarPriceChange_AddItem: {
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||||
|
OP_Trader,
|
||||||
|
sizeof(structs::TraderStatus_Struct)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||||
|
data->action = emu->Action;
|
||||||
|
data->sub_action = BazaarPriceChange_AddItem;
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) PriceUpdate action <green>[{}] AddItem subaction <yellow>[{}]",
|
||||||
|
data->action,
|
||||||
|
data->sub_action
|
||||||
|
);
|
||||||
|
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarPriceChange_RemoveItem: {
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||||
|
OP_Trader,
|
||||||
|
sizeof(structs::TraderStatus_Struct)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||||
|
data->action = emu->Action;
|
||||||
|
data->sub_action = BazaarPriceChange_RemoveItem;
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) PriceUpdate action <green>[{}] RemoveItem subaction <yellow>[{}]",
|
||||||
|
data->action,
|
||||||
|
data->sub_action
|
||||||
|
);
|
||||||
|
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarPriceChange_UpdatePrice: {
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||||
|
OP_Trader,
|
||||||
|
sizeof(structs::TraderStatus_Struct)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||||
|
data->action = emu->Action;
|
||||||
|
data->sub_action = BazaarPriceChange_UpdatePrice;
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) PriceUpdate action <green>[{}] UpdatePrice subaction <yellow>[{}]",
|
||||||
|
data->action,
|
||||||
|
data->sub_action
|
||||||
|
);
|
||||||
|
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BuyTraderItem: {
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
auto eq = (structs::TraderBuy_Struct *) in->pBuffer;
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) BuyTraderItem action <green>[{}] item_id <green>[{}] item_sn <green>[{}] buyer <green>[{}]",
|
||||||
|
action,
|
||||||
|
eq->item_id,
|
||||||
|
eq->serial_number,
|
||||||
|
eq->buyer_name
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading("(RoF2) action <red>[{}]", action);
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3641,14 +3864,26 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
OUT(Action);
|
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
OUT(Price);
|
emu->item_id,
|
||||||
OUT(TraderID);
|
emu->price,
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
emu->quantity,
|
||||||
OUT(ItemID);
|
emu->trader_id
|
||||||
OUT(Quantity);
|
);
|
||||||
OUT(AlreadySold);
|
__packet->SetOpcode(OP_TraderShop);
|
||||||
|
OUT(action);
|
||||||
|
OUT(method);
|
||||||
|
OUT(sub_action);
|
||||||
|
OUT(trader_id);
|
||||||
|
OUT(item_id);
|
||||||
|
OUT(price);
|
||||||
|
OUT(already_sold);
|
||||||
|
OUT(quantity);
|
||||||
|
OUT_str(buyer_name);
|
||||||
|
OUT_str(seller_name);
|
||||||
|
OUT_str(item_name);
|
||||||
|
OUT_str(serial_number);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -3657,71 +3892,74 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) trader_id <green>[{}] item_id <green>[{}]",
|
||||||
|
emu->trader_id,
|
||||||
|
emu->item_id
|
||||||
|
);
|
||||||
|
|
||||||
OUT(TraderID);
|
eq->TraderID = emu->trader_id;
|
||||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
auto serial = fmt::format("{:016}\n", emu->item_id);
|
||||||
LogTrading("ENCODE(OP_TraderDelItem): TraderID [{}], SerialNumber: [{}]", emu->TraderID, emu->ItemID);
|
strn0cpy(eq->SerialNumber, serial.c_str(), sizeof(eq->SerialNumber));
|
||||||
|
LogTrading("(RoF2) TraderID <green>[{}], SerialNumber: <green>[{}]", emu->trader_id, emu->item_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_TraderShop)
|
ENCODE(OP_TraderShop)
|
||||||
{
|
{
|
||||||
uint32 psize = (*p)->size;
|
auto action = *(uint32 *) (*p)->pBuffer;
|
||||||
if (psize == sizeof(TraderClick_Struct))
|
|
||||||
{
|
|
||||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
|
||||||
|
|
||||||
eq->Code = 28; // Seen on Live
|
switch (action) {
|
||||||
OUT(TraderID);
|
case ClickTrader: {
|
||||||
OUT(Approval);
|
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) ClickTrader action <green>[{}] trader_id <green>[{}]",
|
||||||
|
action,
|
||||||
|
emu->TraderID
|
||||||
|
);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
eq->action = structs::RoF2BazaarTraderBuyerActions::ClickTrader; // Seen on Live
|
||||||
}
|
eq->trader_id = emu->TraderID;
|
||||||
else if (psize == sizeof(BazaarWelcome_Struct))
|
eq->unknown_008 = emu->Approval;
|
||||||
{
|
|
||||||
ENCODE_LENGTH_EXACT(BazaarWelcome_Struct);
|
|
||||||
SETUP_DIRECT_ENCODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct);
|
|
||||||
|
|
||||||
eq->Code = emu->Beginning.Action;
|
FINISH_ENCODE();
|
||||||
eq->EntityID = emu->Unknown012;
|
break;
|
||||||
OUT(Traders);
|
}
|
||||||
OUT(Items);
|
case structs::RoF2BazaarTraderBuyerActions::BuyTraderItem: {
|
||||||
eq->Traders2 = emu->Traders;
|
ENCODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
eq->Items2 = emu->Items;
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
LogTrading("ENCODE(OP_TraderShop): BazaarWelcome_Struct Code [{}], Traders [{}], Items [{}]",
|
OUT(action);
|
||||||
eq->Code, eq->Traders, eq->Items);
|
OUT(method);
|
||||||
|
OUT(trader_id);
|
||||||
|
OUT(item_id);
|
||||||
|
OUT(price);
|
||||||
|
OUT(already_sold);
|
||||||
|
OUT(quantity);
|
||||||
|
OUT_str(buyer_name);
|
||||||
|
OUT_str(seller_name);
|
||||||
|
OUT_str(item_name);
|
||||||
|
OUT_str(serial_number);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
break;
|
||||||
else if (psize == sizeof(TraderBuy_Struct))
|
}
|
||||||
{
|
default: {
|
||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
OUT(Action);
|
dest->FastQueuePacket(&in);
|
||||||
OUT(TraderID);
|
}
|
||||||
|
|
||||||
//memcpy(eq->BuyerName, emu->BuyerName, sizeof(eq->BuyerName));
|
|
||||||
//memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
|
||||||
|
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
|
||||||
OUT(ItemID);
|
|
||||||
OUT(AlreadySold);
|
|
||||||
OUT(Price);
|
|
||||||
OUT(Quantity);
|
|
||||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
|
||||||
|
|
||||||
LogTrading("ENCODE(OP_TraderShop): Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
|
||||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, emu->ItemName);
|
|
||||||
|
|
||||||
FINISH_ENCODE();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogTrading("ENCODE(OP_TraderShop): Encode Size Unknown ([{}])", psize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4067,20 +4305,20 @@ namespace RoF2
|
|||||||
|
|
||||||
structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer;
|
structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer;
|
||||||
|
|
||||||
Bitfields->gender = emu->gender;
|
Bitfields->gender = emu->gender;
|
||||||
Bitfields->ispet = emu->is_pet;
|
Bitfields->ispet = emu->is_pet;
|
||||||
Bitfields->afk = emu->afk;
|
Bitfields->afk = emu->afk;
|
||||||
Bitfields->anon = emu->anon;
|
Bitfields->anon = emu->anon;
|
||||||
Bitfields->gm = emu->gm;
|
Bitfields->gm = emu->gm;
|
||||||
Bitfields->sneak = 0;
|
Bitfields->sneak = 0;
|
||||||
Bitfields->lfg = emu->lfg;
|
Bitfields->lfg = emu->lfg;
|
||||||
Bitfields->invis = emu->invis;
|
Bitfields->invis = emu->invis;
|
||||||
Bitfields->linkdead = 0;
|
Bitfields->linkdead = 0;
|
||||||
Bitfields->showhelm = emu->showhelm;
|
Bitfields->showhelm = emu->showhelm;
|
||||||
Bitfields->trader = 0;
|
Bitfields->trader = emu->trader ? 1 : 0;
|
||||||
Bitfields->targetable = 1;
|
Bitfields->targetable = 1;
|
||||||
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
||||||
Bitfields->showname = ShowName;
|
Bitfields->showname = ShowName;
|
||||||
|
|
||||||
if (emu->DestructibleObject)
|
if (emu->DestructibleObject)
|
||||||
{
|
{
|
||||||
@ -4431,6 +4669,7 @@ namespace RoF2
|
|||||||
char *Buffer = (char *)__packet->pBuffer;
|
char *Buffer = (char *)__packet->pBuffer;
|
||||||
|
|
||||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
||||||
|
LogTrading("(RoF2) action <green>[{}]", SubAction);
|
||||||
|
|
||||||
if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct)))
|
if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct)))
|
||||||
return;
|
return;
|
||||||
@ -4440,6 +4679,7 @@ namespace RoF2
|
|||||||
IN(Beginning.Action);
|
IN(Beginning.Action);
|
||||||
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
||||||
IN(SerialNumber);
|
IN(SerialNumber);
|
||||||
|
LogTrading("(RoF2) action <green>[{}] serial_number <green>[{}]", eq->Beginning.Action, eq->SerialNumber);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
@ -5331,40 +5571,61 @@ namespace RoF2
|
|||||||
|
|
||||||
DECODE(OP_Trader)
|
DECODE(OP_Trader)
|
||||||
{
|
{
|
||||||
uint32 psize = __packet->size;
|
auto action = *(uint32 *)__packet->pBuffer;
|
||||||
if (psize == sizeof(structs::ClickTrader_Struct))
|
|
||||||
{
|
|
||||||
DECODE_LENGTH_EXACT(structs::ClickTrader_Struct);
|
|
||||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
switch (action) {
|
||||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
|
||||||
for (uint32 i = 0; i < 80; i++)
|
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||||
{
|
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
||||||
emu->SerialNumber[i] = 0; // eq->SerialNumber[i];
|
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
|
||||||
emu->ItemCost[i] = eq->ItemCost[i];
|
|
||||||
|
emu->action = TraderOn;
|
||||||
|
std::copy_n(eq->item_cost, RoF2::invtype::BAZAAR_SIZE, emu->item_cost);
|
||||||
|
std::transform(
|
||||||
|
std::begin(eq->items),
|
||||||
|
std::end(eq->items),
|
||||||
|
std::begin(emu->serial_number),
|
||||||
|
[&](const structs::TraderItemSerial_Struct x) {
|
||||||
|
return Strings::ToUnsignedBigInt(x.serial_number,0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading("(RoF2) EndTraderMode action <green>[{}]", action);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
emu->action = TraderOff;
|
||||||
}
|
emu->entity_id = eq->entity_id;
|
||||||
else if (psize == sizeof(structs::Trader_ShowItems_Struct))
|
|
||||||
{
|
|
||||||
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
|
||||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
FINISH_DIRECT_DECODE();
|
||||||
emu->TraderID = eq->TraderID;
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BazaarTraderBuyerActions::ListTraderItems: {
|
||||||
|
LogTrading("(RoF2) ListTraderItems action <green>[{}]", action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BazaarTraderBuyerActions::PriceUpdate: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::TraderPriceUpdate_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
||||||
|
LogTrading("(RoF2) PriceUpdate action <green>[{}]", action);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
emu->Action = PriceUpdate;
|
||||||
}
|
emu->SerialNumber = Strings::ToUnsignedBigInt(eq->serial_number, 0);
|
||||||
else if (psize == sizeof(structs::TraderStatus_Struct))
|
if (emu->SerialNumber == 0) {
|
||||||
{
|
LogTrading("(RoF2) Price change with invalid serial number <red>[{}]", eq->serial_number);
|
||||||
DECODE_LENGTH_EXACT(structs::TraderStatus_Struct);
|
}
|
||||||
SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct);
|
emu->NewPrice = eq->new_price;
|
||||||
|
|
||||||
emu->Code = eq->Code; // 11 = Start Trader, 2 = End Trader, 22 = ? - Guessing
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
FINISH_DIRECT_DECODE();
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5372,73 +5633,136 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
IN(Action);
|
IN(action);
|
||||||
IN(Price);
|
IN(price);
|
||||||
IN(TraderID);
|
IN(trader_id);
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||||
IN(ItemID);
|
IN(item_id);
|
||||||
IN(Quantity);
|
IN(quantity);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
DECODE(OP_TraderShop)
|
DECODE(OP_TraderShop)
|
||||||
{
|
{
|
||||||
uint32 psize = __packet->size;
|
uint32 action = *(uint32 *)__packet->pBuffer;
|
||||||
if (psize == sizeof(structs::TraderClick_Struct))
|
|
||||||
{
|
|
||||||
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
|
||||||
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
|
||||||
|
|
||||||
IN(Code);
|
switch (action) {
|
||||||
IN(TraderID);
|
case structs::RoF2BazaarTraderBuyerActions::BazaarSearch: {
|
||||||
IN(Approval);
|
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
|
||||||
LogTrading("DECODE(OP_TraderShop): TraderClick_Struct Code [{}], TraderID [{}], Approval [{}]",
|
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
|
||||||
eq->Code, eq->TraderID, eq->Approval);
|
LogTrading(
|
||||||
|
"(RoF2) BazaarSearch action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
__packet->SetOpcode(OP_BazaarSearch);
|
||||||
}
|
emu->action = BazaarSearch;
|
||||||
else if (psize == sizeof(structs::BazaarWelcome_Struct))
|
emu->type = eq->type == UINT32_MAX ? UINT8_MAX : eq->type;
|
||||||
{
|
IN(item_stat);
|
||||||
// Don't think this size gets used in RoF+ - Leaving for now...
|
IN(max_cost);
|
||||||
DECODE_LENGTH_EXACT(structs::BazaarWelcome_Struct);
|
IN(min_cost);
|
||||||
SETUP_DIRECT_DECODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct);
|
IN(max_level);
|
||||||
|
IN(min_level);
|
||||||
|
IN(race);
|
||||||
|
IN(slot);
|
||||||
|
IN(trader_id);
|
||||||
|
IN(_class);
|
||||||
|
IN(prestige);
|
||||||
|
IN(search_scope);
|
||||||
|
IN(max_results);
|
||||||
|
IN(augment);
|
||||||
|
IN_str(item_name);
|
||||||
|
|
||||||
emu->Beginning.Action = eq->Code;
|
FINISH_DIRECT_DECODE();
|
||||||
IN(Traders);
|
break;
|
||||||
IN(Items);
|
}
|
||||||
LogTrading("DECODE(OP_TraderShop): BazaarWelcome_Struct Code [{}], Traders [{}], Items [{}]",
|
case structs::RoF2BazaarTraderBuyerActions::ClickTrader: {
|
||||||
eq->Code, eq->Traders, eq->Items);
|
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
emu->Code = ClickTrader;
|
||||||
}
|
emu->TraderID = eq->trader_id;
|
||||||
else if (psize == sizeof(structs::TraderBuy_Struct))
|
emu->Approval = eq->unknown_008;
|
||||||
{
|
LogTrading("(RoF2) ClickTrader action <green>[{}], trader_id <green>[{}], approval <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->trader_id,
|
||||||
|
eq->unknown_008
|
||||||
|
);
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BazaarTraderBuyerActions::BazaarInspect: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::BazaarInspect_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
|
||||||
|
|
||||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
__packet->SetOpcode(OP_BazaarSearch);
|
||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
IN(item_id);
|
||||||
|
IN(trader_id);
|
||||||
|
emu->action = BazaarInspect;
|
||||||
|
emu->serial_number = Strings::ToUnsignedInt(eq->serial_number, 0);
|
||||||
|
if (emu->serial_number == 0) {
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) trader_id = <green>[{}] requested a BazaarInspect with an invalid serial number of <red>[{}]",
|
||||||
|
eq->trader_id,
|
||||||
|
eq->serial_number
|
||||||
|
);
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IN(Action);
|
LogTrading("(RoF2) BazaarInspect action <green>[{}] item_id <green>[{}] serial_number <green>[{}]",
|
||||||
IN(Price);
|
action,
|
||||||
IN(TraderID);
|
eq->item_id,
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
eq->serial_number
|
||||||
IN(ItemID);
|
);
|
||||||
IN(Quantity);
|
FINISH_DIRECT_DECODE();
|
||||||
LogTrading("DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 [{}], Unknown008 [{}], Unknown012 [{}], Unknown076 [{}], Unknown276 [{}]",
|
break;
|
||||||
eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276);
|
}
|
||||||
LogTrading("DECODE(OP_TraderShop): TraderBuy_Struct Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
|
||||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName);
|
__packet->SetOpcode(OP_BazaarSearch);
|
||||||
|
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BazaarTraderBuyerActions::BuyTraderItem: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
__packet->SetOpcode(OP_TraderBuy);
|
||||||
}
|
IN(action);
|
||||||
else if (psize == 4)
|
IN(method);
|
||||||
{
|
IN(trader_id);
|
||||||
LogTrading("DECODE(OP_TraderShop): Forwarding packet as-is with size 4");
|
IN(item_id);
|
||||||
}
|
IN(price);
|
||||||
else
|
IN(already_sold);
|
||||||
{
|
IN(quantity);
|
||||||
LogTrading("DECODE(OP_TraderShop): Decode Size Unknown ([{}])", psize);
|
IN_str(buyer_name);
|
||||||
|
IN_str(seller_name);
|
||||||
|
IN_str(item_name);
|
||||||
|
IN_str(serial_number);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5541,19 +5865,7 @@ namespace RoF2
|
|||||||
RoF2::structs::ItemSerializationHeader hdr;
|
RoF2::structs::ItemSerializationHeader hdr;
|
||||||
|
|
||||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||||
|
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
|
||||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
|
|
||||||
if (packet_type == ItemPacketParcel) {
|
|
||||||
strn0cpy(
|
|
||||||
hdr.unknown000,
|
|
||||||
fmt::format(
|
|
||||||
"{:03}PAR{:010}\0",
|
|
||||||
inst->GetMerchantSlot(),
|
|
||||||
item->ID
|
|
||||||
).c_str(),
|
|
||||||
sizeof(hdr.unknown000)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr.stacksize =
|
hdr.stacksize =
|
||||||
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
|
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
|
||||||
|
|||||||
@ -43,6 +43,7 @@ E(OP_ApplyPoison)
|
|||||||
E(OP_AugmentInfo)
|
E(OP_AugmentInfo)
|
||||||
E(OP_Barter)
|
E(OP_Barter)
|
||||||
E(OP_BazaarSearch)
|
E(OP_BazaarSearch)
|
||||||
|
E(OP_BecomeTrader)
|
||||||
E(OP_BeginCast)
|
E(OP_BeginCast)
|
||||||
E(OP_BlockedBuffs)
|
E(OP_BlockedBuffs)
|
||||||
E(OP_Buff)
|
E(OP_Buff)
|
||||||
|
|||||||
@ -3106,28 +3106,43 @@ struct EnvDamage2_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Bazaar Stuff
|
//Bazaar Stuff
|
||||||
|
enum RoF2BazaarTraderBuyerActions {
|
||||||
|
Zero = 0,
|
||||||
|
BeginTraderMode = 1,
|
||||||
|
EndTraderMode = 2,
|
||||||
|
PriceUpdate = 3,
|
||||||
|
EndTransaction = 4,
|
||||||
|
BazaarSearch = 7,
|
||||||
|
WelcomeMessage = 9,
|
||||||
|
BuyTraderItem = 10,
|
||||||
|
ListTraderItems = 11,
|
||||||
|
BazaarInspect = 18,
|
||||||
|
ClickTrader = 28,
|
||||||
|
ItemMove = 19,
|
||||||
|
ReconcileItems = 20
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarTrader_StartTraderMode = 1,
|
BazaarTrader_StartTraderMode = 1,
|
||||||
BazaarTrader_EndTraderMode = 2,
|
BazaarTrader_EndTraderMode = 2,
|
||||||
BazaarTrader_UpdatePrice = 3,
|
BazaarTrader_UpdatePrice = 3,
|
||||||
BazaarTrader_EndTransaction = 4,
|
BazaarTrader_EndTransaction = 4,
|
||||||
BazaarSearchResults = 7,
|
BazaarSearchResults = 7,
|
||||||
BazaarWelcome = 9,
|
BazaarWelcome = 9,
|
||||||
BazaarBuyItem = 10,
|
BazaarBuyItem = 10,
|
||||||
BazaarTrader_ShowItems = 11,
|
BazaarTrader_ShowItems = 11,
|
||||||
BazaarSearchDone = 12,
|
BazaarSearchDone = 12,
|
||||||
BazaarTrader_CustomerBrowsing = 13,
|
BazaarTrader_CustomerBrowsing = 13,
|
||||||
BazaarInspectItem = 18,
|
BazaarInspectItem = 18,
|
||||||
BazaarSearchDone2 = 19,
|
BazaarSearchDone2 = 19,
|
||||||
BazaarTrader_StartTraderMode2 = 22
|
BazaarTrader_StartTraderMode2 = 22
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarPriceChange_Fail = 0,
|
BazaarPriceChange_Fail = 0,
|
||||||
BazaarPriceChange_UpdatePrice = 1,
|
BazaarPriceChange_UpdatePrice = 1,
|
||||||
BazaarPriceChange_RemoveItem = 2,
|
BazaarPriceChange_RemoveItem = 2,
|
||||||
BazaarPriceChange_AddItem = 3
|
BazaarPriceChange_AddItem = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarWindowStart_Struct {
|
struct BazaarWindowStart_Struct {
|
||||||
@ -3136,34 +3151,51 @@ struct BazaarWindowStart_Struct {
|
|||||||
uint16 Unknown002;
|
uint16 Unknown002;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BazaarDeliveryCost_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 voucher_delivery_cost;
|
||||||
|
float parcel_deliver_cost; //percentage of item cost
|
||||||
|
uint32 unknown_010;
|
||||||
|
};
|
||||||
|
|
||||||
struct BazaarWelcome_Struct {
|
struct BazaarWelcome_Struct {
|
||||||
uint32 Code;
|
uint32 action;
|
||||||
uint32 EntityID;
|
uint32 unknown_004;
|
||||||
uint32 Traders;
|
uint32 num_of_traders;
|
||||||
uint32 Items;
|
uint32 num_of_items;
|
||||||
uint32 Traders2;
|
|
||||||
uint32 Items2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearch_Struct {
|
struct BazaarSearch_Struct {
|
||||||
BazaarWindowStart_Struct Beginning;
|
/*000*/ uint32 action;
|
||||||
uint32 TraderID;
|
/*004*/ uint8 search_scope;//1 all traders 0 local traders
|
||||||
uint32 Class_;
|
/*005*/ uint8 unknown_005{0};
|
||||||
uint32 Race;
|
/*006*/ uint16 unknown_006{0};
|
||||||
uint32 ItemStat;
|
/*008*/ uint32 unknown_008{0};
|
||||||
uint32 Slot;
|
/*012*/ uint32 unknown_012{0};
|
||||||
uint32 Type;
|
/*016*/ uint32 trader_id;
|
||||||
char Name[64];
|
/*020*/ uint32 _class;
|
||||||
uint32 MinPrice;
|
/*024*/ uint32 race;
|
||||||
uint32 MaxPrice;
|
/*028*/ uint32 item_stat;
|
||||||
uint32 Minlevel;
|
/*032*/ uint32 slot;
|
||||||
uint32 MaxLlevel;
|
/*036*/ uint32 type;
|
||||||
|
/*040*/ char item_name[64];
|
||||||
|
/*104*/ uint32 min_cost;
|
||||||
|
/*108*/ uint32 max_cost;
|
||||||
|
/*112*/ uint32 min_level;
|
||||||
|
/*116*/ uint32 max_level;
|
||||||
|
/*120*/ uint32 max_results;
|
||||||
|
/*124*/ uint32 prestige;
|
||||||
|
/*128*/ uint32 augment;
|
||||||
};
|
};
|
||||||
struct BazaarInspect_Struct{
|
|
||||||
uint32 ItemID;
|
struct BazaarInspect_Struct {
|
||||||
uint32 Unknown004;
|
uint32 action;
|
||||||
char Name[64];
|
uint32 unknown_004;
|
||||||
|
uint32 trader_id;
|
||||||
|
char serial_number[17];
|
||||||
|
char unknown_029[3];
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 unknown_036;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NewBazaarInspect_Struct {
|
struct NewBazaarInspect_Struct {
|
||||||
@ -3184,18 +3216,23 @@ struct BazaarReturnDone_Struct{
|
|||||||
uint32 Unknown016;
|
uint32 Unknown016;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearchResults_Struct {
|
struct BazaarSearchDetails_Struct { //24+name+17
|
||||||
/*000*/ BazaarWindowStart_Struct Beginning;
|
/*014*/ uint32 trader_id;
|
||||||
/*004*/ uint32 SellerID;
|
/*018*/ char serial_num[17];
|
||||||
/*008*/ char SellerName[64];
|
/*022*/ uint32 cost;
|
||||||
/*072*/ uint32 NumItems;
|
/*026*/ uint32 quanity;
|
||||||
/*076*/ uint32 ItemID;
|
/*030*/ uint32 id;
|
||||||
/*080*/ uint32 SerialNumber;
|
/*034*/ uint32 icon;
|
||||||
/*084*/ uint32 Unknown084;
|
/*038*/ char name[1];
|
||||||
/*088*/ char ItemName[64];
|
/*039*/ uint32 stat;
|
||||||
/*152*/ uint32 Cost;
|
};
|
||||||
/*156*/ uint32 ItemStat;
|
|
||||||
/*160*/
|
struct BazaarSearchResults_Struct { //14
|
||||||
|
/*000*/ uint32 unknown000;
|
||||||
|
/*004*/ uint16 zone_id;
|
||||||
|
/*006*/ uint32 entity_id;
|
||||||
|
/*010*/ uint32 num_items;
|
||||||
|
/*014*/ BazaarSearchDetails_Struct items[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerSideFilters_Struct {
|
struct ServerSideFilters_Struct {
|
||||||
@ -3398,21 +3435,26 @@ struct WhoAllPlayerPart4 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemSerial_Struct {
|
struct TraderItemSerial_Struct {
|
||||||
char SerialNumber[17];
|
char serial_number[17];
|
||||||
uint8 Unknown18;
|
uint8 unknown_018;
|
||||||
|
|
||||||
|
void operator=(uint32 a) {
|
||||||
|
auto _tmp = fmt::format("{:016}", a);
|
||||||
|
strn0cpy(this->serial_number, _tmp.c_str(), sizeof(this->serial_number));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_Struct {
|
struct BeginTrader_Struct {
|
||||||
/*0000*/ uint32 Code;
|
/*0000*/ uint32 action;
|
||||||
/*0004*/ TraderItemSerial_Struct items[200];
|
/*0004*/ TraderItemSerial_Struct items[200];
|
||||||
/*3604*/ uint32 ItemCost[200];
|
/*3604*/ uint32 item_cost[200];
|
||||||
/*4404*/
|
/*4404*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClickTrader_Struct {
|
struct ClickTrader_Struct {
|
||||||
/*0000*/ uint32 Code;
|
/*0000*/ uint32 action;
|
||||||
/*0004*/ TraderItemSerial_Struct items[200];
|
/*0004*/ TraderItemSerial_Struct items[200];
|
||||||
/*3604*/ uint32 ItemCost[200];
|
/*3604*/ uint32 item_cost[200];
|
||||||
/*4404*/
|
/*4404*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3421,67 +3463,55 @@ struct GetItems_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BecomeTrader_Struct {
|
struct BecomeTrader_Struct {
|
||||||
uint32 id;
|
uint32 entity_id;
|
||||||
uint32 code;
|
uint32 action;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BazaarWindowRemoveTrader_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 trader_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TraderPriceUpdate_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char serial_number[17];
|
||||||
|
char unknown_021[3];
|
||||||
|
uint32 unknown_024;
|
||||||
|
uint32 new_price;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct {
|
struct Trader_ShowItems_Struct {
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint16 TraderID;
|
/*004*/ uint32 entity_id;
|
||||||
/*008*/ uint32 Unknown08;
|
/*008*/ uint32 unknown_008;
|
||||||
/*012*/
|
/*012*/
|
||||||
};
|
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct_WIP {
|
|
||||||
/*000*/ uint32 Code;
|
|
||||||
/*004*/ char SerialNumber[17];
|
|
||||||
/*021*/ uint8 Unknown21;
|
|
||||||
/*022*/ uint16 TraderID;
|
|
||||||
/*026*/ uint32 Stacksize;
|
|
||||||
/*030*/ uint32 Price;
|
|
||||||
/*032*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderStatus_Struct {
|
struct TraderStatus_Struct {
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Uknown04;
|
/*004*/ uint32 sub_action;
|
||||||
/*008*/ uint32 Uknown08;
|
/*008*/ uint32 uknown_008;
|
||||||
/*012*/
|
/*012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 method;
|
||||||
/*008*/ uint32 Unknown008;
|
/*008*/ uint32 sub_action;
|
||||||
/*012*/ uint32 Unknown012;
|
/*012*/ uint32 unknown_012;
|
||||||
/*016*/ uint32 TraderID;
|
/*016*/ uint32 trader_id;
|
||||||
/*020*/ char BuyerName[64];
|
/*020*/ char buyer_name[64];
|
||||||
/*084*/ char SellerName[64];
|
/*084*/ char seller_name[64];
|
||||||
/*148*/ char Unknown148[32];
|
/*148*/ char unknown_148[32];
|
||||||
/*180*/ char ItemName[64];
|
/*180*/ char item_name[64];
|
||||||
/*244*/ char SerialNumber[16];
|
/*244*/ char serial_number[17];
|
||||||
/*260*/ uint32 Unknown076;
|
/*261*/ char unknown_261[3];
|
||||||
/*264*/ uint32 ItemID;
|
/*264*/ uint32 item_id;
|
||||||
/*268*/ uint32 Price;
|
/*268*/ uint32 price;
|
||||||
/*272*/ uint32 AlreadySold;
|
/*272*/ uint32 already_sold;
|
||||||
/*276*/ uint32 Unknown276;
|
/*276*/ uint32 unknown_276;
|
||||||
/*280*/ uint32 Quantity;
|
/*280*/ uint32 quantity;
|
||||||
/*284*/
|
/*284*/
|
||||||
};
|
|
||||||
|
|
||||||
struct TraderBuy_Struct_OLD {
|
|
||||||
/*000*/ uint32 Action;
|
|
||||||
/*004*/ uint32 Unknown004;
|
|
||||||
/*008*/ uint32 Price;
|
|
||||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
|
||||||
/*016*/ uint32 TraderID;
|
|
||||||
/*020*/ char ItemName[64];
|
|
||||||
/*084*/ uint32 Unknown076;
|
|
||||||
/*088*/ uint32 ItemID;
|
|
||||||
/*092*/ uint32 AlreadySold;
|
|
||||||
/*096*/ uint32 Quantity;
|
|
||||||
/*100*/ uint32 Unknown092;
|
|
||||||
/*104*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemUpdate_Struct{
|
struct TraderItemUpdate_Struct{
|
||||||
@ -3502,15 +3532,15 @@ struct MoneyUpdate_Struct{
|
|||||||
struct TraderDelItem_Struct{
|
struct TraderDelItem_Struct{
|
||||||
/*000*/ uint32 Unknown000;
|
/*000*/ uint32 Unknown000;
|
||||||
/*004*/ uint32 TraderID;
|
/*004*/ uint32 TraderID;
|
||||||
/*008*/ char SerialNumber[16];
|
/*008*/ char SerialNumber[17];
|
||||||
/*024*/ uint32 Unknown012;
|
/*024*/ uint32 Unknown012;
|
||||||
/*028*/
|
/*028*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 TraderID;
|
/*004*/ uint32 trader_id;
|
||||||
/*008*/ uint32 Approval;
|
/*008*/ uint32 unknown_008;
|
||||||
/*012*/
|
/*012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3376,17 +3376,17 @@ struct TraderStatus_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 unknown_004;
|
||||||
/*008*/ uint32 Price;
|
/*008*/ uint32 price;
|
||||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
/*012*/ uint32 unknown_008; // Probably high order bits of a 64 bit price.
|
||||||
/*016*/ uint32 TraderID;
|
/*016*/ uint32 trader_id;
|
||||||
/*020*/ char ItemName[64];
|
/*020*/ char item_name[64];
|
||||||
/*084*/ uint32 Unknown076;
|
/*084*/ uint32 unknown_076;
|
||||||
/*088*/ uint32 ItemID;
|
/*088*/ uint32 item_id;
|
||||||
/*092*/ uint32 AlreadySold;
|
/*092*/ uint32 already_sold;
|
||||||
/*096*/ uint32 Quantity;
|
/*096*/ uint32 quantity;
|
||||||
/*100*/ uint32 Unknown092;
|
/*100*/ uint32 unknown_092;
|
||||||
/*104*/
|
/*104*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2286,13 +2286,13 @@ namespace SoD
|
|||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
|
||||||
OUT(Action);
|
OUT(action);
|
||||||
OUT(Price);
|
OUT(price);
|
||||||
OUT(TraderID);
|
OUT(trader_id);
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
OUT(ItemID);
|
OUT(item_id);
|
||||||
OUT(Quantity);
|
OUT(quantity);
|
||||||
OUT(AlreadySold);
|
OUT(already_sold);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -3517,12 +3517,12 @@ namespace SoD
|
|||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
MEMSET_IN(TraderBuy_Struct);
|
MEMSET_IN(TraderBuy_Struct);
|
||||||
|
|
||||||
IN(Action);
|
IN(action);
|
||||||
IN(Price);
|
IN(price);
|
||||||
IN(TraderID);
|
IN(trader_id);
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||||
IN(ItemID);
|
IN(item_id);
|
||||||
IN(Quantity);
|
IN(quantity);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2879,20 +2879,21 @@ struct Trader_ShowItems_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 unknown_004;
|
||||||
/*008*/ uint32 Price;
|
/*008*/ uint32 price;
|
||||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
/*012*/ uint32 unknown_008; // Probably high order bits of a 64 bit price.
|
||||||
/*016*/ uint32 TraderID;
|
/*016*/ uint32 trader_id;
|
||||||
/*020*/ char ItemName[64];
|
/*020*/ char item_name[64];
|
||||||
/*084*/ uint32 Unknown076;
|
/*084*/ uint32 unknown_076;
|
||||||
/*088*/ uint32 ItemID;
|
/*088*/ uint32 item_id;
|
||||||
/*092*/ uint32 AlreadySold;
|
/*092*/ uint32 already_sold;
|
||||||
/*096*/ uint32 Quantity;
|
/*096*/ uint32 quantity;
|
||||||
/*100*/ uint32 Unknown092;
|
/*100*/ uint32 unknown_092;
|
||||||
/*104*/
|
/*104*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct TraderItemUpdate_Struct{
|
struct TraderItemUpdate_Struct{
|
||||||
uint32 unknown0;
|
uint32 unknown0;
|
||||||
uint32 traderid;
|
uint32 traderid;
|
||||||
|
|||||||
@ -270,8 +270,8 @@ namespace SoF
|
|||||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||||
|
|
||||||
OUT(ID);
|
OUT(trader_id);
|
||||||
OUT(Code);
|
OUT(action);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -1902,13 +1902,13 @@ namespace SoF
|
|||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
|
||||||
OUT(Action);
|
OUT(action);
|
||||||
OUT(Price);
|
OUT(price);
|
||||||
OUT(TraderID);
|
OUT(trader_id);
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
OUT(ItemID);
|
OUT(item_id);
|
||||||
OUT(Quantity);
|
OUT(quantity);
|
||||||
OUT(AlreadySold);
|
OUT(already_sold);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -2908,12 +2908,12 @@ namespace SoF
|
|||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
MEMSET_IN(TraderBuy_Struct);
|
MEMSET_IN(TraderBuy_Struct);
|
||||||
|
|
||||||
IN(Action);
|
IN(action);
|
||||||
IN(Price);
|
IN(price);
|
||||||
IN(TraderID);
|
IN(trader_id);
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||||
IN(ItemID);
|
IN(item_id);
|
||||||
IN(Quantity);
|
IN(quantity);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2771,8 +2771,8 @@ struct GetItems_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BecomeTrader_Struct{
|
struct BecomeTrader_Struct{
|
||||||
uint32 ID;
|
uint32 trader_id;
|
||||||
uint32 Code;
|
uint32 action;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct{
|
struct Trader_ShowItems_Struct{
|
||||||
@ -2782,15 +2782,15 @@ struct Trader_ShowItems_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Price;
|
/*004*/ uint32 price;
|
||||||
/*008*/ uint32 TraderID;
|
/*008*/ uint32 trader_id;
|
||||||
/*012*/ char ItemName[64];
|
/*012*/ char item_name[64];
|
||||||
/*076*/ uint32 Unknown076;
|
/*076*/ uint32 unknown_076;
|
||||||
/*080*/ uint32 ItemID;
|
/*080*/ uint32 item_id;
|
||||||
/*084*/ uint32 AlreadySold;
|
/*084*/ uint32 already_sold;
|
||||||
/*088*/ uint32 Quantity;
|
/*088*/ uint32 quantity;
|
||||||
/*092*/ uint32 Unknown092;
|
/*092*/ uint32 unknown_092;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemUpdate_Struct{
|
struct TraderItemUpdate_Struct{
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
eq_struct *eq = (eq_struct *) __packet->pBuffer; \
|
eq_struct *eq = (eq_struct *) __packet->pBuffer; \
|
||||||
|
|
||||||
#define ALLOC_LEN_ENCODE(len) \
|
#define ALLOC_LEN_ENCODE(len) \
|
||||||
__packet->pBuffer = new unsigned char[len]; \
|
__packet->pBuffer = new unsigned char[len] {}; \
|
||||||
__packet->size = len; \
|
__packet->size = len; \
|
||||||
memset(__packet->pBuffer, 0, len); \
|
memset(__packet->pBuffer, 0, len); \
|
||||||
|
|
||||||
@ -124,7 +124,7 @@
|
|||||||
#define SETUP_DIRECT_DECODE(emu_struct, eq_struct) \
|
#define SETUP_DIRECT_DECODE(emu_struct, eq_struct) \
|
||||||
unsigned char *__eq_buffer = __packet->pBuffer; \
|
unsigned char *__eq_buffer = __packet->pBuffer; \
|
||||||
__packet->size = sizeof(emu_struct); \
|
__packet->size = sizeof(emu_struct); \
|
||||||
__packet->pBuffer = new unsigned char[__packet->size]; \
|
__packet->pBuffer = new unsigned char[__packet->size] {}; \
|
||||||
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
||||||
eq_struct *eq = (eq_struct *) __eq_buffer;
|
eq_struct *eq = (eq_struct *) __eq_buffer;
|
||||||
|
|
||||||
@ -133,7 +133,7 @@
|
|||||||
eq_struct* in = (eq_struct*)__packet->pBuffer; \
|
eq_struct* in = (eq_struct*)__packet->pBuffer; \
|
||||||
auto size = strlen(in->var_field); \
|
auto size = strlen(in->var_field); \
|
||||||
__packet->size = sizeof(emu_struct) + size + 1; \
|
__packet->size = sizeof(emu_struct) + size + 1; \
|
||||||
__packet->pBuffer = new unsigned char[__packet->size]; \
|
__packet->pBuffer = new unsigned char[__packet->size] {}; \
|
||||||
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
||||||
eq_struct *eq = (eq_struct *) __eq_buffer;
|
eq_struct *eq = (eq_struct *) __eq_buffer;
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
#include "../strings.h"
|
#include "../strings.h"
|
||||||
#include "../item_instance.h"
|
#include "../item_instance.h"
|
||||||
#include "titanium_structs.h"
|
#include "titanium_structs.h"
|
||||||
|
#include "../rulesys.h"
|
||||||
#include "../path_manager.h"
|
#include "../path_manager.h"
|
||||||
#include "../raid.h"
|
#include "../raid.h"
|
||||||
#include "../guilds.h"
|
#include "../guilds.h"
|
||||||
@ -197,64 +198,135 @@ namespace Titanium
|
|||||||
|
|
||||||
ENCODE(OP_BazaarSearch)
|
ENCODE(OP_BazaarSearch)
|
||||||
{
|
{
|
||||||
if (((*p)->size == sizeof(BazaarReturnDone_Struct)) || ((*p)->size == sizeof(BazaarWelcome_Struct))) {
|
|
||||||
|
|
||||||
EQApplicationPacket *in = *p;
|
|
||||||
*p = nullptr;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//consume the packet
|
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
//store away the emu struct
|
uint32 action = *(uint32 *)in->pBuffer;
|
||||||
unsigned char *__emu_buffer = in->pBuffer;
|
|
||||||
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
|
||||||
|
|
||||||
//determine and verify length
|
switch (action) {
|
||||||
int entrycount = in->size / sizeof(BazaarSearchResults_Struct);
|
case BazaarSearch: {
|
||||||
if (entrycount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0) {
|
LogTrading(
|
||||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d",
|
"Encode OP_BazaarSearch(Ti) BazaarSearch action <green>[{}]",
|
||||||
opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
action
|
||||||
delete in;
|
);
|
||||||
return;
|
std::vector<BazaarSearchResultsFromDB_Struct> results {};
|
||||||
|
auto bsms = (BazaarSearchMessaging_Struct *)in->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(bsms->payload),
|
||||||
|
in->size - sizeof(BazaarSearchMessaging_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(results);
|
||||||
|
|
||||||
|
auto size = results.size() * sizeof(structs::BazaarSearchResults_Struct);
|
||||||
|
auto buffer = new uchar[size];
|
||||||
|
uchar *bufptr = buffer;
|
||||||
|
memset(buffer, 0, size);
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, structs::TiBazaarTraderBuyerActions::BazaarSearch);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
|
||||||
|
bufptr += 4;
|
||||||
|
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
|
||||||
|
bufptr += 4;
|
||||||
|
if (row->stackable) {
|
||||||
|
strn0cpy(
|
||||||
|
reinterpret_cast<char *>(bufptr),
|
||||||
|
fmt::format("{}({})", row->item_name.c_str(), row->charges).c_str(),
|
||||||
|
64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strn0cpy(
|
||||||
|
reinterpret_cast<char *>(bufptr),
|
||||||
|
fmt::format("{}({})", row->item_name.c_str(), row->count).c_str(),
|
||||||
|
64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bufptr += 64;
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->cost);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->item_stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_BazaarSearch, size);
|
||||||
|
memcpy(outapp->pBuffer, buffer, size);
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
|
||||||
|
safe_delete(outapp);
|
||||||
|
safe_delete_array(buffer);
|
||||||
|
safe_delete(in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarInspect:
|
||||||
|
case WelcomeMessage: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BazaarSearch(Ti) BazaarInspect/WelcomeMessage action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BazaarSearch(Ti) unhandled action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//make the EQ struct.
|
|
||||||
in->size = sizeof(structs::BazaarSearchResults_Struct)*entrycount;
|
|
||||||
in->pBuffer = new unsigned char[in->size];
|
|
||||||
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *) in->pBuffer;
|
|
||||||
|
|
||||||
//zero out the packet. We could avoid this memset by setting all fields (including unknowns) in the loop.
|
|
||||||
memset(in->pBuffer, 0, in->size);
|
|
||||||
|
|
||||||
for (int i = 0; i < entrycount; i++, eq++, emu++) {
|
|
||||||
eq->Beginning.Action = emu->Beginning.Action;
|
|
||||||
eq->Beginning.Unknown001 = emu->Beginning.Unknown001;
|
|
||||||
eq->Beginning.Unknown002 = emu->Beginning.Unknown002;
|
|
||||||
eq->NumItems = emu->NumItems;
|
|
||||||
eq->SerialNumber = emu->SerialNumber;
|
|
||||||
eq->SellerID = emu->SellerID;
|
|
||||||
eq->Cost = emu->Cost;
|
|
||||||
eq->ItemStat = emu->ItemStat;
|
|
||||||
strcpy(eq->ItemName, emu->ItemName);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_BecomeTrader)
|
ENCODE(OP_BecomeTrader)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
uint32 action = *(uint32 *)(*p)->pBuffer;
|
||||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
|
||||||
|
|
||||||
OUT(ID);
|
switch (action)
|
||||||
OUT(Code);
|
{
|
||||||
|
case TraderOff:
|
||||||
FINISH_ENCODE();
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BecomeTrader(Ti) TraderOff action <green>[{}] entity_id <green>[{}] trader_name "
|
||||||
|
"<green>[{}]",
|
||||||
|
emu->action,
|
||||||
|
emu->entity_id,
|
||||||
|
emu->trader_name
|
||||||
|
);
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::Zero;
|
||||||
|
eq->entity_id = emu->entity_id;
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderOn:
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BecomeTrader(Ti) TraderOn action <green>[{}] entity_id <green>[{}] trader_name "
|
||||||
|
"<green>[{}]",
|
||||||
|
emu->action,
|
||||||
|
emu->entity_id,
|
||||||
|
emu->trader_name
|
||||||
|
);
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::BeginTraderMode;
|
||||||
|
eq->entity_id = emu->entity_id;
|
||||||
|
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BecomeTrader(Ti) unhandled action <red>[{}] Sending packet as is.",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_Buff)
|
ENCODE(OP_Buff)
|
||||||
@ -2010,32 +2082,170 @@ namespace Titanium
|
|||||||
|
|
||||||
ENCODE(OP_Trader)
|
ENCODE(OP_Trader)
|
||||||
{
|
{
|
||||||
if ((*p)->size != sizeof(TraderBuy_Struct)) {
|
auto action = *(uint32 *) (*p)->pBuffer;
|
||||||
EQApplicationPacket *in = *p;
|
|
||||||
*p = nullptr;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE_FORWARD(OP_TraderBuy);
|
switch (action) {
|
||||||
|
case TraderOn: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader BeginTraderMode action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::BeginTraderMode;
|
||||||
|
OUT(entity_id);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderOff: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader EndTraderMode action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::EndTraderMode;
|
||||||
|
OUT(entity_id);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ListTraderItems: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_Struct, structs::Trader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader ListTraderItems action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::ListTraderItems;
|
||||||
|
std::copy_n(emu->items, UF::invtype::BAZAAR_SIZE, eq->item_id);
|
||||||
|
std::copy_n(emu->item_cost, UF::invtype::BAZAAR_SIZE, eq->item_cost);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BuyTraderItem: {
|
||||||
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::BuyTraderItem;
|
||||||
|
OUT(price);
|
||||||
|
OUT(trader_id);
|
||||||
|
OUT(item_id);
|
||||||
|
OUT(already_sold);
|
||||||
|
OUT(quantity);
|
||||||
|
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ItemMove: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader ItemMove action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
LogError("Unknown Encode OP_Trader action <red>{} received. Unhandled.", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_TraderBuy)
|
ENCODE(OP_TraderBuy)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_TraderBuy item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
emu->item_id,
|
||||||
|
emu->price,
|
||||||
|
emu->quantity,
|
||||||
|
emu->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
OUT(Action);
|
OUT(action);
|
||||||
OUT(Price);
|
OUT(price);
|
||||||
OUT(TraderID);
|
OUT(trader_id);
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
OUT(item_id);
|
||||||
OUT(ItemID);
|
OUT(already_sold);
|
||||||
OUT(Quantity);
|
OUT(quantity);
|
||||||
OUT(AlreadySold);
|
OUT_str(item_name);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_TraderShop)
|
||||||
|
{
|
||||||
|
auto action = *(uint32 *)(*p)->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case ClickTrader: {
|
||||||
|
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"ClickTrader action <green>[{}] trader_id <green>[{}]",
|
||||||
|
action,
|
||||||
|
emu->TraderID
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = 0;
|
||||||
|
eq->trader_id = emu->TraderID;
|
||||||
|
eq->approval = emu->Approval;
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BuyTraderItem: {
|
||||||
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_TraderShop item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::TiBazaarTraderBuyerActions::BuyTraderItem;
|
||||||
|
OUT(price);
|
||||||
|
OUT(trader_id);
|
||||||
|
OUT(item_id);
|
||||||
|
OUT(already_sold);
|
||||||
|
OUT(quantity);
|
||||||
|
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
LogError("Unknown Encode OP_TraderShop action <red>[{}] received. Unhandled.", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_TributeItem)
|
ENCODE(OP_TributeItem)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
||||||
@ -2286,6 +2496,53 @@ namespace Titanium
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_BazaarSearch)
|
||||||
|
{
|
||||||
|
uint32 action = *(uint32 *) __packet->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case structs::TiBazaarTraderBuyerActions::BazaarSearch: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
|
||||||
|
|
||||||
|
emu->action = eq->Beginning.Action;
|
||||||
|
emu->item_stat = eq->ItemStat;
|
||||||
|
emu->max_cost = eq->MaxPrice;
|
||||||
|
emu->min_cost = eq->MinPrice;
|
||||||
|
emu->max_level = eq->MaxLlevel;
|
||||||
|
emu->min_level = eq->Minlevel;
|
||||||
|
emu->race = eq->Race;
|
||||||
|
emu->slot = eq->Slot;
|
||||||
|
emu->type = eq->Type == UINT32_MAX ? UINT8_MAX : eq->Type;
|
||||||
|
emu->trader_entity_id = eq->TraderID;
|
||||||
|
emu->trader_id = 0;
|
||||||
|
emu->_class = eq->Class_;
|
||||||
|
emu->search_scope = eq->TraderID > 0 ? NonRoFBazaarSearchScope : Local_Scope;
|
||||||
|
emu->max_results = RuleI(Bazaar, MaxSearchResults);
|
||||||
|
strn0cpy(emu->item_name, eq->Name, sizeof(emu->item_name));
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::TiBazaarTraderBuyerActions::BazaarInspect: {
|
||||||
|
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
|
||||||
|
|
||||||
|
IN(action);
|
||||||
|
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
||||||
|
IN(serial_number);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::TiBazaarTraderBuyerActions::WelcomeMessage: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading("(Ti) Unhandled action <red>[{}]", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_Buff)
|
DECODE(OP_Buff)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct);
|
DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct);
|
||||||
@ -2925,18 +3182,90 @@ namespace Titanium
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_Trader)
|
||||||
|
{
|
||||||
|
auto action = (uint32) __packet->pBuffer[0];
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case structs::TiBazaarTraderBuyerActions::BeginTraderMode: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Decode OP_Trader BeginTraderMode action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->action = TraderOn;
|
||||||
|
emu->unknown_004 = 0;
|
||||||
|
std::copy_n(eq->serial_number, Titanium::invtype::BAZAAR_SIZE, emu->serial_number);
|
||||||
|
std::copy_n(eq->cost, Titanium::invtype::BAZAAR_SIZE, emu->item_cost);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::TiBazaarTraderBuyerActions::EndTraderMode: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Decode OP_Trader(Ti) EndTraderMode action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->action = TraderOff;
|
||||||
|
IN(entity_id);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::TiBazaarTraderBuyerActions::PriceUpdate:
|
||||||
|
case structs::TiBazaarTraderBuyerActions::ItemMove:
|
||||||
|
case structs::TiBazaarTraderBuyerActions::EndTransaction:
|
||||||
|
case structs::TiBazaarTraderBuyerActions::ListTraderItems: {
|
||||||
|
LogTrading(
|
||||||
|
"Decode OP_Trader(Ti) Price/ItemMove/EndTransaction/ListTraderItems action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::TiBazaarTraderBuyerActions::ReconcileItems: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogError("Unhandled(Ti) action <red>[{}] received.", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_TraderBuy)
|
DECODE(OP_TraderBuy)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
MEMSET_IN(TraderBuy_Struct);
|
MEMSET_IN(TraderBuy_Struct);
|
||||||
|
|
||||||
IN(Action);
|
IN(action);
|
||||||
IN(Price);
|
IN(price);
|
||||||
IN(TraderID);
|
IN(trader_id);
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||||
IN(ItemID);
|
IN(item_id);
|
||||||
IN(Quantity);
|
IN(quantity);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
|
||||||
|
DECODE(OP_TraderShop)
|
||||||
|
{
|
||||||
|
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(Ti) action <green>[{}] trader_id <green>[{}] approval <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->trader_id,
|
||||||
|
eq->approval
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->Code = ClickTrader;
|
||||||
|
emu->TraderID = eq->trader_id;
|
||||||
|
emu->Approval = eq->approval;
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,7 @@ E(OP_TaskDescription)
|
|||||||
E(OP_Track)
|
E(OP_Track)
|
||||||
E(OP_Trader)
|
E(OP_Trader)
|
||||||
E(OP_TraderBuy)
|
E(OP_TraderBuy)
|
||||||
|
E(OP_TraderShop)
|
||||||
E(OP_TributeItem)
|
E(OP_TributeItem)
|
||||||
E(OP_VetRewardsAvaliable)
|
E(OP_VetRewardsAvaliable)
|
||||||
E(OP_WearChange)
|
E(OP_WearChange)
|
||||||
@ -92,6 +93,7 @@ E(OP_ZoneSpawns)
|
|||||||
D(OP_AdventureMerchantSell)
|
D(OP_AdventureMerchantSell)
|
||||||
D(OP_ApplyPoison)
|
D(OP_ApplyPoison)
|
||||||
D(OP_AugmentItem)
|
D(OP_AugmentItem)
|
||||||
|
D(OP_BazaarSearch)
|
||||||
D(OP_Buff)
|
D(OP_Buff)
|
||||||
D(OP_Bug)
|
D(OP_Bug)
|
||||||
D(OP_CastSpell)
|
D(OP_CastSpell)
|
||||||
@ -123,7 +125,9 @@ D(OP_ReadBook)
|
|||||||
D(OP_SetServerFilter)
|
D(OP_SetServerFilter)
|
||||||
D(OP_ShopPlayerSell)
|
D(OP_ShopPlayerSell)
|
||||||
D(OP_ShopRequest)
|
D(OP_ShopRequest)
|
||||||
|
D(OP_Trader)
|
||||||
D(OP_TraderBuy)
|
D(OP_TraderBuy)
|
||||||
|
D(OP_TraderShop)
|
||||||
D(OP_TradeSkillCombine)
|
D(OP_TradeSkillCombine)
|
||||||
D(OP_TributeItem)
|
D(OP_TributeItem)
|
||||||
D(OP_WearChange)
|
D(OP_WearChange)
|
||||||
|
|||||||
@ -2273,24 +2273,29 @@ struct BazaarWelcome_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearch_Struct {
|
struct BazaarSearch_Struct {
|
||||||
BazaarWindowStart_Struct beginning;
|
BazaarWindowStart_Struct Beginning;
|
||||||
uint32 traderid;
|
uint32 TraderID;
|
||||||
uint32 class_;
|
uint32 Class_;
|
||||||
uint32 race;
|
uint32 Race;
|
||||||
uint32 stat;
|
uint32 ItemStat;
|
||||||
uint32 slot;
|
uint32 Slot;
|
||||||
uint32 type;
|
uint32 Type;
|
||||||
char name[64];
|
char Name[64];
|
||||||
uint32 minprice;
|
uint32 MinPrice;
|
||||||
uint32 maxprice;
|
uint32 MaxPrice;
|
||||||
uint32 minlevel;
|
uint32 Minlevel;
|
||||||
uint32 maxlevel;
|
uint32 MaxLlevel;
|
||||||
};
|
};
|
||||||
struct BazaarInspect_Struct{
|
|
||||||
|
struct BazaarInspect_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char player_name[64];
|
||||||
|
uint32 unknown_068;
|
||||||
|
uint32 serial_number;
|
||||||
|
uint32 unknown_076;
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
uint32 unknown;
|
|
||||||
char name[64];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarReturnDone_Struct{
|
struct BazaarReturnDone_Struct{
|
||||||
uint32 type;
|
uint32 type;
|
||||||
uint32 traderid;
|
uint32 traderid;
|
||||||
@ -2298,16 +2303,17 @@ struct BazaarReturnDone_Struct{
|
|||||||
uint32 unknown12;
|
uint32 unknown12;
|
||||||
uint32 unknown16;
|
uint32 unknown16;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearchResults_Struct {
|
struct BazaarSearchResults_Struct {
|
||||||
BazaarWindowStart_Struct Beginning;
|
BazaarWindowStart_Struct Beginning;
|
||||||
uint32 SellerID;
|
uint32 entity_id;
|
||||||
uint32 NumItems; // Don't know. Don't know the significance of this field.
|
uint32 unknown_008;
|
||||||
uint32 SerialNumber;
|
uint32 item_id;
|
||||||
uint32 Unknown016;
|
uint32 serial_number;
|
||||||
uint32 Unknown020; // Something to do with stats as well
|
uint32 unknown_020;
|
||||||
char ItemName[64];
|
char item_name[64];
|
||||||
uint32 Cost;
|
uint32 item_cost;
|
||||||
uint32 ItemStat;
|
uint32 item_stat;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerSideFilters_Struct {
|
struct ServerSideFilters_Struct {
|
||||||
@ -2454,11 +2460,18 @@ struct WhoAllReturnStruct {
|
|||||||
struct WhoAllPlayer player[0];
|
struct WhoAllPlayer player[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BeginTrader_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 unknown04;
|
||||||
|
uint64 serial_number[80];
|
||||||
|
uint32 cost[80];
|
||||||
|
};
|
||||||
|
|
||||||
struct Trader_Struct {
|
struct Trader_Struct {
|
||||||
uint32 code;
|
uint32 action;
|
||||||
uint32 itemid[160];
|
uint32 unknown004;
|
||||||
uint32 unknown;
|
uint64 item_id[80];
|
||||||
uint32 itemcost[80];
|
uint32 item_cost[80];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClickTrader_Struct {
|
struct ClickTrader_Struct {
|
||||||
@ -2471,27 +2484,28 @@ struct GetItems_Struct{
|
|||||||
uint32 items[80];
|
uint32 items[80];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BecomeTrader_Struct{
|
struct BecomeTrader_Struct {
|
||||||
uint32 ID;
|
uint32 entity_id;
|
||||||
uint32 Code;
|
uint32 action;
|
||||||
|
char trader_name[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct{
|
struct Trader_ShowItems_Struct{
|
||||||
uint32 code;
|
uint32 action;
|
||||||
uint32 traderid;
|
uint32 entity_id;
|
||||||
uint32 unknown08[3];
|
uint32 unknown08[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 action;
|
||||||
/*004*/ uint32 Price;
|
/*004*/ uint32 price;
|
||||||
/*008*/ uint32 TraderID;
|
/*008*/ uint32 trader_id;
|
||||||
/*012*/ char ItemName[64];
|
/*012*/ char item_name[64];
|
||||||
/*076*/ uint32 Unknown076;
|
/*076*/ uint32 unknown_076;
|
||||||
/*080*/ uint32 ItemID;
|
/*080*/ uint32 item_id;
|
||||||
/*084*/ uint32 AlreadySold;
|
/*084*/ uint32 already_sold;
|
||||||
/*088*/ uint32 Quantity;
|
/*088*/ uint32 quantity;
|
||||||
/*092*/ uint32 Unknown092;
|
/*092*/ uint32 unknown_092;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2517,8 +2531,9 @@ struct TraderDelItem_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
uint32 traderid;
|
uint32 trader_id;
|
||||||
uint32 unknown4[2];
|
uint32 action;
|
||||||
|
uint32 unknown_004;
|
||||||
uint32 approval;
|
uint32 approval;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3744,6 +3759,21 @@ struct GuildMemberRank_Struct {
|
|||||||
/*076*/ uint32 alt_banker; //Banker/Alt bit 00 - none 10 - Alt 11 - Alt and Banker 01 - Banker. Banker not functional for RoF2+
|
/*076*/ uint32 alt_banker; //Banker/Alt bit 00 - none 10 - Alt 11 - Alt and Banker 01 - Banker. Banker not functional for RoF2+
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TiBazaarTraderBuyerActions {
|
||||||
|
Zero = 0,
|
||||||
|
BeginTraderMode = 1,
|
||||||
|
EndTraderMode = 2,
|
||||||
|
PriceUpdate = 3,
|
||||||
|
EndTransaction = 4,
|
||||||
|
BazaarSearch = 7,
|
||||||
|
WelcomeMessage = 9,
|
||||||
|
BuyTraderItem = 10,
|
||||||
|
ListTraderItems = 11,
|
||||||
|
BazaarInspect = 18,
|
||||||
|
ItemMove = 19,
|
||||||
|
ReconcileItems = 20
|
||||||
|
};
|
||||||
|
|
||||||
}; /*structs*/
|
}; /*structs*/
|
||||||
|
|
||||||
}; /*Titanium*/
|
}; /*Titanium*/
|
||||||
|
|||||||
@ -37,6 +37,8 @@
|
|||||||
#include "../races.h"
|
#include "../races.h"
|
||||||
#include "../raid.h"
|
#include "../raid.h"
|
||||||
#include "../guilds.h"
|
#include "../guilds.h"
|
||||||
|
//#include "../repositories/trader_repository.h"
|
||||||
|
#include "../cereal/include/cereal/types/vector.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -307,50 +309,134 @@ namespace UF
|
|||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
char *Buffer = (char *)in->pBuffer;
|
uint32 action = *(uint32 *)in->pBuffer;
|
||||||
|
|
||||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
switch (action) {
|
||||||
|
case BazaarSearch: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BazaarSearch(UF) BazaarSearch action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
std::vector<BazaarSearchResultsFromDB_Struct> results {};
|
||||||
|
auto bsms = (BazaarSearchMessaging_Struct *)in->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(bsms->payload),
|
||||||
|
in->size - sizeof(BazaarSearchMessaging_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(results);
|
||||||
|
|
||||||
if (SubAction != BazaarSearchResults)
|
auto size = results.size() * sizeof(BazaarSearchResults_Struct);
|
||||||
{
|
auto buffer = new uchar[size];
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
uchar *bufptr = buffer;
|
||||||
return;
|
memset(buffer, 0, size);
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, structs::UFBazaarTraderBuyerActions::BazaarSearch);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
|
||||||
|
strn0cpy(reinterpret_cast<char *>(bufptr), row->trader_name.c_str(), 64);
|
||||||
|
bufptr += 64;
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 1);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
|
||||||
|
bufptr += 4;
|
||||||
|
if (row->stackable) {
|
||||||
|
strn0cpy(
|
||||||
|
reinterpret_cast<char *>(bufptr),
|
||||||
|
fmt::format("{}({})", row->item_name.c_str(), row->charges).c_str(),
|
||||||
|
64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strn0cpy(
|
||||||
|
reinterpret_cast<char *>(bufptr),
|
||||||
|
fmt::format("{}({})", row->item_name.c_str(), row->count).c_str(),
|
||||||
|
64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bufptr += 64;
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->cost);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->item_stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = new EQApplicationPacket(OP_BazaarSearch, size);
|
||||||
|
memcpy(outapp->pBuffer, buffer, size);
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
|
||||||
|
safe_delete(outapp);
|
||||||
|
safe_delete_array(buffer);
|
||||||
|
safe_delete(in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarInspect:
|
||||||
|
case WelcomeMessage: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BazaarSearch(UF) BazaarInspect/WelcomeMessage action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BazaarSearch(UF) unhandled action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char *__emu_buffer = in->pBuffer;
|
ENCODE(OP_BecomeTrader)
|
||||||
|
{
|
||||||
|
uint32 action = *(uint32 *)(*p)->pBuffer;
|
||||||
|
|
||||||
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
switch (action)
|
||||||
|
|
||||||
int EntryCount = in->size / sizeof(BazaarSearchResults_Struct);
|
|
||||||
|
|
||||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
|
||||||
{
|
{
|
||||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
case TraderOff:
|
||||||
delete in;
|
{
|
||||||
return;
|
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BecomeTrader(UF) TraderOff action <green>[{}] entity_id <green>[{}] trader_name "
|
||||||
|
"<green>[{}]",
|
||||||
|
emu->action,
|
||||||
|
emu->entity_id,
|
||||||
|
emu->trader_name
|
||||||
|
);
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::Zero;
|
||||||
|
eq->entity_id = emu->entity_id;
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderOn:
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BecomeTrader(UF) TraderOn action <green>[{}] entity_id <green>[{}] trader_name "
|
||||||
|
"<green>[{}]",
|
||||||
|
emu->action,
|
||||||
|
emu->entity_id,
|
||||||
|
emu->trader_name
|
||||||
|
);
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::BeginTraderMode;
|
||||||
|
eq->entity_id = emu->entity_id;
|
||||||
|
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_BecomeTrader(UF) unhandled action <red>[{}] Sending packet as is.",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
in->size = EntryCount * sizeof(structs::BazaarSearchResults_Struct);
|
|
||||||
in->pBuffer = new unsigned char[in->size];
|
|
||||||
memset(in->pBuffer, 0, in->size);
|
|
||||||
|
|
||||||
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *)in->pBuffer;
|
|
||||||
|
|
||||||
for (int i = 0; i < EntryCount; ++i, ++emu, ++eq)
|
|
||||||
{
|
|
||||||
OUT(Beginning.Action);
|
|
||||||
OUT(SellerID);
|
|
||||||
memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
|
||||||
OUT(NumItems);
|
|
||||||
OUT(ItemID);
|
|
||||||
OUT(SerialNumber);
|
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
|
||||||
OUT(Cost);
|
|
||||||
OUT(ItemStat);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_Buff)
|
ENCODE(OP_Buff)
|
||||||
@ -2743,32 +2829,170 @@ namespace UF
|
|||||||
|
|
||||||
ENCODE(OP_Trader)
|
ENCODE(OP_Trader)
|
||||||
{
|
{
|
||||||
if ((*p)->size != sizeof(TraderBuy_Struct)) {
|
auto action = *(uint32 *) (*p)->pBuffer;
|
||||||
EQApplicationPacket *in = *p;
|
|
||||||
*p = nullptr;
|
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE_FORWARD(OP_TraderBuy);
|
switch (action) {
|
||||||
|
case TraderOn: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader BeginTraderMode action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::BeginTraderMode;
|
||||||
|
OUT(entity_id);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderOff: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader EndTraderMode action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::EndTraderMode;
|
||||||
|
OUT(entity_id);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ListTraderItems: {
|
||||||
|
ENCODE_LENGTH_EXACT(Trader_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(Trader_Struct, structs::Trader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader ListTraderItems action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::ListTraderItems;
|
||||||
|
std::copy_n(emu->items, UF::invtype::BAZAAR_SIZE, eq->item_id);
|
||||||
|
std::copy_n(emu->item_cost, UF::invtype::BAZAAR_SIZE, eq->item_cost);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BuyTraderItem: {
|
||||||
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::BuyTraderItem;
|
||||||
|
OUT(price);
|
||||||
|
OUT(trader_id);
|
||||||
|
OUT(item_id);
|
||||||
|
OUT(already_sold);
|
||||||
|
OUT(quantity);
|
||||||
|
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ItemMove: {
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_Trader ItemMove action <green>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
LogError("Unknown Encode OP_Trader action <red>{} received. Unhandled.", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_TraderBuy)
|
ENCODE(OP_TraderBuy)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_TraderBuy item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
emu->item_id,
|
||||||
|
emu->price,
|
||||||
|
emu->quantity,
|
||||||
|
emu->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
OUT(Action);
|
OUT(action);
|
||||||
OUT(Price);
|
OUT(price);
|
||||||
OUT(TraderID);
|
OUT(trader_id);
|
||||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
OUT(item_id);
|
||||||
OUT(ItemID);
|
OUT(already_sold);
|
||||||
OUT(Quantity);
|
OUT(quantity);
|
||||||
OUT(AlreadySold);
|
OUT_str(item_name);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_TraderShop)
|
||||||
|
{
|
||||||
|
auto action = *(uint32 *)(*p)->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case ClickTrader: {
|
||||||
|
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"ClickTrader action <green>[{}] trader_id <green>[{}]",
|
||||||
|
action,
|
||||||
|
emu->TraderID
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = 0;
|
||||||
|
eq->trader_id = emu->TraderID;
|
||||||
|
eq->approval = emu->Approval;
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BuyTraderItem: {
|
||||||
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Encode OP_TraderShop item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
|
eq->action = structs::UFBazaarTraderBuyerActions::BuyTraderItem;
|
||||||
|
OUT(price);
|
||||||
|
OUT(trader_id);
|
||||||
|
OUT(item_id);
|
||||||
|
OUT(already_sold);
|
||||||
|
OUT(quantity);
|
||||||
|
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
EQApplicationPacket *in = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&in, ack_req);
|
||||||
|
LogError("Unknown Encode OP_TraderShop action <red>[{}] received. Unhandled.", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_TributeItem)
|
ENCODE(OP_TributeItem)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
||||||
@ -3040,7 +3264,7 @@ namespace UF
|
|||||||
Bitfields->targetable = 1;
|
Bitfields->targetable = 1;
|
||||||
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
||||||
Bitfields->statue = 0;
|
Bitfields->statue = 0;
|
||||||
Bitfields->trader = 0;
|
Bitfields->trader = emu->trader ? 1 : 0;
|
||||||
Bitfields->buyer = 0;
|
Bitfields->buyer = 0;
|
||||||
|
|
||||||
Bitfields->showname = ShowName;
|
Bitfields->showname = ShowName;
|
||||||
@ -3363,20 +3587,49 @@ namespace UF
|
|||||||
|
|
||||||
DECODE(OP_BazaarSearch)
|
DECODE(OP_BazaarSearch)
|
||||||
{
|
{
|
||||||
char *Buffer = (char *)__packet->pBuffer;
|
uint32 action = *(uint32 *) __packet->pBuffer;
|
||||||
|
|
||||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
switch (action) {
|
||||||
|
case structs::UFBazaarTraderBuyerActions::BazaarSearch: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
|
||||||
|
|
||||||
if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct)))
|
emu->action = eq->Beginning.Action;
|
||||||
return;
|
emu->item_stat = eq->ItemStat;
|
||||||
|
emu->max_cost = eq->MaxPrice;
|
||||||
|
emu->min_cost = eq->MinPrice;
|
||||||
|
emu->max_level = eq->MaxLlevel;
|
||||||
|
emu->min_level = eq->Minlevel;
|
||||||
|
emu->race = eq->Race;
|
||||||
|
emu->slot = eq->Slot;
|
||||||
|
emu->type = eq->Type == UINT32_MAX ? UINT8_MAX : eq->Type;
|
||||||
|
emu->trader_entity_id = eq->TraderID;
|
||||||
|
emu->trader_id = 0;
|
||||||
|
emu->_class = eq->Class_;
|
||||||
|
emu->search_scope = eq->TraderID > 0 ? NonRoFBazaarSearchScope : Local_Scope;
|
||||||
|
emu->max_results = RuleI(Bazaar, MaxSearchResults);
|
||||||
|
strn0cpy(emu->item_name, eq->Name, sizeof(emu->item_name));
|
||||||
|
|
||||||
SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct);
|
FINISH_DIRECT_DECODE();
|
||||||
MEMSET_IN(structs::NewBazaarInspect_Struct);
|
break;
|
||||||
IN(Beginning.Action);
|
}
|
||||||
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
case structs::UFBazaarTraderBuyerActions::BazaarInspect: {
|
||||||
IN(SerialNumber);
|
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
IN(action);
|
||||||
|
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
||||||
|
IN(serial_number);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::UFBazaarTraderBuyerActions::WelcomeMessage: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTrading("(UF) Unhandled action <red>[{}]", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DECODE(OP_BookButton)
|
DECODE(OP_BookButton)
|
||||||
@ -4059,18 +4312,97 @@ namespace UF
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_Trader)
|
||||||
|
{
|
||||||
|
auto action = (uint32) __packet->pBuffer[0];
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case structs::UFBazaarTraderBuyerActions::BeginTraderMode: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Decode OP_Trader BeginTraderMode action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->action = TraderOn;
|
||||||
|
emu->unknown_004 = 0;
|
||||||
|
std::copy_n(eq->serial_number, UF::invtype::BAZAAR_SIZE, emu->serial_number);
|
||||||
|
std::copy_n(eq->cost, UF::invtype::BAZAAR_SIZE, emu->item_cost);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::UFBazaarTraderBuyerActions::EndTraderMode: {
|
||||||
|
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"Decode OP_Trader(UF) EndTraderMode action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->action = TraderOff;
|
||||||
|
IN(entity_id);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::UFBazaarTraderBuyerActions::PriceUpdate:
|
||||||
|
case structs::UFBazaarTraderBuyerActions::ItemMove:
|
||||||
|
case structs::UFBazaarTraderBuyerActions::EndTransaction:
|
||||||
|
case structs::UFBazaarTraderBuyerActions::ListTraderItems: {
|
||||||
|
LogTrading(
|
||||||
|
"Decode OP_Trader(UF) Price/ItemMove/EndTransaction/ListTraderItems action <red>[{}]",
|
||||||
|
action
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::UFBazaarTraderBuyerActions::ReconcileItems: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogError("Unhandled(UF) action <red>[{}] received.", action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_TraderBuy)
|
DECODE(OP_TraderBuy)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
MEMSET_IN(TraderBuy_Struct);
|
LogTrading(
|
||||||
|
"Decode OP_TraderBuy(UF) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||||
|
eq->item_id,
|
||||||
|
eq->price,
|
||||||
|
eq->quantity,
|
||||||
|
eq->trader_id
|
||||||
|
);
|
||||||
|
|
||||||
IN(Action);
|
emu->action = BuyTraderItem;
|
||||||
IN(Price);
|
IN(price);
|
||||||
IN(TraderID);
|
IN(trader_id);
|
||||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
IN(item_id);
|
||||||
IN(ItemID);
|
IN(quantity);
|
||||||
IN(Quantity);
|
IN(already_sold);
|
||||||
|
strn0cpy(emu->item_name, eq->item_name, sizeof(eq->item_name));
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
|
||||||
|
DECODE(OP_TraderShop)
|
||||||
|
{
|
||||||
|
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
LogTrading(
|
||||||
|
"(UF) action <green>[{}] trader_id <green>[{}] approval <green>[{}]",
|
||||||
|
eq->action,
|
||||||
|
eq->trader_id,
|
||||||
|
eq->approval
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->Code = ClickTrader;
|
||||||
|
emu->TraderID = eq->trader_id;
|
||||||
|
emu->Approval = eq->approval;
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ E(OP_ApplyPoison)
|
|||||||
E(OP_AugmentInfo)
|
E(OP_AugmentInfo)
|
||||||
E(OP_Barter)
|
E(OP_Barter)
|
||||||
E(OP_BazaarSearch)
|
E(OP_BazaarSearch)
|
||||||
|
E(OP_BecomeTrader)
|
||||||
E(OP_Buff)
|
E(OP_Buff)
|
||||||
E(OP_BuffCreate)
|
E(OP_BuffCreate)
|
||||||
E(OP_CancelTrade)
|
E(OP_CancelTrade)
|
||||||
@ -100,6 +101,7 @@ E(OP_TaskDescription)
|
|||||||
E(OP_Track)
|
E(OP_Track)
|
||||||
E(OP_Trader)
|
E(OP_Trader)
|
||||||
E(OP_TraderBuy)
|
E(OP_TraderBuy)
|
||||||
|
E(OP_TraderShop)
|
||||||
E(OP_TributeItem)
|
E(OP_TributeItem)
|
||||||
E(OP_VetRewardsAvaliable)
|
E(OP_VetRewardsAvaliable)
|
||||||
E(OP_WearChange)
|
E(OP_WearChange)
|
||||||
@ -160,7 +162,9 @@ D(OP_SetServerFilter)
|
|||||||
D(OP_ShopPlayerBuy)
|
D(OP_ShopPlayerBuy)
|
||||||
D(OP_ShopPlayerSell)
|
D(OP_ShopPlayerSell)
|
||||||
D(OP_ShopRequest)
|
D(OP_ShopRequest)
|
||||||
|
D(OP_Trader)
|
||||||
D(OP_TraderBuy)
|
D(OP_TraderBuy)
|
||||||
|
D(OP_TraderShop)
|
||||||
D(OP_TradeSkillCombine)
|
D(OP_TradeSkillCombine)
|
||||||
D(OP_TributeItem)
|
D(OP_TributeItem)
|
||||||
D(OP_WearChange)
|
D(OP_WearChange)
|
||||||
|
|||||||
@ -2640,23 +2640,23 @@ struct EnvDamage2_Struct {
|
|||||||
//Bazaar Stuff
|
//Bazaar Stuff
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarTrader_StartTraderMode = 1,
|
BazaarTrader_StartTraderMode = 1,
|
||||||
BazaarTrader_EndTraderMode = 2,
|
BazaarTrader_EndTraderMode = 2,
|
||||||
BazaarTrader_UpdatePrice = 3,
|
BazaarTrader_UpdatePrice = 3,
|
||||||
BazaarTrader_EndTransaction = 4,
|
BazaarTrader_EndTransaction = 4,
|
||||||
BazaarSearchResults = 7,
|
BazaarSearchResults = 7,
|
||||||
BazaarWelcome = 9,
|
BazaarWelcome = 9,
|
||||||
BazaarBuyItem = 10,
|
BazaarBuyItem = 10,
|
||||||
BazaarTrader_ShowItems = 11,
|
BazaarTrader_ShowItems = 11,
|
||||||
BazaarSearchDone = 12,
|
BazaarSearchDone = 12,
|
||||||
BazaarTrader_CustomerBrowsing = 13
|
BazaarTrader_CustomerBrowsing = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarPriceChange_Fail = 0,
|
BazaarPriceChange_Fail = 0,
|
||||||
BazaarPriceChange_UpdatePrice = 1,
|
BazaarPriceChange_UpdatePrice = 1,
|
||||||
BazaarPriceChange_RemoveItem = 2,
|
BazaarPriceChange_RemoveItem = 2,
|
||||||
BazaarPriceChange_AddItem = 3
|
BazaarPriceChange_AddItem = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarWindowStart_Struct {
|
struct BazaarWindowStart_Struct {
|
||||||
@ -2687,10 +2687,14 @@ struct BazaarSearch_Struct {
|
|||||||
uint32 Minlevel;
|
uint32 Minlevel;
|
||||||
uint32 MaxLlevel;
|
uint32 MaxLlevel;
|
||||||
};
|
};
|
||||||
struct BazaarInspect_Struct{
|
|
||||||
uint32 ItemID;
|
struct BazaarInspect_Struct {
|
||||||
uint32 Unknown004;
|
uint32 action;
|
||||||
char Name[64];
|
char player_name[64];
|
||||||
|
uint32 unknown_068;
|
||||||
|
uint32 serial_number;
|
||||||
|
uint32 unknown_076;
|
||||||
|
uint32 item_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NewBazaarInspect_Struct {
|
struct NewBazaarInspect_Struct {
|
||||||
@ -2929,10 +2933,17 @@ struct WhoAllPlayerPart4 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_Struct {
|
struct Trader_Struct {
|
||||||
uint32 code;
|
uint32 action;
|
||||||
uint32 itemid[160];
|
uint32 unknown004;
|
||||||
uint32 unknown;
|
uint64 item_id[80];
|
||||||
uint32 itemcost[80];
|
uint32 item_cost[80];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BeginTrader_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 unknown04;
|
||||||
|
uint64 serial_number[80];
|
||||||
|
uint32 cost[80];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClickTrader_Struct {
|
struct ClickTrader_Struct {
|
||||||
@ -2945,30 +2956,30 @@ struct GetItems_Struct{
|
|||||||
uint32 items[80];
|
uint32 items[80];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BecomeTrader_Struct{
|
struct BecomeTrader_Struct {
|
||||||
uint32 id;
|
uint32 entity_id;
|
||||||
uint32 code;
|
uint32 action;
|
||||||
|
char trader_name[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct{
|
struct Trader_ShowItems_Struct{
|
||||||
uint32 code;
|
uint32 action;
|
||||||
uint32 traderid;
|
uint32 entity_id;
|
||||||
uint32 unknown08[3];
|
uint32 unknown08[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
/*000*/ uint32 Action;
|
uint32 action;
|
||||||
/*004*/ uint32 Unknown004;
|
uint32 unknown_004;
|
||||||
/*008*/ uint32 Price;
|
uint32 price;
|
||||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
uint32 unknown_008; // Probably high order bits of a 64 bit price.
|
||||||
/*016*/ uint32 TraderID;
|
uint32 trader_id;
|
||||||
/*020*/ char ItemName[64];
|
char item_name[64];
|
||||||
/*084*/ uint32 Unknown076;
|
uint32 unknown_076;
|
||||||
/*088*/ uint32 ItemID;
|
uint32 item_id;
|
||||||
/*092*/ uint32 AlreadySold;
|
uint32 already_sold;
|
||||||
/*096*/ uint32 Quantity;
|
uint32 quantity;
|
||||||
/*100*/ uint32 Unknown092;
|
uint32 unknown_092;
|
||||||
/*104*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemUpdate_Struct{
|
struct TraderItemUpdate_Struct{
|
||||||
@ -3002,8 +3013,9 @@ struct TraderDelItem_Struct{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
uint32 traderid;
|
uint32 trader_id;
|
||||||
uint32 unknown4[2];
|
uint32 action;
|
||||||
|
uint32 unknown_004;
|
||||||
uint32 approval;
|
uint32 approval;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4674,6 +4686,30 @@ struct SayLinkBodyFrame_Struct {
|
|||||||
/*050*/
|
/*050*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TraderPriceUpdate_Struct {
|
||||||
|
/*000*/ uint32 action;
|
||||||
|
/*004*/ uint32 sub_action;
|
||||||
|
/*008*/ int32 serial_number;
|
||||||
|
/*012*/ uint32 unknown_012;
|
||||||
|
/*016*/ uint32 new_price;
|
||||||
|
/*020*/ uint32 unknown_016;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UFBazaarTraderBuyerActions {
|
||||||
|
Zero = 0,
|
||||||
|
BeginTraderMode = 1,
|
||||||
|
EndTraderMode = 2,
|
||||||
|
PriceUpdate = 3,
|
||||||
|
EndTransaction = 4,
|
||||||
|
BazaarSearch = 7,
|
||||||
|
WelcomeMessage = 9,
|
||||||
|
BuyTraderItem = 10,
|
||||||
|
ListTraderItems = 11,
|
||||||
|
BazaarInspect = 18,
|
||||||
|
ItemMove = 19,
|
||||||
|
ReconcileItems = 20
|
||||||
|
};
|
||||||
|
|
||||||
}; /*structs*/
|
}; /*structs*/
|
||||||
|
|
||||||
}; /*UF*/
|
}; /*UF*/
|
||||||
|
|||||||
@ -19,40 +19,70 @@
|
|||||||
class BaseTraderRepository {
|
class BaseTraderRepository {
|
||||||
public:
|
public:
|
||||||
struct Trader {
|
struct Trader {
|
||||||
|
uint64_t id;
|
||||||
uint32_t char_id;
|
uint32_t char_id;
|
||||||
uint32_t item_id;
|
uint32_t item_id;
|
||||||
uint32_t serialnumber;
|
uint32_t aug_slot_1;
|
||||||
int32_t charges;
|
uint32_t aug_slot_2;
|
||||||
uint32_t item_cost;
|
uint32_t aug_slot_3;
|
||||||
|
uint32_t aug_slot_4;
|
||||||
|
uint32_t aug_slot_5;
|
||||||
|
uint32_t aug_slot_6;
|
||||||
|
int32_t item_sn;
|
||||||
|
int32_t item_charges;
|
||||||
|
uint64_t item_cost;
|
||||||
uint8_t slot_id;
|
uint8_t slot_id;
|
||||||
|
uint32_t char_entity_id;
|
||||||
|
uint32_t char_zone_id;
|
||||||
|
int8_t active_transaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
{
|
{
|
||||||
return std::string("char_id");
|
return std::string("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> Columns()
|
static std::vector<std::string> Columns()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
"id",
|
||||||
"char_id",
|
"char_id",
|
||||||
"item_id",
|
"item_id",
|
||||||
"serialnumber",
|
"aug_slot_1",
|
||||||
"charges",
|
"aug_slot_2",
|
||||||
|
"aug_slot_3",
|
||||||
|
"aug_slot_4",
|
||||||
|
"aug_slot_5",
|
||||||
|
"aug_slot_6",
|
||||||
|
"item_sn",
|
||||||
|
"item_charges",
|
||||||
"item_cost",
|
"item_cost",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
|
"char_entity_id",
|
||||||
|
"char_zone_id",
|
||||||
|
"active_transaction",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> SelectColumns()
|
static std::vector<std::string> SelectColumns()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
"id",
|
||||||
"char_id",
|
"char_id",
|
||||||
"item_id",
|
"item_id",
|
||||||
"serialnumber",
|
"aug_slot_1",
|
||||||
"charges",
|
"aug_slot_2",
|
||||||
|
"aug_slot_3",
|
||||||
|
"aug_slot_4",
|
||||||
|
"aug_slot_5",
|
||||||
|
"aug_slot_6",
|
||||||
|
"item_sn",
|
||||||
|
"item_charges",
|
||||||
"item_cost",
|
"item_cost",
|
||||||
"slot_id",
|
"slot_id",
|
||||||
|
"char_entity_id",
|
||||||
|
"char_zone_id",
|
||||||
|
"active_transaction",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,12 +123,22 @@ public:
|
|||||||
{
|
{
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.char_id = 0;
|
e.id = 0;
|
||||||
e.item_id = 0;
|
e.char_id = 0;
|
||||||
e.serialnumber = 0;
|
e.item_id = 0;
|
||||||
e.charges = 0;
|
e.aug_slot_1 = 0;
|
||||||
e.item_cost = 0;
|
e.aug_slot_2 = 0;
|
||||||
e.slot_id = 0;
|
e.aug_slot_3 = 0;
|
||||||
|
e.aug_slot_4 = 0;
|
||||||
|
e.aug_slot_5 = 0;
|
||||||
|
e.aug_slot_6 = 0;
|
||||||
|
e.item_sn = 0;
|
||||||
|
e.item_charges = 0;
|
||||||
|
e.item_cost = 0;
|
||||||
|
e.slot_id = 0;
|
||||||
|
e.char_entity_id = 0;
|
||||||
|
e.char_zone_id = 0;
|
||||||
|
e.active_transaction = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -109,7 +149,7 @@ public:
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
for (auto &trader : traders) {
|
for (auto &trader : traders) {
|
||||||
if (trader.char_id == trader_id) {
|
if (trader.id == trader_id) {
|
||||||
return trader;
|
return trader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,12 +175,22 @@ public:
|
|||||||
if (results.RowCount() == 1) {
|
if (results.RowCount() == 1) {
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||||
|
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||||
|
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||||
|
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
||||||
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
|
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
|
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
|
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -174,12 +224,21 @@ public:
|
|||||||
|
|
||||||
auto columns = Columns();
|
auto columns = Columns();
|
||||||
|
|
||||||
v.push_back(columns[0] + " = " + std::to_string(e.char_id));
|
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
|
||||||
v.push_back(columns[1] + " = " + std::to_string(e.item_id));
|
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
|
||||||
v.push_back(columns[2] + " = " + std::to_string(e.serialnumber));
|
v.push_back(columns[3] + " = " + std::to_string(e.aug_slot_1));
|
||||||
v.push_back(columns[3] + " = " + std::to_string(e.charges));
|
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_2));
|
||||||
v.push_back(columns[4] + " = " + std::to_string(e.item_cost));
|
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_3));
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.slot_id));
|
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
|
||||||
|
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_5));
|
||||||
|
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
|
||||||
|
v.push_back(columns[9] + " = " + std::to_string(e.item_sn));
|
||||||
|
v.push_back(columns[10] + " = " + std::to_string(e.item_charges));
|
||||||
|
v.push_back(columns[11] + " = " + std::to_string(e.item_cost));
|
||||||
|
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
|
||||||
|
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
|
||||||
|
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(columns[15] + " = " + std::to_string(e.active_transaction));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -187,7 +246,7 @@ public:
|
|||||||
TableName(),
|
TableName(),
|
||||||
Strings::Implode(", ", v),
|
Strings::Implode(", ", v),
|
||||||
PrimaryKey(),
|
PrimaryKey(),
|
||||||
e.char_id
|
e.id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -201,12 +260,22 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.char_id));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.serialnumber));
|
v.push_back(std::to_string(e.aug_slot_1));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.aug_slot_2));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_3));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_4));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_5));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_6));
|
||||||
|
v.push_back(std::to_string(e.item_sn));
|
||||||
|
v.push_back(std::to_string(e.item_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -217,7 +286,7 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (results.Success()) {
|
if (results.Success()) {
|
||||||
e.char_id = results.LastInsertedID();
|
e.id = results.LastInsertedID();
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,12 +305,22 @@ public:
|
|||||||
for (auto &e: entries) {
|
for (auto &e: entries) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.char_id));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.serialnumber));
|
v.push_back(std::to_string(e.aug_slot_1));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.aug_slot_2));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_3));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_4));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_5));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_6));
|
||||||
|
v.push_back(std::to_string(e.item_sn));
|
||||||
|
v.push_back(std::to_string(e.item_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@ -275,12 +354,22 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||||
|
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||||
|
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||||
|
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
||||||
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
|
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
|
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
|
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -305,12 +394,22 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||||
|
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||||
|
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||||
|
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
||||||
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
|
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
|
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
|
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -385,12 +484,22 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.char_id));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.serialnumber));
|
v.push_back(std::to_string(e.aug_slot_1));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.aug_slot_2));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_3));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_4));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_5));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_6));
|
||||||
|
v.push_back(std::to_string(e.item_sn));
|
||||||
|
v.push_back(std::to_string(e.item_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -413,12 +522,22 @@ public:
|
|||||||
for (auto &e: entries) {
|
for (auto &e: entries) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.char_id));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.serialnumber));
|
v.push_back(std::to_string(e.aug_slot_1));
|
||||||
v.push_back(std::to_string(e.charges));
|
v.push_back(std::to_string(e.aug_slot_2));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_3));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_4));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_5));
|
||||||
|
v.push_back(std::to_string(e.aug_slot_6));
|
||||||
|
v.push_back(std::to_string(e.item_sn));
|
||||||
|
v.push_back(std::to_string(e.item_charges));
|
||||||
v.push_back(std::to_string(e.item_cost));
|
v.push_back(std::to_string(e.item_cost));
|
||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,43 +7,6 @@
|
|||||||
|
|
||||||
class ItemsRepository: public BaseItemsRepository {
|
class ItemsRepository: public BaseItemsRepository {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* This file was auto generated and can be modified and extended upon
|
|
||||||
*
|
|
||||||
* Base repository methods are automatically
|
|
||||||
* generated in the "base" version of this repository. The base repository
|
|
||||||
* is immutable and to be left untouched, while methods in this class
|
|
||||||
* are used as extension methods for more specific persistence-layer
|
|
||||||
* accessors or mutators.
|
|
||||||
*
|
|
||||||
* Base Methods (Subject to be expanded upon in time)
|
|
||||||
*
|
|
||||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
|
||||||
*
|
|
||||||
* InsertOne
|
|
||||||
* UpdateOne
|
|
||||||
* DeleteOne
|
|
||||||
* FindOne
|
|
||||||
* GetWhere(std::string where_filter)
|
|
||||||
* DeleteWhere(std::string where_filter)
|
|
||||||
* InsertMany
|
|
||||||
* All
|
|
||||||
*
|
|
||||||
* Example custom methods in a repository
|
|
||||||
*
|
|
||||||
* ItemsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
|
||||||
* ItemsRepository::GetWhereNeverExpires()
|
|
||||||
* ItemsRepository::GetWhereXAndY()
|
|
||||||
* ItemsRepository::DeleteWhereXAndY()
|
|
||||||
*
|
|
||||||
* Most of the above could be covered by base methods, but if you as a developer
|
|
||||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
|
||||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
|
||||||
* method and encapsulate filters there
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Custom extended repository methods here
|
|
||||||
static std::vector<int32> GetItemIDsBySearchCriteria(
|
static std::vector<int32> GetItemIDsBySearchCriteria(
|
||||||
Database& db,
|
Database& db,
|
||||||
std::string search_string,
|
std::string search_string,
|
||||||
@ -73,6 +36,8 @@ public:
|
|||||||
|
|
||||||
return item_id_list;
|
return item_id_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_ITEMS_REPOSITORY_H
|
#endif //EQEMU_ITEMS_REPOSITORY_H
|
||||||
|
|||||||
@ -1,50 +1,224 @@
|
|||||||
#ifndef EQEMU_TRADER_REPOSITORY_H
|
#ifndef EQEMU_TRADER_REPOSITORY_H
|
||||||
#define EQEMU_TRADER_REPOSITORY_H
|
#define EQEMU_TRADER_REPOSITORY_H
|
||||||
|
|
||||||
#include "../database.h"
|
#include "../../common/shareddb.h"
|
||||||
#include "../strings.h"
|
#include "../strings.h"
|
||||||
#include "base/base_trader_repository.h"
|
#include "base/base_trader_repository.h"
|
||||||
|
#include "items_repository.h"
|
||||||
|
#include "../../common/item_data.h"
|
||||||
|
#include "../../common/races.h"
|
||||||
|
#include "../cereal/include/cereal/archives/binary.hpp"
|
||||||
|
#include "../cereal/include/cereal/types/string.hpp"
|
||||||
|
|
||||||
class TraderRepository: public BaseTraderRepository {
|
class TraderRepository : public BaseTraderRepository {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
struct DistinctTraders_Struct {
|
||||||
* This file was auto generated and can be modified and extended upon
|
uint32 trader_id;
|
||||||
*
|
uint32 zone_id;
|
||||||
* Base repository methods are automatically
|
uint32 entity_id;
|
||||||
* generated in the "base" version of this repository. The base repository
|
std::string trader_name;
|
||||||
* is immutable and to be left untouched, while methods in this class
|
};
|
||||||
* are used as extension methods for more specific persistence-layer
|
|
||||||
* accessors or mutators.
|
|
||||||
*
|
|
||||||
* Base Methods (Subject to be expanded upon in time)
|
|
||||||
*
|
|
||||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
|
||||||
*
|
|
||||||
* InsertOne
|
|
||||||
* UpdateOne
|
|
||||||
* DeleteOne
|
|
||||||
* FindOne
|
|
||||||
* GetWhere(std::string where_filter)
|
|
||||||
* DeleteWhere(std::string where_filter)
|
|
||||||
* InsertMany
|
|
||||||
* All
|
|
||||||
*
|
|
||||||
* Example custom methods in a repository
|
|
||||||
*
|
|
||||||
* TraderRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
|
||||||
* TraderRepository::GetWhereNeverExpires()
|
|
||||||
* TraderRepository::GetWhereXAndY()
|
|
||||||
* TraderRepository::DeleteWhereXAndY()
|
|
||||||
*
|
|
||||||
* Most of the above could be covered by base methods, but if you as a developer
|
|
||||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
|
||||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
|
||||||
* method and encapsulate filters there
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Custom extended repository methods here
|
struct BulkTraders_Struct {
|
||||||
|
uint32 count{0};
|
||||||
|
uint32 name_length{0};
|
||||||
|
std::vector<DistinctTraders_Struct> traders{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WelcomeData_Struct {
|
||||||
|
uint32 count_of_traders;
|
||||||
|
uint32 count_of_items;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<BazaarSearchResultsFromDB_Struct>
|
||||||
|
GetBazaarSearchResults(
|
||||||
|
SharedDatabase &db,
|
||||||
|
BazaarSearchCriteria_Struct search,
|
||||||
|
uint32 char_zone_id
|
||||||
|
);
|
||||||
|
|
||||||
|
static BulkTraders_Struct GetDistinctTraders(Database &db)
|
||||||
|
{
|
||||||
|
BulkTraders_Struct all_entries{};
|
||||||
|
std::vector<DistinctTraders_Struct> distinct_traders;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_entity_id, c.name "
|
||||||
|
"FROM trader AS t "
|
||||||
|
"JOIN character_data AS c ON t.char_id = c.id;"
|
||||||
|
);
|
||||||
|
|
||||||
|
distinct_traders.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row: results) {
|
||||||
|
DistinctTraders_Struct e{};
|
||||||
|
|
||||||
|
e.trader_id = Strings::ToInt(row[0]);
|
||||||
|
e.zone_id = Strings::ToInt(row[1]);
|
||||||
|
e.entity_id = Strings::ToInt(row[2]);
|
||||||
|
e.trader_name = row[3] ? row[3] : "";
|
||||||
|
all_entries.name_length += e.trader_name.length() + 1;
|
||||||
|
|
||||||
|
all_entries.traders.push_back(e);
|
||||||
|
}
|
||||||
|
all_entries.count = results.RowCount();
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WelcomeData_Struct GetWelcomeData(Database &db)
|
||||||
|
{
|
||||||
|
WelcomeData_Struct e{};
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader;");
|
||||||
|
|
||||||
|
if (!results.RowCount()) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto r = results.begin();
|
||||||
|
e.count_of_traders = Strings::ToInt(r[0]);
|
||||||
|
e.count_of_items = Strings::ToInt(r[1]);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateItem(Database &db, uint32 char_id, uint32 new_price, uint32 item_id, uint32 item_charges)
|
||||||
|
{
|
||||||
|
std::vector<BaseTraderRepository::Trader> items{};
|
||||||
|
if (item_charges == 0) {
|
||||||
|
items = GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"char_id = '{}' AND item_id = '{}'",
|
||||||
|
char_id,
|
||||||
|
item_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
items = GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"char_id = '{}' AND item_id = '{}' AND item_charges = '{}'",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
item_charges
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &i: items) {
|
||||||
|
i.item_cost = new_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReplaceMany(db, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Trader GetTraderItem(Database &db, uint32 trader_id, uint32 item_id, uint32 item_cost)
|
||||||
|
{
|
||||||
|
Trader item{};
|
||||||
|
|
||||||
|
auto query = fmt::format(
|
||||||
|
"SELECT t.char_id, t.item_id, t.serialnumber, t.charges, t.item_cost, t.slot_id, t.entity_id FROM trader AS t "
|
||||||
|
"WHERE t.entity_id = {} AND t.item_id = {} AND t.item_cost = {} "
|
||||||
|
"LIMIT 1;",
|
||||||
|
trader_id,
|
||||||
|
item_id,
|
||||||
|
item_cost
|
||||||
|
);
|
||||||
|
auto results = db.QueryDatabase(query);
|
||||||
|
|
||||||
|
if (results.RowCount() == 0) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
item.char_id = Strings::ToInt(row[0]);
|
||||||
|
item.item_id = Strings::ToInt(row[1]);
|
||||||
|
item.item_sn = Strings::ToInt(row[2]);
|
||||||
|
item.item_charges = Strings::ToInt(row[3]);
|
||||||
|
item.item_cost = Strings::ToInt(row[4]);
|
||||||
|
item.slot_id = Strings::ToInt(row[5]);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateQuantity(Database &db, uint32 char_id, uint32 serial_number, int16 quantity)
|
||||||
|
{
|
||||||
|
const auto trader_item = GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format("char_id = '{}' AND item_sn = '{}' ", char_id, serial_number)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (trader_item.empty() || trader_item.size() > 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto m = trader_item[0];
|
||||||
|
m.item_charges = quantity;
|
||||||
|
|
||||||
|
return UpdateOne(db, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Trader GetItemBySerialNumber(Database &db, uint32 serial_number)
|
||||||
|
{
|
||||||
|
Trader e{};
|
||||||
|
const auto trader_item = GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format("`item_sn` = '{}' LIMIT 1", serial_number)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (trader_item.empty()) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return trader_item.at(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Trader GetItemBySerialNumber(Database &db, std::string serial_number)
|
||||||
|
{
|
||||||
|
Trader e{};
|
||||||
|
auto sn = Strings::ToUnsignedBigInt(serial_number);
|
||||||
|
const auto trader_item = GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format("`item_sn` = '{}' LIMIT 1", sn)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (trader_item.empty()) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return trader_item.at(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateActiveTransaction(Database &db, uint32 id, bool status)
|
||||||
|
{
|
||||||
|
auto e = FindOne(db, id);
|
||||||
|
if (!e.id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.active_transaction = status == true ? 1 : 0;
|
||||||
|
|
||||||
|
return UpdateOne(db, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteMany(Database &db, const std::vector<Trader> &entries)
|
||||||
|
{
|
||||||
|
std::vector<std::string> delete_ids;
|
||||||
|
|
||||||
|
for (auto const &e: entries) {
|
||||||
|
delete_ids.push_back(std::to_string(e.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_TRADER_REPOSITORY_H
|
#endif //EQEMU_TRADER_REPOSITORY_H
|
||||||
|
|||||||
@ -783,6 +783,9 @@ RULE_BOOL(Bazaar, AuditTrail, false, "Setting whether a path to the trader shoul
|
|||||||
RULE_INT(Bazaar, MaxSearchResults, 50, "Maximum number of search results in Bazaar")
|
RULE_INT(Bazaar, MaxSearchResults, 50, "Maximum number of search results in Bazaar")
|
||||||
RULE_BOOL(Bazaar, EnableWarpToTrader, true, "Setting whether teleport to the selected trader should be active")
|
RULE_BOOL(Bazaar, EnableWarpToTrader, true, "Setting whether teleport to the selected trader should be active")
|
||||||
RULE_INT(Bazaar, MaxBarterSearchResults, 200, "The maximum results returned in the /barter search")
|
RULE_INT(Bazaar, MaxBarterSearchResults, 200, "The maximum results returned in the /barter search")
|
||||||
|
RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a bazaar purchase as a percentage of item cost. Default is 20% of item cost. RoF+ Only.")
|
||||||
|
RULE_INT(Bazaar, VoucherDeliveryCost, 200, "Number of vouchers for direct delivery for a bazaar purchase. Default is 200 vouchers. RoF+ Only.")
|
||||||
|
RULE_BOOL(Bazaar, EnableParcelDelivery, true, "Enable bazaar purchases via parcel delivery. Default is True.")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Mail)
|
RULE_CATEGORY(Mail)
|
||||||
|
|||||||
@ -138,6 +138,9 @@
|
|||||||
#define ServerOP_RaidMOTD 0x0113
|
#define ServerOP_RaidMOTD 0x0113
|
||||||
#define ServerOP_RaidNote 0x0114
|
#define ServerOP_RaidNote 0x0114
|
||||||
|
|
||||||
|
#define ServerOP_TraderMessaging 0x0120
|
||||||
|
#define ServerOP_BazaarPurchase 0x0121
|
||||||
|
|
||||||
#define ServerOP_InstanceUpdateTime 0x014F
|
#define ServerOP_InstanceUpdateTime 0x014F
|
||||||
#define ServerOP_AdventureRequest 0x0150
|
#define ServerOP_AdventureRequest 0x0150
|
||||||
#define ServerOP_AdventureRequestAccept 0x0151
|
#define ServerOP_AdventureRequestAccept 0x0151
|
||||||
@ -1938,6 +1941,27 @@ struct ServerOP_GuildMessage_Struct {
|
|||||||
char url[2048]{0};
|
char url[2048]{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TraderMessaging_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 zone_id;
|
||||||
|
uint32 trader_id;
|
||||||
|
uint32 entity_id;
|
||||||
|
char trader_name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BazaarPurchaseMessaging_Struct {
|
||||||
|
TraderBuy_Struct trader_buy_struct;
|
||||||
|
uint32 item_aug_1;
|
||||||
|
uint32 item_aug_2;
|
||||||
|
uint32 item_aug_3;
|
||||||
|
uint32 item_aug_4;
|
||||||
|
uint32 item_aug_5;
|
||||||
|
uint32 item_aug_6;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint32 item_quantity_available;
|
||||||
|
uint32 id;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -745,6 +745,15 @@ bool Strings::Contains(const std::string& subject, const std::string& search)
|
|||||||
return subject.find(search) != std::string::npos;
|
return subject.find(search) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Strings::ContainsLower(const std::string& subject, const std::string& search)
|
||||||
|
{
|
||||||
|
if (subject.length() < search.length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToLower(subject).find(ToLower(search)) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 Strings::TimeToSeconds(std::string time_string)
|
uint32 Strings::TimeToSeconds(std::string time_string)
|
||||||
{
|
{
|
||||||
if (time_string.empty()) {
|
if (time_string.empty()) {
|
||||||
|
|||||||
@ -86,6 +86,7 @@ class Strings {
|
|||||||
public:
|
public:
|
||||||
static bool Contains(std::vector<std::string> container, const std::string& element);
|
static bool Contains(std::vector<std::string> container, const std::string& element);
|
||||||
static bool Contains(const std::string& subject, const std::string& search);
|
static bool Contains(const std::string& subject, const std::string& search);
|
||||||
|
static bool ContainsLower(const std::string& subject, const std::string& search);
|
||||||
static int ToInt(const std::string &s, int fallback = 0);
|
static int ToInt(const std::string &s, int fallback = 0);
|
||||||
static int64 ToBigInt(const std::string &s, int64 fallback = 0);
|
static int64 ToBigInt(const std::string &s, int64 fallback = 0);
|
||||||
static uint32 ToUnsignedInt(const std::string &s, uint32 fallback = 0);
|
static uint32 ToUnsignedInt(const std::string &s, uint32 fallback = 0);
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9279
|
#define CURRENT_BINARY_DATABASE_VERSION 9280
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9044
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9044
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -430,6 +430,7 @@ OP_BazaarSearch=0x39d6
|
|||||||
OP_TraderDelItem=0x5829
|
OP_TraderDelItem=0x5829
|
||||||
OP_BecomeTrader=0x61b3
|
OP_BecomeTrader=0x61b3
|
||||||
OP_TraderShop=0x31df
|
OP_TraderShop=0x31df
|
||||||
|
OP_TraderBulkSend=0x6a96
|
||||||
OP_Trader=0x4ef5
|
OP_Trader=0x4ef5
|
||||||
OP_Barter=0x243a
|
OP_Barter=0x243a
|
||||||
OP_TraderBuy=0x0000
|
OP_TraderBuy=0x0000
|
||||||
|
|||||||
@ -1424,6 +1424,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
case ServerOP_ReloadLoot:
|
case ServerOP_ReloadLoot:
|
||||||
case ServerOP_RezzPlayerAccept:
|
case ServerOP_RezzPlayerAccept:
|
||||||
case ServerOP_SpawnStatusChange:
|
case ServerOP_SpawnStatusChange:
|
||||||
|
case ServerOP_TraderMessaging:
|
||||||
case ServerOP_UpdateSpawn:
|
case ServerOP_UpdateSpawn:
|
||||||
case ServerOP_WWDialogueWindow:
|
case ServerOP_WWDialogueWindow:
|
||||||
case ServerOP_WWLDoNUpdate:
|
case ServerOP_WWLDoNUpdate:
|
||||||
@ -1744,6 +1745,18 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_BazaarPurchase: {
|
||||||
|
auto in = (BazaarPurchaseMessaging_Struct *)pack->pBuffer;
|
||||||
|
if (in->trader_buy_struct.trader_id <= 0) {
|
||||||
|
LogTrading(
|
||||||
|
"World Message <red>[{}] received with invalid trader_id <red>[{}]",
|
||||||
|
"ServerOP_BazaarPurchase",
|
||||||
|
in->trader_buy_struct.trader_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneserver_list.SendPacket(Zones::BAZAAR, pack);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
||||||
DumpPacket(pack->pBuffer, pack->size);
|
DumpPacket(pack->pBuffer, pack->size);
|
||||||
|
|||||||
@ -4157,7 +4157,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TEST CODE: test for bazaar trader crashing with charm items
|
// TEST CODE: test for bazaar trader crashing with charm items
|
||||||
if (Trader)
|
if (IsTrader())
|
||||||
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
||||||
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
||||||
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
||||||
@ -4249,7 +4249,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TEST CODE: test for bazaar trader crashing with charm items
|
// TEST CODE: test for bazaar trader crashing with charm items
|
||||||
if (Trader)
|
if (IsTrader())
|
||||||
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
||||||
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
||||||
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
||||||
|
|||||||
@ -202,11 +202,11 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
|||||||
ip = eqs->GetRemoteIP();
|
ip = eqs->GetRemoteIP();
|
||||||
port = ntohs(eqs->GetRemotePort());
|
port = ntohs(eqs->GetRemotePort());
|
||||||
client_state = CLIENT_CONNECTING;
|
client_state = CLIENT_CONNECTING;
|
||||||
Trader=false;
|
SetTrader(false);
|
||||||
Buyer = false;
|
Buyer = false;
|
||||||
Haste = 0;
|
Haste = 0;
|
||||||
CustomerID = 0;
|
SetCustomerID(0);
|
||||||
TraderID = 0;
|
SetTraderID(0);
|
||||||
TrackingID = 0;
|
TrackingID = 0;
|
||||||
WID = 0;
|
WID = 0;
|
||||||
account_id = 0;
|
account_id = 0;
|
||||||
@ -421,8 +421,9 @@ Client::~Client() {
|
|||||||
if (merc)
|
if (merc)
|
||||||
merc->Depop();
|
merc->Depop();
|
||||||
|
|
||||||
if(Trader)
|
if(IsTrader()) {
|
||||||
database.DeleteTraderItem(CharacterID());
|
TraderEndTrader();
|
||||||
|
}
|
||||||
|
|
||||||
if(Buyer)
|
if(Buyer)
|
||||||
ToggleBuyerMode(false);
|
ToggleBuyerMode(false);
|
||||||
@ -2163,6 +2164,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
ns->spawn.anon = m_pp.anon;
|
ns->spawn.anon = m_pp.anon;
|
||||||
ns->spawn.gm = GetGM() ? 1 : 0;
|
ns->spawn.gm = GetGM() ? 1 : 0;
|
||||||
ns->spawn.guildID = GuildID();
|
ns->spawn.guildID = GuildID();
|
||||||
|
ns->spawn.trader = IsTrader();
|
||||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||||
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
||||||
ns->spawn.show_name = true;
|
ns->spawn.show_name = true;
|
||||||
@ -11969,7 +11971,7 @@ void Client::SendPath(Mob* target)
|
|||||||
RuleB(Bazaar, EnableWarpToTrader) &&
|
RuleB(Bazaar, EnableWarpToTrader) &&
|
||||||
target->IsClient() &&
|
target->IsClient() &&
|
||||||
(
|
(
|
||||||
target->CastToClient()->Trader ||
|
target->CastToClient()->IsTrader() ||
|
||||||
target->CastToClient()->Buyer
|
target->CastToClient()->Buyer
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -69,6 +69,7 @@ namespace EQ
|
|||||||
#include "../common/events/player_events.h"
|
#include "../common/events/player_events.h"
|
||||||
#include "../common/data_verification.h"
|
#include "../common/data_verification.h"
|
||||||
#include "../common/repositories/character_parcels_repository.h"
|
#include "../common/repositories/character_parcels_repository.h"
|
||||||
|
#include "../common/repositories/trader_repository.h"
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
// since windows defines these within windef.h (which windows.h include)
|
// since windows defines these within windef.h (which windows.h include)
|
||||||
@ -280,10 +281,20 @@ public:
|
|||||||
void AI_Stop();
|
void AI_Stop();
|
||||||
void AI_Process();
|
void AI_Process();
|
||||||
void AI_SpellCast();
|
void AI_SpellCast();
|
||||||
void Trader_ShowItems();
|
void TraderShowItems();
|
||||||
void Trader_CustomerBrowsing(Client *Customer);
|
void Trader_CustomerBrowsing(Client *Customer);
|
||||||
void Trader_EndTrader();
|
|
||||||
void Trader_StartTrader();
|
void TraderEndTrader();
|
||||||
|
void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||||
|
void SendBazaarDone(uint32 trader_id);
|
||||||
|
void SendBulkBazaarTraders();
|
||||||
|
void DoBazaarInspect(const BazaarInspect_Struct &in);
|
||||||
|
void SendBazaarDeliveryCosts();
|
||||||
|
static std::string DetermineMoneyString(uint64 copper);
|
||||||
|
|
||||||
|
void SendTraderMode(BazaarTraderBarterActions status);
|
||||||
|
void TraderStartTrader(const EQApplicationPacket *app);
|
||||||
|
// void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||||
uint8 WithCustomer(uint16 NewCustomer);
|
uint8 WithCustomer(uint16 NewCustomer);
|
||||||
void KeyRingLoad();
|
void KeyRingLoad();
|
||||||
void KeyRingAdd(uint32 item_id);
|
void KeyRingAdd(uint32 item_id);
|
||||||
@ -315,15 +326,17 @@ public:
|
|||||||
void Tell_StringID(uint32 string_id, const char *who, const char *message);
|
void Tell_StringID(uint32 string_id, const char *who, const char *message);
|
||||||
void SendColoredText(uint32 color, std::string message);
|
void SendColoredText(uint32 color, std::string message);
|
||||||
void SendBazaarResults(uint32 trader_id, uint32 in_class, uint32 in_race, uint32 item_stat, uint32 item_slot, uint32 item_type, char item_name[64], uint32 min_price, uint32 max_price);
|
void SendBazaarResults(uint32 trader_id, uint32 in_class, uint32 in_race, uint32 item_stat, uint32 item_slot, uint32 item_type, char item_name[64], uint32 min_price, uint32 max_price);
|
||||||
void SendTraderItem(uint32 item_id,uint16 quantity);
|
void SendTraderItem(uint32 item_id,uint16 quantity, TraderRepository::Trader &trader);
|
||||||
|
void DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria);
|
||||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||||
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
||||||
EQ::ItemInstance* FindTraderItemBySerialNumber(int32 SerialNumber);
|
EQ::ItemInstance* FindTraderItemBySerialNumber(int32 SerialNumber);
|
||||||
void FindAndNukeTraderItem(int32 item_id,int16 quantity,Client* customer,uint16 traderslot);
|
void FindAndNukeTraderItem(int32 serial_number, int16 quantity, Client* customer, uint16 trader_slot);
|
||||||
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
|
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 trader_slot, int32 serial_number, int32 item_id = 0);
|
||||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
void BuyTraderItem(TraderBuy_Struct* tbs, Client* trader, const EQApplicationPacket* app);
|
||||||
|
void BuyTraderItemOutsideBazaar(TraderBuy_Struct* tbs, const EQApplicationPacket* app);
|
||||||
void FinishTrade(
|
void FinishTrade(
|
||||||
Mob *with,
|
Mob *with,
|
||||||
bool finalizer = false,
|
bool finalizer = false,
|
||||||
@ -335,7 +348,7 @@ public:
|
|||||||
void DoParcelCancel();
|
void DoParcelCancel();
|
||||||
void DoParcelSend(const Parcel_Struct *parcel_in);
|
void DoParcelSend(const Parcel_Struct *parcel_in);
|
||||||
void DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in);
|
void DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in);
|
||||||
void SendParcel(const Parcel_Struct &parcel);
|
void SendParcel(Parcel_Struct &parcel);
|
||||||
void SendParcelStatus();
|
void SendParcelStatus();
|
||||||
void SendParcelAck();
|
void SendParcelAck();
|
||||||
void SendParcelRetrieveAck();
|
void SendParcelRetrieveAck();
|
||||||
@ -355,6 +368,13 @@ public:
|
|||||||
int32 FindNextFreeParcelSlot(uint32 char_id);
|
int32 FindNextFreeParcelSlot(uint32 char_id);
|
||||||
void SendParcelIconStatus();
|
void SendParcelIconStatus();
|
||||||
|
|
||||||
|
void SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions action);
|
||||||
|
void SendBecomeTrader(BazaarTraderBarterActions action, uint32 trader_id);
|
||||||
|
|
||||||
|
bool IsThereACustomer() const { return customer_id ? true : false; }
|
||||||
|
uint32 GetCustomerID() { return customer_id; }
|
||||||
|
void SetCustomerID(uint32 id) { customer_id = id; }
|
||||||
|
|
||||||
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
||||||
void ShowBuyLines(const EQApplicationPacket *app);
|
void ShowBuyLines(const EQApplicationPacket *app);
|
||||||
void SellToBuyer(const EQApplicationPacket *app);
|
void SellToBuyer(const EQApplicationPacket *app);
|
||||||
@ -485,7 +505,7 @@ public:
|
|||||||
|
|
||||||
void ServerFilter(SetServerFilter_Struct* filter);
|
void ServerFilter(SetServerFilter_Struct* filter);
|
||||||
void BulkSendTraderInventory(uint32 char_id);
|
void BulkSendTraderInventory(uint32 char_id);
|
||||||
void SendSingleTraderItem(uint32 char_id, int uniqueid);
|
void SendSingleTraderItem(uint32 char_id, int serial_number);
|
||||||
void BulkSendMerchantInventory(int merchant_id, int npcid);
|
void BulkSendMerchantInventory(int merchant_id, int npcid);
|
||||||
|
|
||||||
inline uint8 GetLanguageSkill(uint8 language_id) const { return m_pp.languages[language_id]; }
|
inline uint8 GetLanguageSkill(uint8 language_id) const { return m_pp.languages[language_id]; }
|
||||||
@ -1067,7 +1087,11 @@ public:
|
|||||||
bool IsValidSlot(uint32 slot);
|
bool IsValidSlot(uint32 slot);
|
||||||
bool IsBankSlot(uint32 slot);
|
bool IsBankSlot(uint32 slot);
|
||||||
|
|
||||||
inline bool IsTrader() const { return(Trader); }
|
bool IsTrader() const { return trader; }
|
||||||
|
void SetTrader(bool status) { trader = status; }
|
||||||
|
uint16 GetTraderID() { return trader_id; }
|
||||||
|
void SetTraderID(uint16 id) { trader_id = id; }
|
||||||
|
|
||||||
inline bool IsBuyer() const { return(Buyer); }
|
inline bool IsBuyer() const { return(Buyer); }
|
||||||
eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; }
|
eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; }
|
||||||
void SetFilter(eqFilterType filter_id, eqFilterMode filter_mode) { ClientFilters[filter_id] = filter_mode; }
|
void SetFilter(eqFilterType filter_id, eqFilterMode filter_mode) { ClientFilters[filter_id] = filter_mode; }
|
||||||
@ -1800,8 +1824,6 @@ private:
|
|||||||
void RemoveBandolier(const EQApplicationPacket *app);
|
void RemoveBandolier(const EQApplicationPacket *app);
|
||||||
void SetBandolier(const EQApplicationPacket *app);
|
void SetBandolier(const EQApplicationPacket *app);
|
||||||
|
|
||||||
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
|
||||||
|
|
||||||
int32 CalcItemATKCap() final;
|
int32 CalcItemATKCap() final;
|
||||||
int32 CalcHaste();
|
int32 CalcHaste();
|
||||||
|
|
||||||
@ -1880,13 +1902,13 @@ private:
|
|||||||
uint16 controlling_boat_id;
|
uint16 controlling_boat_id;
|
||||||
uint16 controlled_mob_id;
|
uint16 controlled_mob_id;
|
||||||
uint16 TrackingID;
|
uint16 TrackingID;
|
||||||
uint16 CustomerID;
|
bool trader;
|
||||||
uint16 TraderID;
|
uint16 trader_id;
|
||||||
|
uint16 customer_id;
|
||||||
uint32 account_creation;
|
uint32 account_creation;
|
||||||
uint8 firstlogon;
|
uint8 firstlogon;
|
||||||
uint32 mercid; // current merc
|
uint32 mercid; // current merc
|
||||||
uint8 mercSlot; // selected merc slot
|
uint8 mercSlot; // selected merc slot
|
||||||
bool Trader;
|
|
||||||
bool Buyer;
|
bool Buyer;
|
||||||
std::string BuyerWelcomeMessage;
|
std::string BuyerWelcomeMessage;
|
||||||
int32 m_parcel_platinum;
|
int32 m_parcel_platinum;
|
||||||
|
|||||||
@ -918,6 +918,10 @@ void Client::CompleteConnect()
|
|||||||
CastToClient()->FastQueuePacket(&outapp);
|
CastToClient()->FastQueuePacket(&outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
|
||||||
|
SendBulkBazaarTraders();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: load these states
|
// TODO: load these states
|
||||||
// We at least will set them to the correct state for now
|
// We at least will set them to the correct state for now
|
||||||
if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) {
|
if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) {
|
||||||
@ -1074,9 +1078,6 @@ void Client::Handle_Connect_OP_ReqClientSpawn(const EQApplicationPacket *app)
|
|||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
if (strncasecmp(zone->GetShortName(), "bazaar", 6) == 0)
|
|
||||||
SendBazaarWelcome();
|
|
||||||
|
|
||||||
conn_state = ZoneContentsSent;
|
conn_state = ZoneContentsSent;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -3787,7 +3788,7 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
case Barter_BuyerModeOn:
|
case Barter_BuyerModeOn:
|
||||||
{
|
{
|
||||||
if (!Trader) {
|
if (!IsTrader()) {
|
||||||
ToggleBuyerMode(true);
|
ToggleBuyerMode(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -3864,7 +3865,7 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
case Barter_Welcome:
|
case Barter_Welcome:
|
||||||
{
|
{
|
||||||
SendBazaarWelcome();
|
//SendBazaarWelcome();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3918,7 +3919,7 @@ void Client::Handle_OP_BazaarInspect(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
BazaarInspect_Struct* bis = (BazaarInspect_Struct*)app->pBuffer;
|
BazaarInspect_Struct* bis = (BazaarInspect_Struct*)app->pBuffer;
|
||||||
|
|
||||||
const EQ::ItemData* item = database.GetItem(bis->ItemID);
|
const EQ::ItemData* item = database.GetItem(bis->item_id);
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
Message(Chat::Red, "Error: This item does not exist!");
|
Message(Chat::Red, "Error: This item does not exist!");
|
||||||
@ -3937,39 +3938,47 @@ void Client::Handle_OP_BazaarInspect(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_BazaarSearch(const EQApplicationPacket *app)
|
void Client::Handle_OP_BazaarSearch(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
|
uint32 action = *(uint32 *) app->pBuffer;
|
||||||
|
|
||||||
if (app->size == sizeof(BazaarSearch_Struct)) {
|
switch (action) {
|
||||||
|
case BazaarSearch: {
|
||||||
|
BazaarSearchCriteria_Struct *bss = (BazaarSearchCriteria_Struct *) app->pBuffer;
|
||||||
|
BazaarSearchCriteria_Struct search_details{};
|
||||||
|
|
||||||
BazaarSearch_Struct* bss = (BazaarSearch_Struct*)app->pBuffer;
|
search_details.action = BazaarSearchResults;
|
||||||
|
search_details.augment = bss->augment;
|
||||||
|
search_details._class = bss->_class;
|
||||||
|
search_details.item_stat = bss->item_stat;
|
||||||
|
search_details.min_cost = bss->min_cost;
|
||||||
|
search_details.max_cost = bss->max_cost;
|
||||||
|
search_details.min_level = bss->min_level;
|
||||||
|
search_details.max_level = bss->max_level;
|
||||||
|
search_details.max_results = bss->max_results;
|
||||||
|
search_details.prestige = bss->prestige;
|
||||||
|
search_details.race = bss->race;
|
||||||
|
search_details.search_scope = bss->search_scope;
|
||||||
|
search_details.slot = bss->slot;
|
||||||
|
search_details.trader_entity_id = bss->trader_entity_id;
|
||||||
|
search_details.trader_id = bss->trader_id;
|
||||||
|
search_details.type = bss->type;
|
||||||
|
strn0cpy(search_details.item_name, bss->item_name, sizeof(search_details.item_name));
|
||||||
|
|
||||||
SendBazaarResults(bss->TraderID, bss->Class_, bss->Race, bss->ItemStat, bss->Slot, bss->Type,
|
DoBazaarSearch(search_details);
|
||||||
bss->Name, bss->MinPrice * 1000, bss->MaxPrice * 1000);
|
break;
|
||||||
}
|
}
|
||||||
else if (app->size == sizeof(BazaarWelcome_Struct)) {
|
case BazaarInspect: {
|
||||||
|
auto in = (BazaarInspect_Struct *) app->pBuffer;
|
||||||
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)app->pBuffer;
|
DoBazaarInspect(*in);
|
||||||
|
break;
|
||||||
if (bws->Beginning.Action == BazaarWelcome)
|
}
|
||||||
SendBazaarWelcome();
|
case WelcomeMessage: {
|
||||||
}
|
SendBazaarWelcome();
|
||||||
else if (app->size == sizeof(NewBazaarInspect_Struct)) {
|
break;
|
||||||
|
}
|
||||||
NewBazaarInspect_Struct *nbis = (NewBazaarInspect_Struct*)app->pBuffer;
|
default: {
|
||||||
|
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
|
||||||
Client *c = entity_list.GetClientByName(nbis->Name);
|
|
||||||
if (c) {
|
|
||||||
EQ::ItemInstance* inst = c->FindTraderItemBySerialNumber(nbis->SerialNumber);
|
|
||||||
if (inst)
|
|
||||||
SendItemPacket(0, inst, ItemPacketViewLink);
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
LogTrading("Malformed BazaarSearch_Struct packet received, ignoring");
|
|
||||||
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_Begging(const EQApplicationPacket *app)
|
void Client::Handle_OP_Begging(const EQApplicationPacket *app)
|
||||||
@ -4973,8 +4982,8 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
|||||||
|
|
||||||
if (cy != m_Position.y || cx != m_Position.x) {
|
if (cy != m_Position.y || cx != m_Position.x) {
|
||||||
// End trader mode if we move
|
// End trader mode if we move
|
||||||
if (Trader) {
|
if (IsTrader()) {
|
||||||
Trader_EndTrader();
|
TraderEndTrader();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||||
@ -15494,174 +15503,49 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
//
|
//
|
||||||
// SoF sends 1 or more unhandled OP_Trader packets of size 96 when a trade has completed.
|
// SoF sends 1 or more unhandled OP_Trader packets of size 96 when a trade has completed.
|
||||||
// I don't know what they are for (yet), but it doesn't seem to matter that we ignore them.
|
// I don't know what they are for (yet), but it doesn't seem to matter that we ignore them.
|
||||||
|
auto action = *(uint32 *)app->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
uint32 max_items = 80;
|
case TraderOff: {
|
||||||
|
TraderEndTrader();
|
||||||
/*
|
|
||||||
if (GetClientVersion() >= EQClientRoF)
|
|
||||||
max_items = 200;
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Show Items
|
|
||||||
if (app->size == sizeof(Trader_ShowItems_Struct))
|
|
||||||
{
|
|
||||||
Trader_ShowItems_Struct* sis = (Trader_ShowItems_Struct*)app->pBuffer;
|
|
||||||
|
|
||||||
switch (sis->Code)
|
|
||||||
{
|
|
||||||
case BazaarTrader_EndTraderMode: {
|
|
||||||
Trader_EndTrader();
|
|
||||||
LogTrading("End Trader Session");
|
LogTrading("End Trader Session");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BazaarTrader_EndTransaction: {
|
case TraderOn: {
|
||||||
|
if (Buyer) {
|
||||||
Client* c = entity_list.GetClientByID(sis->TraderID);
|
TraderEndTrader();
|
||||||
if (c)
|
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||||
{
|
|
||||||
c->WithCustomer(0);
|
|
||||||
LogTrading("End Transaction");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogTrading("Null Client Pointer");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BazaarTrader_ShowItems: {
|
|
||||||
Trader_ShowItems();
|
|
||||||
LogTrading("Show Trader Items");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
LogTrading("Unhandled action code in OP_Trader ShowItems_Struct");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (app->size == sizeof(ClickTrader_Struct))
|
|
||||||
{
|
|
||||||
if (Buyer) {
|
|
||||||
Trader_EndTrader();
|
|
||||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClickTrader_Struct* ints = (ClickTrader_Struct*)app->pBuffer;
|
|
||||||
|
|
||||||
if (ints->Code == BazaarTrader_StartTraderMode)
|
|
||||||
{
|
|
||||||
GetItems_Struct* gis = GetTraderItems();
|
|
||||||
|
|
||||||
LogTrading("Start Trader Mode");
|
|
||||||
// Verify there are no NODROP or items with a zero price
|
|
||||||
bool TradeItemsValid = true;
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < max_items; i++) {
|
|
||||||
|
|
||||||
if (gis->Items[i] == 0) break;
|
|
||||||
|
|
||||||
if (ints->ItemCost[i] == 0) {
|
|
||||||
Message(Chat::Red, "Item in Trader Satchel with no price. Unable to start trader mode");
|
|
||||||
TradeItemsValid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const EQ::ItemData *Item = database.GetItem(gis->Items[i]);
|
|
||||||
|
|
||||||
if (!Item) {
|
|
||||||
Message(Chat::Red, "Unexpected error. Unable to start trader mode");
|
|
||||||
TradeItemsValid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Item->NoDrop == 0) {
|
|
||||||
Message(Chat::Red, "NODROP Item in Trader Satchel. Unable to start trader mode");
|
|
||||||
TradeItemsValid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TradeItemsValid) {
|
|
||||||
Trader_EndTrader();
|
|
||||||
safe_delete(gis);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 i = 0; i < max_items; i++) {
|
TraderStartTrader(app);
|
||||||
if (database.GetItem(gis->Items[i])) {
|
|
||||||
database.SaveTraderItem(CharacterID(), gis->Items[i], gis->SerialNumber[i],
|
|
||||||
gis->Charges[i], ints->ItemCost[i], i);
|
|
||||||
|
|
||||||
auto inst = FindTraderItemBySerialNumber(gis->SerialNumber[i]);
|
|
||||||
if (inst)
|
|
||||||
inst->SetPrice(ints->ItemCost[i]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//return; //sony doesnt memset so assume done on first bad item
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
safe_delete(gis);
|
|
||||||
|
|
||||||
Trader_StartTrader();
|
|
||||||
|
|
||||||
// This refreshes the Trader window to display the End Trader button
|
|
||||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF)
|
|
||||||
{
|
|
||||||
auto outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct));
|
|
||||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)outapp->pBuffer;
|
|
||||||
tss->Code = BazaarTrader_StartTraderMode2;
|
|
||||||
QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogTrading("Unknown TraderStruct code of: [{}]\n",
|
|
||||||
ints->Code);
|
|
||||||
|
|
||||||
LogError("Unknown TraderStruct code of: [{}]\n", ints->Code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (app->size == sizeof(TraderStatus_Struct))
|
|
||||||
{
|
|
||||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer;
|
|
||||||
|
|
||||||
LogTrading("Trader Status Code: [{}]", tss->Code);
|
|
||||||
|
|
||||||
switch (tss->Code)
|
|
||||||
{
|
|
||||||
case BazaarTrader_EndTraderMode: {
|
|
||||||
Trader_EndTrader();
|
|
||||||
LogTrading("End Trader Session");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BazaarTrader_ShowItems: {
|
case PriceUpdate:
|
||||||
Trader_ShowItems();
|
case ItemMove: {
|
||||||
|
LogTrading("Trader Price Update");
|
||||||
|
TraderPriceUpdate(app);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EndTransaction: {
|
||||||
|
auto sis = (Trader_ShowItems_Struct *) app->pBuffer;
|
||||||
|
Client *c = entity_list.GetClientByID(sis->entity_id);
|
||||||
|
if (c) {
|
||||||
|
c->WithCustomer(0);
|
||||||
|
LogTrading("End Transaction");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ListTraderItems: {
|
||||||
|
TraderShowItems();
|
||||||
LogTrading("Show Trader Items");
|
LogTrading("Show Trader Items");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LogTrading("Unhandled action code in OP_Trader ShowItems_Struct");
|
LogError("Unknown size for OP_Trader: [{}]\n", app->size);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (app->size == sizeof(TraderPriceUpdate_Struct))
|
|
||||||
{
|
|
||||||
LogTrading("Trader Price Update");
|
|
||||||
HandleTraderPriceUpdate(app);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogTrading("Unknown size for OP_Trader: [{}]\n", app->size);
|
|
||||||
LogError("Unknown size for OP_Trader: [{}]\n", app->size);
|
|
||||||
DumpPacket(app);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||||
@ -15670,23 +15554,80 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
//
|
//
|
||||||
// Client has elected to buy an item from a Trader
|
// Client has elected to buy an item from a Trader
|
||||||
//
|
//
|
||||||
if (app->size != sizeof(TraderBuy_Struct)) {
|
auto in = (TraderBuy_Struct *) app->pBuffer;
|
||||||
LogError("Wrong size: OP_TraderBuy, size=[{}], expected [{}]", app->size, sizeof(TraderBuy_Struct));
|
auto trader = entity_list.GetClientByID(in->trader_id);
|
||||||
return;
|
|
||||||
|
switch (in->method) {
|
||||||
|
case ByVendor: {
|
||||||
|
if (trader) {
|
||||||
|
LogTrading("Buy item directly from vendor id <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||||
|
"serial_number <green>[{}]",
|
||||||
|
in->trader_id,
|
||||||
|
in->item_id,
|
||||||
|
in->quantity,
|
||||||
|
in->serial_number
|
||||||
|
);
|
||||||
|
BuyTraderItem(in, trader, app);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ByParcel: {
|
||||||
|
if (!RuleB(Parcel, EnableParcelMerchants) || !RuleB(Bazaar, EnableParcelDelivery)) {
|
||||||
|
LogTrading(
|
||||||
|
"Bazaar purchase attempt by parcel delivery though 'Parcel:EnableParcelMerchants' or "
|
||||||
|
"'Bazaar::EnableParcelDelivery' not enabled."
|
||||||
|
);
|
||||||
|
Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
"The bazaar parcel delivey system is not enabled on this server. Please visit the vendor directly in the Bazaar."
|
||||||
|
);
|
||||||
|
in->method = ByParcel;
|
||||||
|
in->sub_action = Failed;
|
||||||
|
TradeRequestFailed(app);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LogTrading("Buy item by parcel delivery <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||||
|
"serial_number <green>[{}]",
|
||||||
|
in->trader_id,
|
||||||
|
in->item_id,
|
||||||
|
in->quantity,
|
||||||
|
in->serial_number
|
||||||
|
);
|
||||||
|
BuyTraderItemOutsideBazaar(in, app);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ByDirectToInventory: {
|
||||||
|
if (!RuleB(Parcel, EnableDirectToInventoryDelivery)) {
|
||||||
|
LogTrading("Bazaar purchase attempt by direct inventory delivery though "
|
||||||
|
"'Parcel:EnableDirectToInventoryDelivery' not enabled."
|
||||||
|
);
|
||||||
|
Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
"Direct inventory delivey is not enabled on this server. Please visit the vendor directly."
|
||||||
|
);
|
||||||
|
in->method = ByDirectToInventory;
|
||||||
|
in->sub_action = Failed;
|
||||||
|
TradeRequestFailed(app);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trader = entity_list.GetClientByCharID(in->trader_id);
|
||||||
|
LogTrading("Buy item by direct inventory delivery <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||||
|
"serial_number <green>[{}]",
|
||||||
|
in->trader_id,
|
||||||
|
in->item_id,
|
||||||
|
in->quantity,
|
||||||
|
in->serial_number
|
||||||
|
);
|
||||||
|
Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
"Direct inventory delivey is not yet implemented. Please visit the vendor directly or purchase via parcel delivery."
|
||||||
|
);
|
||||||
|
in->method = ByDirectToInventory;
|
||||||
|
in->sub_action = Failed;
|
||||||
|
TradeRequestFailed(app);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
|
||||||
|
|
||||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)) {
|
|
||||||
BuyTraderItem(tbs, Trader, app);
|
|
||||||
LogTrading("Client::Handle_OP_TraderBuy: Buy Trader Item ");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogTrading("Client::Handle_OP_TraderBuy: Null Client Pointer");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_TradeRequest(const EQApplicationPacket *app)
|
void Client::Handle_OP_TradeRequest(const EQApplicationPacket *app)
|
||||||
@ -15749,126 +15690,76 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
// Bazaar Trader:
|
auto in = (TraderClick_Struct *) app->pBuffer;
|
||||||
|
LogTrading("Handle_OP_TraderShop: TraderClick_Struct TraderID [{}], Code [{}], Unknown008 [{}], Approval [{}]",
|
||||||
|
in->TraderID,
|
||||||
|
in->Code,
|
||||||
|
in->Unknown008,
|
||||||
|
in->Approval
|
||||||
|
);
|
||||||
|
|
||||||
if (app->size == sizeof(TraderClick_Struct))
|
switch (in->Code) {
|
||||||
{
|
case ClickTrader: {
|
||||||
|
LogTrading("Handle_OP_TraderShop case ClickTrader [{}]", in->Code);
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||||
|
auto data = (TraderClick_Struct *) outapp->pBuffer;
|
||||||
|
auto trader_client = entity_list.GetClientByID(in->TraderID);
|
||||||
|
|
||||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
if (trader_client) {
|
||||||
|
data->Approval = trader_client->WithCustomer(GetID());
|
||||||
LogTrading("Handle_OP_TraderShop: TraderClick_Struct TraderID [{}], Code [{}], Unknown008 [{}], Approval [{}]",
|
LogTrading("Client::Handle_OP_TraderShop: Shop Request ([{}]) to ([{}]) with Approval: [{}]",
|
||||||
tcs->TraderID, tcs->Code, tcs->Unknown008, tcs->Approval);
|
GetCleanName(),
|
||||||
|
trader_client->GetCleanName(),
|
||||||
if (tcs->Code == BazaarWelcome)
|
data->Approval
|
||||||
{
|
);
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
|
||||||
SendBazaarWelcome();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
|
||||||
// browse their goods.
|
|
||||||
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
|
||||||
|
|
||||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
|
||||||
|
|
||||||
Client* Trader = entity_list.GetClientByID(tcs->TraderID);
|
|
||||||
|
|
||||||
if (Trader)
|
|
||||||
{
|
|
||||||
outtcs->Approval = Trader->WithCustomer(GetID());
|
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Shop Request ([{}]) to ([{}]) with Approval: [{}]", GetCleanName(), Trader->GetCleanName(), outtcs->Approval);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LogTrading("Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
LogTrading("Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||||
" returned a nullptr pointer");
|
" returned a nullptr pointer"
|
||||||
safe_delete(outapp);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
outtcs->TraderID = tcs->TraderID;
|
data->Code = ClickTrader;
|
||||||
|
data->TraderID = in->TraderID;
|
||||||
|
data->Unknown008 = 0x3f800000;
|
||||||
|
QueuePacket(outapp.get());
|
||||||
|
|
||||||
outtcs->Unknown008 = 0x3f800000;
|
if (data->Approval) {
|
||||||
|
BulkSendTraderInventory(trader_client->CharacterID());
|
||||||
QueuePacket(outapp);
|
trader_client->Trader_CustomerBrowsing(this);
|
||||||
|
SetTraderID(in->TraderID);
|
||||||
|
LogTrading("Client::Handle_OP_TraderShop: Trader Inventory Sent to [{}] from [{}]",
|
||||||
if (outtcs->Approval) {
|
GetID(),
|
||||||
BulkSendTraderInventory(Trader->CharacterID());
|
in->TraderID
|
||||||
Trader->Trader_CustomerBrowsing(this);
|
);
|
||||||
TraderID = tcs->TraderID;
|
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Trader Inventory Sent");
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
MessageString(Chat::Yellow, TRADER_BUSY);
|
MessageString(Chat::Yellow, TRADER_BUSY);
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Trader Busy");
|
LogTrading("Client::Handle_OP_TraderShop: Trader Busy");
|
||||||
}
|
}
|
||||||
|
|
||||||
safe_delete(outapp);
|
break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
case EndTransaction: {
|
||||||
}
|
Client *c = entity_list.GetClientByID(GetTraderID());
|
||||||
else if (app->size == sizeof(BazaarWelcome_Struct))
|
SetTraderID(0);
|
||||||
{
|
if (c) {
|
||||||
// RoF+
|
|
||||||
// Client requested Bazaar Welcome Info (Trader and Item Total Counts)
|
|
||||||
SendBazaarWelcome();
|
|
||||||
LogTrading("Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
|
||||||
}
|
|
||||||
else if (app->size == sizeof(TraderBuy_Struct))
|
|
||||||
{
|
|
||||||
// RoF+
|
|
||||||
// Customer has purchased an item from the Trader
|
|
||||||
|
|
||||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
|
||||||
|
|
||||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID))
|
|
||||||
{
|
|
||||||
BuyTraderItem(tbs, Trader, app);
|
|
||||||
LogTrading("Handle_OP_TraderShop: Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
|
||||||
tbs->Action, tbs->Price, tbs->TraderID, tbs->ItemID, tbs->Quantity, tbs->ItemName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogTrading("OP_TraderShop: Null Client Pointer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (app->size == 4)
|
|
||||||
{
|
|
||||||
// RoF+
|
|
||||||
// Customer has closed the trade window
|
|
||||||
uint32 Command = *((uint32 *)app->pBuffer);
|
|
||||||
|
|
||||||
if (Command == 4)
|
|
||||||
{
|
|
||||||
Client* c = entity_list.GetClientByID(TraderID);
|
|
||||||
TraderID = 0;
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
c->WithCustomer(0);
|
c->WithCustomer(0);
|
||||||
LogTrading("End Transaction - Code [{}]", Command);
|
LogTrading("End Transaction - Code [{}]", in->Code);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
LogTrading("Null Client Pointer for Trader - Code [{}]", in->Code);
|
||||||
LogTrading("Null Client Pointer for Trader - Code [{}]", Command);
|
|
||||||
}
|
}
|
||||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
|
||||||
QueuePacket(&empty);
|
auto outapp = new EQApplicationPacket(OP_ShopEndConfirm);
|
||||||
|
QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
default: {
|
||||||
{
|
|
||||||
LogTrading("Unhandled Code [{}]", Command);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
LogTrading("Unknown size for OP_TraderShop: [{}]\n", app->size);
|
|
||||||
LogError("Unknown size for OP_TraderShop: [{}]\n", app->size);
|
|
||||||
DumpPacket(app);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
||||||
|
|||||||
@ -994,22 +994,22 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
|||||||
uint8 Client::WithCustomer(uint16 NewCustomer){
|
uint8 Client::WithCustomer(uint16 NewCustomer){
|
||||||
|
|
||||||
if(NewCustomer == 0) {
|
if(NewCustomer == 0) {
|
||||||
CustomerID = 0;
|
SetCustomerID(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CustomerID == 0) {
|
if(GetCustomerID() == 0) {
|
||||||
CustomerID = NewCustomer;
|
SetCustomerID(NewCustomer);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the player browsing our wares hasn't gone away.
|
// Check that the player browsing our wares hasn't gone away.
|
||||||
|
|
||||||
Client* c = entity_list.GetClientByID(CustomerID);
|
Client* c = entity_list.GetClientByID(GetCustomerID());
|
||||||
|
|
||||||
if(!c) {
|
if(!c) {
|
||||||
LogTrading("Previous customer has gone away");
|
LogTrading("Previous customer has gone away");
|
||||||
CustomerID = NewCustomer;
|
SetCustomerID(NewCustomer);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ void command_parcels(Client *c, const Seperator *sep)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto results = CharacterParcelsRepository::GetWhere(
|
auto results = CharacterParcelsRepository::GetWhere(
|
||||||
database,
|
database,
|
||||||
fmt::format("char_id = '{}' ORDER BY slot_id ASC", player_id.at(0).char_id)
|
fmt::format("char_id = '{}' ORDER BY slot_id ASC", player_id.at(0).char_id)
|
||||||
);
|
);
|
||||||
@ -120,8 +120,8 @@ void command_parcels(Client *c, const Seperator *sep)
|
|||||||
auto note = std::string(sep->argplus[5]);
|
auto note = std::string(sep->argplus[5]);
|
||||||
|
|
||||||
auto send_to_client = CharacterParcelsRepository::GetParcelCountAndCharacterName(
|
auto send_to_client = CharacterParcelsRepository::GetParcelCountAndCharacterName(
|
||||||
database,
|
database,
|
||||||
to_name
|
to_name
|
||||||
);
|
);
|
||||||
if (send_to_client.at(0).character_name.empty()) {
|
if (send_to_client.at(0).character_name.empty()) {
|
||||||
c->MessageString(Chat::Yellow, CANT_FIND_PLAYER, to_name.c_str());
|
c->MessageString(Chat::Yellow, CANT_FIND_PLAYER, to_name.c_str());
|
||||||
@ -164,14 +164,14 @@ void command_parcels(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CharacterParcelsRepository::CharacterParcels parcel_out;
|
CharacterParcelsRepository::CharacterParcels parcel_out;
|
||||||
parcel_out.from_name = c->GetName();
|
parcel_out.from_name = c->GetName();
|
||||||
parcel_out.note = note;
|
parcel_out.note = note;
|
||||||
parcel_out.sent_date = time(nullptr);
|
parcel_out.sent_date = time(nullptr);
|
||||||
parcel_out.quantity = quantity == 0 ? 1 : quantity;
|
parcel_out.quantity = quantity == 0 ? 1 : quantity;
|
||||||
parcel_out.item_id = PARCEL_MONEY_ITEM_ID;
|
parcel_out.item_id = PARCEL_MONEY_ITEM_ID;
|
||||||
parcel_out.char_id = send_to_client.at(0).char_id;
|
parcel_out.char_id = send_to_client.at(0).char_id;
|
||||||
parcel_out.slot_id = next_slot;
|
parcel_out.slot_id = next_slot;
|
||||||
parcel_out.id = 0;
|
parcel_out.id = 0;
|
||||||
|
|
||||||
auto result = CharacterParcelsRepository::InsertOne(database, parcel_out);
|
auto result = CharacterParcelsRepository::InsertOne(database, parcel_out);
|
||||||
if (!result.id) {
|
if (!result.id) {
|
||||||
@ -205,7 +205,7 @@ void command_parcels(Client *c, const Seperator *sep)
|
|||||||
e.quantity = parcel_out.quantity;
|
e.quantity = parcel_out.quantity;
|
||||||
e.sent_date = parcel_out.sent_date;
|
e.sent_date = parcel_out.sent_date;
|
||||||
|
|
||||||
RecordPlayerEventLogWithClient(c, PlayerEvent::PARCEL_SEND, e);
|
RecordPlayerEventLogWithClient (c, PlayerEvent::PARCEL_SEND, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parcel_Struct ps{};
|
Parcel_Struct ps{};
|
||||||
@ -242,14 +242,14 @@ void command_parcels(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CharacterParcelsRepository::CharacterParcels parcel_out;
|
CharacterParcelsRepository::CharacterParcels parcel_out;
|
||||||
parcel_out.from_name = c->GetName();
|
parcel_out.from_name = c->GetName();
|
||||||
parcel_out.note = note.empty() ? "" : note;
|
parcel_out.note = note.empty() ? "" : note;
|
||||||
parcel_out.sent_date = time(nullptr);
|
parcel_out.sent_date = time(nullptr);
|
||||||
parcel_out.quantity = quantity;
|
parcel_out.quantity = quantity;
|
||||||
parcel_out.item_id = item_id;
|
parcel_out.item_id = item_id;
|
||||||
parcel_out.char_id = send_to_client.at(0).char_id;
|
parcel_out.char_id = send_to_client.at(0).char_id;
|
||||||
parcel_out.slot_id = next_slot;
|
parcel_out.slot_id = next_slot;
|
||||||
parcel_out.id = 0;
|
parcel_out.id = 0;
|
||||||
|
|
||||||
auto result = CharacterParcelsRepository::InsertOne(database, parcel_out);
|
auto result = CharacterParcelsRepository::InsertOne(database, parcel_out);
|
||||||
if (!result.id) {
|
if (!result.id) {
|
||||||
@ -283,7 +283,7 @@ void command_parcels(Client *c, const Seperator *sep)
|
|||||||
e.quantity = parcel_out.quantity;
|
e.quantity = parcel_out.quantity;
|
||||||
e.sent_date = parcel_out.sent_date;
|
e.sent_date = parcel_out.sent_date;
|
||||||
|
|
||||||
RecordPlayerEventLogWithClient(c, PlayerEvent::PARCEL_SEND, e);
|
RecordPlayerEventLogWithClient (c, PlayerEvent::PARCEL_SEND, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parcel_Struct ps{};
|
Parcel_Struct ps{};
|
||||||
@ -300,8 +300,8 @@ void SendParcelsSubCommands(Client *c)
|
|||||||
c->Message(Chat::White, "#parcels listdb [Character Name]");
|
c->Message(Chat::White, "#parcels listdb [Character Name]");
|
||||||
c->Message(Chat::White, "#parcels listmemory [Character Name] (Must be in the same zone)");
|
c->Message(Chat::White, "#parcels listmemory [Character Name] (Must be in the same zone)");
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
"#parcels add [Character Name] [item id] [quantity] [note]. To send money use item id of 99990. Quantity is valid for stackable items, charges on an item, or amount of copper."
|
"#parcels add [Character Name] [item id] [quantity] [note]. To send money use item id of 99990. Quantity is valid for stackable items, charges on an item, or amount of copper."
|
||||||
);
|
);
|
||||||
c->Message(Chat::White, "#parcels details [Character Name]");
|
c->Message(Chat::White, "#parcels details [Character Name]");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -164,10 +164,11 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Slot {} | {} ({}){}",
|
"Slot {} | {} ({}/{}){}",
|
||||||
((scope_bit & peekWorld) ? (EQ::invslot::WORLD_BEGIN + index_main) : index_main),
|
((scope_bit & peekWorld) ? (EQ::invslot::WORLD_BEGIN + index_main) : index_main),
|
||||||
linker.GenerateLink(),
|
linker.GenerateLink(),
|
||||||
item_data->ID,
|
item_data->ID,
|
||||||
|
c->GetInv().GetItem(((scope_bit &peekWorld) ? (EQ::invslot::WORLD_BEGIN + index_main) : index_main))->GetSerialNumber(),
|
||||||
(
|
(
|
||||||
inst_main->IsStackable() && inst_main->GetCharges() > 0 ?
|
inst_main->IsStackable() && inst_main->GetCharges() > 0 ?
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -228,7 +229,7 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Slot {} Bag Slot {} | {} ({}){}",
|
"Slot {} Bag Slot {}/{} | {} ({}/{}){}",
|
||||||
(
|
(
|
||||||
(scope_bit & peekWorld) ?
|
(scope_bit & peekWorld) ?
|
||||||
INVALID_INDEX :
|
INVALID_INDEX :
|
||||||
@ -238,6 +239,7 @@ void ShowInventory(Client *c, const Seperator *sep)
|
|||||||
sub_index,
|
sub_index,
|
||||||
linker.GenerateLink(),
|
linker.GenerateLink(),
|
||||||
item_data->ID,
|
item_data->ID,
|
||||||
|
c->GetInv().GetItem(EQ::InventoryProfile::CalcSlotId(index_main, sub_index))->GetSerialNumber(),
|
||||||
(
|
(
|
||||||
inst_sub->IsStackable() && inst_sub->GetCharges() > 0 ?
|
inst_sub->IsStackable() && inst_sub->GetCharges() > 0 ?
|
||||||
fmt::format(
|
fmt::format(
|
||||||
|
|||||||
@ -1864,19 +1864,19 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
LogInventory("Dest slot [{}] has item [{}] ([{}]) with [{}] charges in it", dst_slot_id, dst_inst->GetItem()->Name, dst_inst->GetItem()->ID, dst_inst->GetCharges());
|
LogInventory("Dest slot [{}] has item [{}] ([{}]) with [{}] charges in it", dst_slot_id, dst_inst->GetItem()->Name, dst_inst->GetItem()->ID, dst_inst->GetCharges());
|
||||||
dstitemid = dst_inst->GetItem()->ID;
|
dstitemid = dst_inst->GetItem()->ID;
|
||||||
}
|
}
|
||||||
if (Trader && srcitemid>0){
|
if (IsTrader() && srcitemid>0){
|
||||||
EQ::ItemInstance* srcbag;
|
EQ::ItemInstance* srcbag;
|
||||||
EQ::ItemInstance* dstbag;
|
EQ::ItemInstance* dstbag;
|
||||||
uint32 srcbagid =0;
|
uint32 srcbagid =0;
|
||||||
uint32 dstbagid = 0;
|
uint32 dstbagid = 0;
|
||||||
|
|
||||||
if (src_slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN && src_slot_id <= EQ::invbag::GENERAL_BAGS_END) {
|
if (src_slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN && src_slot_id <= EQ::invbag::GENERAL_BAGS_END) {
|
||||||
srcbag = m_inv.GetItem(((int)(src_slot_id / 10)) - 3);
|
srcbag = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(src_slot_id));
|
||||||
if (srcbag)
|
if (srcbag)
|
||||||
srcbagid = srcbag->GetItem()->ID;
|
srcbagid = srcbag->GetItem()->ID;
|
||||||
}
|
}
|
||||||
if (dst_slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN && dst_slot_id <= EQ::invbag::GENERAL_BAGS_END) {
|
if (dst_slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN && dst_slot_id <= EQ::invbag::GENERAL_BAGS_END) {
|
||||||
dstbag = m_inv.GetItem(((int)(dst_slot_id / 10)) - 3);
|
dstbag = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(dst_slot_id));
|
||||||
if (dstbag)
|
if (dstbag)
|
||||||
dstbagid = dstbag->GetItem()->ID;
|
dstbagid = dstbag->GetItem()->ID;
|
||||||
}
|
}
|
||||||
@ -1884,7 +1884,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
(dstbagid && dstbag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
|
(dstbagid && dstbag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
|
||||||
(srcitemid && src_inst && src_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
|
(srcitemid && src_inst && src_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
|
||||||
(dstitemid && dst_inst && dst_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)) {
|
(dstitemid && dst_inst && dst_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)) {
|
||||||
Trader_EndTrader();
|
TraderEndTrader();
|
||||||
Message(Chat::Red,"You cannot move your Trader Satchels, or items inside them, while Trading.");
|
Message(Chat::Red,"You cannot move your Trader Satchels, or items inside them, while Trading.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2180,6 +2180,27 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LogInventory("Moving entire item from slot [{}] to slot [{}]", src_slot_id, dst_slot_id);
|
LogInventory("Moving entire item from slot [{}] to slot [{}]", src_slot_id, dst_slot_id);
|
||||||
|
if (src_inst->IsStackable() &&
|
||||||
|
dst_slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN &&
|
||||||
|
dst_slot_id <= EQ::invbag::GENERAL_BAGS_END
|
||||||
|
) {
|
||||||
|
EQ::ItemInstance *bag = nullptr;
|
||||||
|
bag = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(dst_slot_id));
|
||||||
|
if (bag) {
|
||||||
|
if (bag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) {
|
||||||
|
PutItemInInventory(dst_slot_id, *src_inst, true);
|
||||||
|
//This resets the UF client to recognize the new serial item of the placed item
|
||||||
|
//if it came from a stack without having to close the trader window and re-open.
|
||||||
|
//It is not required for the RoF2 client.
|
||||||
|
if (ClientVersion() < EQ::versions::ClientVersion::RoF2) {
|
||||||
|
auto outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct));
|
||||||
|
auto data = (TraderBuy_Struct *) outapp->pBuffer;
|
||||||
|
data->action = BazaarBuyItem;
|
||||||
|
FastQueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (src_slot_id <= EQ::invslot::EQUIPMENT_END) {
|
if (src_slot_id <= EQ::invslot::EQUIPMENT_END) {
|
||||||
if(src_inst) {
|
if(src_inst) {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ void Client::SendBulkParcels()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendParcel(const Parcel_Struct &parcel_in)
|
void Client::SendParcel(Parcel_Struct &parcel_in)
|
||||||
{
|
{
|
||||||
auto results = CharacterParcelsRepository::GetWhere(
|
auto results = CharacterParcelsRepository::GetWhere(
|
||||||
database,
|
database,
|
||||||
|
|||||||
@ -195,6 +195,7 @@
|
|||||||
#define PARCEL_DELAY 734 //%1 tells you, 'You must give me a chance to send the last parcel before I can send another!'
|
#define PARCEL_DELAY 734 //%1 tells you, 'You must give me a chance to send the last parcel before I can send another!'
|
||||||
#define PARCEL_DUPLICATE_DELETE 737 //Duplicate lore items are not allowed! Your duplicate %1 has been deleted!
|
#define PARCEL_DUPLICATE_DELETE 737 //Duplicate lore items are not allowed! Your duplicate %1 has been deleted!
|
||||||
#define PARCEL_DELIVER_3 741 //%1 told you, 'I will deliver the stack of %2 %3 to %4 as soon as possible!'
|
#define PARCEL_DELIVER_3 741 //%1 told you, 'I will deliver the stack of %2 %3 to %4 as soon as possible!'
|
||||||
|
#define TRADER_MODE_FAILED_ROF2 785 //Your attempt to become a trader has failed.
|
||||||
#define PARCEL_INV_FULL 790 //%1 tells you, 'Your inventory appears full! Unable to retrieve parceled item.'
|
#define PARCEL_INV_FULL 790 //%1 tells you, 'Your inventory appears full! Unable to retrieve parceled item.'
|
||||||
#define AA_CAP 1000 //You have reached the AA point cap, and cannot gain any further experience until some of your stored AA point pool is used.
|
#define AA_CAP 1000 //You have reached the AA point cap, and cannot gain any further experience until some of your stored AA point pool is used.
|
||||||
#define GM_GAINXP 1002 //[GM] You have gained %1 AXP and %2 EXP (%3).
|
#define GM_GAINXP 1002 //[GM] You have gained %1 AXP and %2 EXP (%3).
|
||||||
@ -427,6 +428,9 @@
|
|||||||
#define GENERIC_STRING 6688 //%1 (used to any basic message)
|
#define GENERIC_STRING 6688 //%1 (used to any basic message)
|
||||||
#define SENTINEL_TRIG_YOU 6724 //You have triggered your sentinel.
|
#define SENTINEL_TRIG_YOU 6724 //You have triggered your sentinel.
|
||||||
#define SENTINEL_TRIG_OTHER 6725 //%1 has triggered your sentinel.
|
#define SENTINEL_TRIG_OTHER 6725 //%1 has triggered your sentinel.
|
||||||
|
#define TRADER_MODE_OFF 6741 //Bazaar Trader Mode *OFF*
|
||||||
|
#define TRADER_MODE_ON 6742 //Bazaar Trader Mode *ON*
|
||||||
|
#define TRADER_SET_PRICE 6754 //To become a merchant you must assign a price to an item in your list. Do this by selecting an item, then selecting a money amount, and then clicking set price.
|
||||||
#define IDENTIFY_SPELL 6765 //Item Lore: %1.
|
#define IDENTIFY_SPELL 6765 //Item Lore: %1.
|
||||||
#define PET_NOW_HOLDING 6834 //Now holding, Master. I will not start attacks until ordered.
|
#define PET_NOW_HOLDING 6834 //Now holding, Master. I will not start attacks until ordered.
|
||||||
#define PET_ON_GHOLD 6843 //Pet greater hold has been set to on.
|
#define PET_ON_GHOLD 6843 //Pet greater hold has been set to on.
|
||||||
|
|||||||
2028
zone/trading.cpp
2028
zone/trading.cpp
File diff suppressed because it is too large
Load Diff
@ -3915,10 +3915,98 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
case ServerOP_TraderMessaging: {
|
||||||
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int)pack->opcode, pack->size);
|
auto in = (TraderMessaging_Struct *) pack->pBuffer;
|
||||||
break;
|
for (auto const &c: entity_list.GetClientList()) {
|
||||||
}
|
if (c.second->ClientVersion() >= EQ::versions::ClientVersion::RoF2) {
|
||||||
|
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct));
|
||||||
|
auto out = (BecomeTrader_Struct *) outapp->pBuffer;
|
||||||
|
switch (in->action) {
|
||||||
|
case TraderOn: {
|
||||||
|
out->action = AddTraderToBazaarWindow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TraderOff: {
|
||||||
|
out->action = RemoveTraderFromBazaarWindow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
out->action = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->entity_id = in->entity_id;
|
||||||
|
out->zone_id = in->zone_id;
|
||||||
|
out->trader_id = in->trader_id;
|
||||||
|
strn0cpy(out->trader_name, in->trader_name, sizeof(out->trader_name));
|
||||||
|
|
||||||
|
c.second->QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
if (zone && zone->GetZoneID() == Zones::BAZAAR) {
|
||||||
|
if (in->action == TraderOn) {
|
||||||
|
c.second->SendBecomeTrader(TraderOn, in->entity_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c.second->SendBecomeTrader(TraderOff, in->entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_BazaarPurchase: {
|
||||||
|
auto in = (BazaarPurchaseMessaging_Struct *) pack->pBuffer;
|
||||||
|
auto trader_pc = entity_list.GetClientByCharID(in->trader_buy_struct.trader_id);
|
||||||
|
if (!trader_pc) {
|
||||||
|
LogTrading("Request trader_id <red>[{}] could not be found in zone_id <red>[{}]",
|
||||||
|
in->trader_buy_struct.trader_id,
|
||||||
|
zone->GetZoneID()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item_sn = Strings::ToUnsignedBigInt(in->trader_buy_struct.serial_number);
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_Trader, sizeof(TraderBuy_Struct));
|
||||||
|
auto data = (TraderBuy_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
|
memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct));
|
||||||
|
|
||||||
|
if (trader_pc->ClientVersion() < EQ::versions::ClientVersion::RoF) {
|
||||||
|
data->price = in->trader_buy_struct.price * in->trader_buy_struct.quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraderRepository::UpdateQuantity(
|
||||||
|
database,
|
||||||
|
trader_pc->CharacterID(),
|
||||||
|
item_sn,
|
||||||
|
in->item_quantity_available - in->trader_buy_struct.quantity
|
||||||
|
);
|
||||||
|
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||||
|
|
||||||
|
trader_pc->RemoveItemBySerialNumber(item_sn, in->trader_buy_struct.quantity);
|
||||||
|
trader_pc->AddMoneyToPP(in->trader_buy_struct.price * in->trader_buy_struct.quantity, true);
|
||||||
|
trader_pc->QueuePacket(outapp.get());
|
||||||
|
|
||||||
|
if (player_event_logs.IsEventEnabled(PlayerEvent::TRADER_SELL)) {
|
||||||
|
auto e = PlayerEvent::TraderSellEvent{
|
||||||
|
.item_id = in->trader_buy_struct.item_id,
|
||||||
|
.item_name = in->trader_buy_struct.item_name,
|
||||||
|
.buyer_id = in->buyer_id,
|
||||||
|
.buyer_name = in->trader_buy_struct.buyer_name,
|
||||||
|
.price = in->trader_buy_struct.price,
|
||||||
|
.charges = in->trader_buy_struct.quantity,
|
||||||
|
.total_cost = (in->trader_buy_struct.price * in->trader_buy_struct.quantity),
|
||||||
|
.player_money_balance = trader_pc->GetCarriedMoney(),
|
||||||
|
};
|
||||||
|
|
||||||
|
RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int) pack->opcode, pack->size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,7 @@
|
|||||||
#include "../common/repositories/merc_stance_entries_repository.h"
|
#include "../common/repositories/merc_stance_entries_repository.h"
|
||||||
#include "../common/repositories/alternate_currency_repository.h"
|
#include "../common/repositories/alternate_currency_repository.h"
|
||||||
#include "../common/repositories/graveyard_repository.h"
|
#include "../common/repositories/graveyard_repository.h"
|
||||||
|
#include "../common/repositories/trader_repository.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@ -1197,7 +1198,7 @@ bool Zone::Init(bool is_static) {
|
|||||||
|
|
||||||
//clear trader items if we are loading the bazaar
|
//clear trader items if we are loading the bazaar
|
||||||
if (strncasecmp(short_name, "bazaar", 6) == 0) {
|
if (strncasecmp(short_name, "bazaar", 6) == 0) {
|
||||||
database.DeleteTraderItem(0);
|
TraderRepository::Truncate(database);
|
||||||
database.DeleteBuyLines(0);
|
database.DeleteBuyLines(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
273
zone/zonedb.cpp
273
zone/zonedb.cpp
@ -51,6 +51,9 @@
|
|||||||
#include "../common/repositories/character_corpse_items_repository.h"
|
#include "../common/repositories/character_corpse_items_repository.h"
|
||||||
#include "../common/repositories/zone_repository.h"
|
#include "../common/repositories/zone_repository.h"
|
||||||
|
|
||||||
|
#include "../common/repositories/trader_repository.h"
|
||||||
|
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
@ -302,187 +305,114 @@ void ZoneDatabase::DeleteWorldContainer(uint32 parent_id, uint32 zone_id)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Trader_Struct* ZoneDatabase::LoadTraderItem(uint32 char_id)
|
std::unique_ptr<EQ::ItemInstance> ZoneDatabase::LoadSingleTraderItem(uint32 char_id, int serial_number)
|
||||||
{
|
{
|
||||||
auto loadti = new Trader_Struct;
|
auto results = TraderRepository::GetWhere(
|
||||||
memset(loadti,0,sizeof(Trader_Struct));
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`char_id` = '{}' AND `item_sn` = '{}' ORDER BY slot_id",
|
||||||
|
char_id,
|
||||||
|
serial_number
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
std::string query = StringFormat("SELECT * FROM trader WHERE char_id = %i ORDER BY slot_id LIMIT 80", char_id);
|
if (results.empty()) {
|
||||||
auto results = QueryDatabase(query);
|
LogTrading("Could not find item serial number {} for character id {}", serial_number, char_id);
|
||||||
if (!results.Success()) {
|
|
||||||
LogTrading("Failed to load trader information!\n");
|
|
||||||
return loadti;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadti->Code = BazaarTrader_ShowItems;
|
int item_id = results.at(0).item_id;
|
||||||
for (auto& row = results.begin(); row != results.end(); ++row) {
|
int charges = results.at(0).item_charges;
|
||||||
if (Strings::ToInt(row[5]) >= 80 || Strings::ToInt(row[4]) < 0) {
|
int cost = results.at(0).item_cost;
|
||||||
LogTrading("Bad Slot number when trying to load trader information!\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadti->Items[Strings::ToInt(row[5])] = Strings::ToInt(row[1]);
|
const EQ::ItemData *item = database.GetItem(item_id);
|
||||||
loadti->ItemCost[Strings::ToInt(row[5])] = Strings::ToInt(row[4]);
|
if (!item) {
|
||||||
|
LogTrading("Unable to create item.");
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
return loadti;
|
|
||||||
|
if (item->NoDrop == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<EQ::ItemInstance> inst(
|
||||||
|
database.CreateItem(
|
||||||
|
item_id,
|
||||||
|
charges,
|
||||||
|
results.at(0).aug_slot_1,
|
||||||
|
results.at(0).aug_slot_2,
|
||||||
|
results.at(0).aug_slot_3,
|
||||||
|
results.at(0).aug_slot_4,
|
||||||
|
results.at(0).aug_slot_5,
|
||||||
|
results.at(0).aug_slot_6
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (!inst) {
|
||||||
|
LogTrading("Unable to create item instance.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->SetCharges(charges);
|
||||||
|
inst->SetSerialNumber(serial_number);
|
||||||
|
inst->SetMerchantSlot(serial_number);
|
||||||
|
inst->SetPrice(cost);
|
||||||
|
|
||||||
|
if (inst->IsStackable()) {
|
||||||
|
inst->SetMerchantCount(charges);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
TraderCharges_Struct* ZoneDatabase::LoadTraderItemWithCharges(uint32 char_id)
|
void ZoneDatabase::UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 charges, uint32 new_price) {
|
||||||
{
|
|
||||||
auto loadti = new TraderCharges_Struct;
|
|
||||||
memset(loadti,0,sizeof(TraderCharges_Struct));
|
|
||||||
|
|
||||||
std::string query = StringFormat("SELECT * FROM trader WHERE char_id=%i ORDER BY slot_id LIMIT 80", char_id);
|
LogTrading("ZoneDatabase::UpdateTraderPrice([{}], [{}], [{}], [{}])", char_id, item_id, charges, new_price);
|
||||||
auto results = QueryDatabase(query);
|
const EQ::ItemData *item = database.GetItem(item_id);
|
||||||
if (!results.Success()) {
|
|
||||||
LogTrading("Failed to load trader information!\n");
|
|
||||||
return loadti;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& row = results.begin(); row != results.end(); ++row) {
|
|
||||||
if (Strings::ToInt(row[5]) >= 80 || Strings::ToInt(row[5]) < 0) {
|
|
||||||
LogTrading("Bad Slot number when trying to load trader information!\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadti->ItemID[Strings::ToInt(row[5])] = Strings::ToInt(row[1]);
|
|
||||||
loadti->SerialNumber[Strings::ToInt(row[5])] = Strings::ToInt(row[2]);
|
|
||||||
loadti->Charges[Strings::ToInt(row[5])] = Strings::ToInt(row[3]);
|
|
||||||
loadti->ItemCost[Strings::ToInt(row[5])] = Strings::ToInt(row[4]);
|
|
||||||
}
|
|
||||||
return loadti;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQ::ItemInstance* ZoneDatabase::LoadSingleTraderItem(uint32 CharID, int SerialNumber) {
|
|
||||||
std::string query = StringFormat("SELECT * FROM trader WHERE char_id = %i AND serialnumber = %i "
|
|
||||||
"ORDER BY slot_id LIMIT 80", CharID, SerialNumber);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (results.RowCount() == 0) {
|
|
||||||
LogTrading("Bad result from query\n"); fflush(stdout);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& row = results.begin();
|
|
||||||
|
|
||||||
int ItemID = Strings::ToInt(row[1]);
|
|
||||||
int Charges = Strings::ToInt(row[3]);
|
|
||||||
int Cost = Strings::ToInt(row[4]);
|
|
||||||
|
|
||||||
const EQ::ItemData *item = database.GetItem(ItemID);
|
|
||||||
|
|
||||||
if(!item) {
|
if(!item) {
|
||||||
LogTrading("Unable to create item\n");
|
|
||||||
fflush(stdout);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->NoDrop == 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
EQ::ItemInstance* inst = database.CreateItem(item);
|
|
||||||
if(!inst) {
|
|
||||||
LogTrading("Unable to create item instance\n");
|
|
||||||
fflush(stdout);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inst->SetCharges(Charges);
|
|
||||||
inst->SetSerialNumber(SerialNumber);
|
|
||||||
inst->SetMerchantSlot(SerialNumber);
|
|
||||||
inst->SetPrice(Cost);
|
|
||||||
|
|
||||||
if(inst->IsStackable())
|
|
||||||
inst->SetMerchantCount(Charges);
|
|
||||||
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneDatabase::SaveTraderItem(uint32 CharID, uint32 ItemID, uint32 SerialNumber, int32 Charges, uint32 ItemCost, uint8 Slot){
|
|
||||||
|
|
||||||
std::string query = StringFormat("REPLACE INTO trader VALUES(%i, %i, %i, %i, %i, %i)",
|
|
||||||
CharID, ItemID, SerialNumber, Charges, ItemCost, Slot);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
LogDebug("[CLIENT] Failed to save trader item: [{}] for char_id: [{}], the error was: [{}]\n", ItemID, CharID, results.ErrorMessage().c_str());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneDatabase::UpdateTraderItemCharges(int CharID, uint32 SerialNumber, int32 Charges) {
|
|
||||||
LogTrading("ZoneDatabase::UpdateTraderItemCharges([{}], [{}], [{}])", CharID, SerialNumber, Charges);
|
|
||||||
|
|
||||||
std::string query = StringFormat("UPDATE trader SET charges = %i WHERE char_id = %i AND serialnumber = %i",
|
|
||||||
Charges, CharID, SerialNumber);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
LogDebug("[CLIENT] Failed to update charges for trader item: [{}] for char_id: [{}], the error was: [{}]\n", SerialNumber, CharID, results.ErrorMessage().c_str());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneDatabase::UpdateTraderItemPrice(int CharID, uint32 ItemID, uint32 Charges, uint32 NewPrice) {
|
|
||||||
|
|
||||||
LogTrading("ZoneDatabase::UpdateTraderPrice([{}], [{}], [{}], [{}])", CharID, ItemID, Charges, NewPrice);
|
|
||||||
|
|
||||||
const EQ::ItemData *item = database.GetItem(ItemID);
|
|
||||||
|
|
||||||
if(!item)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(NewPrice == 0) {
|
if (new_price == 0) {
|
||||||
LogTrading("Removing Trader items from the DB for CharID [{}], ItemID [{}]", CharID, ItemID);
|
LogTrading("Removing Trader items from the DB for char_id [{}], item_id [{}]", char_id, item_id);
|
||||||
|
|
||||||
std::string query = StringFormat("DELETE FROM trader WHERE char_id = %i AND item_id = %i",CharID, ItemID);
|
auto results = TraderRepository::DeleteWhere(
|
||||||
auto results = QueryDatabase(query);
|
database,
|
||||||
if (!results.Success())
|
fmt::format(
|
||||||
LogDebug("[CLIENT] Failed to remove trader item(s): [{}] for char_id: [{}], the error was: [{}]\n", ItemID, CharID, results.ErrorMessage().c_str());
|
"`char_id` = '{}' AND `item_id` = {}",
|
||||||
|
char_id,
|
||||||
|
item_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (!results) {
|
||||||
|
LogDebug("[CLIENT] Failed to remove trader item(s): [{}] for char_id: [{}]",
|
||||||
|
item_id,
|
||||||
|
char_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!item->Stackable) {
|
if (!item->Stackable) {
|
||||||
std::string query = StringFormat("UPDATE trader SET item_cost = %i "
|
auto results = TraderRepository::UpdateItem(database, char_id, new_price, item_id, charges);
|
||||||
"WHERE char_id = %i AND item_id = %i AND charges=%i",
|
if (!results) {
|
||||||
NewPrice, CharID, ItemID, Charges);
|
LogTrading(
|
||||||
auto results = QueryDatabase(query);
|
"Failed to update price for trader item [{}] for char_id: [{}]",
|
||||||
if (!results.Success())
|
item_id,
|
||||||
LogDebug("[CLIENT] Failed to update price for trader item: [{}] for char_id: [{}], the error was: [{}]\n", ItemID, CharID, results.ErrorMessage().c_str());
|
char_id
|
||||||
|
);
|
||||||
return;
|
}
|
||||||
}
|
return;
|
||||||
|
|
||||||
std::string query = StringFormat("UPDATE trader SET item_cost = %i "
|
|
||||||
"WHERE char_id = %i AND item_id = %i",
|
|
||||||
NewPrice, CharID, ItemID);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
LogDebug("[CLIENT] Failed to update price for trader item: [{}] for char_id: [{}], the error was: [{}]\n", ItemID, CharID, results.ErrorMessage().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneDatabase::DeleteTraderItem(uint32 char_id){
|
|
||||||
|
|
||||||
if(char_id==0) {
|
|
||||||
const std::string query = "DELETE FROM trader";
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
LogDebug("[CLIENT] Failed to delete all trader items data, the error was: [{}]\n", results.ErrorMessage().c_str());
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string query = StringFormat("DELETE FROM trader WHERE char_id = %i", char_id);
|
auto results = TraderRepository::UpdateItem(database, char_id, new_price, item_id, 0);
|
||||||
auto results = QueryDatabase(query);
|
if (!results) {
|
||||||
if (!results.Success())
|
LogTrading(
|
||||||
LogDebug("[CLIENT] Failed to delete trader item data for char_id: [{}], the error was: [{}]\n", char_id, results.ErrorMessage().c_str());
|
"Failed to update price for trader item [{}] for char_id: [{}]",
|
||||||
|
item_id,
|
||||||
}
|
char_id
|
||||||
void ZoneDatabase::DeleteTraderItem(uint32 CharID,uint16 SlotID) {
|
);
|
||||||
|
}
|
||||||
std::string query = StringFormat("DELETE FROM trader WHERE char_id = %i And slot_id = %i", CharID, SlotID);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
LogDebug("[CLIENT] Failed to delete trader item data for char_id: [{}], the error was: [{}]\n",CharID, results.ErrorMessage().c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneDatabase::DeleteBuyLines(uint32 CharID) {
|
void ZoneDatabase::DeleteBuyLines(uint32 CharID) {
|
||||||
@ -526,10 +456,22 @@ void ZoneDatabase::UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string query = StringFormat("UPDATE buyer SET quantity = %i WHERE charid = %i AND buyslot = %i", Quantity, CharID, BuySlot);
|
std::string query = StringFormat(
|
||||||
auto results = QueryDatabase(query);
|
"UPDATE buyer SET quantity = %i WHERE charid = %i AND buyslot = %i",
|
||||||
if (!results.Success())
|
Quantity,
|
||||||
LogDebug("[CLIENT] Failed to update quantity in buyslot [{}] for charid: [{}], the error was: [{}]\n", BuySlot, CharID, results.ErrorMessage().c_str());
|
CharID,
|
||||||
|
BuySlot
|
||||||
|
);
|
||||||
|
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogTrading(
|
||||||
|
"Failed to update quantity in buyslot [{}] for charid [{}], the error was [{}]\n",
|
||||||
|
BuySlot,
|
||||||
|
CharID,
|
||||||
|
results.ErrorMessage().c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,6 +572,7 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct*
|
|||||||
pp->raidAutoconsent = e.raid_auto_consent;
|
pp->raidAutoconsent = e.raid_auto_consent;
|
||||||
pp->guildAutoconsent = e.guild_auto_consent;
|
pp->guildAutoconsent = e.guild_auto_consent;
|
||||||
pp->RestTimer = e.RestTimer;
|
pp->RestTimer = e.RestTimer;
|
||||||
|
pp->char_id = e.id;
|
||||||
m_epp->aa_effects = e.e_aa_effects;
|
m_epp->aa_effects = e.e_aa_effects;
|
||||||
m_epp->perAA = e.e_percent_to_aa;
|
m_epp->perAA = e.e_percent_to_aa;
|
||||||
m_epp->expended_aa = e.e_expended_aa_spent;
|
m_epp->expended_aa = e.e_expended_aa_spent;
|
||||||
|
|||||||
@ -389,11 +389,11 @@ public:
|
|||||||
/* Traders */
|
/* Traders */
|
||||||
void SaveTraderItem(uint32 char_id,uint32 itemid,uint32 uniqueid, int32 charges,uint32 itemcost,uint8 slot);
|
void SaveTraderItem(uint32 char_id,uint32 itemid,uint32 uniqueid, int32 charges,uint32 itemcost,uint8 slot);
|
||||||
void UpdateTraderItemCharges(int char_id, uint32 ItemInstID, int32 charges);
|
void UpdateTraderItemCharges(int char_id, uint32 ItemInstID, int32 charges);
|
||||||
void UpdateTraderItemPrice(int CharID, uint32 ItemID, uint32 Charges, uint32 NewPrice);
|
void UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 charges, uint32 new_price);
|
||||||
void DeleteTraderItem(uint32 char_id);
|
void DeleteTraderItem(uint32 char_id);
|
||||||
void DeleteTraderItem(uint32 char_id,uint16 slot_id);
|
void DeleteTraderItem(uint32 char_id,uint16 slot_id);
|
||||||
|
|
||||||
EQ::ItemInstance* LoadSingleTraderItem(uint32 char_id, int uniqueid);
|
std::unique_ptr<EQ::ItemInstance> LoadSingleTraderItem(uint32 char_id, int serial_number);
|
||||||
Trader_Struct* LoadTraderItem(uint32 char_id);
|
Trader_Struct* LoadTraderItem(uint32 char_id);
|
||||||
TraderCharges_Struct* LoadTraderItemWithCharges(uint32 char_id);
|
TraderCharges_Struct* LoadTraderItemWithCharges(uint32 char_id);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user