mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
[Feature] Add Barter/Buyer Features (#4405)
* Add Barter/Buyer Features Adds barter and buyer features, for ROF2 only at this time including item compensation * Remove FKs from buyer tables Remove FKs from buyer tables * Bug fix for Find Buyer and mutli item selling Update for quantity purchases not correctly providing multi items. Update for Find Buyer functionality based on zone instancing. Update buyer messaging Update buyer LORE duplicate check * Revert zone instance comment * Revert zone_id packet size field * Add zone instancing to barter/buyer --------- Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
@@ -651,7 +651,6 @@ Json::Value ApiGetClientListDetail(EQ::Net::WebsocketServerConnection *connectio
|
||||
row["base_wis"] = client->GetBaseWIS();
|
||||
row["become_npc_level"] = client->GetBecomeNPCLevel();
|
||||
row["boat_id"] = client->GetBoatID();
|
||||
row["buyer_welcome_message"] = client->GetBuyerWelcomeMessage();
|
||||
row["calc_atk"] = client->CalcATK();
|
||||
row["calc_base_mana"] = client->CalcBaseMana();
|
||||
row["calc_current_weight"] = client->CalcCurrentWeight();
|
||||
|
||||
+113
-9
@@ -203,7 +203,6 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
port = ntohs(eqs->GetRemotePort());
|
||||
client_state = CLIENT_CONNECTING;
|
||||
SetTrader(false);
|
||||
Buyer = false;
|
||||
Haste = 0;
|
||||
SetCustomerID(0);
|
||||
SetTraderID(0);
|
||||
@@ -386,6 +385,8 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
m_parcel_merchant_engaged = false;
|
||||
m_parcels.clear();
|
||||
|
||||
m_buyer_id = 0;
|
||||
|
||||
SetBotPulling(false);
|
||||
SetBotPrecombat(false);
|
||||
|
||||
@@ -429,8 +430,9 @@ Client::~Client() {
|
||||
TraderEndTrader();
|
||||
}
|
||||
|
||||
if(Buyer)
|
||||
if(IsBuyer()) {
|
||||
ToggleBuyerMode(false);
|
||||
}
|
||||
|
||||
if(conn_state != ClientConnectFinished) {
|
||||
LogDebug("Client [{}] was destroyed before reaching the connected state:", GetName());
|
||||
@@ -2163,12 +2165,13 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
Mob::FillSpawnStruct(ns, ForWho);
|
||||
|
||||
// Populate client-specific spawn information
|
||||
ns->spawn.afk = AFK;
|
||||
ns->spawn.lfg = LFG; // afk and lfg are cleared on zoning on live
|
||||
ns->spawn.anon = m_pp.anon;
|
||||
ns->spawn.gm = GetGM() ? 1 : 0;
|
||||
ns->spawn.guildID = GuildID();
|
||||
ns->spawn.trader = IsTrader();
|
||||
ns->spawn.afk = AFK;
|
||||
ns->spawn.lfg = LFG; // afk and lfg are cleared on zoning on live
|
||||
ns->spawn.anon = m_pp.anon;
|
||||
ns->spawn.gm = GetGM() ? 1 : 0;
|
||||
ns->spawn.guildID = GuildID();
|
||||
ns->spawn.trader = IsTrader();
|
||||
ns->spawn.buyer = IsBuyer();
|
||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
||||
ns->spawn.show_name = true;
|
||||
@@ -11993,7 +11996,7 @@ void Client::SendPath(Mob* target)
|
||||
target->IsClient() &&
|
||||
(
|
||||
target->CastToClient()->IsTrader() ||
|
||||
target->CastToClient()->Buyer
|
||||
target->CastToClient()->IsBuyer()
|
||||
)
|
||||
) {
|
||||
Message(
|
||||
@@ -12597,3 +12600,104 @@ void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::AddMoneyToPPWithOverflow(uint64 copper, bool update_client)
|
||||
{
|
||||
//I noticed in the ROF2 client that the client auto updates the currency values using overflow
|
||||
//Therefore, I created this method to ensure that the db matches and clients don't see 10 pp 5 gp
|
||||
//becoming 9pp 15 gold with the current AddMoneyToPP method.
|
||||
|
||||
auto add_pp = copper / 1000;
|
||||
auto add_gp = (copper - add_pp * 1000) / 100;
|
||||
auto add_sp = (copper - add_pp * 1000 - add_gp * 100) / 10;
|
||||
auto add_cp = copper - add_pp * 1000 - add_gp * 100 - add_sp * 10;
|
||||
|
||||
m_pp.copper += add_cp;
|
||||
if (m_pp.copper >= 10) {
|
||||
m_pp.silver += m_pp.copper / 10;
|
||||
m_pp.copper = m_pp.copper % 10;
|
||||
}
|
||||
|
||||
m_pp.silver += add_sp;
|
||||
if (m_pp.silver >= 10) {
|
||||
m_pp.gold += m_pp.silver / 10;
|
||||
m_pp.silver = m_pp.silver % 10;
|
||||
}
|
||||
|
||||
m_pp.gold += add_gp;
|
||||
if (m_pp.gold >= 10) {
|
||||
m_pp.platinum += m_pp.gold / 10;
|
||||
m_pp.gold = m_pp.gold % 10;
|
||||
}
|
||||
|
||||
m_pp.platinum += add_pp;
|
||||
|
||||
if (update_client) {
|
||||
SendMoneyUpdate();
|
||||
}
|
||||
|
||||
RecalcWeight();
|
||||
SaveCurrency();
|
||||
|
||||
LogDebug("Client::AddMoneyToPPWithOverflow() [{}] should have: plat:[{}] gold:[{}] silver:[{}] copper:[{}]",
|
||||
GetName(),
|
||||
m_pp.platinum,
|
||||
m_pp.gold,
|
||||
m_pp.silver,
|
||||
m_pp.copper
|
||||
);
|
||||
}
|
||||
|
||||
bool Client::TakeMoneyFromPPWithOverFlow(uint64 copper, bool update_client)
|
||||
{
|
||||
int32 remove_pp = copper / 1000;
|
||||
int32 remove_gp = (copper - remove_pp * 1000) / 100;
|
||||
int32 remove_sp = (copper - remove_pp * 1000 - remove_gp * 100) / 10;
|
||||
int32 remove_cp = copper - remove_pp * 1000 - remove_gp * 100 - remove_sp * 10;
|
||||
|
||||
uint64 current_money = GetCarriedMoney();
|
||||
|
||||
if (copper > current_money) {
|
||||
return false; //client does not have enough money on them
|
||||
}
|
||||
|
||||
m_pp.copper -= remove_cp;
|
||||
if (m_pp.copper < 0) {
|
||||
m_pp.silver -= 1;
|
||||
m_pp.copper = m_pp.copper + 10;
|
||||
if (m_pp.copper >= 10) {
|
||||
m_pp.silver += m_pp.copper / 10;
|
||||
m_pp.copper = m_pp.copper % 10;
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.silver -= remove_sp;
|
||||
if (m_pp.silver < 0) {
|
||||
m_pp.gold -= 1;
|
||||
m_pp.silver = m_pp.silver + 10;
|
||||
if (m_pp.silver >= 10) {
|
||||
m_pp.gold += m_pp.silver / 10;
|
||||
m_pp.silver = m_pp.silver % 10;
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.gold -= remove_gp;
|
||||
if (m_pp.gold < 0) {
|
||||
m_pp.platinum -= 1;
|
||||
m_pp.gold = m_pp.gold + 10;
|
||||
if (m_pp.gold >= 10) {
|
||||
m_pp.platinum += m_pp.gold / 10;
|
||||
m_pp.gold = m_pp.gold % 10;
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.platinum -= remove_pp;
|
||||
|
||||
if (update_client) {
|
||||
SendMoneyUpdate();
|
||||
}
|
||||
|
||||
SaveCurrency();
|
||||
RecalcWeight();
|
||||
return true;
|
||||
}
|
||||
+35
-7
@@ -71,6 +71,7 @@ namespace EQ
|
||||
#include "../common/repositories/character_parcels_repository.h"
|
||||
#include "../common/repositories/trader_repository.h"
|
||||
#include "../common/guild_base.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// since windows defines these within windef.h (which windows.h include)
|
||||
@@ -289,6 +290,7 @@ public:
|
||||
void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||
void SendBazaarDone(uint32 trader_id);
|
||||
void SendBulkBazaarTraders();
|
||||
void SendBulkBazaarBuyers();
|
||||
void DoBazaarInspect(const BazaarInspect_Struct &in);
|
||||
void SendBazaarDeliveryCosts();
|
||||
static std::string DetermineMoneyString(uint64 copper);
|
||||
@@ -308,8 +310,10 @@ public:
|
||||
bool TryStacking(EQ::ItemInstance* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true);
|
||||
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
||||
void SendBuyerPacket(Client* Buyer);
|
||||
void SendBuyerToBarterWindow(Client* buyer, uint32 action);
|
||||
GetItems_Struct* GetTraderItems();
|
||||
void SendBazaarWelcome();
|
||||
void SendBarterWelcome();
|
||||
void DyeArmor(EQ::TintProfile* dye);
|
||||
void DyeArmorBySlot(uint8 slot, uint8 red, uint8 green, uint8 blue, uint8 use_tint = 0x00);
|
||||
uint8 SlotConvert(uint8 slot,bool bracer=false);
|
||||
@@ -376,14 +380,35 @@ public:
|
||||
uint32 GetCustomerID() { return customer_id; }
|
||||
void SetCustomerID(uint32 id) { customer_id = id; }
|
||||
|
||||
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
||||
void SetBuyerID(uint32 id) { m_buyer_id = id; }
|
||||
uint32 GetBuyerID() { return m_buyer_id; }
|
||||
bool IsBuyer() { return m_buyer_id != 0 ? true : false; }
|
||||
void SetBarterTime() { m_barter_time = time(nullptr); }
|
||||
uint32 GetBarterTime() { return m_barter_time; }
|
||||
void SetBuyerWelcomeMessage(const char* welcome_message);
|
||||
void SendBuyerGreeting(uint32 char_id);
|
||||
void SendSellerBrowsing(const std::string &browser);
|
||||
void SendBuyerMode(bool status);
|
||||
bool IsInBuyerSpace();
|
||||
void SendBuyLineUpdate(const BuyerLineItems_Struct &buy_line);
|
||||
void CheckIfMovedItemIsPartOfBuyLines(uint32 item_id);
|
||||
|
||||
void SendBuyerResults(BarterSearchRequest_Struct& bsr);
|
||||
void ShowBuyLines(const EQApplicationPacket *app);
|
||||
void SellToBuyer(const EQApplicationPacket *app);
|
||||
void ToggleBuyerMode(bool TurnOn);
|
||||
void UpdateBuyLine(const EQApplicationPacket *app);
|
||||
void ModifyBuyLine(const EQApplicationPacket *app);
|
||||
void CreateStartingBuyLines(const EQApplicationPacket *app);
|
||||
void BuyerItemSearch(const EQApplicationPacket *app);
|
||||
void SetBuyerWelcomeMessage(const char* WelcomeMessage) { BuyerWelcomeMessage = WelcomeMessage; }
|
||||
const char* GetBuyerWelcomeMessage() { return BuyerWelcomeMessage.c_str(); }
|
||||
void SendWindowUpdatesToSellerAndBuyer(BuyerLineSellItem_Struct& blsi);
|
||||
void SendBarterBuyerClientMessage(BuyerLineSellItem_Struct& blsi, BarterBuyerActions action, BarterBuyerSubActions sub_action, BarterBuyerSubActions error_code);
|
||||
bool BuildBuyLineMap(std::map<uint32, BuylineItemDetails_Struct>& item_map, BuyerBuyLines_Struct& bl);
|
||||
bool BuildBuyLineMapFromVector(std::map<uint32, BuylineItemDetails_Struct>& item_map, std::vector<BuyerLineItems_Struct>& bl);
|
||||
void RemoveItemFromBuyLineMap(std::map<uint32, BuylineItemDetails_Struct>& item_map, const BuyerLineItems_Struct& bl);
|
||||
bool ValidateBuyLineItems(std::map<uint32, BuylineItemDetails_Struct>& item_map);
|
||||
int64 ValidateBuyLineCost(std::map<uint32, BuylineItemDetails_Struct>& item_map);
|
||||
bool DoBarterBuyerChecks(BuyerLineSellItem_Struct& sell_line);
|
||||
bool DoBarterSellerChecks(BuyerLineSellItem_Struct& sell_line);
|
||||
|
||||
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
bool ShouldISpawnFor(Client *c) { return !GMHideMe(c) && !IsHoveringForRespawn(); }
|
||||
@@ -827,9 +852,11 @@ public:
|
||||
void QuestReadBook(const char* text, uint8 type);
|
||||
void SendMoneyUpdate();
|
||||
bool TakeMoneyFromPP(uint64 copper, bool update_client = false);
|
||||
bool TakeMoneyFromPPWithOverFlow(uint64 copper, bool update_client);
|
||||
bool TakePlatinum(uint32 platinum, bool update_client = false);
|
||||
void AddMoneyToPP(uint64 copper, bool update_client = false);
|
||||
void AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client = false);
|
||||
void AddMoneyToPPWithOverflow(uint64 copper, bool update_client);
|
||||
void AddPlatinum(uint32 platinu, bool update_client = false);
|
||||
bool HasMoney(uint64 copper);
|
||||
uint64 GetCarriedMoney();
|
||||
@@ -1058,6 +1085,8 @@ public:
|
||||
int32 GetItemIDAt(int16 slot_id);
|
||||
int32 GetAugmentIDAt(int16 slot_id, uint8 augslot);
|
||||
bool PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, bool client_update = false);
|
||||
bool PutItemInInventoryWithStacking(EQ::ItemInstance* inst);
|
||||
bool FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items);
|
||||
bool PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update = false);
|
||||
void SendCursorBuffer();
|
||||
void DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true);
|
||||
@@ -1096,7 +1125,6 @@ public:
|
||||
uint16 GetTraderID() { return trader_id; }
|
||||
void SetTraderID(uint16 id) { trader_id = id; }
|
||||
|
||||
inline bool IsBuyer() const { return(Buyer); }
|
||||
eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; }
|
||||
void SetFilter(eqFilterType filter_id, eqFilterMode filter_mode) { ClientFilters[filter_id] = filter_mode; }
|
||||
|
||||
@@ -1913,8 +1941,8 @@ private:
|
||||
uint8 firstlogon;
|
||||
uint32 mercid; // current merc
|
||||
uint8 mercSlot; // selected merc slot
|
||||
bool Buyer;
|
||||
std::string BuyerWelcomeMessage;
|
||||
uint32 m_buyer_id;
|
||||
uint32 m_barter_time;
|
||||
int32 m_parcel_platinum;
|
||||
int32 m_parcel_gold;
|
||||
int32 m_parcel_silver;
|
||||
|
||||
+89
-93
@@ -65,6 +65,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/repositories/account_repository.h"
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/guild_tributes_repository.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/character_stats_record_repository.h"
|
||||
@@ -758,8 +759,6 @@ void Client::CompleteConnect()
|
||||
|
||||
entity_list.SendIllusionWearChange(this);
|
||||
|
||||
entity_list.SendTraders(this);
|
||||
|
||||
SendWearChangeAndLighting(EQ::textures::LastTexture);
|
||||
Mob* pet = GetPet();
|
||||
if (pet) {
|
||||
@@ -3759,116 +3758,104 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
char* Buf = (char *)app->pBuffer;
|
||||
auto in = (BuyerGeneric_Struct *)app->pBuffer;
|
||||
|
||||
// The first 4 bytes of the packet determine the action. A lot of Barter packets require the
|
||||
// packet the client sent, sent back to it as an acknowledgement.
|
||||
//
|
||||
uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buf);
|
||||
//uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buf);
|
||||
|
||||
|
||||
switch (Action)
|
||||
{
|
||||
switch (in->action) {
|
||||
|
||||
case Barter_BuyerSearch:
|
||||
{
|
||||
BuyerItemSearch(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_SellerSearch:
|
||||
{
|
||||
BarterSearchRequest_Struct *bsr = (BarterSearchRequest_Struct*)app->pBuffer;
|
||||
SendBuyerResults(bsr->SearchString, bsr->SearchID);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerModeOn:
|
||||
{
|
||||
if (!IsTrader()) {
|
||||
ToggleBuyerMode(true);
|
||||
case Barter_BuyerSearch: {
|
||||
BuyerItemSearch(app);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
Buf = (char *)app->pBuffer;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerModeOff);
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
|
||||
case Barter_SellerSearch: {
|
||||
auto bsr = (BarterSearchRequest_Struct *) app->pBuffer;
|
||||
SendBuyerResults(*bsr);
|
||||
break;
|
||||
}
|
||||
QueuePacket(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerModeOff:
|
||||
{
|
||||
QueuePacket(app);
|
||||
ToggleBuyerMode(false);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerModeOn: {
|
||||
if (!IsTrader()) {
|
||||
ToggleBuyerMode(true);
|
||||
}
|
||||
else {
|
||||
ToggleBuyerMode(false);
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerItemUpdate:
|
||||
{
|
||||
UpdateBuyLine(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerModeOff: {
|
||||
ToggleBuyerMode(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerItemRemove:
|
||||
{
|
||||
BuyerRemoveItem_Struct* bris = (BuyerRemoveItem_Struct*)app->pBuffer;
|
||||
database.RemoveBuyLine(CharacterID(), bris->BuySlot);
|
||||
QueuePacket(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemUpdate: {
|
||||
ModifyBuyLine(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_SellItem:
|
||||
{
|
||||
SellToBuyer(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemStart: {
|
||||
CreateStartingBuyLines(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerInspectBegin:
|
||||
{
|
||||
ShowBuyLines(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemRemove: {
|
||||
auto bris = (BuyerRemoveItem_Struct *) app->pBuffer;
|
||||
BuyerBuyLinesRepository::DeleteBuyLine(database, CharacterID(), bris->buy_slot_id);
|
||||
QueuePacket(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerInspectEnd:
|
||||
{
|
||||
BuyerInspectRequest_Struct* bir = (BuyerInspectRequest_Struct*)app->pBuffer;
|
||||
Client *Buyer = entity_list.GetClientByID(bir->BuyerID);
|
||||
if (Buyer)
|
||||
Buyer->WithCustomer(0);
|
||||
case Barter_SellItem: {
|
||||
SellToBuyer(app);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerInspectBegin: {
|
||||
ShowBuyLines(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BarterItemInspect:
|
||||
{
|
||||
BarterItemSearchLinkRequest_Struct* bislr = (BarterItemSearchLinkRequest_Struct*)app->pBuffer;
|
||||
case Barter_BuyerInspectEnd: {
|
||||
auto bir = (BuyerInspectRequest_Struct *) app->pBuffer;
|
||||
auto buyer = entity_list.GetClientByID(bir->buyer_id);
|
||||
if (buyer) {
|
||||
buyer->WithCustomer(0);
|
||||
}
|
||||
|
||||
const EQ::ItemData* item = database.GetItem(bislr->ItemID);
|
||||
break;
|
||||
}
|
||||
case Barter_BarterItemInspect: {
|
||||
auto bislr = (BarterItemSearchLinkRequest_Struct *) app->pBuffer;
|
||||
const EQ::ItemData *item = database.GetItem(bislr->item_id);
|
||||
|
||||
if (!item)
|
||||
Message(Chat::Red, "Error: This item does not exist!");
|
||||
else
|
||||
{
|
||||
EQ::ItemInstance* inst = database.CreateItem(item);
|
||||
if (inst)
|
||||
{
|
||||
if (!item) {
|
||||
Message(Chat::Red, "Error: This item does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *inst = database.CreateItem(item);
|
||||
if (inst) {
|
||||
SendItemPacket(0, inst, ItemPacketViewLink);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_Welcome:
|
||||
{
|
||||
//SendBazaarWelcome();
|
||||
SendBarterWelcome();
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_WelcomeMessageUpdate:
|
||||
{
|
||||
BuyerWelcomeMessageUpdate_Struct* bwmu = (BuyerWelcomeMessageUpdate_Struct*)app->pBuffer;
|
||||
SetBuyerWelcomeMessage(bwmu->WelcomeMessage);
|
||||
case Barter_WelcomeMessageUpdate: {
|
||||
auto bwmu = (BuyerWelcomeMessageUpdate_Struct *) app->pBuffer;
|
||||
SetBuyerWelcomeMessage(bwmu->welcome_message);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3892,15 +3879,20 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_Unknown23:
|
||||
case Barter_Greeting:
|
||||
{
|
||||
// Sent by SoD client for no discernible reason.
|
||||
auto data = (BuyerGreeting_Struct *)app->pBuffer;
|
||||
SendBuyerGreeting(data->buyer_id);
|
||||
}
|
||||
case Barter_OpenBarterWindow:
|
||||
{
|
||||
SendBulkBazaarBuyers();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Message(Chat::Red, "Unrecognised Barter action.");
|
||||
LogTrading("Unrecognised Barter Action [{}]", Action);
|
||||
LogTrading("Unrecognised Barter Action [{}]", in->action);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4982,6 +4974,10 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
TraderEndTrader();
|
||||
}
|
||||
|
||||
if (IsBuyer()) {
|
||||
ToggleBuyerMode(false);
|
||||
}
|
||||
|
||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||
if ((hidden || improved_hidden) && !sneaking) {
|
||||
hidden = false;
|
||||
@@ -15640,7 +15636,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
case TraderOn: {
|
||||
if (Buyer) {
|
||||
if (IsBuyer()) {
|
||||
TraderEndTrader();
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
return;
|
||||
@@ -15686,7 +15682,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
auto trader = entity_list.GetClientByID(in->trader_id);
|
||||
|
||||
switch (in->method) {
|
||||
case ByVendor: {
|
||||
case BazaarByVendor: {
|
||||
if (trader) {
|
||||
LogTrading("Buy item directly from vendor id <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||
"serial_number <green>[{}]",
|
||||
@@ -15699,7 +15695,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ByParcel: {
|
||||
case BazaarByParcel: {
|
||||
if (!RuleB(Parcel, EnableParcelMerchants) || !RuleB(Bazaar, EnableParcelDelivery)) {
|
||||
LogTrading(
|
||||
"Bazaar purchase attempt by parcel delivery though 'Parcel:EnableParcelMerchants' or "
|
||||
@@ -15709,7 +15705,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
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->method = BazaarByParcel;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
@@ -15724,7 +15720,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
BuyTraderItemOutsideBazaar(in, app);
|
||||
break;
|
||||
}
|
||||
case ByDirectToInventory: {
|
||||
case BazaarByDirectToInventory: {
|
||||
if (!RuleB(Parcel, EnableDirectToInventoryDelivery)) {
|
||||
LogTrading("Bazaar purchase attempt by direct inventory delivery though "
|
||||
"'Parcel:EnableDirectToInventoryDelivery' not enabled."
|
||||
@@ -15733,7 +15729,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
Chat::Yellow,
|
||||
"Direct inventory delivey is not enabled on this server. Please visit the vendor directly."
|
||||
);
|
||||
in->method = ByDirectToInventory;
|
||||
in->method = BazaarByDirectToInventory;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
@@ -15750,7 +15746,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
Chat::Yellow,
|
||||
"Direct inventory delivey is not yet implemented. Please visit the vendor directly or purchase via parcel delivery."
|
||||
);
|
||||
in->method = ByDirectToInventory;
|
||||
in->method = BazaarByDirectToInventory;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
break;
|
||||
|
||||
@@ -1864,6 +1864,10 @@ 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());
|
||||
dstitemid = dst_inst->GetItem()->ID;
|
||||
}
|
||||
if (IsBuyer() && srcitemid > 0) {
|
||||
CheckIfMovedItemIsPartOfBuyLines(srcitemid);
|
||||
}
|
||||
|
||||
if (IsTrader() && srcitemid>0){
|
||||
EQ::ItemInstance* srcbag;
|
||||
EQ::ItemInstance* dstbag;
|
||||
@@ -4850,3 +4854,63 @@ bool Client::HasItemOnCorpse(uint32 item_id)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::PutItemInInventoryWithStacking(EQ::ItemInstance *inst)
|
||||
{
|
||||
auto free_id = GetInv().FindFirstFreeSlotThatFitsItem(inst->GetItem());
|
||||
if (inst->IsStackable()) {
|
||||
if (TryStacking(inst, ItemPacketTrade, true, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (free_id != INVALID_INDEX) {
|
||||
if (PutItemInInventory(free_id, *inst, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
bool Client::FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items)
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (int16 i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||
if ((((uint64) 1 << i) & GetInv().GetLookup()->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *inv_item = GetInv().GetItem(i);
|
||||
|
||||
if (!inv_item) {
|
||||
// Found available slot in personal inventory. Fits all sizes
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count >= items.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inv_item->IsClassBag()) {
|
||||
for (auto const& item:items) {
|
||||
auto item_tmp = database.GetItem(item.item_id);
|
||||
if (EQ::InventoryProfile::CanItemFitInContainer(item_tmp, inv_item->GetItem())) {
|
||||
int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN);
|
||||
uint8 bag_size = inv_item->GetItem()->BagSlots;
|
||||
|
||||
for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||
auto bag_item = GetInv().GetItem(base_slot_id + bag_slot);
|
||||
if (!bag_item) {
|
||||
// Found a bag slot that fits the item
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count >= items.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <cmath>
|
||||
#include "../common/strings.h"
|
||||
#include "../common/data_verification.h"
|
||||
#include <numbers>
|
||||
#include "../common/types.h"
|
||||
|
||||
constexpr float position_eps = 0.0001f;
|
||||
|
||||
@@ -282,3 +284,54 @@ float CalculateHeadingAngleBetweenPositions(float x1, float y1, float x2, float
|
||||
return (90.0f - angle + 270.0f) * 511.5f * 0.0027777778f;
|
||||
}
|
||||
}
|
||||
bool IsWithinCircularArc(glm::vec4 arc_center, glm::vec4 point, uint32 arc_offset, uint32 arc_radius, uint32 arc_radius_limit)
|
||||
{
|
||||
auto CheckClockwise = [](double v_x, double v_y, double check_x, double check_y) -> bool {
|
||||
return -v_y * check_x + v_x * check_y >= 0;
|
||||
};
|
||||
|
||||
auto CheckRadiusLimit = [](double check_x, double check_y, uint32 radius, uint32 radius_limit) -> bool {
|
||||
auto w = check_x * check_x + check_y * check_y;
|
||||
if (w >= radius_limit * radius_limit && w <= radius * radius) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto DegreesToRadians = [](float in) -> double {
|
||||
return in / 180.0f * std::numbers::pi;
|
||||
};
|
||||
|
||||
auto h = arc_center.w / 512.0f * 360.0f + arc_offset;
|
||||
auto a = DegreesToRadians(h);
|
||||
|
||||
auto vs_x = -arc_radius * cos(a);
|
||||
auto vs_y = arc_radius * sin(a);
|
||||
|
||||
h += 90;
|
||||
a = DegreesToRadians(h);
|
||||
auto ve_x = -arc_radius * cos(a);
|
||||
auto ve_y = arc_radius * sin(a);
|
||||
|
||||
double check_x = point.x - arc_center.x;
|
||||
double check_y = point.y - arc_center.y;
|
||||
|
||||
return CheckClockwise(vs_x, vs_y, check_x, check_y) && CheckRadiusLimit(check_x, check_y, arc_radius, arc_radius_limit) && !CheckClockwise(ve_x, ve_y, check_x, check_y);
|
||||
}
|
||||
|
||||
bool IsWithinSquare(glm::vec4 center, uint32 area, glm::vec4 position) {
|
||||
auto l = std::abs(std::sqrt(area));
|
||||
if (l <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto x_min = center.x - l;
|
||||
auto x_max = center.x + l;
|
||||
auto y_min = center.y - l;
|
||||
auto y_max = center.y + l;
|
||||
|
||||
auto x = position.x;
|
||||
auto y = position.y;
|
||||
|
||||
return x > x_min && x < x_max && y > y_min && y < y_max;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/geometric.hpp>
|
||||
#include "../common/types.h"
|
||||
|
||||
std::string to_string(const glm::vec4 &position);
|
||||
std::string to_string(const glm::vec3 &position);
|
||||
@@ -62,4 +63,7 @@ bool IsPositionWithinSimpleCylinder(const glm::vec4 &p1, const glm::vec4 &cylind
|
||||
|
||||
float CalculateHeadingAngleBetweenPositions(float x1, float y1, float x2, float y2);
|
||||
|
||||
bool IsWithinCircularArc(glm::vec4 arc_center, glm::vec4 point, uint32 arc_offset, uint32 arc_radius, uint32 arc_radius_limit);
|
||||
bool IsWithinSquare(glm::vec4 center, uint32 area, glm::vec4 position);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -413,6 +413,8 @@
|
||||
#define MAX_ACTIVE_TASKS 6010 //Sorry %3, you already have the maximum number of active tasks.
|
||||
#define TASK_REQUEST_COOLDOWN_TIMER 6011 //Sorry, %3, but you can't request another task for %4 minutes and %5 seconds.
|
||||
#define FORAGE_MASTERY 6012 //Your forage mastery has enabled you to find something else!
|
||||
#define BUYER_WELCOME 6065 //There are %1 Buyers waiting to purchase your loot. Type /barter to search for them, or use /buyer to set up your own Buy Lines.
|
||||
#define BUYER_GREETING 6070 //%1 greets you, '%2'
|
||||
#define GUILD_BANK_CANNOT_DEPOSIT 6097 // Cannot deposit this item. Containers must be empty, and only one of each LORE and no NO TRADE or TEMPORARY items may be deposited.
|
||||
#define GUILD_BANK_FULL 6098 // There is no more room in the Guild Bank.
|
||||
#define GUILD_BANK_TRANSFERRED 6100 // '%1' transferred to Guild Bank from Deposits.
|
||||
|
||||
+1274
-616
File diff suppressed because it is too large
Load Diff
@@ -3997,6 +3997,310 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_BuyerMessaging: {
|
||||
auto in = (BuyerMessaging_Struct *) pack->pBuffer;
|
||||
|
||||
switch (in->action) {
|
||||
case Barter_AddToBarterWindow: {
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||
OP_Barter,
|
||||
sizeof(BuyerAddBuyertoBarterWindow_Struct)
|
||||
);
|
||||
auto emu = (BuyerAddBuyertoBarterWindow_Struct *) outapp->pBuffer;
|
||||
|
||||
emu->action = Barter_AddToBarterWindow;
|
||||
emu->buyer_entity_id = in->buyer_entity_id;
|
||||
emu->buyer_id = in->buyer_id;
|
||||
emu->zone_id = in->zone_id;
|
||||
strn0cpy(emu->buyer_name, in->buyer_name, sizeof(emu->buyer_name));
|
||||
|
||||
entity_list.QueueClients(nullptr, outapp.get());
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_RemoveFromBarterWindow: {
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||
OP_Barter,
|
||||
sizeof(BuyerRemoveBuyerFromBarterWindow_Struct)
|
||||
);
|
||||
auto emu = (BuyerRemoveBuyerFromBarterWindow_Struct *) outapp->pBuffer;
|
||||
|
||||
emu->action = Barter_RemoveFromBarterWindow;
|
||||
emu->buyer_id = in->buyer_id;
|
||||
|
||||
entity_list.QueueClients(nullptr, outapp.get());
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_FailedTransaction: {
|
||||
auto seller = entity_list.GetClientByID(in->seller_entity_id);
|
||||
auto buyer = entity_list.GetClientByID(in->buyer_entity_id);
|
||||
|
||||
BuyerLineSellItem_Struct sell_line{};
|
||||
sell_line.item_id = in->buy_item_id;
|
||||
sell_line.item_quantity = in->buy_item_qty;
|
||||
sell_line.item_cost = in->buy_item_cost;
|
||||
sell_line.seller_name = in->seller_name;
|
||||
sell_line.buyer_name = in->buyer_name;
|
||||
sell_line.seller_quantity = in->seller_quantity;
|
||||
sell_line.slot = in->slot;
|
||||
strn0cpy(sell_line.item_name, in->item_name, sizeof(sell_line.item_name));
|
||||
|
||||
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
|
||||
std::unique_ptr<EQ::ItemInstance> inst(database.CreateItem(in->buy_item_id, in->seller_quantity));
|
||||
|
||||
switch (in->sub_action) {
|
||||
case Barter_FailedBuyerChecks:
|
||||
case Barter_FailedSellerChecks: {
|
||||
if (seller) {
|
||||
LogTradingDetail("Significant barter transaction failure.");
|
||||
seller->Message(
|
||||
Chat::Red,
|
||||
"Significant barter transaction error. Transaction rolled back."
|
||||
);
|
||||
seller->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_SellerTransactionComplete,
|
||||
Barter_Failure,
|
||||
Barter_Failure
|
||||
);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
|
||||
PlayerEvent::BarterTransaction e{};
|
||||
e.status = "Failed Barter Transaction";
|
||||
e.item_id = sell_line.item_id;
|
||||
e.item_quantity = sell_line.seller_quantity;
|
||||
e.item_name = sell_line.item_name;
|
||||
e.trade_items = sell_line.trade_items;
|
||||
for (auto &i: e.trade_items) {
|
||||
i *= sell_line.seller_quantity;
|
||||
}
|
||||
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
|
||||
e.buyer_name = sell_line.buyer_name;
|
||||
e.seller_name = sell_line.seller_name;
|
||||
RecordPlayerEventLogWithClient(seller, PlayerEvent::BARTER_TRANSACTION, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (buyer) {
|
||||
LogError("Significant barter transaction failure. Replacing {} and {} {} to {}",
|
||||
buyer->DetermineMoneyString(total_cost),
|
||||
sell_line.seller_quantity,
|
||||
sell_line.item_name,
|
||||
buyer->GetCleanName());
|
||||
buyer->AddMoneyToPPWithOverflow(total_cost, true);
|
||||
buyer->RemoveItem(sell_line.item_id, sell_line.seller_quantity);
|
||||
|
||||
buyer->Message(
|
||||
Chat::Red,
|
||||
"Significant barter transaction error. Transaction rolled back."
|
||||
);
|
||||
buyer->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_BuyerTransactionComplete,
|
||||
Barter_Failure,
|
||||
Barter_Failure
|
||||
);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
|
||||
PlayerEvent::BarterTransaction e{};
|
||||
e.status = "Failed Barter Transaction";
|
||||
e.item_id = sell_line.item_id;
|
||||
e.item_quantity = sell_line.seller_quantity;
|
||||
e.item_name = sell_line.item_name;
|
||||
e.trade_items = sell_line.trade_items;
|
||||
for (auto &i: e.trade_items) {
|
||||
i *= sell_line.seller_quantity;
|
||||
}
|
||||
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
|
||||
e.buyer_name = sell_line.buyer_name;
|
||||
e.seller_name = sell_line.seller_name;
|
||||
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (seller) {
|
||||
seller->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_SellerTransactionComplete,
|
||||
Barter_Failure,
|
||||
Barter_Failure
|
||||
);
|
||||
}
|
||||
|
||||
if (buyer) {
|
||||
buyer->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_BuyerTransactionComplete,
|
||||
Barter_Failure,
|
||||
Barter_Failure
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Barter_SellItem: {
|
||||
auto buyer = entity_list.GetClientByID(in->buyer_entity_id);
|
||||
if (!buyer) {
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_BuyerCouldNotBeFound;
|
||||
worldserver.SendPacket(pack);
|
||||
return;
|
||||
}
|
||||
|
||||
BuyerLineSellItem_Struct sell_line{};
|
||||
sell_line.item_id = in->buy_item_id;
|
||||
sell_line.item_quantity = in->buy_item_qty;
|
||||
sell_line.item_cost = in->buy_item_cost;
|
||||
sell_line.seller_name = in->seller_name;
|
||||
sell_line.buyer_name = in->buyer_name;
|
||||
sell_line.buyer_entity_id = in->buyer_entity_id;
|
||||
sell_line.seller_quantity = in->seller_quantity;
|
||||
sell_line.slot = in->slot;
|
||||
strn0cpy(sell_line.item_name, in->item_name, sizeof(sell_line.item_name));
|
||||
|
||||
if (!buyer->DoBarterBuyerChecks(sell_line)) {
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
|
||||
BuyerLineSellItem_Struct blis{};
|
||||
blis.enabled = 1;
|
||||
blis.item_toggle = 1;
|
||||
blis.item_cost = in->buy_item_cost;
|
||||
blis.item_id = in->buy_item_id;
|
||||
blis.item_quantity = in->buy_item_qty;
|
||||
blis.item_icon = in->buy_item_icon;
|
||||
blis.slot = in->slot;
|
||||
blis.seller_quantity = in->seller_quantity;
|
||||
blis.buyer_entity_id = in->buyer_entity_id;
|
||||
strn0cpy(blis.item_name, in->item_name, sizeof(blis.item_name));
|
||||
|
||||
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
|
||||
std::unique_ptr<EQ::ItemInstance> inst(database.CreateItem(in->buy_item_id, in->seller_quantity));
|
||||
|
||||
if (inst->IsStackable()) {
|
||||
if (!buyer->PutItemInInventoryWithStacking(inst.get())) {
|
||||
buyer->Message(Chat::Red, "Error putting item in your inventory.");
|
||||
buyer->AddMoneyToPPWithOverflow(total_cost, true);
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 1; i <= sell_line.seller_quantity; i++) {
|
||||
inst->SetCharges(1);
|
||||
if (!buyer->PutItemInInventoryWithStacking(inst.get())) {
|
||||
buyer->Message(Chat::Red, "Error putting item in your inventory.");
|
||||
buyer->AddMoneyToPPWithOverflow(total_cost, true);
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
goto exit_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!buyer->TakeMoneyFromPPWithOverFlow(total_cost, false)) {
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
|
||||
buyer->SendWindowUpdatesToSellerAndBuyer(blis);
|
||||
buyer->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_BuyerTransactionComplete,
|
||||
Barter_Success,
|
||||
Barter_Success
|
||||
);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
|
||||
PlayerEvent::BarterTransaction e{};
|
||||
e.status = "Successful Barter Transaction";
|
||||
e.item_id = sell_line.item_id;
|
||||
e.item_quantity = sell_line.seller_quantity;
|
||||
e.item_name = sell_line.item_name;
|
||||
e.trade_items = sell_line.trade_items;
|
||||
for (auto &i: e.trade_items) {
|
||||
i *= sell_line.seller_quantity;
|
||||
}
|
||||
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
|
||||
e.buyer_name = sell_line.buyer_name;
|
||||
e.seller_name = sell_line.seller_name;
|
||||
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
|
||||
}
|
||||
|
||||
in->action = Barter_BuyerTransactionComplete;
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
exit_loop:
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerTransactionComplete: {
|
||||
auto seller = entity_list.GetClientByID(in->seller_entity_id);
|
||||
if (!seller) {
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_SellerCouldNotBeFound;
|
||||
worldserver.SendPacket(pack);
|
||||
return;
|
||||
}
|
||||
|
||||
BuyerLineSellItem_Struct sell_line{};
|
||||
sell_line.item_id = in->buy_item_id;
|
||||
sell_line.item_quantity = in->buy_item_qty;
|
||||
sell_line.item_cost = in->buy_item_cost;
|
||||
sell_line.seller_name = in->seller_name;
|
||||
sell_line.buyer_name = in->buyer_name;
|
||||
sell_line.seller_quantity = in->seller_quantity;
|
||||
sell_line.slot = in->slot;
|
||||
strn0cpy(sell_line.item_name, in->item_name, sizeof(sell_line.item_name));
|
||||
|
||||
if (!seller->DoBarterSellerChecks(sell_line)) {
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->action = Barter_FailedSellerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
|
||||
seller->RemoveItem(in->buy_item_id, in->seller_quantity);
|
||||
seller->AddMoneyToPPWithOverflow(total_cost, false);
|
||||
seller->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_SellerTransactionComplete,
|
||||
Barter_Success,
|
||||
Barter_Success
|
||||
);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
|
||||
PlayerEvent::BarterTransaction e{};
|
||||
e.status = "Successful Barter Transaction";
|
||||
e.item_id = sell_line.item_id;
|
||||
e.item_quantity = sell_line.seller_quantity;
|
||||
e.item_name = sell_line.item_name;
|
||||
e.trade_items = sell_line.trade_items;
|
||||
for (auto &i: e.trade_items) {
|
||||
i *= sell_line.seller_quantity;
|
||||
}
|
||||
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
|
||||
e.buyer_name = sell_line.buyer_name;
|
||||
e.seller_name = sell_line.seller_name;
|
||||
RecordPlayerEventLogWithClient(seller, PlayerEvent::BARTER_TRANSACTION, e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int) pack->opcode, pack->size);
|
||||
break;
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#include "../common/repositories/alternate_currency_repository.h"
|
||||
#include "../common/repositories/graveyard_repository.h"
|
||||
#include "../common/repositories/trader_repository.h"
|
||||
#include "../common/repositories/buyer_repository.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
@@ -416,24 +416,6 @@ void ZoneDatabase::UpdateTraderItemPrice(int char_id, uint32 item_id, uint32 cha
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneDatabase::DeleteBuyLines(uint32 CharID) {
|
||||
|
||||
if(CharID==0) {
|
||||
const std::string query = "DELETE FROM buyer";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogDebug("[CLIENT] Failed to delete all buyer items data, the error was: [{}]\n",results.ErrorMessage().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string query = StringFormat("DELETE FROM buyer WHERE charid = %i", CharID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogDebug("[CLIENT] Failed to delete buyer item data for charid: [{}], the error was: [{}]\n",CharID,results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
void ZoneDatabase::AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, const char* ItemName, uint32 Quantity, uint32 Price) {
|
||||
std::string query = StringFormat("REPLACE INTO buyer VALUES(%i, %i, %i, \"%s\", %i, %i)",
|
||||
CharID, BuySlot, ItemID, ItemName, Quantity, Price);
|
||||
|
||||
@@ -400,7 +400,6 @@ public:
|
||||
/* Buyer/Barter */
|
||||
void AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, const char *ItemName, uint32 Quantity, uint32 Price);
|
||||
void RemoveBuyLine(uint32 CharID, uint32 BuySlot);
|
||||
void DeleteBuyLines(uint32 CharID);
|
||||
void UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user