diff --git a/common/database/database_update_manifest.cpp b/common/database/database_update_manifest.cpp index 208fd6151..4cf689bb7 100644 --- a/common/database/database_update_manifest.cpp +++ b/common/database/database_update_manifest.cpp @@ -6789,6 +6789,29 @@ UPDATE `character_corpse_items` SET `equip_slot` = ((`equip_slot` - 321) + 5410) UPDATE `character_corpse_items` SET `equip_slot` = ((`equip_slot` - 331) + 5610) WHERE `equip_slot` BETWEEN 331 AND 340; -- Bag 9 UPDATE `character_corpse_items` SET `equip_slot` = ((`equip_slot` - 341) + 5810) WHERE `equip_slot` BETWEEN 341 AND 350; -- Bag 10 )", + }, + ManifestEntry{ + .version = 9304, + .description = "2024_12_01_2024_update_guild_bank", + .check = "SHOW COLUMNS FROM `guild_bank` LIKE 'augment_1_id'", + .condition = "empty", + .match = "", + .sql = R"( +ALTER TABLE `guild_bank` + DROP INDEX `guildid`, + CHANGE COLUMN `guildid` `guild_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`, + CHANGE COLUMN `itemid` `item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `slot`, + CHANGE COLUMN `whofor` `who_for` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_general_ci' AFTER `permissions`, + ADD COLUMN `augment_one_id` INT UNSIGNED NULL DEFAULT '0' AFTER `item_id`, + ADD COLUMN `augment_two_id` INT UNSIGNED NULL DEFAULT '0' AFTER `augment_one_id`, + ADD COLUMN `augment_three_id` INT UNSIGNED NULL DEFAULT '0' AFTER `augment_two_id`, + ADD COLUMN `augment_four_id` INT UNSIGNED NULL DEFAULT '0' AFTER `augment_three_id`, + ADD COLUMN `augment_five_id` INT UNSIGNED NULL DEFAULT '0' AFTER `augment_four_id`, + ADD COLUMN `augment_six_id` INT UNSIGNED NULL DEFAULT '0' AFTER `augment_five_id`, + CHANGE COLUMN `qty` `quantity` INT(10) NOT NULL DEFAULT '0' AFTER `augment_six_id`; +ALTER TABLE `guild_bank` + ADD INDEX `guild_id` (`guild_id`); +)" } // -- template; copy/paste this when you need to create a new entry // ManifestEntry{ diff --git a/common/emu_constants.h b/common/emu_constants.h index 63361dbf3..085fcd828 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -130,6 +130,8 @@ namespace EQ using RoF2::invtype::MAIL_SIZE; using RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE; using RoF2::invtype::KRONO_SIZE; + using RoF2::invtype::GUILD_BANK_MAIN_SIZE; + using RoF2::invtype::GUILD_BANK_DEPOSIT_SIZE; using RoF2::invtype::OTHER_SIZE; using RoF2::invtype::TRADE_NPC_SIZE; diff --git a/common/eq_limits.cpp b/common/eq_limits.cpp index eda4d6a19..1bfbb6d29 100644 --- a/common/eq_limits.cpp +++ b/common/eq_limits.cpp @@ -173,7 +173,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, - ClientUnknown::INULL + ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL ), ClientUnknown::INULL, @@ -200,7 +200,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, - Client62::INULL + Client62::INULL, Client62::INULL, Client62::INULL ), Client62::INULL, @@ -227,7 +227,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Titanium::invtype::VIEW_MOD_PC_SIZE, Titanium::invtype::VIEW_MOD_BANK_SIZE, Titanium::invtype::VIEW_MOD_SHARED_BANK_SIZE, Titanium::invtype::VIEW_MOD_LIMBO_SIZE, Titanium::invtype::ALT_STORAGE_SIZE, Titanium::invtype::ARCHIVED_SIZE, Titanium::INULL, Titanium::INULL, Titanium::INULL, - Titanium::invtype::OTHER_SIZE + Titanium::INULL, Titanium::INULL, Titanium::invtype::OTHER_SIZE ), Titanium::invslot::EQUIPMENT_BITMASK, @@ -254,7 +254,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers SoF::invtype::VIEW_MOD_PC_SIZE, SoF::invtype::VIEW_MOD_BANK_SIZE, SoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoF::invtype::VIEW_MOD_LIMBO_SIZE, SoF::invtype::ALT_STORAGE_SIZE, SoF::invtype::ARCHIVED_SIZE, SoF::INULL, SoF::INULL, SoF::INULL, - SoF::invtype::OTHER_SIZE + SoF::INULL, SoF::INULL, SoF::invtype::OTHER_SIZE ), SoF::invslot::EQUIPMENT_BITMASK, @@ -281,7 +281,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers SoD::invtype::VIEW_MOD_PC_SIZE, SoD::invtype::VIEW_MOD_BANK_SIZE, SoD::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoD::invtype::VIEW_MOD_LIMBO_SIZE, SoD::invtype::ALT_STORAGE_SIZE, SoD::invtype::ARCHIVED_SIZE, SoD::INULL, SoD::INULL, SoD::INULL, - SoD::invtype::OTHER_SIZE + SoD::INULL, SoD::INULL, SoD::invtype::OTHER_SIZE ), SoD::invslot::EQUIPMENT_BITMASK, @@ -308,7 +308,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers UF::invtype::VIEW_MOD_PC_SIZE, UF::invtype::VIEW_MOD_BANK_SIZE, UF::invtype::VIEW_MOD_SHARED_BANK_SIZE, UF::invtype::VIEW_MOD_LIMBO_SIZE, UF::invtype::ALT_STORAGE_SIZE, UF::invtype::ARCHIVED_SIZE, UF::INULL, UF::INULL, UF::INULL, - UF::invtype::OTHER_SIZE + UF::INULL, UF::INULL, UF::invtype::OTHER_SIZE ), UF::invslot::EQUIPMENT_BITMASK, @@ -335,7 +335,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers RoF::invtype::VIEW_MOD_PC_SIZE, RoF::invtype::VIEW_MOD_BANK_SIZE, RoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF::invtype::VIEW_MOD_LIMBO_SIZE, RoF::invtype::ALT_STORAGE_SIZE, RoF::invtype::ARCHIVED_SIZE, RoF::invtype::MAIL_SIZE, RoF::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF::INULL, - RoF::invtype::OTHER_SIZE + RoF::INULL,RoF::INULL,RoF::invtype::OTHER_SIZE ), RoF::invslot::EQUIPMENT_BITMASK, @@ -362,7 +362,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::invtype::ALT_STORAGE_SIZE, RoF2::invtype::ARCHIVED_SIZE, RoF2::invtype::MAIL_SIZE, RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF2::invtype::KRONO_SIZE, - RoF2::invtype::OTHER_SIZE + RoF2::invtype::GUILD_BANK_MAIN_SIZE,RoF2::invtype::GUILD_BANK_DEPOSIT_SIZE, RoF2::invtype::OTHER_SIZE ), RoF2::invslot::EQUIPMENT_BITMASK, @@ -389,7 +389,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, - EntityLimits::NPC::INULL + EntityLimits::NPC::INULL, EntityLimits::NPC::INULL,EntityLimits::NPC::INULL ), EntityLimits::NPC::INULL, @@ -416,7 +416,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, - EntityLimits::NPCMerchant::INULL + EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL ), EntityLimits::NPCMerchant::INULL, @@ -443,7 +443,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, - EntityLimits::Merc::INULL + EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL ), EntityLimits::Merc::INULL, @@ -470,7 +470,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, - EntityLimits::Bot::INULL + EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL ), EntityLimits::Bot::invslot::EQUIPMENT_BITMASK, @@ -497,7 +497,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, - EntityLimits::ClientPet::INULL + EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL ), EntityLimits::ClientPet::INULL, @@ -524,7 +524,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, - EntityLimits::NPCPet::INULL + EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL ), EntityLimits::NPCPet::INULL, @@ -551,7 +551,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, - EntityLimits::MercPet::INULL + EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL ), EntityLimits::MercPet::INULL, @@ -578,7 +578,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, - EntityLimits::BotPet::INULL + EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL ), EntityLimits::BotPet::INULL, @@ -605,7 +605,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Titanium::invtype::VIEW_MOD_PC_SIZE, Titanium::invtype::VIEW_MOD_BANK_SIZE, Titanium::invtype::VIEW_MOD_SHARED_BANK_SIZE, Titanium::invtype::VIEW_MOD_LIMBO_SIZE, Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL, - Titanium::INULL + Titanium::INULL, Titanium::INULL, Titanium::INULL ), Titanium::INULL, @@ -632,7 +632,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers SoF::invtype::VIEW_MOD_PC_SIZE, SoF::invtype::VIEW_MOD_BANK_SIZE, SoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoF::invtype::VIEW_MOD_LIMBO_SIZE, SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL, - SoF::INULL + SoF::INULL, SoF::INULL, SoF::INULL ), SoF::INULL, @@ -659,7 +659,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers SoD::invtype::VIEW_MOD_PC_SIZE, SoD::invtype::VIEW_MOD_BANK_SIZE, SoD::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoD::invtype::VIEW_MOD_LIMBO_SIZE, SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL, - SoD::INULL + SoD::INULL, SoD::INULL, SoD::INULL ), SoD::INULL, @@ -686,7 +686,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers UF::invtype::VIEW_MOD_PC_SIZE, UF::invtype::VIEW_MOD_BANK_SIZE, UF::invtype::VIEW_MOD_SHARED_BANK_SIZE, UF::invtype::VIEW_MOD_LIMBO_SIZE, UF::INULL, UF::INULL, UF::INULL, UF::INULL, UF::INULL, - UF::INULL + UF::INULL, UF::INULL, UF::INULL ), UF::INULL, @@ -713,7 +713,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers RoF::invtype::VIEW_MOD_PC_SIZE, RoF::invtype::VIEW_MOD_BANK_SIZE, RoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF::invtype::VIEW_MOD_LIMBO_SIZE, RoF::INULL, RoF::INULL, RoF::INULL, RoF::INULL, RoF::INULL, - RoF::INULL + RoF::INULL, RoF::INULL, RoF::INULL ), RoF::INULL, @@ -740,7 +740,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::INULL, RoF2::INULL, RoF2::INULL, RoF2::INULL, RoF2::INULL, - RoF2::INULL + RoF2::INULL, RoF2::INULL, RoF2::INULL ), RoF2::INULL, diff --git a/common/eq_limits.h b/common/eq_limits.h index fed765207..6c00e411e 100644 --- a/common/eq_limits.h +++ b/common/eq_limits.h @@ -87,7 +87,7 @@ namespace EQ int16 ViewMODPC, ViewMODBank, ViewMODSharedBank; int16 ViewMODLimbo, AltStorage, Archived; int16 Mail, GuildTrophyTribute, Krono; - int16 Other; + int16 GuildBankMain,GuildBankDeposit, Other; InventoryTypeSize_Struct( int16 Possessions, int16 Bank, int16 SharedBank, @@ -98,7 +98,7 @@ namespace EQ int16 ViewMODPC, int16 ViewMODBank, int16 ViewMODSharedBank, int16 ViewMODLimbo, int16 AltStorage, int16 Archived, int16 Mail, int16 GuildTrophyTribute, int16 Krono, - int16 Other + int16 GuildBankMain,int16 GuildBankDeposit, int16 Other ) : Possessions(Possessions), Bank(Bank), SharedBank(SharedBank), Trade(Trade), World(World), Limbo(Limbo), @@ -108,7 +108,7 @@ namespace EQ ViewMODPC(ViewMODPC), ViewMODBank(ViewMODBank), ViewMODSharedBank(ViewMODSharedBank), ViewMODLimbo(ViewMODLimbo), AltStorage(AltStorage), Archived(Archived), Mail(Mail), GuildTrophyTribute(GuildTrophyTribute), Krono(Krono), - Other(Other) + GuildBankMain(GuildBankMain), GuildBankDeposit(GuildBankDeposit), Other(Other) { } }; diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 0ad3bcbd3..2e01f8e37 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -19,17 +19,17 @@ #ifndef EQ_PACKET_STRUCTS_H #define EQ_PACKET_STRUCTS_H -#include "types.h" +#include #include #include -#include #include -#include "../common/version.h" -#include "emu_constants.h" -#include "textures.h" #include "../cereal/include/cereal/archives/binary.hpp" #include "../cereal/include/cereal/types/string.hpp" #include "../cereal/include/cereal/types/vector.hpp" +#include "../common/version.h" +#include "emu_constants.h" +#include "textures.h" +#include "types.h" static const uint32 BUFF_COUNT = 42; static const uint32 PET_BUFF_COUNT = 30; @@ -5529,56 +5529,65 @@ struct GuildBankWithdrawItem_Struct struct GuildBankItemUpdate_Struct { - void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, - uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + void Init( + uint32 inAction, + uint32 inUnknown004, + uint16 inSlotID, + uint16 inArea, + uint16 inUnknown012, + uint32 inItemID, + uint32 inIcon, + uint32 inQuantity, + uint32 inPermissions, + uint32 inAllowMerge, + bool inUseable) { - Action = inAction; - Unknown004 = inUnknown004; - SlotID = inSlotID; - Area = inArea; - Unknown012 = inUnknown012; - ItemID = inItemID; - Icon = inIcon; - Quantity = inQuantity; - Permissions = inPermissions; - AllowMerge = inAllowMerge; - Useable = inUseable; - ItemName[0] = '\0'; - Donator[0] = '\0'; - WhoFor[0] = '\0'; + action = inAction; + unknown004 = inUnknown004; + slot_id = inSlotID; + area = inArea; + display = inUnknown012; + item_id = inItemID; + icon_id = inIcon; + quantity = inQuantity; + permissions = inPermissions; + allow_merge = inAllowMerge; + is_useable = inUseable; + item_name[0] = '\0'; + donator[0] = '\0'; + who_for[0] = '\0'; }; -/*000*/ uint32 Action; -/*004*/ uint32 Unknown004; -/*008*/ uint16 SlotID; -/*010*/ uint16 Area; -/*012*/ uint32 Unknown012; -/*016*/ uint32 ItemID; -/*020*/ uint32 Icon; -/*024*/ uint32 Quantity; -/*028*/ uint32 Permissions; -/*032*/ uint8 AllowMerge; -/*033*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. -/*034*/ char ItemName[64]; -/*098*/ char Donator[64]; -/*162*/ char WhoFor[64]; -/*226*/ uint16 Unknown226; +/*000*/ uint32 action; +/*004*/ uint32 unknown004; +/*008*/ uint16 slot_id; +/*010*/ uint16 area; +/*012*/ uint32 display; +/*016*/ uint32 item_id; +/*020*/ uint32 icon_id; +/*024*/ uint32 quantity; +/*028*/ uint32 permissions; +/*032*/ uint8 allow_merge; +/*033*/ uint8 is_useable; // Used in conjunction with the Public-if-useable permission. +/*034*/ char item_name[64]; +/*098*/ char donator[64]; +/*162*/ char who_for[64]; +/*226*/ uint16 unknown226; }; // newer clients (RoF+) send a list that contains 240 entries // The packets don't actually use all 64 chars in the strings, but we'll just overallocate for these -struct GuildBankItemListEntry_Struct -{ - uint8 vaild; +struct GuildBankItemListEntry_Struct { + uint8 vaild; uint32 permissions; - char whofor[64]; - char donator[64]; + char whofor[64]; + char donator[64]; uint32 item_id; uint32 item_icon; uint32 quantity; - uint8 allow_merge; // 1 here for non-full stacks - uint8 usable; - char item_name[64]; + uint8 allow_merge; // 1 here for non-full stacks + uint8 usable; + char item_name[64]; }; struct GuildBankClear_Struct diff --git a/common/events/player_events.h b/common/events/player_events.h index 177c983d6..615a475a8 100644 --- a/common/events/player_events.h +++ b/common/events/player_events.h @@ -65,6 +65,9 @@ namespace PlayerEvent { BARTER_TRANSACTION, SPEECH, EVOLVE_ITEM, + GUILD_BANK_DEPOSIT, + GUILD_BANK_WITHDRAWAL, + GUILD_BANK_MOVE_TO_BANK_AREA, MAX // dont remove }; @@ -130,6 +133,10 @@ namespace PlayerEvent { "Barter Transaction", "Player Speech", "Evolve Item Update" + "Barter Transaction", + "Guild Bank Item Deposit", + "Guild Bank Item Withdrawal", + "Guild Bank Move From Deposit Area to Bank Area" }; // Generic struct used by all events @@ -1274,6 +1281,38 @@ namespace PlayerEvent { ); } }; + + struct GuildBankTransaction { + uint32 char_id; + uint32 guild_id; + uint32 item_id; + uint32 aug_slot_one; + uint32 aug_slot_two; + uint32 aug_slot_three; + uint32 aug_slot_four; + uint32 aug_slot_five; + uint32 aug_slot_six; + uint32 quantity; + uint32 permission; + + // cereal + template + void serialize(Archive &ar) + { + ar( + CEREAL_NVP(char_id), + CEREAL_NVP(guild_id), + CEREAL_NVP(item_id), + CEREAL_NVP(aug_slot_one), + CEREAL_NVP(aug_slot_two), + CEREAL_NVP(aug_slot_three), + CEREAL_NVP(aug_slot_four), + CEREAL_NVP(aug_slot_five), + CEREAL_NVP(aug_slot_six), + CEREAL_NVP(quantity) + ); + } + }; } #endif //EQEMU_PLAYER_EVENTS_H diff --git a/common/guild_base.cpp b/common/guild_base.cpp index 04275fa5b..3f34c3625 100644 --- a/common/guild_base.cpp +++ b/common/guild_base.cpp @@ -547,60 +547,62 @@ uint32 BaseGuildManager::UpdateDbCreateGuild(std::string name, uint32 leader) bool BaseGuildManager::UpdateDbDeleteGuild(uint32 guild_id, bool local_delete, bool db_delete) { + auto const where_filter = fmt::format("guild_id = {}", guild_id); + auto const bank_items = GuildBankRepository::GetWhere(*m_db, where_filter); + if (local_delete) { - auto where_filter = fmt::format("guildid = {}", guild_id); - auto bank_items = GuildBankRepository::GetWhere(*m_db, where_filter); if (!bank_items.empty()) { LogError( - "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.", + "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " + "again.", guild_id, bank_items.size() ); LogGuilds( - "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.", + "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " + "again.", guild_id, bank_items.size() ); + return false; } - else { - std::map::iterator res; - res = m_guilds.find(guild_id); - if (res != m_guilds.end()) { - delete res->second; - m_guilds.erase(res); - LogGuilds("Deleted guild [{}] from memory", guild_id); - //Does this need to be sent to world? - } + + auto res = m_guilds.find(guild_id); + if (res != m_guilds.end()) { + safe_delete(res->second); + m_guilds.erase(res); + LogGuilds("Deleted guild [{}] from memory", guild_id); + // Does this need to be sent to world? } } if (db_delete) { - auto where_filter = fmt::format("guildid = {}", guild_id); - auto bank_items = GuildBankRepository::GetWhere(*m_db, where_filter); if (!bank_items.empty()) { LogError( - "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.", + "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " + "again.", guild_id, bank_items.size() ); LogGuilds( - "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.", + "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " + "again.", guild_id, bank_items.size() ); + return false; } - else { - auto where_filter = fmt::format("guild_id = {}", guild_id); - GuildTributesRepository::DeleteOne(*m_db, guild_id); - GuildsRepository::DeleteOne(*m_db, guild_id); - GuildRanksRepository::DeleteWhere(*m_db, where_filter); - GuildPermissionsRepository::DeleteWhere(*m_db, where_filter); - GuildMembersRepository::DeleteWhere(*m_db, where_filter); - LogGuilds("Deleted guild [{}] from the database", guild_id); - } + + GuildTributesRepository::DeleteOne(*m_db, guild_id); + GuildsRepository::DeleteOne(*m_db, guild_id); + GuildRanksRepository::DeleteWhere(*m_db, where_filter); + GuildPermissionsRepository::DeleteWhere(*m_db, where_filter); + GuildMembersRepository::DeleteWhere(*m_db, where_filter); + LogGuilds("Deleted guild [{}] from the database", guild_id); } + return true; } diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 9a6facac7..0e23bb429 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1213,22 +1213,22 @@ namespace RoF case 1: { // GuildBankItemUpdate auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; - eq->Action = 0; - OUT(Unknown004); - eq->Unknown08 = 0; - OUT(SlotID); - OUT(Area); - OUT(Unknown012); - OUT(ItemID); - OUT(Icon); - OUT(Quantity); - OUT(Permissions); - OUT(AllowMerge); - OUT(Useable); - OUT_str(ItemName); - OUT_str(Donator); - OUT_str(WhoFor); - OUT(Unknown226); + eq->action = 0; + OUT(unknown004); + eq->unknown008 = 0; + OUT(slot_id); + OUT(area); + OUT(display); + OUT(item_id); + OUT(icon_id); + OUT(quantity); + OUT(permissions); + OUT(allow_merge); + OUT(is_useable); + OUT_str(item_name); + OUT_str(donator); + OUT_str(who_for); + OUT(unknown226); break; } default: diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 3e05972e6..1cbbb5c5d 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -1743,22 +1743,19 @@ namespace RoF2 case 1: { // GuildBankItemUpdate auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; - eq->Action = 0; - OUT(Unknown004); - eq->Unknown08 = 0; - OUT(SlotID); - OUT(Area); - OUT(Unknown012); - OUT(ItemID); - OUT(Icon); - OUT(Quantity); - OUT(Permissions); - OUT(AllowMerge); - OUT(Useable); - OUT_str(ItemName); - OUT_str(Donator); - OUT_str(WhoFor); - OUT(Unknown226); + eq->action = 0; + OUT(display); + OUT(slot_id); + OUT(area); + OUT(item_id); + OUT(icon_id); + OUT(quantity); + OUT(permissions); + OUT(allow_merge); + OUT(is_useable); + OUT_str(item_name); + OUT_str(donator); + OUT_str(who_for); break; } default: diff --git a/common/patches/rof2_limits.h b/common/patches/rof2_limits.h index 4230be80d..668b0df74 100644 --- a/common/patches/rof2_limits.h +++ b/common/patches/rof2_limits.h @@ -101,6 +101,8 @@ namespace RoF2 const int16 MAIL_SIZE = 0;//unknown const int16 GUILD_TROPHY_TRIBUTE_SIZE = 0;//unknown const int16 KRONO_SIZE = 0;//unknown + const int16 GUILD_BANK_MAIN_SIZE = 200; + const int16 GUILD_BANK_DEPOSIT_SIZE = 40; const int16 OTHER_SIZE = 0;//unknown const int16 TRADE_NPC_SIZE = 4; // defined by implication diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 5f1fe4252..b6ad6bbf1 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -1965,41 +1965,39 @@ struct GuildBankWithdrawItem_Struct struct GuildBankItemUpdate_Struct { - void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown016, uint32 inItemID, uint32 inIcon, uint32 inQuantity, uint32 inPermissions, uint32 inAllowMerge, bool inUseable) { - Action = inAction; - Unknown004 = inUnknown004; - SlotID = inSlotID; - Area = inArea; - Unknown012 = inUnknown012; - ItemID = inItemID; - Icon = inIcon; - Quantity = inQuantity; - Permissions = inPermissions; - AllowMerge = inAllowMerge; - Useable = inUseable; - ItemName[0] = '\0'; - Donator[0] = '\0'; - WhoFor[0] = '\0'; + action = inAction; + slot_id = inSlotID; + area = inArea; + display = inUnknown016; + item_id = inItemID; + icon_id = inIcon; + quantity = inQuantity; + permissions = inPermissions; + allow_merge = inAllowMerge; + is_useable = inUseable; + item_name[0] = '\0'; + donator[0] = '\0'; + who_for[0] = '\0'; }; -/*000*/ uint32 Action; -/*004*/ uint32 Unknown004; -/*008*/ uint32 Unknown08; -/*012*/ uint16 SlotID; -/*014*/ uint16 Area; -/*016*/ uint32 Unknown012; -/*020*/ uint32 ItemID; -/*024*/ uint32 Icon; -/*028*/ uint32 Quantity; -/*032*/ uint32 Permissions; -/*036*/ uint8 AllowMerge; -/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. -/*038*/ char ItemName[64]; -/*102*/ char Donator[64]; -/*166*/ char WhoFor[64]; -/*230*/ uint16 Unknown226; +/*000*/ uint32 action; +/*004*/ uint32 not_used004; //disassemble of client did not use this +/*008*/ uint32 not_used008; //disassemble of client did not use this +/*012*/ uint16 slot_id; +/*014*/ uint16 area; +/*016*/ uint32 display; +/*020*/ uint32 item_id; +/*024*/ uint32 icon_id; +/*028*/ uint32 quantity; +/*032*/ uint32 permissions; +/*036*/ uint8 allow_merge; +/*037*/ uint8 is_useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char item_name[64]; +/*102*/ char donator[64]; +/*166*/ char who_for[64]; }; struct GuildBankClear_Struct diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index d502eddd6..d065a2b04 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -1946,38 +1946,38 @@ struct GuildBankItemUpdate_Struct void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, uint32 inPermissions, uint32 inAllowMerge, bool inUseable) { - Action = inAction; - Unknown004 = inUnknown004; - SlotID = inSlotID; - Area = inArea; - Unknown012 = inUnknown012; - ItemID = inItemID; - Icon = inIcon; - Quantity = inQuantity; - Permissions = inPermissions; - AllowMerge = inAllowMerge; - Useable = inUseable; - ItemName[0] = '\0'; - Donator[0] = '\0'; - WhoFor[0] = '\0'; + action = inAction; + unknown004 = inUnknown004; + slot_id = inSlotID; + area = inArea; + display = inUnknown012; + item_id = inItemID; + icon_id = inIcon; + quantity = inQuantity; + permissions = inPermissions; + allow_merge = inAllowMerge; + is_useable = inUseable; + item_name[0] = '\0'; + donator[0] = '\0'; + who_for[0] = '\0'; }; -/*000*/ uint32 Action; -/*004*/ uint32 Unknown004; -/*008*/ uint32 Unknown08; -/*012*/ uint16 SlotID; -/*014*/ uint16 Area; -/*016*/ uint32 Unknown012; -/*020*/ uint32 ItemID; -/*024*/ uint32 Icon; -/*028*/ uint32 Quantity; -/*032*/ uint32 Permissions; -/*036*/ uint8 AllowMerge; -/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. -/*038*/ char ItemName[64]; -/*102*/ char Donator[64]; -/*166*/ char WhoFor[64]; -/*230*/ uint16 Unknown226; +/*000*/ uint32 action; +/*004*/ uint32 unknown004; +/*008*/ uint32 unknown008; +/*012*/ uint16 slot_id; +/*014*/ uint16 area; +/*016*/ uint32 display; +/*020*/ uint32 item_id; +/*024*/ uint32 icon_id; +/*028*/ uint32 quantity; +/*032*/ uint32 permissions; +/*036*/ uint8 allow_merge; +/*037*/ uint8 is_useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char item_name[64]; +/*102*/ char donator[64]; +/*166*/ char who_for[64]; +/*230*/ uint16 unknown226; }; struct GuildBankClear_Struct diff --git a/common/repositories/base/base_guild_bank_repository.h b/common/repositories/base/base_guild_bank_repository.h index bd359a77d..a857987ac 100644 --- a/common/repositories/base/base_guild_bank_repository.h +++ b/common/repositories/base/base_guild_bank_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_GUILD_BANK_REPOSITORY_H @@ -16,19 +16,24 @@ #include "../../strings.h" #include - class BaseGuildBankRepository { public: struct GuildBank { uint32_t id; - uint32_t guildid; + uint32_t guild_id; uint8_t area; uint32_t slot; - uint32_t itemid; - uint32_t qty; + uint32_t item_id; + uint32_t augment_one_id; + uint32_t augment_two_id; + uint32_t augment_three_id; + uint32_t augment_four_id; + uint32_t augment_five_id; + uint32_t augment_six_id; + int32_t quantity; std::string donator; uint8_t permissions; - std::string whofor; + std::string who_for; }; static std::string PrimaryKey() @@ -40,14 +45,20 @@ public: { return { "id", - "guildid", + "guild_id", "area", "slot", - "itemid", - "qty", + "item_id", + "augment_one_id", + "augment_two_id", + "augment_three_id", + "augment_four_id", + "augment_five_id", + "augment_six_id", + "quantity", "donator", "permissions", - "whofor", + "who_for", }; } @@ -55,14 +66,20 @@ public: { return { "id", - "guildid", + "guild_id", "area", "slot", - "itemid", - "qty", + "item_id", + "augment_one_id", + "augment_two_id", + "augment_three_id", + "augment_four_id", + "augment_five_id", + "augment_six_id", + "quantity", "donator", "permissions", - "whofor", + "who_for", }; } @@ -103,15 +120,21 @@ public: { GuildBank e{}; - e.id = 0; - e.guildid = 0; - e.area = 0; - e.slot = 0; - e.itemid = 0; - e.qty = 0; - e.donator = ""; - e.permissions = 0; - e.whofor = ""; + e.id = 0; + e.guild_id = 0; + e.area = 0; + e.slot = 0; + e.item_id = 0; + e.augment_one_id = 0; + e.augment_two_id = 0; + e.augment_three_id = 0; + e.augment_four_id = 0; + e.augment_five_id = 0; + e.augment_six_id = 0; + e.quantity = 0; + e.donator = ""; + e.permissions = 0; + e.who_for = ""; return e; } @@ -148,15 +171,21 @@ public: if (results.RowCount() == 1) { GuildBank e{}; - e.id = static_cast(strtoul(row[0], nullptr, 10)); - e.guildid = static_cast(strtoul(row[1], nullptr, 10)); - e.area = static_cast(strtoul(row[2], nullptr, 10)); - e.slot = static_cast(strtoul(row[3], nullptr, 10)); - e.itemid = static_cast(strtoul(row[4], nullptr, 10)); - e.qty = static_cast(strtoul(row[5], nullptr, 10)); - e.donator = row[6] ? row[6] : ""; - e.permissions = static_cast(strtoul(row[7], nullptr, 10)); - e.whofor = row[8] ? row[8] : ""; + e.id = row[0] ? static_cast(strtoul(row[0], nullptr, 10)) : 0; + e.guild_id = row[1] ? static_cast(strtoul(row[1], nullptr, 10)) : 0; + e.area = row[2] ? static_cast(strtoul(row[2], nullptr, 10)) : 0; + e.slot = row[3] ? static_cast(strtoul(row[3], nullptr, 10)) : 0; + e.item_id = row[4] ? static_cast(strtoul(row[4], nullptr, 10)) : 0; + e.augment_one_id = row[5] ? static_cast(strtoul(row[5], nullptr, 10)) : 0; + e.augment_two_id = row[6] ? static_cast(strtoul(row[6], nullptr, 10)) : 0; + e.augment_three_id = row[7] ? static_cast(strtoul(row[7], nullptr, 10)) : 0; + e.augment_four_id = row[8] ? static_cast(strtoul(row[8], nullptr, 10)) : 0; + e.augment_five_id = row[9] ? static_cast(strtoul(row[9], nullptr, 10)) : 0; + e.augment_six_id = row[10] ? static_cast(strtoul(row[10], nullptr, 10)) : 0; + e.quantity = row[11] ? static_cast(atoi(row[11])) : 0; + e.donator = row[12] ? row[12] : ""; + e.permissions = row[13] ? static_cast(strtoul(row[13], nullptr, 10)) : 0; + e.who_for = row[14] ? row[14] : ""; return e; } @@ -190,14 +219,20 @@ public: auto columns = Columns(); - v.push_back(columns[1] + " = " + std::to_string(e.guildid)); + v.push_back(columns[1] + " = " + std::to_string(e.guild_id)); v.push_back(columns[2] + " = " + std::to_string(e.area)); v.push_back(columns[3] + " = " + std::to_string(e.slot)); - v.push_back(columns[4] + " = " + std::to_string(e.itemid)); - v.push_back(columns[5] + " = " + std::to_string(e.qty)); - v.push_back(columns[6] + " = '" + Strings::Escape(e.donator) + "'"); - v.push_back(columns[7] + " = " + std::to_string(e.permissions)); - v.push_back(columns[8] + " = '" + Strings::Escape(e.whofor) + "'"); + v.push_back(columns[4] + " = " + std::to_string(e.item_id)); + v.push_back(columns[5] + " = " + std::to_string(e.augment_one_id)); + v.push_back(columns[6] + " = " + std::to_string(e.augment_two_id)); + v.push_back(columns[7] + " = " + std::to_string(e.augment_three_id)); + v.push_back(columns[8] + " = " + std::to_string(e.augment_four_id)); + v.push_back(columns[9] + " = " + std::to_string(e.augment_five_id)); + v.push_back(columns[10] + " = " + std::to_string(e.augment_six_id)); + v.push_back(columns[11] + " = " + std::to_string(e.quantity)); + v.push_back(columns[12] + " = '" + Strings::Escape(e.donator) + "'"); + v.push_back(columns[13] + " = " + std::to_string(e.permissions)); + v.push_back(columns[14] + " = '" + Strings::Escape(e.who_for) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -220,14 +255,20 @@ public: std::vector v; v.push_back(std::to_string(e.id)); - v.push_back(std::to_string(e.guildid)); + v.push_back(std::to_string(e.guild_id)); v.push_back(std::to_string(e.area)); v.push_back(std::to_string(e.slot)); - v.push_back(std::to_string(e.itemid)); - v.push_back(std::to_string(e.qty)); + v.push_back(std::to_string(e.item_id)); + v.push_back(std::to_string(e.augment_one_id)); + v.push_back(std::to_string(e.augment_two_id)); + v.push_back(std::to_string(e.augment_three_id)); + v.push_back(std::to_string(e.augment_four_id)); + v.push_back(std::to_string(e.augment_five_id)); + v.push_back(std::to_string(e.augment_six_id)); + v.push_back(std::to_string(e.quantity)); v.push_back("'" + Strings::Escape(e.donator) + "'"); v.push_back(std::to_string(e.permissions)); - v.push_back("'" + Strings::Escape(e.whofor) + "'"); + v.push_back("'" + Strings::Escape(e.who_for) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -258,14 +299,20 @@ public: std::vector v; v.push_back(std::to_string(e.id)); - v.push_back(std::to_string(e.guildid)); + v.push_back(std::to_string(e.guild_id)); v.push_back(std::to_string(e.area)); v.push_back(std::to_string(e.slot)); - v.push_back(std::to_string(e.itemid)); - v.push_back(std::to_string(e.qty)); + v.push_back(std::to_string(e.item_id)); + v.push_back(std::to_string(e.augment_one_id)); + v.push_back(std::to_string(e.augment_two_id)); + v.push_back(std::to_string(e.augment_three_id)); + v.push_back(std::to_string(e.augment_four_id)); + v.push_back(std::to_string(e.augment_five_id)); + v.push_back(std::to_string(e.augment_six_id)); + v.push_back(std::to_string(e.quantity)); v.push_back("'" + Strings::Escape(e.donator) + "'"); v.push_back(std::to_string(e.permissions)); - v.push_back("'" + Strings::Escape(e.whofor) + "'"); + v.push_back("'" + Strings::Escape(e.who_for) + "'"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); } @@ -299,15 +346,21 @@ public: for (auto row = results.begin(); row != results.end(); ++row) { GuildBank e{}; - e.id = static_cast(strtoul(row[0], nullptr, 10)); - e.guildid = static_cast(strtoul(row[1], nullptr, 10)); - e.area = static_cast(strtoul(row[2], nullptr, 10)); - e.slot = static_cast(strtoul(row[3], nullptr, 10)); - e.itemid = static_cast(strtoul(row[4], nullptr, 10)); - e.qty = static_cast(strtoul(row[5], nullptr, 10)); - e.donator = row[6] ? row[6] : ""; - e.permissions = static_cast(strtoul(row[7], nullptr, 10)); - e.whofor = row[8] ? row[8] : ""; + e.id = row[0] ? static_cast(strtoul(row[0], nullptr, 10)) : 0; + e.guild_id = row[1] ? static_cast(strtoul(row[1], nullptr, 10)) : 0; + e.area = row[2] ? static_cast(strtoul(row[2], nullptr, 10)) : 0; + e.slot = row[3] ? static_cast(strtoul(row[3], nullptr, 10)) : 0; + e.item_id = row[4] ? static_cast(strtoul(row[4], nullptr, 10)) : 0; + e.augment_one_id = row[5] ? static_cast(strtoul(row[5], nullptr, 10)) : 0; + e.augment_two_id = row[6] ? static_cast(strtoul(row[6], nullptr, 10)) : 0; + e.augment_three_id = row[7] ? static_cast(strtoul(row[7], nullptr, 10)) : 0; + e.augment_four_id = row[8] ? static_cast(strtoul(row[8], nullptr, 10)) : 0; + e.augment_five_id = row[9] ? static_cast(strtoul(row[9], nullptr, 10)) : 0; + e.augment_six_id = row[10] ? static_cast(strtoul(row[10], nullptr, 10)) : 0; + e.quantity = row[11] ? static_cast(atoi(row[11])) : 0; + e.donator = row[12] ? row[12] : ""; + e.permissions = row[13] ? static_cast(strtoul(row[13], nullptr, 10)) : 0; + e.who_for = row[14] ? row[14] : ""; all_entries.push_back(e); } @@ -332,15 +385,21 @@ public: for (auto row = results.begin(); row != results.end(); ++row) { GuildBank e{}; - e.id = static_cast(strtoul(row[0], nullptr, 10)); - e.guildid = static_cast(strtoul(row[1], nullptr, 10)); - e.area = static_cast(strtoul(row[2], nullptr, 10)); - e.slot = static_cast(strtoul(row[3], nullptr, 10)); - e.itemid = static_cast(strtoul(row[4], nullptr, 10)); - e.qty = static_cast(strtoul(row[5], nullptr, 10)); - e.donator = row[6] ? row[6] : ""; - e.permissions = static_cast(strtoul(row[7], nullptr, 10)); - e.whofor = row[8] ? row[8] : ""; + e.id = row[0] ? static_cast(strtoul(row[0], nullptr, 10)) : 0; + e.guild_id = row[1] ? static_cast(strtoul(row[1], nullptr, 10)) : 0; + e.area = row[2] ? static_cast(strtoul(row[2], nullptr, 10)) : 0; + e.slot = row[3] ? static_cast(strtoul(row[3], nullptr, 10)) : 0; + e.item_id = row[4] ? static_cast(strtoul(row[4], nullptr, 10)) : 0; + e.augment_one_id = row[5] ? static_cast(strtoul(row[5], nullptr, 10)) : 0; + e.augment_two_id = row[6] ? static_cast(strtoul(row[6], nullptr, 10)) : 0; + e.augment_three_id = row[7] ? static_cast(strtoul(row[7], nullptr, 10)) : 0; + e.augment_four_id = row[8] ? static_cast(strtoul(row[8], nullptr, 10)) : 0; + e.augment_five_id = row[9] ? static_cast(strtoul(row[9], nullptr, 10)) : 0; + e.augment_six_id = row[10] ? static_cast(strtoul(row[10], nullptr, 10)) : 0; + e.quantity = row[11] ? static_cast(atoi(row[11])) : 0; + e.donator = row[12] ? row[12] : ""; + e.permissions = row[13] ? static_cast(strtoul(row[13], nullptr, 10)) : 0; + e.who_for = row[14] ? row[14] : ""; all_entries.push_back(e); } @@ -399,6 +458,90 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const GuildBank &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.guild_id)); + v.push_back(std::to_string(e.area)); + v.push_back(std::to_string(e.slot)); + v.push_back(std::to_string(e.item_id)); + v.push_back(std::to_string(e.augment_one_id)); + v.push_back(std::to_string(e.augment_two_id)); + v.push_back(std::to_string(e.augment_three_id)); + v.push_back(std::to_string(e.augment_four_id)); + v.push_back(std::to_string(e.augment_five_id)); + v.push_back(std::to_string(e.augment_six_id)); + v.push_back(std::to_string(e.quantity)); + v.push_back("'" + Strings::Escape(e.donator) + "'"); + v.push_back(std::to_string(e.permissions)); + v.push_back("'" + Strings::Escape(e.who_for) + "'"); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.guild_id)); + v.push_back(std::to_string(e.area)); + v.push_back(std::to_string(e.slot)); + v.push_back(std::to_string(e.item_id)); + v.push_back(std::to_string(e.augment_one_id)); + v.push_back(std::to_string(e.augment_two_id)); + v.push_back(std::to_string(e.augment_three_id)); + v.push_back(std::to_string(e.augment_four_id)); + v.push_back(std::to_string(e.augment_five_id)); + v.push_back(std::to_string(e.augment_six_id)); + v.push_back(std::to_string(e.quantity)); + v.push_back("'" + Strings::Escape(e.donator) + "'"); + v.push_back(std::to_string(e.permissions)); + v.push_back("'" + Strings::Escape(e.who_for) + "'"); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_GUILD_BANK_REPOSITORY_H diff --git a/common/version.h b/common/version.h index 3922f2694..9cb1866c1 100644 --- a/common/version.h +++ b/common/version.h @@ -42,7 +42,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9303 +#define CURRENT_BINARY_DATABASE_VERSION 9304 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054 #endif diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 4a6c54541..2a372b93c 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -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()); - } } } diff --git a/zone/entity.cpp b/zone/entity.cpp index e2c00a5bd..bbc20fab0 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2332,30 +2332,18 @@ void EntityList::QueueClientsGuild(const EQApplicationPacket *app, uint32 guild_ } } -void EntityList::QueueClientsGuildBankItemUpdate(const GuildBankItemUpdate_Struct *gbius, uint32 GuildID) +void EntityList::QueueClientsGuildBankItemUpdate(GuildBankItemUpdate_Struct *gbius, uint32 guild_id) { - auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto outapp = std::make_unique(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto data = reinterpret_cast(outapp->pBuffer); - GuildBankItemUpdate_Struct *outgbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; + memcpy(data, gbius, sizeof(GuildBankItemUpdate_Struct)); - memcpy(outgbius, gbius, sizeof(GuildBankItemUpdate_Struct)); - - const EQ::ItemData *Item = database.GetItem(gbius->ItemID); - - auto it = client_list.begin(); - while (it != client_list.end()) { - Client *client = it->second; - - if (client->IsInGuild(GuildID)) { - if (Item && (gbius->Permissions == GuildBankPublicIfUsable)) - outgbius->Useable = Item->IsEquipable(client->GetBaseRace(), client->GetBaseClass()); - - client->QueuePacket(outapp); + for (auto const &[key, client]: client_list) { + if (client->IsInGuild(guild_id)) { + client->QueuePacket(outapp.get()); } - - ++it; } - safe_delete(outapp); } void EntityList::MessageStatus(uint32 to_guild_id, int to_minstatus, uint32 type, const char *message, ...) diff --git a/zone/entity.h b/zone/entity.h index 86a8a0220..2250a5a71 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -429,7 +429,7 @@ public: void QueueClients(Mob* sender, const EQApplicationPacket* app, bool ignore_sender=false, bool ackreq = true); void QueueClientsStatus(Mob* sender, const EQApplicationPacket* app, bool ignore_sender = false, uint8 minstatus = AccountStatus::Player, uint8 maxstatus = AccountStatus::Player); void QueueClientsGuild(const EQApplicationPacket* app, uint32 guildeqid = 0); - void QueueClientsGuildBankItemUpdate(const GuildBankItemUpdate_Struct *gbius, uint32 GuildID); + void QueueClientsGuildBankItemUpdate(GuildBankItemUpdate_Struct *gbius, uint32 GuildID); void QueueClientsByTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, Mob* SkipThisMob = 0, bool ackreq = true, bool HoTT = true, uint32 ClientVersionBits = 0xFFFFFFFF, bool inspect_buffs = false, bool clear_target_window = false); void QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, EQ::versions::ClientVersionBitmask client_version_bits = EQ::versions::ClientVersionBitmask::maskAllClients); diff --git a/zone/gm_commands/guild.cpp b/zone/gm_commands/guild.cpp index 897f3275b..979a624fe 100755 --- a/zone/gm_commands/guild.cpp +++ b/zone/gm_commands/guild.cpp @@ -603,35 +603,73 @@ void command_guild(Client* c, const Seperator* sep) auto guild_id = Strings::ToUnsignedInt(sep->arg[2]); auto guild = guild_mgr.GetGuildByGuildID(guild_id); - PlayerEvent::LootItemEvent e{}; - e.charges = -1; - e.corpse_name = "Test Corpse Name"; - e.item_id = 123456789; - e.item_name = "Test Item Name"; - e.npc_id = 987654321; - e.augment_1_id = 11; - e.augment_2_id = 0; - e.augment_3_id = 0; - e.augment_4_id = 44; - e.augment_5_id = 55; - e.augment_6_id = 66; - - RecordPlayerEventLogWithClient(c, PlayerEvent::LOOT_ITEM, e); - - PlayerEvent::DestroyItemEvent e2{}; - e2.charges = -1; - e2.attuned = true; - e.augment_1_id = 11; - e.augment_2_id = 0; - e.augment_3_id = 0; - e.augment_4_id = 44; - e.augment_5_id = 55; - e.augment_6_id = 66; - e2.item_id = 123456789; - e2.item_name = "Test Item Destroy Name"; - e2.reason = "Test Item Destroy Reason"; - - RecordPlayerEventLogWithClient(c, PlayerEvent::ITEM_DESTROY, e2); + // PlayerEvent::LootItemEvent e{}; + // e.charges = -1; + // e.corpse_name = "Test Corpse Name"; + // e.item_id = 123456789; + // e.item_name = "Test Item Name"; + // e.npc_id = 987654321; + // e.augment_1_id = 11; + // e.augment_2_id = 0; + // e.augment_3_id = 0; + // e.augment_4_id = 44; + // e.augment_5_id = 55; + // e.augment_6_id = 66; + // + // RecordPlayerEventLogWithClient(c, PlayerEvent::LOOT_ITEM, e); + // + // PlayerEvent::DestroyItemEvent e2{}; + // e2.charges = -1; + // e2.attuned = true; + // e.augment_1_id = 11; + // e.augment_2_id = 0; + // e.augment_3_id = 0; + // e.augment_4_id = 44; + // e.augment_5_id = 55; + // e.augment_6_id = 66; + // e2.item_id = 123456789; + // e2.item_name = "Test Item Destroy Name"; + // e2.reason = "Test Item Destroy Reason"; + // + // RecordPlayerEventLogWithClient(c, PlayerEvent::ITEM_DESTROY, e2); + // auto id = Strings::ToUnsignedInt(sep->arg[3]); + // //auto guild = guild_mgr.GetGuildByGuildID(guild_id); + // // c->SendGuildMembersList(); + // auto bank = GuildBanks->GetGuildBank(guild_id); + // if (id == 1) { + // for (auto &[key, item]: bank->items.main_area) { + // auto i = ItemsRepository::FindOne(content_db, item.item_id); + // c->Message(Chat::Yellow, fmt::format("key:{:02} item:{:05} Name:{:40} Qty:{:40} Slot:{}", + // key, item.item_id, i.Name, item.quantity, item.slot).c_str()); + // } + // return; + // } + // if (id == 2) { + // for (auto &[key, item]: bank->items.deposit_area) { + // auto i = ItemsRepository::FindOne(content_db, item.item_id); + // c->Message(Chat::Yellow, fmt::format("key:{:02} item:{:05} Name:{} Qty:{:40} Slot:{}", + // key, item.item_id, i.Name, item.quantity, item.slot).c_str()); + // } + // return; + // } + // if (id == 3) { + // for (auto &[key, item]: bank->items.main_area) { + // if (item.item_id == 30416) { + // auto i = ItemsRepository::FindOne(content_db, item.item_id); + // c->Message(Chat::Yellow, fmt::format("key:{:02} item:{:05} Name:{:40} Qty:{:40} Slot:{}", + // key, item.item_id, i.Name, item.quantity, item.slot).c_str()); + // } + // } + // return; + // } + // if (id == 4) { + // c->Message(Chat::Yellow, "Guild Test 4"); + // auto inst = database.CreateItem(30416, 30); + // database.UpdateInventorySlot(c->CharacterID(), inst, -1); + // safe_delete(inst); + // + // return; + // } } } } diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index a453e5e9b..f6e540c20 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -16,15 +16,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "guild_mgr.h" +#include "../common/emu_versions.h" +#include "../common/repositories/guild_bank_repository.h" +#include "../common/repositories/guild_ranks_repository.h" #include "../common/servertalk.h" #include "../common/strings.h" -#include "string_ids.h" #include "client.h" -#include "guild_mgr.h" +#include "string_ids.h" #include "worldserver.h" #include "zonedb.h" -#include "../common/emu_versions.h" -#include "../common/repositories/guild_ranks_repository.h" ZoneGuildManager guild_mgr; @@ -684,155 +685,108 @@ ZoneGuildManager::~ZoneGuildManager() GuildBankManager::~GuildBankManager() { - auto Iterator = Banks.begin(); - while(Iterator != Banks.end()) - { - safe_delete(*Iterator); - - ++Iterator; - } } -bool GuildBankManager::Load(uint32 guildID) +void GuildBankManager::Load(uint32 guild_id) { + auto results = GuildBankRepository::GetWhere( + database, + fmt::format("`guild_id` = '{}' ORDER BY `area`, `slot`", guild_id) + ); - std::string query = StringFormat("SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` " - "FROM `guild_bank` WHERE `guildid` = %i", guildID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - return false; + auto bank = std::make_shared(); + bank->guild_id = guild_id; + int32 deposit_slot = 0; + int32 main_slot = 0; + + for (auto &it: results) { + if (it.area == GuildBankMainArea) { + it.slot = deposit_slot; + bank->items.main_area.emplace(deposit_slot, it); + deposit_slot++; + } + else { + it.slot = main_slot; + bank->items.deposit_area.emplace(main_slot, it); + main_slot++; + } } - auto bank = new GuildBank; - - bank->GuildID = guildID; - - for (int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - bank->Items.MainArea[i].ItemID = 0; - - for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) - bank->Items.DepositArea[i].ItemID = 0; - - char donator[64], whoFor[64]; - - for (auto row = results.begin(); row != results.end(); ++row) { - int area = Strings::ToInt(row[0]); - int slot = Strings::ToInt(row[1]); - int itemID = Strings::ToInt(row[2]); - int qty = Strings::ToInt(row[3]); - - if (row[4]) - strn0cpy(donator, row[4], sizeof(donator)); - else - donator[0] = '\0'; - - int permissions = Strings::ToInt(row[5]); - - if (row[6]) - strn0cpy(whoFor, row[6], sizeof(whoFor)); - else - whoFor[0] = '\0'; - - if (slot < 0) - continue; - - GuildBankItem *itemSection = nullptr; - - if (area == GuildBankMainArea && slot < GUILD_BANK_MAIN_AREA_SIZE) - itemSection = bank->Items.MainArea; - else if (area != GuildBankMainArea && slot < GUILD_BANK_DEPOSIT_AREA_SIZE) - itemSection = bank->Items.DepositArea; - else - continue; - - itemSection[slot].ItemID = itemID; - itemSection[slot].Quantity = qty; - - strn0cpy(itemSection[slot].Donator, donator, sizeof(donator)); - - itemSection[slot].Permissions = permissions; - - strn0cpy(itemSection[slot].WhoFor, whoFor, sizeof(whoFor)); - } - - Banks.push_back(bank); - - return true; + banks.push_back(bank); } -bool GuildBankManager::IsLoaded(uint32 GuildID) +bool GuildBankManager::IsLoaded(uint32 guild_id) { - auto Iterator = GetGuildBank(GuildID); - - return (Iterator != Banks.end()); + return GetGuildBank(guild_id) ? true : false; } void GuildBankManager::SendGuildBank(Client *c) { - if(!c || !c->IsInAGuild()) - return; - - if(!IsLoaded(c->GuildID())) - Load(c->GuildID()); - - auto Iterator = GetGuildBank(c->GuildID()); - - if(Iterator == Banks.end()) - { - LogError("Unable to find guild bank for guild ID [{}]", c->GuildID()); - + if (!c || !c->IsInAGuild()) { return; } - auto &guild_bank = *Iterator; + if (!IsLoaded(c->GuildID())) { + Load(c->GuildID()); + } + + auto guild_bank = GetGuildBank(c->GuildID()); + if (!guild_bank) { + LogError("Unable to find guild bank for guild ID [{}]", c->GuildID()); + return; + } // RoF+ uses a bulk list packet -- This is also how the Action 0 of older clients basically works if (c->ClientVersionBit() & EQ::versions::maskRoFAndLater) { + auto outapp = new EQApplicationPacket(OP_GuildBankItemList, sizeof(GuildBankItemListEntry_Struct) * 240); - for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { - const EQ::ItemData *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); - if (Item) { + for (int i = 0; i < c->GetInv().GetLookup()->InventoryTypeSize.GuildBankDeposit; i++) { + const EQ::ItemData *item = database.GetItem(guild_bank->items.deposit_area[i].item_id); + if (item) { outapp->WriteUInt8(1); - outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Permissions); - outapp->WriteString(guild_bank->Items.DepositArea[i].WhoFor); - outapp->WriteString(guild_bank->Items.DepositArea[i].Donator); - outapp->WriteUInt32(Item->ID); - outapp->WriteUInt32(Item->Icon); - if (Item->Stackable) { - outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Quantity); - outapp->WriteUInt8(Item->StackSize == guild_bank->Items.DepositArea[i].Quantity ? 1 : 1); - } else { + outapp->WriteUInt32(guild_bank->items.deposit_area[i].permissions); + outapp->WriteString(guild_bank->items.deposit_area[i].who_for.c_str()); + outapp->WriteString(guild_bank->items.deposit_area[i].donator.c_str()); + outapp->WriteUInt32(item->ID); + outapp->WriteUInt32(item->Icon); + if (item->Stackable) { + outapp->WriteUInt32(guild_bank->items.deposit_area[i].quantity); + outapp->WriteUInt8(item->StackSize == guild_bank->items.deposit_area[i].quantity ? 1 : 1); + } + else { outapp->WriteUInt32(1); outapp->WriteUInt8(0); } - outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); - outapp->WriteString(Item->Name); - } else { + outapp->WriteUInt8(item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(item->Name); + } + else { outapp->WriteUInt8(0); // empty } } - outapp->SetWritePosition(outapp->GetWritePosition() + 20); // newer clients have 40 deposit slots, keep them 0 for now - for (int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { - const EQ::ItemData *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); + for (int i = 0; i < c->GetInv().GetLookup()->InventoryTypeSize.GuildBankMain; ++i) { + const EQ::ItemData *Item = database.GetItem(guild_bank->items.main_area[i].item_id); if (Item) { outapp->WriteUInt8(1); - outapp->WriteUInt32(guild_bank->Items.MainArea[i].Permissions); - outapp->WriteString(guild_bank->Items.MainArea[i].WhoFor); - outapp->WriteString(guild_bank->Items.MainArea[i].Donator); + outapp->WriteUInt32(guild_bank->items.main_area[i].permissions); + outapp->WriteString(guild_bank->items.main_area[i].who_for.c_str()); + outapp->WriteString(guild_bank->items.main_area[i].donator.c_str()); outapp->WriteUInt32(Item->ID); outapp->WriteUInt32(Item->Icon); if (Item->Stackable) { - outapp->WriteUInt32(guild_bank->Items.MainArea[i].Quantity); - outapp->WriteUInt8(Item->StackSize == guild_bank->Items.MainArea[i].Quantity ? 1 : 1); - } else { + outapp->WriteUInt32(guild_bank->items.main_area[i].quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->items.main_area[i].quantity ? 1 : 1); + } + else { outapp->WriteUInt32(1); outapp->WriteUInt8(0); } outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); outapp->WriteString(Item->Name); - } else { + } + else { outapp->WriteUInt8(0); // empty } } @@ -842,653 +796,593 @@ void GuildBankManager::SendGuildBank(Client *c) return; } - for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) - { - if(guild_bank->Items.DepositArea[i].ItemID > 0) - { - const EQ::ItemData *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); - - if(!Item) + for (int i = 0; i < c->GetInv().GetLookup()->InventoryTypeSize.GuildBankDeposit; ++i) { + if (guild_bank->items.deposit_area[i].item_id > 0) { + const EQ::ItemData *item = database.GetItem(guild_bank->items.deposit_area[i].item_id); + if (!item) { continue; - - auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); - - GuildBankItemUpdate_Struct *gbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; - - if(!Item->Stackable) - gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, 1, - guild_bank->Items.DepositArea[i].Permissions, 0, 0); - else - { - if(guild_bank->Items.DepositArea[i].Quantity == Item->StackSize) - gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 1, 0); - else - gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 1, 0); } - strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto gbius = (GuildBankItemUpdate_Struct *) outapp->pBuffer; - strn0cpy(gbius->Donator, guild_bank->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); + if (!item->Stackable) { + gbius->Init( + GuildBankItemUpdate, + 1, + i, + GuildBankDepositArea, + 1, + item->ID, + item->Icon, + 1, + guild_bank->items.deposit_area[i].permissions, + 0, + false + ); + } + else { + if (guild_bank->items.deposit_area[i].quantity == item->StackSize) { + gbius->Init( + GuildBankItemUpdate, + 1, + i, + GuildBankDepositArea, + 1, + item->ID, + item->Icon, + guild_bank->items.deposit_area[i].quantity, + guild_bank->items.deposit_area[i].permissions, + 1, + false + ); + } + else { + gbius->Init( + GuildBankItemUpdate, + 1, + i, + GuildBankDepositArea, + 1, + item->ID, + item->Icon, + guild_bank->items.deposit_area[i].quantity, + guild_bank->items.deposit_area[i].permissions, + 1, + false + ); + } + } - strn0cpy(gbius->WhoFor, guild_bank->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->item_name, item->Name, sizeof(gbius->item_name)); + strn0cpy(gbius->donator, guild_bank->items.deposit_area[i].donator.c_str(), sizeof(gbius->donator)); + strn0cpy(gbius->who_for, guild_bank->items.deposit_area[i].who_for.c_str(), sizeof(gbius->who_for)); c->FastQueuePacket(&outapp); } } - for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - { - if(guild_bank->Items.MainArea[i].ItemID > 0) - { - const EQ::ItemData *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); + for (int i = 0; i < c->GetInv().GetLookup()->InventoryTypeSize.GuildBankMain; ++i) { + if (guild_bank->items.main_area[i].item_id > 0) { + const EQ::ItemData *item = database.GetItem(guild_bank->items.main_area[i].item_id); - if(!Item) + if (!item) { continue; - - bool Useable = Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()); - - auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); - - GuildBankItemUpdate_Struct *gbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; - - if(!Item->Stackable) - gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, - guild_bank->Items.MainArea[i].Permissions, 0, Useable); - else - { - if(guild_bank->Items.MainArea[i].Quantity == Item->StackSize) - gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 1, Useable); - else - gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 1, Useable); } - strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); + bool useable = item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto gbius = (GuildBankItemUpdate_Struct *) outapp->pBuffer; - strn0cpy(gbius->Donator, guild_bank->Items.MainArea[i].Donator, sizeof(gbius->Donator)); + if (!item->Stackable) { + gbius->Init( + GuildBankItemUpdate, + 1, + i, + GuildBankMainArea, + 1, + item->ID, + item->Icon, + 1, + guild_bank->items.main_area[i].permissions, + 0, + useable + ); + } + else { + if (guild_bank->items.main_area[i].quantity == item->StackSize) { + gbius->Init( + GuildBankItemUpdate, + 1, + i, + GuildBankMainArea, + 1, + item->ID, + item->Icon, + guild_bank->items.main_area[i].quantity, + guild_bank->items.main_area[i].permissions, + 1, + useable + ); + } + else { + gbius->Init( + GuildBankItemUpdate, + 1, + i, + GuildBankMainArea, + 1, + item->ID, + item->Icon, + guild_bank->items.main_area[i].quantity, + guild_bank->items.main_area[i].permissions, + 1, + useable + ); + } + } - strn0cpy(gbius->WhoFor, guild_bank->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->item_name, item->Name, sizeof(gbius->item_name)); + strn0cpy(gbius->donator, guild_bank->items.main_area[i].donator.c_str(), sizeof(gbius->donator)); + strn0cpy(gbius->who_for, guild_bank->items.main_area[i].who_for.c_str(), sizeof(gbius->who_for)); c->FastQueuePacket(&outapp); } } } -bool GuildBankManager::IsAreaFull(uint32 GuildID, uint16 Area) + +bool GuildBankManager::IsAreaFull(uint32 guild_id, uint16 area) { - auto Iterator = GetGuildBank(GuildID); + return NextFreeBankSlot(guild_id, area) == -1; +} - if(Iterator == Banks.end()) - return true; - - GuildBankItem* BankArea = nullptr; - - int AreaSize = 0; - - if(Area == GuildBankMainArea) - { - BankArea = &(*Iterator)->Items.MainArea[0]; - - AreaSize = GUILD_BANK_MAIN_AREA_SIZE; - } - else - { - BankArea = &(*Iterator)->Items.DepositArea[0]; - - AreaSize = GUILD_BANK_DEPOSIT_AREA_SIZE; +bool GuildBankManager::AddItem(GuildBankRepository::GuildBank &guild_bank_item, Client* c) +{ + auto guild_bank = GetGuildBank(guild_bank_item.guild_id); + if (!guild_bank) { + LogError("Unable to find guild bank for guild ID [{}]", guild_bank_item.guild_id); + return false; } - for(int i = 0; i < AreaSize; ++i) - if(BankArea[i].ItemID == 0) + switch (guild_bank_item.area) { + case GuildBankMainArea: { + for (auto &[key, item]: guild_bank->items.main_area) { + if (item.item_id == 0) { + item.slot = NextFreeBankSlot(guild_bank_item.guild_id, GuildBankMainArea); + guild_bank_item.slot = item.slot; + auto e = GuildBankRepository::InsertOne(database, guild_bank_item); + if (!e.id) { + return false; + } + + guild_bank_item.id = e.id; + item = guild_bank_item; + break; + } + } + break; + } + case GuildBankDepositArea: { + for (auto &[key, item]: guild_bank->items.deposit_area) { + if (item.item_id == 0) { + item.slot = NextFreeBankSlot(guild_bank_item.guild_id, GuildBankDepositArea); + guild_bank_item.slot = item.slot; + auto e = GuildBankRepository::InsertOne(database, guild_bank_item); + if (!e.id) { + return false; + } + guild_bank_item.id = e.id; + item = guild_bank_item; + break; + } + } + break; + } + default: { return false; + } + } + + SendGuildBankItemUpdate(guild_bank_item.guild_id, guild_bank_item.slot, guild_bank_item.area, true, c); return true; } -bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32 QtyOrCharges, const char *Donator, uint8 Permissions, const char *WhoFor) +int GuildBankManager::Promote(uint32 guild_id, int slot_id, Client* c) { - auto Iterator = GetGuildBank(GuildID); - - if(Iterator == Banks.end()) - { - LogError("Unable to find guild bank for guild ID [{}]", GuildID); - - return false; + if (slot_id < 0) { + return -1; } - GuildBankItem* BankArea = nullptr; - - int AreaSize = 0; - - if(Area == GuildBankMainArea) - { - BankArea = &(*Iterator)->Items.MainArea[0]; - - AreaSize = GUILD_BANK_MAIN_AREA_SIZE; - } - else - { - BankArea = &(*Iterator)->Items.DepositArea[0]; - - AreaSize = GUILD_BANK_DEPOSIT_AREA_SIZE; + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { + return -1; } - int Slot = -1; - - for(int i = 0; i < AreaSize; ++i) - { - if(BankArea[i].ItemID == 0) - { - BankArea[i].ItemID = ItemID; - - BankArea[i].Quantity = QtyOrCharges; - - strn0cpy(BankArea[i].Donator, Donator, sizeof(BankArea[i].Donator)); - - BankArea[i].Permissions = Permissions; - - strn0cpy(BankArea[i].WhoFor, WhoFor, sizeof(BankArea[i].WhoFor)); - - Slot = i; - - break; - } + auto it_deposit = guild_bank->items.deposit_area.find(slot_id); + if (it_deposit == std::end(guild_bank->items.deposit_area)) { + return -1; } - if(Slot < 0) - { - LogError("No space to add item to the guild bank"); + auto new_item = GuildBankRepository::NewEntity(); + new_item.id = it_deposit->second.id; + new_item.guild_id = it_deposit->second.guild_id; + new_item.area = GuildBankMainArea; + new_item.slot = NextFreeBankSlot(guild_id, GuildBankMainArea); + new_item.item_id = it_deposit->second.item_id; + new_item.augment_one_id = it_deposit->second.augment_one_id; + new_item.augment_two_id = it_deposit->second.augment_two_id; + new_item.augment_three_id = it_deposit->second.augment_three_id; + new_item.augment_four_id = it_deposit->second.augment_four_id; + new_item.augment_five_id = it_deposit->second.augment_five_id; + new_item.augment_six_id = it_deposit->second.augment_six_id; + new_item.quantity = it_deposit->second.quantity; + new_item.donator = it_deposit->second.donator; + new_item.who_for = it_deposit->second.who_for; + new_item.permissions = it_deposit->second.permissions; - return false; - } + GuildBankRepository::UpdateOne(database, new_item); - std::string query = StringFormat("INSERT INTO `guild_bank` " - "(`guildid`, `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `WhoFor`) " - "VALUES (%i, %i, %i, %i, %i, '%s', %i, '%s')", - GuildID, Area, Slot, ItemID, QtyOrCharges, Donator, Permissions, WhoFor); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - return false; - } + SendGuildBankItemUpdate(it_deposit->second.guild_id, it_deposit->second.slot, it_deposit->second.area, false, c); + it_deposit->second = std::move(GuildBankRepository::NewEntity()); + guild_bank->items.main_area[new_item.slot] = new_item; + SendGuildBankItemUpdate(new_item.guild_id, new_item.slot, new_item.area, true, c); - const EQ::ItemData *Item = database.GetItem(ItemID); - - GuildBankItemUpdate_Struct gbius; - - if(!Item->Stackable) - gbius.Init(GuildBankItemUpdate, 1, Slot, Area, 1, ItemID, Item->Icon, Item->Stackable ? QtyOrCharges : 1, Permissions, 0, 0); - else - { - if(QtyOrCharges == Item->StackSize) - gbius.Init(GuildBankItemUpdate, 1, Slot, Area, 1, ItemID, Item->Icon, Item->Stackable ? QtyOrCharges : 1, Permissions, 1, 0); - else - gbius.Init(GuildBankItemUpdate, 1, Slot, Area, 1, ItemID, Item->Icon, Item->Stackable ? QtyOrCharges : 1, Permissions, 1, 0); - } - - strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - - strn0cpy(gbius.Donator, Donator, sizeof(gbius.Donator)); - - strn0cpy(gbius.WhoFor, WhoFor, sizeof(gbius.WhoFor)); - - entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); - - return true; + return new_item.slot; } -int GuildBankManager::Promote(uint32 guildID, int slotID) +void GuildBankManager::SetPermissions(uint32 guild_id, uint16 slot_id, uint32 permissions, const char *member_name, Client* c) { - if((slotID < 0) || (slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))) - return -1; - - auto iter = GetGuildBank(guildID); - - if(iter == Banks.end()) - return -1; - - if((*iter)->Items.DepositArea[slotID].ItemID == 0) - return -1; - - int mainSlot = -1; - - for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - if((*iter)->Items.MainArea[i].ItemID == 0) { - mainSlot = i; - break; - } - - if(mainSlot == -1) - return -1; - - (*iter)->Items.MainArea[mainSlot].ItemID = (*iter)->Items.DepositArea[slotID].ItemID; - (*iter)->Items.MainArea[mainSlot].Quantity = (*iter)->Items.DepositArea[slotID].Quantity; - (*iter)->Items.MainArea[mainSlot].Permissions = (*iter)->Items.DepositArea[slotID].Permissions; - - strn0cpy((*iter)->Items.MainArea[mainSlot].Donator, (*iter)->Items.DepositArea[slotID].Donator, sizeof((*iter)->Items.MainArea[mainSlot].Donator)); - strn0cpy((*iter)->Items.MainArea[mainSlot].WhoFor, (*iter)->Items.DepositArea[slotID].WhoFor, sizeof((*iter)->Items.MainArea[mainSlot].WhoFor)); - - std::string query = StringFormat("UPDATE `guild_bank` SET `area` = 1, `slot` = %i " - "WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i " - "LIMIT 1", mainSlot, guildID, slotID); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - return -1; + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { + return; } - (*iter)->Items.DepositArea[slotID].ItemID = 0; + auto item = &guild_bank->items.main_area[slot_id]; + item->permissions = permissions; + item->who_for.clear(); - const EQ::ItemData *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID); - - GuildBankItemUpdate_Struct gbius; - - if(!Item->Stackable) - gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0); - else - { - if((*iter)->Items.MainArea[mainSlot].Quantity == Item->StackSize) - gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0); - else - gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0); + if (permissions == GuildBankSingleMember) { + item->who_for = member_name; } - strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - - entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); - - gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0); - - entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); - - return mainSlot; + GuildBankRepository::UpdateOne(database, *item); + SendGuildBankItemUpdate(item->guild_id, item->slot, item->area, true, c); } -void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 permissions, const char *memberName) +std::unique_ptr GuildBankManager::GetItem(uint32 guild_id, uint16 area, uint16 slot_id, uint32 quantity) { - if((slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))) - return; - - auto iter = GetGuildBank(guildID); - - if(iter == Banks.end()) - return; - - if((*iter)->Items.MainArea[slotID].ItemID == 0) - return; - - std::string query = StringFormat("UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' " - "WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1", - permissions, memberName, guildID, slotID); - auto results = database.QueryDatabase(query); - if(!results.Success()) - { - return; - } - - (*iter)->Items.MainArea[slotID].Permissions = permissions; - - if(permissions == GuildBankSingleMember) - strn0cpy((*iter)->Items.MainArea[slotID].WhoFor, memberName, sizeof((*iter)->Items.MainArea[slotID].WhoFor)); - else - (*iter)->Items.MainArea[slotID].WhoFor[0] = '\0'; - - const EQ::ItemData *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID); - - GuildBankItemUpdate_Struct gbius; - - if(!Item->Stackable) - gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*iter)->Items.MainArea[slotID].Permissions, 0, 0); - else - { - if((*iter)->Items.MainArea[slotID].Quantity == Item->StackSize) - gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0); - else - gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0); - } - - - strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - - strn0cpy(gbius.WhoFor, (*iter)->Items.MainArea[slotID].WhoFor, sizeof(gbius.WhoFor)); - - entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); -} - -EQ::ItemInstance* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) -{ - auto Iterator = GetGuildBank(GuildID); - - if(Iterator == Banks.end()) + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { return nullptr; - - GuildBankItem* BankArea = nullptr; - - EQ::ItemInstance* inst = nullptr; - - if(Area == GuildBankDepositArea) - { - if((SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))) - return nullptr; - - inst = database.CreateItem((*Iterator)->Items.DepositArea[SlotID].ItemID); - - if(!inst) - return nullptr; - - BankArea = &(*Iterator)->Items.DepositArea[0]; - } - else - { - - if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))) - return nullptr; - - inst = database.CreateItem((*Iterator)->Items.MainArea[SlotID].ItemID); - - if(!inst) - return nullptr; - - BankArea = &(*Iterator)->Items.MainArea[0]; } - if(!inst->IsStackable()) - inst->SetCharges(BankArea[SlotID].Quantity); - else - { - if(Quantity <= BankArea[SlotID].Quantity) - inst->SetCharges(Quantity); - else - inst->SetCharges(BankArea[SlotID].Quantity); + std::unique_ptr inst; + + if (area == GuildBankDepositArea) { + if (slot_id > guild_bank->items.deposit_area.size()) { + return nullptr; + } + + inst.reset(database.CreateItem( + guild_bank->items.deposit_area[slot_id].item_id, + guild_bank->items.deposit_area[slot_id].quantity, + guild_bank->items.deposit_area[slot_id].augment_one_id, + guild_bank->items.deposit_area[slot_id].augment_two_id, + guild_bank->items.deposit_area[slot_id].augment_three_id, + guild_bank->items.deposit_area[slot_id].augment_four_id, + guild_bank->items.deposit_area[slot_id].augment_five_id, + guild_bank->items.deposit_area[slot_id].augment_six_id) + ); + + if (!inst) { + return nullptr; + } + + if (!inst->IsStackable()) { + inst->SetCharges(guild_bank->items.deposit_area[slot_id].quantity); + } + else { + if (quantity <= guild_bank->items.deposit_area[slot_id].quantity) { + inst->SetCharges(quantity); + } + else { + inst->SetCharges(guild_bank->items.deposit_area[slot_id].quantity); + } + } + } + else { + if (slot_id > guild_bank->items.main_area.size()) { + return nullptr; + } + + inst.reset(database.CreateItem( + guild_bank->items.main_area[slot_id].item_id, + guild_bank->items.main_area[slot_id].quantity, + guild_bank->items.main_area[slot_id].augment_one_id, + guild_bank->items.main_area[slot_id].augment_two_id, + guild_bank->items.main_area[slot_id].augment_three_id, + guild_bank->items.main_area[slot_id].augment_four_id, + guild_bank->items.main_area[slot_id].augment_five_id, + guild_bank->items.main_area[slot_id].augment_six_id) + ); + + if (!inst) { + return nullptr; + } + + if (!inst->IsStackable()) { + inst->SetCharges(guild_bank->items.main_area[slot_id].quantity); + } + else { + if (quantity <= guild_bank->items.main_area[slot_id].quantity) { + inst->SetCharges(quantity); + } + else { + inst->SetCharges(guild_bank->items.main_area[slot_id].quantity); + } + } } return inst; } -bool GuildBankManager::HasItem(uint32 GuildID, uint32 ItemID) +bool GuildBankManager::HasItem(uint32 guild_id, uint32 item_id) { - auto Iterator = GetGuildBank(GuildID); - - if(Iterator == Banks.end()) + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { return false; + } - for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - if((*Iterator)->Items.MainArea[i].ItemID == ItemID) + for (auto const &[slot, item]: guild_bank->items.deposit_area) { + if (item.item_id == item_id) { return true; + } + } - for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) - if((*Iterator)->Items.DepositArea[i].ItemID == ItemID) + for (auto const &[slot, item]: guild_bank->items.main_area) { + if (item.item_id == item_id) { return true; + } + } return false; } -std::list::iterator GuildBankManager::GetGuildBank(uint32 GuildID) +std::shared_ptr GuildBankManager::GetGuildBank(const uint32 guild_id) { - auto Iterator = Banks.begin(); + if (!GuildBanks) { + return nullptr; + } - while(Iterator != Banks.end()) - { - if((*Iterator)->GuildID == GuildID) + for (auto &b:banks) { + if (b->guild_id == guild_id) { + return b; + } + } + + return nullptr; +} + +bool GuildBankManager::DeleteItem(uint32 guild_id, uint16 area, uint16 slot_id, uint32 quantity, Client* c) +{ + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { + return false; + } + + auto item = &guild_bank->items.deposit_area[slot_id]; + + if (area == GuildBankMainArea) { + item = &guild_bank->items.main_area[slot_id]; + } + + if (item->item_id == 0) { + return false; + } + + // delete the item + if (item->quantity == quantity) { + SendGuildBankItemUpdate(item->guild_id, item->slot, item->area, false, c); + GuildBankRepository::DeleteOne(database, item->id); + + item->item_id = 0; + item->id = 0; + item->guild_id = 0; + item->slot = 0; + item->quantity = 0; + item->permissions = 0; + item->donator.clear(); + item->who_for.clear(); + + return true; + } + + //otherwise update the quantity + item->quantity -= quantity; + GuildBankRepository::UpdateOne(database, *item); + SendGuildBankItemUpdate(item->guild_id, item->slot, item->area, true, c); + + return true; +} + +bool GuildBankManager::MergeStacks(uint32 guild_id, uint16 slot_id, Client* c) +{ + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { + return false; + } + + auto merge_bank_item = &guild_bank->items.main_area[slot_id]; + const auto merge_item = database.GetItem(merge_bank_item->item_id); + + if (merge_bank_item->item_id == 0 || !merge_item) { + return false; + } + + const int16 stack_size = merge_item->StackSize; + std::vector queue{}; + std::vector queue_delete{}; + std::vector queue_updates{}; + + for (auto &[key, item]: guild_bank->items.main_area) { + if (item.item_id == merge_bank_item->item_id && item.slot != slot_id) { + queue.push_back(&item); + } + } + + if (queue.empty()) { + return false; + } + + std::ranges::sort(queue.begin(), queue.end(), [](auto &a, auto &b) { return a->quantity < b->quantity; }); + + for (auto const &i: queue) { + const int16 remaining_stack_size = stack_size - static_cast(merge_bank_item->quantity); + merge_bank_item->quantity += i->quantity; + + if (merge_bank_item->quantity <= stack_size) { + i->item_id = 0; + queue_delete.push_back(std::to_string(i->id)); + queue_updates.push_back(*i); + continue; + } + + if (merge_bank_item->quantity > stack_size) { + merge_bank_item->quantity = stack_size; + i->quantity -= remaining_stack_size; + queue_updates.push_back(*i); + queue_updates.push_back(*merge_bank_item); break; - - ++Iterator; - } - - return Iterator; -} - -bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity) -{ - auto iter = GetGuildBank(guildID); - - if(iter == Banks.end()) - return false; - - GuildBankItem* BankArea = nullptr; - - if(area == GuildBankMainArea) - { - if(slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) - return false; - - BankArea = &(*iter)->Items.MainArea[0]; - } else { - if(slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)) - return false; - - BankArea = &(*iter)->Items.DepositArea[0]; - } - - bool deleted = true; - - const EQ::ItemData *Item = database.GetItem(BankArea[slotID].ItemID); - - if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) { - std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i " - "AND `area` = %i AND `slot` = %i LIMIT 1", - guildID, area, slotID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - return false; } - - BankArea[slotID].ItemID = 0; - - } else { - std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i WHERE `guildid` = %i " - "AND `area` = %i AND `slot` = %i LIMIT 1", - BankArea[slotID].Quantity - quantity, guildID, area, slotID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - return false; - } - - BankArea[slotID].Quantity -= quantity; - - deleted = false; } - GuildBankItemUpdate_Struct gbius; - - if(!deleted) - { - gbius.Init(GuildBankItemUpdate, 1, slotID, area, 1, Item->ID, Item->Icon, BankArea[slotID].Quantity, BankArea[slotID].Permissions, 1, 0); - - strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - - strn0cpy(gbius.WhoFor, BankArea[slotID].WhoFor, sizeof(gbius.WhoFor)); + if (merge_bank_item->quantity < stack_size) { + queue_updates.push_back(*merge_bank_item); + queue.push_back(merge_bank_item); } - else - gbius.Init(GuildBankItemUpdate, 1, slotID, area, 0, 0, 0, 0, 0, 0, 0); - entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); + GuildBankRepository::ReplaceMany(database, queue_updates); + if (!queue_delete.empty()) { + GuildBankRepository::DeleteWhere( + database, fmt::format("`id` IN({})", Strings::Implode(",", queue_delete)).c_str() + ); + } - return true; - -} - -bool GuildBankManager::MergeStacks(uint32 GuildID, uint16 SlotID) -{ - if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) - return false; - - auto Iterator = GetGuildBank(GuildID); - - if(Iterator == Banks.end()) - return false; - - GuildBankItem* BankArea = &(*Iterator)->Items.MainArea[0]; - - if(BankArea[SlotID].ItemID == 0) - return false; - - const EQ::ItemData *Item = database.GetItem(BankArea[SlotID].ItemID); - - if(!Item->Stackable) - return false; - - uint32 ItemID = BankArea[SlotID].ItemID; - - for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE - 1; ++i) - { - if(BankArea[i].ItemID != ItemID) + for (auto const &i: queue_updates) { + if (i.item_id == 0) { + SendGuildBankItemUpdate(i.guild_id, i.slot, GuildBankMainArea, false, c); continue; - - if(BankArea[i].Quantity == Item->StackSize) - continue; - - bool Merged = false; - - for(int j = i + 1; j < GUILD_BANK_MAIN_AREA_SIZE; ++j) - { - if(BankArea[j].ItemID != ItemID) - continue; - - if(BankArea[j].Permissions != BankArea[i].Permissions) - continue; - - if(BankArea[i].Permissions == 1) - if(strncmp(BankArea[i].WhoFor, BankArea[j].WhoFor, sizeof(BankArea[i].WhoFor))) - continue; - - if((BankArea[i].Quantity + BankArea[j].Quantity) <= Item->StackSize) - { - BankArea[i].Quantity += BankArea[j].Quantity; - - DeleteItem(GuildID, GuildBankMainArea, j, BankArea[j].Quantity); - - Merged = true; - - if(BankArea[i].Quantity == Item->StackSize) - break; - } - else - { - uint32 QuantityToMove = Item->StackSize - BankArea[i].Quantity; - - DeleteItem(GuildID, GuildBankMainArea, j, QuantityToMove); - - BankArea[i].Quantity = Item->StackSize; - - Merged = true; - - break; - } - } - - if(Merged) - { - UpdateItemQuantity(GuildID, GuildBankMainArea, i, BankArea[i].Quantity); - - GuildBankItemUpdate_Struct gbius; - - if(BankArea[i].Quantity == Item->StackSize) - gbius.Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, ItemID, Item->Icon, BankArea[i].Quantity, BankArea[i].Permissions, 1, 0); - else - gbius.Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, ItemID, Item->Icon, BankArea[i].Quantity, BankArea[i].Permissions, 1, 0); - - strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - - strn0cpy(gbius.WhoFor, BankArea[i].WhoFor, sizeof(gbius.WhoFor)); - - entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); } + SendGuildBankItemUpdate(i.guild_id, i.slot, GuildBankMainArea, true, c); } return true; } -bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity) +bool GuildBankManager::SplitStack(uint32 guild_id, uint16 slot_id, uint32 quantity, Client* c) { - if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { return false; + } - auto Iterator = GetGuildBank(GuildID); - - if(Iterator == Banks.end()) + if (IsAreaFull(guild_id, GuildBankMainArea)) { return false; + } - if(IsAreaFull(GuildID, GuildBankMainArea)) + auto split_bank_item = &guild_bank->items.main_area[slot_id]; + const auto split_item = database.GetItem(split_bank_item->item_id); + + if (split_bank_item->item_id == 0 || !split_item) { return false; + } - GuildBankItem* BankArea = &(*Iterator)->Items.MainArea[0]; + auto new_item = GuildBankRepository::NewEntity(); + new_item = *split_bank_item; + new_item.id = 0; + new_item.slot = NextFreeBankSlot(guild_id, GuildBankMainArea); + new_item.quantity = quantity; + split_bank_item->quantity -= quantity; - if(BankArea[SlotID].ItemID == 0) - return false; + GuildBankRepository::UpdateOne(database, *split_bank_item); + auto e = GuildBankRepository::InsertOne(database, new_item); + new_item.id = e.id; + guild_bank->items.main_area[new_item.slot] = new_item; - if(BankArea[SlotID].Quantity <= Quantity || Quantity == 0) - return false; - - const EQ::ItemData *Item = database.GetItem(BankArea[SlotID].ItemID); - - if(!Item->Stackable) - return false; - - AddItem(GuildID, GuildBankMainArea, BankArea[SlotID].ItemID, Quantity, "", BankArea[SlotID].Permissions, BankArea[SlotID].WhoFor); - - DeleteItem(GuildID, GuildBankMainArea, SlotID, Quantity); + SendGuildBankItemUpdate(split_bank_item->guild_id, split_bank_item->slot, split_bank_item->area, true, c); + SendGuildBankItemUpdate(new_item.guild_id, new_item.slot, new_item.area, true, c); return true; } -void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity) +// void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity) +// { +// // Helper method for MergeStacks. Assuming all passed parameters are valid. +// // +// std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i " +// "WHERE `guildid` = %i AND `area` = %i " +// "AND `slot` = %i LIMIT 1", +// quantity, guildID, area, slotID); +// auto results = database.QueryDatabase(query); +// if(!results.Success()) { +// return; +// } +// +// } + +// bool GuildBankManager::AllowedToWithdraw(uint32 guild_id, uint16 area, uint16 slot_id, const char *name) +// { +// auto guild_bank = GetGuildBank(guild_id); +// if (!guild_bank) { +// return false; +// } +// +// if (area != GuildBankMainArea) { +// return false; +// } +// +// auto item = &guild_bank->items.main_area[slot_id]; +// uint8 permissions = item->permissions; +// +// if (permissions == GuildBankBankerOnly) { +// return false; +// } +// +// return false; +// } + +int32 GuildBankManager::NextFreeBankSlot(uint32 guild_id, uint32 area) { - // Helper method for MergeStacks. Assuming all passed parameters are valid. - // - std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i " - "WHERE `guildid` = %i AND `area` = %i " - "AND `slot` = %i LIMIT 1", - quantity, guildID, area, slotID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - return; + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { + return -1; } -} + if (area == GuildBankMainArea) { + auto it = + std::ranges::find_if(guild_bank->items.main_area.begin(), guild_bank->items.main_area.end(), [&](auto &m) { + return m.second.item_id == 0; + } + ); + if (it == guild_bank->items.main_area.end()) { + return -1; + } -bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name) -{ - // Is a none-Guild Banker allowed to withdraw the item at this slot ? - // This is really here for anti-hacking measures, as the client should not request an item it does not have permission to withdraw. - // - if (SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) { - return false; + return it->first; } - auto Iterator = GetGuildBank(GuildID); - - if (Iterator == Banks.end()) { - return false; + auto it = std::ranges::find_if( + guild_bank->items.deposit_area.begin(), guild_bank->items.deposit_area.end(), [&](auto &m) { + return m.second.item_id == 0; + } + ); + if (it == guild_bank->items.deposit_area.end()) { + return -1; } - if (Area != GuildBankMainArea) { - return false; - } - - uint8 Permissions = (*Iterator)->Items.MainArea[SlotID].Permissions; - - if (Permissions == GuildBankBankerOnly) { - return false; - } - - if (Permissions != - GuildBankSingleMember) { // Public or Public-If-Useable (should really check if item is useable) - return true; - } - - if (!strncmp((*Iterator)->Items.MainArea[SlotID].WhoFor, - Name, - sizeof((*Iterator)->Items.MainArea[SlotID].WhoFor))) { - return true; - } - - return false; + return it->first; } void ZoneGuildManager::UpdateRankPermission(uint32 gid, uint32 charid, uint32 fid, uint32 rank, uint32 value) @@ -1829,3 +1723,40 @@ void ZoneGuildManager::SendToWorldSendGuildMembersList(uint32 guild_id) worldserver.SendPacket(outapp); safe_delete(outapp) } + +void GuildBankManager::SendGuildBankItemUpdate(uint32 guild_id, int32 slot_id, uint32 area, bool display, Client* c) +{ + auto guild_bank = GetGuildBank(guild_id); + if (!guild_bank) { + return; + } + + auto item = guild_bank->items.deposit_area[slot_id]; + if (area == GuildBankMainArea) { + item = guild_bank->items.main_area[slot_id]; + } + + const auto item_data = database.GetItem(item.item_id); + + if (item_data && (item_data->MaxCharges > 0 || item_data->MaxCharges < 0)) { + item.quantity = 1; + } + + GuildBankItemUpdate_Struct gbius{}; + gbius.action = GuildBankItemUpdate; + gbius.slot_id = item.slot; + gbius.area = item.area; + gbius.item_id = item.item_id; + gbius.permissions = item.permissions; + gbius.icon_id = item_data ? item_data->Icon : 0; + gbius.display = display; + gbius.allow_merge = item_data ? item_data->Stackable : false; + gbius.is_useable = item_data ? item_data->IsEquipable(c->GetRace(), c->GetClass()) : false; + gbius.quantity = item.quantity; + + strn0cpy(gbius.item_name, item_data ? item_data->Name : "", sizeof(gbius.item_name)); + strn0cpy(gbius.donator, item.donator.empty() ? "" : item.donator.c_str(), sizeof(gbius.donator)); + strn0cpy(gbius.who_for, item.who_for.empty() ? "" : item.who_for.c_str(), sizeof(gbius.who_for)); + + entity_list.QueueClientsGuildBankItemUpdate(&gbius, guild_id); +} diff --git a/zone/guild_mgr.h b/zone/guild_mgr.h index 00ca287b9..2fe4ae7b2 100644 --- a/zone/guild_mgr.h +++ b/zone/guild_mgr.h @@ -1,10 +1,12 @@ #ifndef GUILD_MGR_H_ #define GUILD_MGR_H_ -#include "../common/types.h" -#include "../common/guild_base.h" -#include #include +#include +#include "../common/guild_base.h" +#include "../common/types.h" + +#include "../common/repositories/guild_bank_repository.h" #include "../zone/petitions.h" extern PetitionList petition_list; @@ -14,38 +16,50 @@ extern PetitionList petition_list; #define PBUFFER 50 #define MBUFFER 50 -#define GUILD_BANK_MAIN_AREA_SIZE 200 -#define GUILD_BANK_DEPOSIT_AREA_SIZE 20 class Client; class ServerPacket; -struct GuildBankItem -{ - uint32 ItemID; - uint32 Quantity; - char Donator[64]; - uint8 Permissions; - char WhoFor[64]; -}; - struct GuildBankItems { - GuildBankItem MainArea[GUILD_BANK_MAIN_AREA_SIZE]; - GuildBankItem DepositArea[GUILD_BANK_DEPOSIT_AREA_SIZE]; + std::map main_area{}; + std::map deposit_area{}; }; struct GuildBank { - uint32 GuildID; - GuildBankItems Items; + uint32 guild_id; + GuildBankItems items{}; + + GuildBank() + { + guild_id = 0; + } }; -enum { GuildBankBulkItems = 0, GuildBankItemUpdate = 1, GuildBankPromote = 3, GuildBankViewItem = 4, GuildBankDeposit = 5, - GuildBankPermissions = 6, GuildBankWithdraw = 7, GuildBankSplitStacks = 8, GuildBankMergeStacks = 9, GuildBankAcknowledge = 10 }; +enum { + GuildBankBulkItems = 0, + GuildBankItemUpdate = 1, + GuildBankPromote = 3, + GuildBankViewItem = 4, + GuildBankDeposit = 5, + GuildBankPermissions = 6, + GuildBankWithdraw = 7, + GuildBankSplitStacks = 8, + GuildBankMergeStacks = 9, + GuildBankAcknowledge = 10 +}; -enum { GuildBankDepositArea = 0, GuildBankMainArea = 1 }; +enum { + GuildBankDepositArea = 0, + GuildBankMainArea = 1 +}; -enum { GuildBankBankerOnly = 0, GuildBankSingleMember = 1, GuildBankPublicIfUsable = 2, GuildBankPublic = 3 }; +enum { + GuildBankBankerOnly = 0, + GuildBankSingleMember = 1, + GuildBankPublicIfUsable = 2, + GuildBankPublic = 3 +}; class ZoneGuildManager : public BaseGuildManager { public: @@ -82,7 +96,7 @@ public: void UpdateRankName(uint32 gid, uint32 rank, std::string rank_name); void SendRankName(uint32 guild_id, uint32 rank, std::string rank_name); void SendAllRankNames(uint32 guild_id, uint32 char_id); - BaseGuildManager::GuildInfo* GetGuildByGuildID(uint32 guild_id); + GuildInfo* GetGuildByGuildID(uint32 guild_id); virtual void SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation); protected: @@ -103,30 +117,30 @@ class GuildBankManager public: ~GuildBankManager(); void SendGuildBank(Client *c); - bool AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32 QtyOrCharges, const char *Donator, uint8 Permissions, const char *WhoFor); - int Promote(uint32 GuildID, int SlotID); - void SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName); - EQ::ItemInstance* GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity); - bool DeleteItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity); - bool HasItem(uint32 GuildID, uint32 ItemID); - bool IsAreaFull(uint32 GuildID, uint16 Area); - bool MergeStacks(uint32 GuildID, uint16 SlotID); - bool SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity); - bool AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name); + bool AddItem(GuildBankRepository::GuildBank &guild_bank_item, Client* client); + int Promote(uint32 GuildID, int SlotID, Client* c); + void SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName, Client* c); + std::unique_ptr GetItem(uint32 guild_id, uint16 area, uint16 slot_id, uint32 quantity); + bool DeleteItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity, Client* c); + bool HasItem(uint32 guild_id, uint32 item_id); + bool IsAreaFull(uint32 guild_id, uint16 area); + int32 NextFreeBankSlot(uint32 guild_id, uint32 area); + bool MergeStacks(uint32 GuildID, uint16 SlotID, Client* c); + bool SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity, Client* c); + //bool AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name); + void SendGuildBankItemUpdate(uint32 guild_id, int32 slot_id, uint32 area, bool display, Client* c); + std::shared_ptr GetGuildBank(uint32 guild_id); private: bool IsLoaded(uint32 GuildID); - bool Load(uint32 GuildID); - std::list::iterator GetGuildBank(uint32 GuildID); + void Load(uint32 GuildID); void UpdateItemQuantity(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity); - std::list Banks; - + std::list> banks{}; }; extern ZoneGuildManager guild_mgr; extern GuildBankManager *GuildBanks; - #endif /*GUILD_MGR_H_*/