From c2e436521411c136330845b50383a99eb4aaf1df Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 7 Jun 2015 22:07:40 -0400 Subject: [PATCH] Implemented rule-based disenchanted bag use --- changelog.txt | 3 + common/ruletypes.h | 1 + .../2014_03_17_EnforceAugmentRules.sql | 2 +- .../2015_06_07_TransformSummonedBagsRule.sql | 1 + zone/client.h | 1 + zone/client_process.cpp | 6 +- zone/inventory.cpp | 181 ++++++++++++++++++ 7 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql diff --git a/changelog.txt b/changelog.txt index cdb2fd5f8..bc96a8ef1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 06/07/2015 == +Uleat: Implemented optional rule for using disenchanted bags. Action triggers at the same point that temporary items are removed. +Optional SQL: utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql == 05/25/2015 == Akkadius: Implemented disjointed zone based time, this can be triggered via quest methods diff --git a/common/ruletypes.h b/common/ruletypes.h index cf77dddf6..d0f198164 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -611,6 +611,7 @@ RULE_BOOL ( Inventory, EnforceAugmentUsability, true) // Forces augmented item u RULE_BOOL ( Inventory, EnforceAugmentWear, true) // Forces augment wear slot validation RULE_BOOL ( Inventory, DeleteTransformationMold, true) //False if you want mold to last forever RULE_BOOL ( Inventory, AllowAnyWeaponTransformation, false) //Weapons can use any weapon transformation +RULE_BOOL ( Inventory, TransformSummonedBags, false) //Transforms summoned bags into disenchanted ones instead of deleting RULE_CATEGORY_END() RULE_CATEGORY( Client ) diff --git a/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql b/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql index e89d4a437..25ec3734d 100644 --- a/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql +++ b/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql @@ -1,3 +1,3 @@ INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentRestriction', 'false', 'Forces augment slot restrictions.'); INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentUsability', 'false', 'Forces augmented item usability.'); -INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentWear', 'false', 'Forces augment wear slot validation.'); \ No newline at end of file +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentWear', 'false', 'Forces augment wear slot validation.'); diff --git a/utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql b/utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql new file mode 100644 index 000000000..d0af46a24 --- /dev/null +++ b/utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:TransformSummonedBags', 'true', 'Transforms summoned bags into disenchanted ones instead of deleting.'); diff --git a/zone/client.h b/zone/client.h index 2015a52ba..de093990c 100644 --- a/zone/client.h +++ b/zone/client.h @@ -906,6 +906,7 @@ public: bool DecreaseByID(uint32 type, uint8 amt); uint8 SlotConvert2(uint8 slot); //Maybe not needed. void Escape(); //AA Escape + void DisenchantSummonedBags(bool client_update = true); void RemoveNoRent(bool client_update = true); void RemoveDuplicateLore(bool client_update = true); void MoveSlotNotAllowed(bool client_update = true); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index be2e1321f..4a16e7698 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -838,7 +838,11 @@ void Client::BulkSendInventoryItems() { } bool deletenorent = database.NoRentExpired(GetName()); - if(deletenorent){ RemoveNoRent(false); } //client was offline for more than 30 minutes, delete no rent items + if (deletenorent) { //client was offline for more than 30 minutes, delete no rent items + if (RuleB(Inventory, TransformSummonedBags)) + DisenchantSummonedBags(false); + RemoveNoRent(false); + } RemoveDuplicateLore(false); MoveSlotNotAllowed(false); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 2ce30fe5e..e1904d59f 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -2158,6 +2158,187 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) { return true; } +static bool IsSummonedBagID(uint32 item_id) +{ + switch (item_id) { + case 17147: // "Spiritual Prismatic Pack" + case 17303: // "Spirit Pouch" + case 17304: // "Dimensional Pocket" + case 17305: // "Dimensional Hole" + case 17306: // "Glowing Backpack" + case 17307: // "Quiver of Marr" + case 17308: // "Bandoleer of Luclin" + case 17309: // "Pouch of Quellious" + case 17310: // "Phantom Satchel" + case 17510: // "Glowing Chest" + case 17900: // "Grandmaster's Satchel" + case 57260: // "Glowing Backpack" + case 57261: // "Pouch of Quellious" + case 57262: // "Phantom Satchel" + case 60224: // "Faded-Glyph Tablet" + case 95199: // "Beginner Artisan Satchel" + case 95200: // "Apprentice Artisan Satchel" + case 95201: // "Freshman Artisan Satchel" + case 95202: // "Journeyman Artisan Satchel" + case 95203: // "Expert Artisan Satchel" + case 95204: // "Master Artisan Satchel" + //case 96960: // "Artisan Satchel" - no 12-slot disenchanted bags + return true; + default: + return false; + } +} + +static uint32 GetDisenchantedBagID(uint8 bag_slots) +{ + switch (bag_slots) { + case 4: + return 77772; // "Small Disenchanted Backpack" + case 6: + return 77774; // "Disenchanted Backpack" + case 8: + return 77776; // "Large Disenchanted Backpack" + case 10: + return 77778; // "Huge Disenchanted Backpack" + default: + return 0; // no suitable conversions + } +} + +static bool CopyBagContents(ItemInst* new_bag, const ItemInst* old_bag) +{ + if (!new_bag || !old_bag) { return false; } + if (new_bag->GetItem()->BagSlots < old_bag->GetItem()->BagSlots) { return false; } + + // pre-check for size comparisons + for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) { + if (!old_bag->GetItem(bag_slot)) { continue; } + if (old_bag->GetItem(bag_slot)->GetItem()->Size > new_bag->GetItem()->BagSize) { + Log.Out(Logs::General, Logs::Inventory, "Copy Bag Contents: Failure due to %s is larger than size capacity of %s (%i > %i)", + old_bag->GetItem(bag_slot)->GetItem()->Name, new_bag->GetItem()->Name, old_bag->GetItem(bag_slot)->GetItem()->Size, new_bag->GetItem()->BagSize); + return false; + } + } + + for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) { + if (!old_bag->GetItem(bag_slot)) { continue; } + new_bag->PutItem(bag_slot, *(old_bag->GetItem(bag_slot))); + } + + return true; +} + +void Client::DisenchantSummonedBags(bool client_update) +{ + for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) { + auto inst = m_inv[slot_id]; + if (!inst) { continue; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; } + if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; } + if (inst->GetTotalItemCount() == 1) { continue; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { continue; } + auto new_item = database.GetItem(new_id); + if (!new_item) { continue; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { continue; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id); + PutItemInInventory(slot_id, *new_inst, client_update); + } + safe_delete(new_inst); + } + + for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) { + auto inst = m_inv[slot_id]; + if (!inst) { continue; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; } + if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; } + if (inst->GetTotalItemCount() == 1) { continue; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { continue; } + auto new_item = database.GetItem(new_id); + if (!new_item) { continue; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { continue; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id); + PutItemInInventory(slot_id, *new_inst, client_update); + } + safe_delete(new_inst); + } + + for (auto slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; ++slot_id) { + auto inst = m_inv[slot_id]; + if (!inst) { continue; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; } + if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; } + if (inst->GetTotalItemCount() == 1) { continue; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { continue; } + auto new_item = database.GetItem(new_id); + if (!new_item) { continue; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { continue; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id); + PutItemInInventory(slot_id, *new_inst, client_update); + } + safe_delete(new_inst); + } + + while (!m_inv.CursorEmpty()) { + auto inst = m_inv[MainCursor]; + if (!inst) { break; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { break; } + if (inst->GetItem()->ItemClass != ItemClassContainer) { break; } + if (inst->GetTotalItemCount() == 1) { break; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { break; } + auto new_item = database.GetItem(new_id); + if (!new_item) { break; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { break; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, MainCursor); + std::list local; + local.push_front(new_inst); + m_inv.PopItem(MainCursor); + safe_delete(inst); + + while (!m_inv.CursorEmpty()) { + auto limbo_inst = m_inv.PopItem(MainCursor); + if (limbo_inst == nullptr) { continue; } + local.push_back(limbo_inst); + } + + for (auto iter = local.begin(); iter != local.end(); ++iter) { + auto cur_inst = *iter; + if (cur_inst == nullptr) { continue; } + m_inv.PushCursor(*cur_inst); + safe_delete(cur_inst); + } + local.clear(); + + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); + database.SaveCursor(this->CharacterID(), s, e); + } + else { + safe_delete(new_inst); // deletes disenchanted bag if not used + } + + break; + } +} + void Client::RemoveNoRent(bool client_update) { for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) {