mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 09:06:46 +00:00
Phase 1 Offline Trading
Cleanup and testing Zone updated builds ok World updated builds ok Update guild_base.h
This commit is contained in:
@@ -59,7 +59,7 @@ EQ::Net::WebsocketLoginStatus CheckLogin(
|
||||
|
||||
ret.account_name = database.GetAccountName(static_cast<uint32>(ret.account_id));
|
||||
ret.logged_in = true;
|
||||
ret.status = database.GetAccountStatus(ret.account_id);
|
||||
ret.status = database.GetAccountStatus(ret.account_id).status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+21
-12
@@ -510,10 +510,10 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
client_data_loaded = false;
|
||||
berserk = false;
|
||||
dead = false;
|
||||
eqs = ieqs;
|
||||
ip = eqs->GetRemoteIP();
|
||||
port = ntohs(eqs->GetRemotePort());
|
||||
client_state = CLIENT_CONNECTING;
|
||||
eqs = ieqs ? ieqs : nullptr;
|
||||
ip = eqs ? eqs->GetRemoteIP() : 0;
|
||||
port = eqs ? ntohs(eqs->GetRemotePort()) : 0;
|
||||
client_state = eqs ? CLIENT_CONNECTING : CLIENT_CONNECTED;
|
||||
SetTrader(false);
|
||||
Haste = 0;
|
||||
SetCustomerID(0);
|
||||
@@ -700,6 +700,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
m_parcels.clear();
|
||||
|
||||
m_buyer_id = 0;
|
||||
m_offline = false;
|
||||
|
||||
SetBotPulling(false);
|
||||
SetBotPrecombat(false);
|
||||
@@ -728,10 +729,12 @@ Client::~Client() {
|
||||
zone->ClearEXPModifier(this);
|
||||
}
|
||||
|
||||
if (!IsZoning()) {
|
||||
if(IsInAGuild()) {
|
||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
||||
if (!IsZoning() && IsInAGuild()) {
|
||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||
if (IsOffline()) {
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), GetZoneID(), time(nullptr), 1);
|
||||
} else {
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,11 +746,11 @@ Client::~Client() {
|
||||
if (merc)
|
||||
merc->Depop();
|
||||
|
||||
if(IsTrader()) {
|
||||
if(IsTrader() && !IsOffline()) {
|
||||
TraderEndTrader();
|
||||
}
|
||||
|
||||
if(IsBuyer()) {
|
||||
if(IsBuyer() && !IsOffline()) {
|
||||
ToggleBuyerMode(false);
|
||||
}
|
||||
|
||||
@@ -779,7 +782,9 @@ Client::~Client() {
|
||||
if(isgrouped && !bZoning && is_zone_loaded)
|
||||
LeaveGroup();
|
||||
|
||||
UpdateWho(2);
|
||||
if (!IsOffline() && !IsTrader()) {
|
||||
UpdateWho(2);
|
||||
}
|
||||
|
||||
if(IsHoveringForRespawn())
|
||||
{
|
||||
@@ -2155,6 +2160,9 @@ void Client::UpdateWho(uint8 remove)
|
||||
s->race = GetRace();
|
||||
s->class_ = GetClass();
|
||||
s->level = GetLevel();
|
||||
s->trader = IsTrader();
|
||||
s->buyer = IsBuyer();
|
||||
s->offline = IsOffline();
|
||||
|
||||
if (m_pp.anon == 0) {
|
||||
s->anon = 0;
|
||||
@@ -2223,7 +2231,7 @@ void Client::FriendsWho(char *FriendsString) {
|
||||
void Client::UpdateAdmin(bool from_database) {
|
||||
int16 tmp = admin;
|
||||
if (from_database) {
|
||||
admin = database.GetAccountStatus(account_id);
|
||||
admin = database.GetAccountStatus(account_id).status;
|
||||
}
|
||||
|
||||
if (tmp == admin && from_database) {
|
||||
@@ -2539,6 +2547,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.guildID = GuildID();
|
||||
ns->spawn.trader = IsTrader();
|
||||
ns->spawn.buyer = IsBuyer();
|
||||
ns->spawn.offline = IsOffline();
|
||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
||||
ns->spawn.show_name = true;
|
||||
|
||||
+71
-1
@@ -416,6 +416,8 @@ public:
|
||||
int32 FindNextFreeParcelSlot(uint32 char_id);
|
||||
int32 FindNextFreeParcelSlotUsingMemory();
|
||||
void SendParcelIconStatus();
|
||||
bool IsOffline() { return m_offline; }
|
||||
void SetOffline(bool status) { m_offline = status; }
|
||||
|
||||
void SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions action);
|
||||
void SendBecomeTrader(BazaarTraderBarterActions action, uint32 trader_id);
|
||||
@@ -508,7 +510,12 @@ public:
|
||||
inline bool ClientDataLoaded() const { return client_data_loaded; }
|
||||
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
|
||||
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); }
|
||||
inline void Disconnect() { eqs->Close(); client_state = DISCONNECTED; }
|
||||
inline void Disconnect() {
|
||||
if (eqs) {
|
||||
eqs->Close();
|
||||
client_state = DISCONNECTED;
|
||||
}
|
||||
}
|
||||
inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); }
|
||||
void Kick(const std::string &reason);
|
||||
void WorldKick();
|
||||
@@ -2117,6 +2124,7 @@ private:
|
||||
uint32 m_trader_count{};
|
||||
std::map<int16, std::tuple<uint32, int32, std::string>> m_trader_merchant_list{}; // itemid, qty, item_unique_id
|
||||
uint32 m_buyer_id;
|
||||
bool m_offline;
|
||||
uint32 m_barter_time;
|
||||
int32 m_parcel_platinum;
|
||||
int32 m_parcel_gold;
|
||||
@@ -2446,6 +2454,68 @@ public:
|
||||
bool IsFilteredAFKPacket(const EQApplicationPacket *p);
|
||||
void CheckAutoIdleAFK(PlayerPositionUpdateClient_Struct *p);
|
||||
void SyncWorldPositionsToClient(bool ignore_idle = false);
|
||||
|
||||
|
||||
Mob* GetMob() {
|
||||
return Mob::GetMob();
|
||||
}
|
||||
|
||||
void Clone(Client& in)
|
||||
{
|
||||
WID = in.WID;
|
||||
admin = in.admin;
|
||||
guild_id = in.guild_id;
|
||||
guildrank = in.guildrank;
|
||||
LFG = in.LFG;
|
||||
AFK = in.AFK;
|
||||
trader_id = in.trader_id;
|
||||
m_buyer_id = in.m_buyer_id;
|
||||
race = in.race;
|
||||
class_ = in.class_;
|
||||
size = in.size;
|
||||
deity = in.deity;
|
||||
texture = in.texture;
|
||||
m_ClientVersion = in.m_ClientVersion;
|
||||
m_ClientVersionBit = in.m_ClientVersionBit;
|
||||
character_id = in.character_id;
|
||||
account_id = in.account_id;
|
||||
lsaccountid = in.lsaccountid;
|
||||
|
||||
m_pp.platinum = in.m_pp.platinum;
|
||||
m_pp.gold = in.m_pp.gold;
|
||||
m_pp.silver = in.m_pp.silver;
|
||||
m_pp.copper = in.m_pp.copper;
|
||||
m_pp.platinum_bank = in.m_pp.platinum_bank;
|
||||
m_pp.gold_bank = in.m_pp.gold_bank;
|
||||
m_pp.silver_bank = in.m_pp.silver_bank;
|
||||
m_pp.copper_bank = in.m_pp.copper_bank;
|
||||
m_pp.platinum_cursor = in.m_pp.platinum_cursor;
|
||||
m_pp.gold_cursor = in.m_pp.gold_cursor;
|
||||
m_pp.silver_cursor = in.m_pp.silver_cursor;
|
||||
m_pp.copper_cursor = in.m_pp.copper_cursor;
|
||||
m_pp.currentRadCrystals = in.m_pp.currentRadCrystals;
|
||||
m_pp.careerRadCrystals = in.m_pp.careerRadCrystals;
|
||||
m_pp.currentEbonCrystals = in.m_pp.currentEbonCrystals;
|
||||
m_pp.careerEbonCrystals = in.m_pp.careerEbonCrystals;
|
||||
m_pp.gm = in.m_pp.gm;
|
||||
|
||||
m_inv.SetInventoryVersion(in.m_ClientVersion);
|
||||
SetBodyType(in.GetBodyType(), false);
|
||||
|
||||
for (auto [slot, item] : in.m_inv.GetPersonal()) {
|
||||
if (item) {
|
||||
m_inv.GetPersonal()[slot] = item->Clone();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [slot, item] : in.m_inv.GetWorn()) {
|
||||
if (item) {
|
||||
m_inv.GetWorn()[slot] = item->Clone();
|
||||
}
|
||||
}
|
||||
|
||||
CloneMob(*in.GetMob());
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+99
-1
@@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/raid.h"
|
||||
#include "../common/repositories/character_offline_transactions_repository.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
@@ -323,6 +324,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_MoveCoin] = &Client::Handle_OP_MoveCoin;
|
||||
ConnectedOpcodes[OP_MoveItem] = &Client::Handle_OP_MoveItem;
|
||||
ConnectedOpcodes[OP_MoveMultipleItems] = &Client::Handle_OP_MoveMultipleItems;
|
||||
ConnectedOpcodes[OP_Offline] = &Client::Handle_OP_Offline;
|
||||
ConnectedOpcodes[OP_OpenContainer] = &Client::Handle_OP_OpenContainer;
|
||||
ConnectedOpcodes[OP_OpenGuildTributeMaster] = &Client::Handle_OP_OpenGuildTributeMaster;
|
||||
ConnectedOpcodes[OP_OpenInventory] = &Client::Handle_OP_OpenInventory;
|
||||
@@ -857,6 +859,54 @@ void Client::CompleteConnect()
|
||||
}
|
||||
}
|
||||
|
||||
auto offline_transactions_trader = CharacterOfflineTransactionsRepository::GetWhere(
|
||||
database, fmt::format("`character_id` = '{}' AND `type` = '{}'", CharacterID(), TRADER_TRANSACTION)
|
||||
);
|
||||
if (offline_transactions_trader.size() > 0) {
|
||||
Message(Chat::Yellow, "You sold the following items while in offline trader mode:");
|
||||
|
||||
for (auto const &t: offline_transactions_trader) {
|
||||
Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"You sold {} {}{} to {} for {}.",
|
||||
t.quantity,
|
||||
t.item_name,
|
||||
t.quantity > 1 ? "s" : "",
|
||||
t.buyer_name,
|
||||
DetermineMoneyString(t.price))
|
||||
.c_str());
|
||||
}
|
||||
|
||||
CharacterOfflineTransactionsRepository::DeleteWhere(
|
||||
database, fmt::format("`character_id` = '{}' AND `type` = '{}'", CharacterID(), TRADER_TRANSACTION)
|
||||
);
|
||||
}
|
||||
|
||||
auto offline_transactions_buyer = CharacterOfflineTransactionsRepository::GetWhere(
|
||||
database, fmt::format("`character_id` = '{}' AND `type` = '{}'", CharacterID(), BUYER_TRANSACTION)
|
||||
);
|
||||
if (offline_transactions_buyer.size() > 0) {
|
||||
Message(Chat::Yellow, "You bought the following items while in offline buyer mode:");
|
||||
|
||||
for (auto const &t: offline_transactions_buyer) {
|
||||
Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"You bought {} {}{} from {} for {}.",
|
||||
t.quantity,
|
||||
t.item_name,
|
||||
t.quantity > 1 ? "s" : "",
|
||||
t.buyer_name,
|
||||
DetermineMoneyString(t.price))
|
||||
.c_str());
|
||||
}
|
||||
|
||||
CharacterOfflineTransactionsRepository::DeleteWhere(
|
||||
database, fmt::format("`character_id` = '{}' AND `type` = '{}'", CharacterID(), BUYER_TRANSACTION)
|
||||
);
|
||||
}
|
||||
|
||||
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
SendParcelStatus();
|
||||
}
|
||||
@@ -900,7 +950,7 @@ void Client::CompleteConnect()
|
||||
SendGuildMembersList();
|
||||
}
|
||||
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr));
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr), 0);
|
||||
|
||||
SendGuildList();
|
||||
if (GetGuildListDirty()) {
|
||||
@@ -17360,3 +17410,51 @@ void Client::SyncWorldPositionsToClient(bool ignore_idle)
|
||||
m_is_idle = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Client::Handle_OP_Offline(const EQApplicationPacket *app)
|
||||
{
|
||||
if (IsThereACustomer()) {
|
||||
auto customer = entity_list.GetClientByID(GetCustomerID());
|
||||
if (customer) {
|
||||
auto end_session = new EQApplicationPacket(OP_ShopEnd);
|
||||
customer->FastQueuePacket(&end_session);
|
||||
}
|
||||
}
|
||||
|
||||
AccountRepository::SetOfflineStatus(database, AccountID(), true);
|
||||
SetOffline(true);
|
||||
|
||||
EQStreamInterface *eqsi = nullptr;
|
||||
auto offline_client = new Client(eqsi);
|
||||
|
||||
database.LoadCharacterData(CharacterID(), &offline_client->GetPP(), &offline_client->GetEPP());
|
||||
offline_client->Clone(*this);
|
||||
offline_client->GetInv().SetGMInventory(true);
|
||||
offline_client->SetPosition(GetX(), GetY(), GetZ());
|
||||
offline_client->SetHeading(GetHeading());
|
||||
offline_client->SetSpawned();
|
||||
offline_client->SetBecomeNPC(false);
|
||||
offline_client->SetOffline(true);
|
||||
entity_list.AddClient(offline_client);
|
||||
|
||||
if (IsBuyer()) {
|
||||
offline_client->SetBuyerID(offline_client->CharacterID());
|
||||
if (!BuyerRepository::UpdateBuyerEntityID(database, CharacterID(), GetID(), offline_client->GetID())) {
|
||||
entity_list.RemoveMob(offline_client->CastToMob()->GetID());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
offline_client->SetTrader(true);
|
||||
}
|
||||
|
||||
OnDisconnect(true);
|
||||
|
||||
auto outapp = new EQApplicationPacket();
|
||||
offline_client->CreateSpawnPacket(outapp);
|
||||
entity_list.QueueClients(nullptr, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
offline_client->UpdateWho(3);
|
||||
}
|
||||
|
||||
@@ -226,6 +226,7 @@
|
||||
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveMultipleItems(const EQApplicationPacket *app);
|
||||
void Handle_OP_Offline(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
||||
|
||||
@@ -178,7 +178,7 @@ bool Client::Process() {
|
||||
}
|
||||
if (IsInAGuild()) {
|
||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||
}
|
||||
|
||||
SetDynamicZoneMemberStatus(DynamicZoneMemberStatus::Offline);
|
||||
@@ -207,7 +207,7 @@ bool Client::Process() {
|
||||
Save();
|
||||
if (IsInAGuild()) {
|
||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||
}
|
||||
|
||||
if (GetMerc())
|
||||
@@ -588,7 +588,7 @@ bool Client::Process() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (client_state != CLIENT_LINKDEAD && !eqs->CheckState(ESTABLISHED)) {
|
||||
if (eqs && client_state != CLIENT_LINKDEAD && !eqs->CheckState(ESTABLISHED)) {
|
||||
OnDisconnect(true);
|
||||
LogInfo("Client linkdead: {}", name);
|
||||
|
||||
@@ -599,7 +599,7 @@ bool Client::Process() {
|
||||
}
|
||||
if (IsInAGuild()) {
|
||||
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
|
||||
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr), 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -617,7 +617,7 @@ bool Client::Process() {
|
||||
|
||||
/************ Get all packets from packet manager out queue and process them ************/
|
||||
EQApplicationPacket *app = nullptr;
|
||||
if (!eqs->CheckState(CLOSING))
|
||||
if (eqs && !eqs->CheckState(CLOSING))
|
||||
{
|
||||
while (app = eqs->PopPacket()) {
|
||||
HandlePacket(app);
|
||||
@@ -627,7 +627,7 @@ bool Client::Process() {
|
||||
|
||||
ClientToNpcAggroProcess();
|
||||
|
||||
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
|
||||
if (eqs && client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
|
||||
{
|
||||
//client logged out or errored out
|
||||
//ResetTrade();
|
||||
|
||||
+22
-6
@@ -5006,15 +5006,31 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who)
|
||||
strcpy(WAPP1->Name, ClientEntry->GetName());
|
||||
Buffer += sizeof(WhoAllPlayerPart1) + strlen(WAPP1->Name);
|
||||
WhoAllPlayerPart2* WAPP2 = (WhoAllPlayerPart2*)Buffer;
|
||||
WAPP2->RankMSGID = 0xFFFFFFFF;
|
||||
|
||||
if (ClientEntry->IsTrader())
|
||||
WAPP2->RankMSGID = 12315;
|
||||
else if (ClientEntry->IsBuyer())
|
||||
WAPP2->RankMSGID = 6056;
|
||||
else if (ClientEntry->Admin() >= AccountStatus::Steward && ClientEntry->GetGM())
|
||||
if (ClientEntry->IsOffline()) {
|
||||
if (ClientEntry->IsTrader()) {
|
||||
WAPP1->PIDMSGID = 0x0430;
|
||||
}
|
||||
if (ClientEntry->IsBuyer()) {
|
||||
WAPP1->PIDMSGID = 0x0420;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ClientEntry->IsTrader()) {
|
||||
WAPP2->RankMSGID = 12315;
|
||||
}
|
||||
else if (ClientEntry->IsBuyer()) {
|
||||
WAPP2->RankMSGID = 6056;
|
||||
}
|
||||
}
|
||||
|
||||
if (ClientEntry->Admin() >= AccountStatus::Steward && ClientEntry->GetGM()) {
|
||||
WAPP2->RankMSGID = 12312;
|
||||
else
|
||||
}
|
||||
else {
|
||||
WAPP2->RankMSGID = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
strcpy(WAPP2->Guild, GuildName.c_str());
|
||||
Buffer += sizeof(WhoAllPlayerPart2) + strlen(WAPP2->Guild);
|
||||
|
||||
+23
-17
@@ -426,10 +426,11 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack)
|
||||
auto outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct));
|
||||
auto gmus = (GuildMemberUpdate_Struct *) outapp->pBuffer;
|
||||
|
||||
gmus->GuildID = sgmus->guild_id;
|
||||
gmus->ZoneID = sgmus->zone_id;
|
||||
gmus->InstanceID = 0;
|
||||
gmus->LastSeen = sgmus->last_seen;
|
||||
gmus->GuildID = sgmus->guild_id;
|
||||
gmus->ZoneID = sgmus->zone_id;
|
||||
gmus->InstanceID = 0;
|
||||
gmus->LastSeen = sgmus->last_seen;
|
||||
gmus->offline_mode = sgmus->offline_mode;
|
||||
strn0cpy(gmus->MemberName, sgmus->member_name, sizeof(gmus->MemberName));
|
||||
|
||||
entity_list.QueueClientsGuild(outapp, sgmus->guild_id);
|
||||
@@ -652,17 +653,24 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack)
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneGuildManager::SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen)
|
||||
void ZoneGuildManager::SendGuildMemberUpdateToWorld(
|
||||
const char *MemberName,
|
||||
uint32 GuildID,
|
||||
uint16 ZoneID,
|
||||
uint32 LastSeen,
|
||||
uint32 offline_mode
|
||||
)
|
||||
{
|
||||
auto pack = new ServerPacket(ServerOP_GuildMemberUpdate, sizeof(ServerGuildMemberUpdate_Struct));
|
||||
|
||||
ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer;
|
||||
sgmus->guild_id = GuildID;
|
||||
auto sgmus = (ServerGuildMemberUpdate_Struct *) pack->pBuffer;
|
||||
sgmus->guild_id = GuildID;
|
||||
sgmus->zone_id = ZoneID;
|
||||
sgmus->last_seen = LastSeen;
|
||||
sgmus->offline_mode = offline_mode;
|
||||
strn0cpy(sgmus->member_name, MemberName, sizeof(sgmus->member_name));
|
||||
sgmus->zone_id = ZoneID;
|
||||
sgmus->last_seen = LastSeen;
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
@@ -1517,14 +1525,12 @@ uint8* ZoneGuildManager::MakeGuildMembers(uint32 guild_id, const char* prefix_na
|
||||
PutField(total_tribute);
|
||||
PutField(last_tribute);
|
||||
SlideStructString(note_buf, ci->public_note);
|
||||
//e->zoneinstance = 0;
|
||||
if (ci->online) {
|
||||
e->zone_id = ci->zone_id; //This routine, if there is a zone_id, will update the entire guild window (roster, notes, tribute) for online characters.
|
||||
e->zone_id = 0; //If zone_id is 0 and we rely on the current world routine, the notes/tribute tabs are not updated for online characters.
|
||||
e->offline_mode = 0;
|
||||
if (ci->online || ci->offline_mode) {
|
||||
e->zone_id = ci->zone_id; //This routine, if there is a zone_id, will update the entire guild window (roster, notes, tribute) for online characters.
|
||||
e->offline_mode = ci->offline_mode;
|
||||
}
|
||||
else {
|
||||
e->zone_id = 0; //If zone_id is 0 and we rely on the current world routine, the notes/tribute tabs are not updated for online characters.
|
||||
}
|
||||
|
||||
#undef SlideStructString
|
||||
#undef PutFieldN
|
||||
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
void RecordInvite(uint32 char_id, uint32 guild_id, uint8 rank);
|
||||
bool VerifyAndClearInvite(uint32 char_id, uint32 guild_id, uint8 rank);
|
||||
void SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen);
|
||||
void SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen, uint32 offline_mode);
|
||||
void RequestOnlineGuildMembers(uint32 FromID, uint32 GuildID);
|
||||
void UpdateRankPermission(uint32 gid, uint32 charid, uint32 fid, uint32 rank, uint32 value);
|
||||
void SendPermissionUpdate(uint32 guild_id, uint32 rank, uint32 function_id, uint32 value);
|
||||
|
||||
+99
@@ -1952,6 +1952,105 @@ private:
|
||||
|
||||
void DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana);
|
||||
void HandleDoorOpen();
|
||||
|
||||
public:
|
||||
Mob* GetMob() { return this; }
|
||||
|
||||
void CloneMob(Mob& in) {
|
||||
strn0cpy(name, in.name, 64);
|
||||
strn0cpy(orig_name, in.orig_name, 64);
|
||||
strn0cpy(lastname, in.lastname, 64);
|
||||
current_hp = in.current_hp;
|
||||
max_hp = in.max_hp;
|
||||
base_hp = in.base_hp;
|
||||
gender = in.gender;
|
||||
race = in.race;
|
||||
base_gender = in.base_gender;
|
||||
base_race = in.race;
|
||||
use_model = in.use_model;
|
||||
class_ = in.class_;
|
||||
bodytype = in.bodytype;
|
||||
orig_bodytype = in.orig_bodytype;
|
||||
deity = in.deity;
|
||||
level = in.level;
|
||||
orig_level = in.orig_level;
|
||||
npctype_id = in.npctype_id;
|
||||
size = in.size;
|
||||
base_size = in.base_size;
|
||||
runspeed = in.runspeed;
|
||||
texture = in.texture;
|
||||
helmtexture = in.helmtexture;
|
||||
armtexture = in.armtexture;
|
||||
bracertexture = in.bracertexture;
|
||||
handtexture = in.handtexture;
|
||||
legtexture = in.legtexture;
|
||||
feettexture = in.feettexture;
|
||||
multitexture = in.multitexture;
|
||||
haircolor = in.haircolor;
|
||||
beardcolor = in.beardcolor;
|
||||
eyecolor1 = in.eyecolor1;
|
||||
eyecolor2 = in.eyecolor2;
|
||||
hairstyle = in.hairstyle;
|
||||
luclinface = in.luclinface;
|
||||
beard = in.beard;
|
||||
drakkin_heritage = in.drakkin_heritage;
|
||||
drakkin_tattoo = in.drakkin_tattoo;
|
||||
drakkin_details = in.drakkin_details;
|
||||
attack_speed = in.attack_speed;
|
||||
attack_delay = in.attack_delay;
|
||||
slow_mitigation = in.slow_mitigation;
|
||||
findable = in.findable;
|
||||
trackable = in.trackable;
|
||||
has_shield_equipped = in.has_shield_equipped;
|
||||
has_two_hand_blunt_equipped = in.has_two_hand_blunt_equipped;
|
||||
has_two_hander_equipped = in.has_two_hander_equipped;
|
||||
has_dual_weapons_equipped = in.has_dual_weapons_equipped;
|
||||
can_facestab = in.can_facestab;
|
||||
has_numhits = in.has_numhits;
|
||||
has_MGB = in.has_MGB;
|
||||
has_ProjectIllusion = in.has_ProjectIllusion;
|
||||
SpellPowerDistanceMod = in.SpellPowerDistanceMod;
|
||||
last_los_check = in.last_los_check;
|
||||
aa_title = in.aa_title;
|
||||
AC = in.AC;
|
||||
ATK = in.ATK;
|
||||
STR = in.STR;
|
||||
STA = in.STA;
|
||||
DEX = in.DEX;
|
||||
AGI = in.AGI;
|
||||
INT = in.INT;
|
||||
WIS = in.WIS;
|
||||
CHA = in.CHA;
|
||||
MR = in.MR;
|
||||
extra_haste = in.extra_haste;
|
||||
bEnraged = in.bEnraged;
|
||||
current_mana = in.current_mana;
|
||||
max_mana = in.max_mana;
|
||||
hp_regen = in.hp_regen;
|
||||
hp_regen_per_second = in.hp_regen_per_second;
|
||||
mana_regen = in.mana_regen;
|
||||
ooc_regen = in.ooc_regen;
|
||||
maxlevel = in.maxlevel;
|
||||
scalerate = in.scalerate;
|
||||
invisible = in.invisible;
|
||||
invisible_undead = in.invisible_undead;
|
||||
invisible_animals = in.invisible_animals;
|
||||
sneaking = in.sneaking;
|
||||
hidden = in.hidden;
|
||||
improved_hidden = in.improved_hidden;
|
||||
invulnerable = in.invulnerable;
|
||||
qglobal = in.qglobal;
|
||||
spawned = in.spawned;
|
||||
rare_spawn = in.rare_spawn;
|
||||
always_aggro = in.always_aggro;
|
||||
heroic_strikethrough = in.heroic_strikethrough;
|
||||
keeps_sold_items = in.keeps_sold_items;
|
||||
|
||||
for (int i = 0; i < MAX_APPEARANCE_EFFECTS; i++) {
|
||||
appearance_effects_id[i] = in.appearance_effects_id[i];
|
||||
appearance_effects_slot[i] = in.appearance_effects_slot[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+44
-20
@@ -26,6 +26,8 @@
|
||||
#include "../common/repositories/trader_repository.h"
|
||||
#include "../common/repositories/buyer_repository.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
#include "../common/repositories/character_offline_transactions_repository.h"
|
||||
#include "../common/repositories/account_repository.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
@@ -907,6 +909,7 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
|
||||
SetTrader(true);
|
||||
SendTraderMode(TraderOn);
|
||||
SendBecomeTraderToWorld(this, TraderOn);
|
||||
UpdateWho();
|
||||
LogTrading("Trader Mode ON for Player [{}] with client version {}.", GetCleanName(), (uint32) ClientVersion());
|
||||
}
|
||||
|
||||
@@ -927,6 +930,7 @@ void Client::TraderEndTrader()
|
||||
|
||||
WithCustomer(0);
|
||||
SetTrader(false);
|
||||
UpdateWho();
|
||||
}
|
||||
|
||||
void Client::SendTraderItem(uint32 ItemID, uint16 Quantity, TraderRepository::Trader &t) {
|
||||
@@ -1402,22 +1406,6 @@ void Client::TradeRequestFailed(TraderBuy_Struct &in)
|
||||
QueuePacket(&outapp);
|
||||
}
|
||||
|
||||
// static void BazaarAuditTrail(const char *seller, const char *buyer, const char *itemName, int quantity, int totalCost, int tranType) {
|
||||
//
|
||||
// const std::string& query = fmt::format(
|
||||
// "INSERT INTO `trader_audit` "
|
||||
// "(`time`, `seller`, `buyer`, `itemname`, `quantity`, `totalcost`, `trantype`) "
|
||||
// "VALUES (NOW(), '{}', '{}', '{}', {}, {}, {})",
|
||||
// seller,
|
||||
// buyer,
|
||||
// Strings::Escape(itemName),
|
||||
// quantity,
|
||||
// totalCost,
|
||||
// tranType
|
||||
// );
|
||||
// database.QueryDatabase(query);
|
||||
// }
|
||||
|
||||
void Client::BuyTraderItem(const EQApplicationPacket *app)
|
||||
{
|
||||
auto in = reinterpret_cast<TraderBuy_Struct *>(app->pBuffer);
|
||||
@@ -1594,6 +1582,7 @@ void Client::BuyTraderItem(const EQApplicationPacket *app)
|
||||
.charges = buy_inst->GetCharges(),
|
||||
.total_cost = total_cost,
|
||||
.player_money_balance = GetCarriedMoney(),
|
||||
.offline_purchase = trader->IsOffline(),
|
||||
};
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::TRADER_PURCHASE, e);
|
||||
@@ -1616,9 +1605,22 @@ void Client::BuyTraderItem(const EQApplicationPacket *app)
|
||||
.charges = buy_inst->GetCharges(),
|
||||
.total_cost = total_cost,
|
||||
.player_money_balance = trader->GetCarriedMoney(),
|
||||
.offline_purchase = trader->IsOffline(),
|
||||
};
|
||||
|
||||
RecordPlayerEventLogWithClient(trader, PlayerEvent::TRADER_SELL, e);
|
||||
|
||||
if (trader->IsOffline()) {
|
||||
auto e = CharacterOfflineTransactionsRepository::NewEntity();
|
||||
e.character_id = trader->CharacterID();
|
||||
e.item_name = buy_inst->GetItem()->Name;
|
||||
e.price = total_cost;
|
||||
e.quantity = quantity;
|
||||
e.type = TRADER_TRANSACTION;
|
||||
e.buyer_name = GetCleanName();
|
||||
|
||||
CharacterOfflineTransactionsRepository::InsertOne(database, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1972,12 +1974,18 @@ void Client::SellToBuyer(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (!DoBarterBuyerChecks(sell_line)) {
|
||||
SendBarterBuyerClientMessage(
|
||||
sell_line, Barter_SellerTransactionComplete, Barter_Failure, Barter_Failure
|
||||
);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
if (!DoBarterSellerChecks(sell_line)) {
|
||||
SendBarterBuyerClientMessage(
|
||||
sell_line, Barter_SellerTransactionComplete, Barter_Failure, Barter_Failure
|
||||
);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
BuyerRepository::UpdateTransactionDate(database, sell_line.buyer_id, time(nullptr));
|
||||
|
||||
@@ -2078,6 +2086,18 @@ void Client::SellToBuyer(const EQApplicationPacket *app)
|
||||
RecordPlayerEventLog(PlayerEvent::BARTER_TRANSACTION, e);
|
||||
}
|
||||
|
||||
if (buyer->IsOffline()) {
|
||||
auto e = CharacterOfflineTransactionsRepository::NewEntity();
|
||||
e.character_id = buyer->CharacterID();
|
||||
e.item_name = sell_line.item_name;
|
||||
e.price = total_cost;
|
||||
e.quantity = sell_line.seller_quantity;
|
||||
e.type = BUYER_TRANSACTION;
|
||||
e.buyer_name = GetCleanName();
|
||||
|
||||
CharacterOfflineTransactionsRepository::InsertOne(database, e);
|
||||
}
|
||||
|
||||
SendWindowUpdatesToSellerAndBuyer(sell_line);
|
||||
SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
@@ -2220,6 +2240,7 @@ void Client::ToggleBuyerMode(bool status)
|
||||
SetCustomerID(0);
|
||||
SendBuyerMode(true);
|
||||
SendBuyerToBarterWindow(this, Barter_AddToBarterWindow);
|
||||
UpdateWho();
|
||||
Message(Chat::Yellow, "Barter Mode ON.");
|
||||
}
|
||||
else {
|
||||
@@ -2232,6 +2253,8 @@ void Client::ToggleBuyerMode(bool status)
|
||||
if (!IsInBuyerSpace()) {
|
||||
Message(Chat::Red, "You must be in a Barter Stall to start Barter Mode.");
|
||||
}
|
||||
|
||||
UpdateWho();
|
||||
Message(Chat::Yellow, fmt::format("Barter Mode OFF. Buy lines deactivated.").c_str());
|
||||
}
|
||||
|
||||
@@ -2793,8 +2816,9 @@ std::string Client::DetermineMoneyString(uint64 cp)
|
||||
|
||||
void Client::BuyTraderItemFromBazaarWindow(const EQApplicationPacket *app)
|
||||
{
|
||||
auto in = reinterpret_cast<TraderBuy_Struct *>(app->pBuffer);
|
||||
auto trader_item = TraderRepository::GetItemByItemUniqueNumber(database, in->item_unique_id);
|
||||
auto in = reinterpret_cast<TraderBuy_Struct *>(app->pBuffer);
|
||||
auto trader_item = TraderRepository::GetItemByItemUniqueNumber(database, in->item_unique_id);
|
||||
auto offline = AccountRepository::GetAllOfflineStatus(database, trader_item.char_id);
|
||||
|
||||
LogTradingDetail(
|
||||
"Packet details: \n"
|
||||
|
||||
@@ -62,6 +62,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/skill_caps.h"
|
||||
#include "../common/server_reload_types.h"
|
||||
#include "queryserv.h"
|
||||
#include "../common/repositories/account_repository.h"
|
||||
#include "../common/repositories/character_offline_transactions_repository.h"
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern Zone *zone;
|
||||
@@ -3876,10 +3878,23 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
.charges = in->item_charges,
|
||||
.total_cost = total_cost,
|
||||
.player_money_balance = trader_pc->GetCarriedMoney(),
|
||||
.offline_purchase = trader_pc->IsOffline(),
|
||||
};
|
||||
RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e);
|
||||
}
|
||||
|
||||
if (trader_pc->IsOffline()) {
|
||||
auto e = CharacterOfflineTransactionsRepository::NewEntity();
|
||||
e.character_id = trader_pc->CharacterID();
|
||||
e.item_name = in->trader_buy_struct.item_name;
|
||||
e.price = in->trader_buy_struct.price * in->trader_buy_struct.quantity;
|
||||
e.quantity = in->trader_buy_struct.quantity;
|
||||
e.type = TRADER_TRANSACTION;
|
||||
e.buyer_name = in->trader_buy_struct.buyer_name;
|
||||
|
||||
CharacterOfflineTransactionsRepository::InsertOne(database, e);
|
||||
}
|
||||
|
||||
in->transaction_status = BazaarPurchaseSuccess;
|
||||
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||
worldserver.SendPacket(pack);
|
||||
@@ -4274,6 +4289,18 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
|
||||
}
|
||||
|
||||
if (buyer->IsOffline()) {
|
||||
auto e = CharacterOfflineTransactionsRepository::NewEntity();
|
||||
e.character_id = buyer->CharacterID();
|
||||
e.item_name = sell_line.item_name;
|
||||
e.price = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
|
||||
e.quantity = sell_line.seller_quantity;
|
||||
e.type = BUYER_TRANSACTION;
|
||||
e.buyer_name = sell_line.seller_name;
|
||||
|
||||
CharacterOfflineTransactionsRepository::InsertOne(database, e);
|
||||
}
|
||||
|
||||
in->action = Barter_BuyerTransactionComplete;
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
@@ -4334,8 +4361,103 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_UsertoWorldCancelOfflineRequest: {
|
||||
auto in = reinterpret_cast<UsertoWorldResponse *>(pack->pBuffer);
|
||||
auto client = entity_list.GetClientByLSID(in->lsaccountid);
|
||||
if (!client) {
|
||||
LogLoginserverDetail("Step 6a(1) - Zone received ServerOP_UsertoWorldCancelOfflineRequest though could "
|
||||
"not find client."
|
||||
);
|
||||
|
||||
auto e = AccountRepository::GetWhere(database, fmt::format("`lsaccount_id` = '{}'", in->lsaccountid));
|
||||
if (!e.empty()) {
|
||||
auto r = e.front();
|
||||
r.offline = 0;
|
||||
AccountRepository::UpdateOne(database, r);
|
||||
LogLoginserverDetail(
|
||||
"Step 6a(2) - Zone cleared offline status in account table for user id {} / {}",
|
||||
r.lsaccount_id,
|
||||
r.charname
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
auto sp = new ServerPacket(ServerOP_UsertoWorldCancelOfflineResponse, pack->size);
|
||||
auto out = reinterpret_cast<UsertoWorldResponse *>(sp->pBuffer);
|
||||
sp->opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||
out->FromID = in->FromID;
|
||||
out->lsaccountid = in->lsaccountid;
|
||||
out->response = in->response;
|
||||
out->ToID = in->ToID;
|
||||
out->worldid = in->worldid;
|
||||
strn0cpy(out->login, in->login, 64);
|
||||
|
||||
LogLoginserverDetail("Step 6a(3) - Zone sending ServerOP_UsertoWorldCancelOfflineResponse back to world");
|
||||
worldserver.SendPacket(sp);
|
||||
safe_delete(sp);
|
||||
break;
|
||||
}
|
||||
|
||||
LogLoginserverDetail(
|
||||
"Step 6b(1) - Zone received ServerOP_UsertoWorldCancelOfflineRequest and found client {}",
|
||||
client->GetCleanName()
|
||||
);
|
||||
LogLoginserverDetail(
|
||||
"Step 6b(2) - Zone cleared offline status in account table for user id {} / {}",
|
||||
client->CharacterID(),
|
||||
client->GetCleanName()
|
||||
);
|
||||
AccountRepository::SetOfflineStatus(database, client->AccountID(), false);
|
||||
|
||||
if (client->IsThereACustomer()) {
|
||||
auto customer = entity_list.GetClientByID(client->GetCustomerID());
|
||||
if (customer) {
|
||||
auto end_session = new EQApplicationPacket(OP_ShopEnd);
|
||||
customer->FastQueuePacket(&end_session);
|
||||
}
|
||||
}
|
||||
|
||||
if (client->IsTrader()) {
|
||||
LogLoginserverDetail("Step 6b(3) - Zone ending trader mode for client {}", client->GetCleanName());
|
||||
client->TraderEndTrader();
|
||||
}
|
||||
|
||||
if (client->IsBuyer()) {
|
||||
LogLoginserverDetail("Step 6b(4) - Zone ending buyer mode for client {}", client->GetCleanName());
|
||||
client->ToggleBuyerMode(false);
|
||||
}
|
||||
|
||||
LogLoginserverDetail("Step 6b(5) - Zone updating UpdateWho(2) for client {}", client->GetCleanName());
|
||||
client->UpdateWho(2);
|
||||
|
||||
auto outapp = new EQApplicationPacket();
|
||||
LogLoginserverDetail("Step 6b(6) - Zone sending despawn packet for client {}", client->GetCleanName());
|
||||
client->CreateDespawnPacket(outapp, false);
|
||||
entity_list.QueueClients(nullptr, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
LogLoginserverDetail("Step 6b(7) - Zone removing client from entity_list");
|
||||
entity_list.RemoveMob(client->CastToMob()->GetID());
|
||||
|
||||
auto sp = new ServerPacket(ServerOP_UsertoWorldCancelOfflineResponse, pack->size);
|
||||
auto out = reinterpret_cast<UsertoWorldResponse *>(sp->pBuffer);
|
||||
sp->opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||
out->FromID = in->FromID;
|
||||
out->lsaccountid = in->lsaccountid;
|
||||
out->response = in->response;
|
||||
out->ToID = in->ToID;
|
||||
out->worldid = in->worldid;
|
||||
strn0cpy(out->login, in->login, 64);
|
||||
|
||||
LogLoginserverDetail("Step 6b(8) - Zone sending ServerOP_UsertoWorldCancelOfflineResponse back to world");
|
||||
worldserver.SendPacket(sp);
|
||||
safe_delete(sp);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int) pack->opcode, pack->size);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user