[Feature] GuildBank Updates (#4674)

* First pass of a re-write of Guild Bank to enable RoF2 features

* Testing - Corrected a few bugs with merging, splitting and withdrawing

* Testing - Corrected a few bugs with depositing of bags

* Added player event logging for deposit, withdrawal and movement between deposit to main area.

* Fix the guilddelete routine

Fix the guilddelete routine as a result of the new guild_bank table structure

* Fix an issue with items not being withdrawn correctly.

* Final Testing Phase 1 - A few failures to be resolved yet.

* Final Testing Phase 2 - Looks good

* Final Testing Phase 3 - Repair a visual bug with withdrawal of items with charges

* Cleanup

* Formatting feedback updates

* Rebase and fix version.h

* Fix manifest issue after changes
This commit is contained in:
Mitch Freeman
2025-02-15 19:48:50 -04:00
committed by GitHub
parent 8201175c2c
commit c09fad5a75
20 changed files with 1419 additions and 1227 deletions
+239 -233
View File
@@ -7585,292 +7585,298 @@ void Client::Handle_OP_GroupUpdate(const EQApplicationPacket *app)
void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
{
if (!GuildBanks)
if (!GuildBanks) {
GuildBankAck();
return;
}
if (zone->GetZoneID() != Zones::GUILDHALL)
{
if (zone->GetZoneID() != Zones::GUILDHALL) {
Message(Chat::Red, "The Guild Bank is not available in this zone.");
GuildBankAck();
return;
}
if (app->size < sizeof(uint32)) {
LogError("Wrong size: OP_GuildBank, size=[{}], expected [{}]", app->size, sizeof(uint32));
DumpPacket(app);
GuildBankAck();
return;
}
char *Buffer = (char *)app->pBuffer;
uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
char *Buffer = (char *) app->pBuffer;
uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
uint32 sentAction = Action;
if (!IsInAGuild())
{
if (!IsInAGuild()) {
Message(Chat::Red, "You must be in a Guild to use the Guild Bank.");
if (Action == GuildBankDeposit)
if (Action == GuildBankDeposit) {
GuildBankDepositAck(true, sentAction);
else
}
else {
GuildBankAck();
}
return;
}
if (!IsGuildBanker())
{
if ((Action != GuildBankDeposit) && (Action != GuildBankViewItem) && (Action != GuildBankWithdraw))
if (Action != GuildBankDeposit && Action != GuildBankViewItem && Action != GuildBankWithdraw)
{
LogError("Suspected hacking attempt on guild bank from [{}]", GetName());
GuildBankAck();
return;
}
}
switch (Action)
{
case GuildBankPromote:
{
if (GuildBanks->IsAreaFull(GuildID(), GuildBankMainArea))
{
MessageString(Chat::Red, GUILD_BANK_FULL);
GuildBankDepositAck(true, sentAction);
return;
}
GuildBankPromote_Struct *gbps = (GuildBankPromote_Struct*)app->pBuffer;
int Slot = GuildBanks->Promote(GuildID(), gbps->Slot);
if (Slot >= 0)
{
EQ::ItemInstance* inst = GuildBanks->GetItem(GuildID(), GuildBankMainArea, Slot, 1);
if (inst)
{
MessageString(Chat::LightGray, GUILD_BANK_TRANSFERRED, inst->GetItem()->Name);
safe_delete(inst);
}
}
else
Message(Chat::Red, "Unexpected error while moving item into Guild Bank.");
GuildBankAck();
break;
}
case GuildBankViewItem:
{
GuildBankViewItem_Struct *gbvis = (GuildBankViewItem_Struct*)app->pBuffer;
EQ::ItemInstance* inst = GuildBanks->GetItem(GuildID(), gbvis->Area, gbvis->SlotID, 1);
if (!inst)
break;
SendItemPacket(0, inst, ItemPacketViewLink);
safe_delete(inst);
break;
}
case GuildBankDeposit: // Deposit Item
{
EQ::ItemInstance *CursorItemInst = GetInv().GetItem(EQ::invslot::slotCursor);
bool Allowed = true;
if (!CursorItemInst)
{
Message(Chat::Red, "No Item on the cursor.");
GuildBankDepositAck(true, sentAction);
return;
}
const EQ::ItemData* CursorItem = CursorItemInst->GetItem();
if (GuildBanks->IsAreaFull(GuildID(), GuildBankDepositArea))
{
MessageString(Chat::Red, GUILD_BANK_FULL);
GuildBankDepositAck(true, sentAction);
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
GetInv().PopItem(EQ::invslot::slotCursor);
PushItemOnCursor(CursorItem, true);
switch (Action) {
case GuildBankPromote: {
if (GuildBanks->IsAreaFull(GuildID(), GuildBankMainArea)) {
MessageString(Chat::Red, GUILD_BANK_FULL);
GuildBankAck();
return;
}
return;
}
auto gbps = (GuildBankPromote_Struct *) app->pBuffer;
int slot_id = GuildBanks->Promote(GuildID(), gbps->Slot, this);
if (!CursorItem->NoDrop || CursorItemInst->IsAttuned())
{
Allowed = false;
}
else if (CursorItemInst->IsNoneEmptyContainer())
{
Allowed = false;
}
else if (CursorItemInst->IsAugmented())
{
Allowed = false;
}
else if (CursorItem->NoRent == 0)
{
Allowed = false;
}
else if (CursorItem->LoreFlag && GuildBanks->HasItem(GuildID(), CursorItem->ID))
{
Allowed = false;
}
if (slot_id >= 0) {
auto inst = GuildBanks->GetItem(GuildID(), GuildBankMainArea, slot_id, 1);
if (inst) {
if (player_event_logs.IsEventEnabled(PlayerEvent::GUILD_BANK_MOVE_TO_BANK_AREA)) {
PlayerEvent::GuildBankTransaction log{};
log.char_id = CharacterID();
log.guild_id = GuildID();
log.item_id = inst->GetID();
log.quantity = inst->GetCharges();
if (inst->IsAugmented()) {
auto augs = inst->GetAugmentIDs();
log.aug_slot_one = augs.at(0);
log.aug_slot_two = augs.at(1);
log.aug_slot_three = augs.at(2);
log.aug_slot_four = augs.at(3);
log.aug_slot_five = augs.at(4);
log.aug_slot_six = augs.at(5);
}
if (!Allowed)
{
MessageString(Chat::Red, GUILD_BANK_CANNOT_DEPOSIT);
GuildBankDepositAck(true, sentAction);
RecordPlayerEventLog(PlayerEvent::GUILD_BANK_MOVE_TO_BANK_AREA, log);
}
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
GetInv().PopItem(EQ::invslot::slotCursor);
PushItemOnCursor(CursorItem, true);
MessageString(Chat::LightGray, GUILD_BANK_TRANSFERRED, inst->GetItem()->Name);
}
}
else {
Message(Chat::Red, "Unexpected error while moving item into Guild Bank.");
}
return;
}
if (GuildBanks->AddItem(GuildID(), GuildBankDepositArea, CursorItem->ID, CursorItemInst->GetCharges(), GetName(), GuildBankBankerOnly, ""))
{
GuildBankDepositAck(false, sentAction);
DeleteItemInInventory(EQ::invslot::slotCursor, 0, false);
}
break;
}
case GuildBankPermissions:
{
GuildBankPermissions_Struct *gbps = (GuildBankPermissions_Struct*)app->pBuffer;
if (gbps->Permissions == 1)
GuildBanks->SetPermissions(GuildID(), gbps->SlotID, gbps->Permissions, gbps->MemberName);
else
GuildBanks->SetPermissions(GuildID(), gbps->SlotID, gbps->Permissions, "");
GuildBankAck();
break;
}
case GuildBankWithdraw:
{
if (GetInv()[EQ::invslot::slotCursor])
{
MessageString(Chat::Red, GUILD_BANK_EMPTY_HANDS);
GuildBankAck();
break;
}
case GuildBankViewItem: {
auto gbvis = (GuildBankViewItem_Struct *) app->pBuffer;
auto inst = GuildBanks->GetItem(GuildID(), gbvis->Area, gbvis->SlotID, 1);
if (!inst) {
break;
}
SendItemPacket(0, inst.get(), ItemPacketViewLink);
break;
}
case GuildBankDeposit: // Deposit Item
{
const auto cursor_item_inst = GetInv().GetItem(EQ::invslot::slotCursor);
bool allowed = true;
if (!cursor_item_inst) {
Message(Chat::Red, "No Item on the cursor.");
GuildBankDepositAck(true, sentAction);
return;
}
const auto cursor_item = cursor_item_inst->GetItem();
if (GuildBanks->IsAreaFull(GuildID(), GuildBankDepositArea)) {
MessageString(Chat::Red, GUILD_BANK_FULL);
GuildBankDepositAck(true, sentAction);
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
GetInv().PopItem(EQ::invslot::slotCursor);
PushItemOnCursor(*cursor_item_inst, true);
}
return;
}
if (!cursor_item->NoDrop ||
cursor_item_inst->IsAttuned() ||
cursor_item_inst->IsNoneEmptyContainer() ||
cursor_item->NoRent == 0 ||
(cursor_item->LoreFlag && GuildBanks->HasItem(GuildID(), cursor_item->ID))
) {
allowed = false;
}
if (!allowed) {
MessageString(Chat::Red, GUILD_BANK_CANNOT_DEPOSIT);
GuildBankDepositAck(true, sentAction);
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
GetInv().PopItem(EQ::invslot::slotCursor);
PushItemOnCursor(*cursor_item_inst, true);
}
return;
}
auto item = GuildBankRepository::NewEntity();
item.guild_id = GuildID();
item.area = GuildBankDepositArea;
item.item_id = cursor_item->ID;
item.quantity = cursor_item_inst->GetCharges();
item.donator = GetCleanName();
item.permissions = GuildBankBankerOnly;
if (cursor_item_inst->IsAugmented()) {
auto const augs = cursor_item_inst->GetAugmentIDs();
item.augment_one_id = augs.at(0);
item.augment_two_id = augs.at(1);
item.augment_three_id = augs.at(2);
item.augment_four_id = augs.at(3);
item.augment_five_id = augs.at(4);
item.augment_six_id = augs.at(5);
}
if (GuildBanks->AddItem(item, this)) {
GuildBankDepositAck(false, sentAction);
DeleteItemInInventory(EQ::invslot::slotCursor, 0, false);
if (player_event_logs.IsEventEnabled(PlayerEvent::GUILD_BANK_DEPOSIT)) {
PlayerEvent::GuildBankTransaction log{};
log.char_id = CharacterID();
log.guild_id = GuildID();
log.item_id = item.item_id;
log.quantity = item.quantity;
log.aug_slot_one = item.augment_one_id;
log.aug_slot_two = item.augment_two_id;
log.aug_slot_three = item.augment_three_id;
log.aug_slot_four = item.augment_four_id;
log.aug_slot_five = item.augment_five_id;
log.aug_slot_six = item.augment_six_id;
RecordPlayerEventLog(PlayerEvent::GUILD_BANK_DEPOSIT, log);
}
}
break;
}
GuildBankWithdrawItem_Struct *gbwis = (GuildBankWithdrawItem_Struct*)app->pBuffer;
case GuildBankPermissions: {
auto gbps = (GuildBankPermissions_Struct *) app->pBuffer;
EQ::ItemInstance* inst = GuildBanks->GetItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity);
if (gbps->Permissions == 1) {
GuildBanks->SetPermissions(GuildID(), gbps->SlotID, gbps->Permissions, gbps->MemberName, this);
}
else {
GuildBanks->SetPermissions(GuildID(), gbps->SlotID, gbps->Permissions, "", this);
}
if (!inst)
{
GuildBankAck();
break;
}
if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_ACTION_BANK_WITHDRAW_ITEMS))
{
Message(Chat::Red, "You do not have permission to withdraw.");
case GuildBankWithdraw: {
if (GetInv()[EQ::invslot::slotCursor]) {
MessageString(Chat::Red, GUILD_BANK_EMPTY_HANDS);
GuildBankAck();
break;
}
auto gbwis = (GuildBankWithdrawItem_Struct *) app->pBuffer;
auto inst = GuildBanks->GetItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity);
if (!inst) {
GuildBankAck();
break;
}
if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_ACTION_BANK_WITHDRAW_ITEMS)) {
Message(Chat::Red, "You do not have permission to withdraw.");
GuildBankAck();
break;
}
if (!IsGuildBanker()) {
LogError("Suspected attempted hack on the guild bank from [{}]", GetName());
GuildBankAck();
break;
}
if (CheckLoreConflict(inst->GetItem())) {
MessageString(Chat::Red, DUP_LORE);
GuildBankAck();
break;
}
if (inst->GetCharges() > 0) {
gbwis->Quantity = inst->GetCharges();
}
if (inst->GetCharges() < 0) {
gbwis->Quantity = 1;
}
PushItemOnCursor(*inst.get());
SendItemPacket(EQ::invslot::slotCursor, inst.get(), ItemPacketLimbo);
GuildBanks->DeleteItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity, this);
if (player_event_logs.IsEventEnabled(PlayerEvent::GUILD_BANK_WITHDRAWAL)) {
PlayerEvent::GuildBankTransaction log{};
log.char_id = CharacterID();
log.guild_id = GuildID();
log.item_id = inst->GetID();
log.quantity = gbwis->Quantity;
if (inst->IsAugmented()) {
auto augs = inst->GetAugmentIDs();
log.aug_slot_one = augs.at(0);
log.aug_slot_two = augs.at(1);
log.aug_slot_three = augs.at(2);
log.aug_slot_four = augs.at(3);
log.aug_slot_five = augs.at(4);
log.aug_slot_six = augs.at(5);
}
RecordPlayerEventLog(PlayerEvent::GUILD_BANK_WITHDRAWAL, log);
}
else {
Message(Chat::Red, "Unable to withdraw 0 quantity of %s", inst->GetItem()->Name);
}
GuildBankAck();
break;
}
case GuildBankSplitStacks: {
if (GuildBanks->IsAreaFull(GuildID(), GuildBankMainArea)) {
MessageString(Chat::Red, GUILD_BANK_FULL);
}
else {
auto gbwis = (GuildBankWithdrawItem_Struct *) app->pBuffer;
GuildBanks->SplitStack(GuildID(), gbwis->SlotID, gbwis->Quantity, this);
}
GuildBankAck();
break;
}
case GuildBankMergeStacks: {
auto gbwis = (GuildBankWithdrawItem_Struct *) app->pBuffer;
GuildBanks->MergeStacks(GuildID(), gbwis->SlotID, this);
GuildBankAck();
safe_delete(inst);
break;
}
if (!IsGuildBanker() && !GuildBanks->AllowedToWithdraw(GuildID(), gbwis->Area, gbwis->SlotID, GetName()))
{
LogError("Suspected attempted hack on the guild bank from [{}]", GetName());
GuildBankAck();
safe_delete(inst);
break;
default: {
Message(Chat::Red, "Unexpected GuildBank action.");
LogError("Received unexpected guild bank action code [{}] from [{}]", Action, GetName());
}
if (CheckLoreConflict(inst->GetItem()))
{
MessageString(Chat::Red, DUP_LORE);
GuildBankAck();
safe_delete(inst);
break;
}
if (gbwis->Quantity > 0)
{
PushItemOnCursor(*inst);
SendItemPacket(EQ::invslot::slotCursor, inst, ItemPacketLimbo);
GuildBanks->DeleteItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity);
}
else
{
Message(Chat::Red, "Unable to withdraw 0 quantity of %s", inst->GetItem()->Name);
}
safe_delete(inst);
GuildBankAck();
break;
}
case GuildBankSplitStacks:
{
if (GuildBanks->IsAreaFull(GuildID(), GuildBankMainArea))
MessageString(Chat::Red, GUILD_BANK_FULL);
else
{
GuildBankWithdrawItem_Struct *gbwis = (GuildBankWithdrawItem_Struct*)app->pBuffer;
GuildBanks->SplitStack(GuildID(), gbwis->SlotID, gbwis->Quantity);
}
GuildBankAck();
break;
}
case GuildBankMergeStacks:
{
GuildBankWithdrawItem_Struct *gbwis = (GuildBankWithdrawItem_Struct*)app->pBuffer;
GuildBanks->MergeStacks(GuildID(), gbwis->SlotID);
GuildBankAck();
break;
}
default:
{
Message(Chat::Red, "Unexpected GuildBank action.");
LogError("Received unexpected guild bank action code [{}] from [{}]", Action, GetName());
}
}
}