From ffa968f64fca86f106bf502e1be2444749a1b675 Mon Sep 17 00:00:00 2001 From: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com> Date: Tue, 4 Jan 2022 17:18:17 -0500 Subject: [PATCH] [Bug Fix] Disallow multiple augments in same item. (#1916) - Disallows multiple augments via #augmentitem or otherwise. - Added ItemInstance::ContainsAugmentByID(item_id) helper method for finding an augment in an item instance. --- common/emu_constants.h | 7 + common/item_instance.cpp | 21 +- common/item_instance.h | 1 + common/ruletypes.h | 1 + zone/client_packet.cpp | 415 +++++++++++++++++---------------------- zone/tradeskills.cpp | 166 +++++++--------- 6 files changed, 280 insertions(+), 331 deletions(-) diff --git a/common/emu_constants.h b/common/emu_constants.h index 88ca7f924..3c5680a37 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -381,4 +381,11 @@ enum Invisibility : uint8 { Special = 255 }; +enum AugmentActions : int { + Insert, + Remove, + Swap, + Destroy +}; + #endif /*COMMON_EMU_CONSTANTS_H*/ diff --git a/common/item_instance.cpp b/common/item_instance.cpp index d0bbbca50..5ff9e9630 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -689,6 +689,25 @@ bool EQ::ItemInstance::IsAugmented() return false; } +bool EQ::ItemInstance::ContainsAugmentByID(uint32 item_id) +{ + if (!m_item || !m_item->IsClassCommon()) { + return false; + } + + if (!item_id) { + return false; + } + + for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) { + if (GetAugmentItemID(augment_slot) == item_id) { + return true; + } + } + + return false; +} + // Has attack/delay? bool EQ::ItemInstance::IsWeapon() const { @@ -1706,4 +1725,4 @@ EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 EvolveInfo::~EvolveInfo() { -} +} \ No newline at end of file diff --git a/common/item_instance.h b/common/item_instance.h index 297908a50..008e4aefd 100644 --- a/common/item_instance.h +++ b/common/item_instance.h @@ -132,6 +132,7 @@ namespace EQ void DeleteAugment(uint8 slot); ItemInstance* RemoveAugment(uint8 index); bool IsAugmented(); + bool ContainsAugmentByID(uint32 item_id); ItemInstance* GetOrnamentationAug(int32 ornamentationAugtype) const; bool UpdateOrnamentationInfo(); static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false); diff --git a/common/ruletypes.h b/common/ruletypes.h index 67d898476..056b568ed 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -744,6 +744,7 @@ RULE_BOOL(Inventory, EnforceAugmentWear, true, "Forces augment wear slot validat 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_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow") RULE_CATEGORY_END() RULE_CATEGORY(Client) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6db486f78..c25aad971 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -2929,18 +2929,16 @@ void Client::Handle_OP_AugmentInfo(const EQApplicationPacket *app) void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) { if (app->size != sizeof(AugmentItem_Struct)) { - LogError("Invalid size for AugmentItem_Struct: Expected: [{}], Got: [{}]", - sizeof(AugmentItem_Struct), app->size); + LogError("Invalid size for AugmentItem_Struct: Expected: [{}], Got: [{}]", sizeof(AugmentItem_Struct), app->size); return; } AugmentItem_Struct* in_augment = (AugmentItem_Struct*)app->pBuffer; - bool deleteItems = false; - if (ClientVersion() >= EQ::versions::ClientVersion::RoF) - { - if ((in_augment->container_slot < EQ::invslot::EQUIPMENT_BEGIN || in_augment->container_slot > EQ::invslot::GENERAL_END) && - (in_augment->container_slot < EQ::invbag::GENERAL_BAGS_BEGIN || in_augment->container_slot > EQ::invbag::GENERAL_BAGS_END)) - { + if (ClientVersion() >= EQ::versions::ClientVersion::RoF) { + if ( + (in_augment->container_slot < EQ::invslot::EQUIPMENT_BEGIN || in_augment->container_slot > EQ::invslot::GENERAL_END) && + (in_augment->container_slot < EQ::invbag::GENERAL_BAGS_BEGIN || in_augment->container_slot > EQ::invbag::GENERAL_BAGS_END) + ) { Message(Chat::Red, "The server does not allow augmentation actions from this slot."); auto cursor_item = m_inv[EQ::invslot::slotCursor]; auto augmented_item = m_inv[in_augment->container_slot]; @@ -2950,20 +2948,16 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) return; } - EQ::ItemInstance *itemOneToPush = nullptr, *itemTwoToPush = nullptr; - - //Log(Logs::DebugLevel::Moderate, Logs::Debug, "cslot: [{}] aslot: [{}] cidx: [{}] aidx: [{}] act: [{}] dest: [{}]", - // in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); + EQ::ItemInstance *item_one_to_push = nullptr, *item_two_to_push = nullptr; EQ::ItemInstance *tobe_auged = nullptr, *old_aug = nullptr, *new_aug = nullptr, *aug = nullptr, *solvent = nullptr; EQ::InventoryProfile& user_inv = GetInv(); uint16 item_slot = in_augment->container_slot; uint16 solvent_slot = in_augment->augment_slot; - uint8 mat = EQ::InventoryProfile::CalcMaterialFromSlot(item_slot); // for when player is augging a piece of equipment while they're wearing it + uint8 material = EQ::InventoryProfile::CalcMaterialFromSlot(item_slot); // for when player is augging a piece of equipment while they're wearing it - if (item_slot == INVALID_INDEX || solvent_slot == INVALID_INDEX) - { + if (item_slot == INVALID_INDEX || solvent_slot == INVALID_INDEX) { Message(Chat::Red, "Error: Invalid Aug Index."); return; } @@ -2971,272 +2965,231 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) tobe_auged = user_inv.GetItem(item_slot); solvent = user_inv.GetItem(solvent_slot); - if (!tobe_auged) - { + if (!tobe_auged) { Message(Chat::Red, "Error: Invalid item passed for augmenting."); return; } - if ((in_augment->augment_action == 1) || (in_augment->augment_action == 2)) - { - // Check for valid distiller if safely removing / swapping an augmentation - - if (!solvent) - { + if (in_augment->augment_action == AugmentActions::Remove || in_augment->augment_action == AugmentActions::Swap) { + if (!solvent) { // Check for valid distiller if safely removing / swapping an augmentation old_aug = tobe_auged->GetAugment(in_augment->augment_index); if (!old_aug || old_aug->GetItem()->AugDistiller != 0) { LogError("Player tried to safely remove an augment without a distiller"); Message(Chat::Red, "Error: Missing an augmentation distiller for safely removing this augment."); return; } - } - else if (solvent->GetItem()->ItemType == EQ::item::ItemTypeAugmentationDistiller) - { + } else if (solvent->GetItem()->ItemType == EQ::item::ItemTypeAugmentationDistiller) { old_aug = tobe_auged->GetAugment(in_augment->augment_index); - if (!old_aug) - { + if (!old_aug) { LogError("Player tried to safely remove a nonexistent augment"); Message(Chat::Red, "Error: No augment found in slot %i for safely removing.", in_augment->augment_index); return; - } - else if (solvent->GetItem()->ID != old_aug->GetItem()->AugDistiller) - { + } else if (solvent->GetItem()->ID != old_aug->GetItem()->AugDistiller) { LogError("Player tried to safely remove an augment with the wrong distiller (item [{}] vs expected [{}])", solvent->GetItem()->ID, old_aug->GetItem()->AugDistiller); Message(Chat::Red, "Error: Wrong augmentation distiller for safely removing this augment."); return; } - } - else if (solvent->GetItem()->ItemType != EQ::item::ItemTypePerfectedAugmentationDistiller) - { + } else if (solvent->GetItem()->ItemType != EQ::item::ItemTypePerfectedAugmentationDistiller) { LogError("Player tried to safely remove an augment with a non-distiller item"); Message(Chat::Red, "Error: Invalid augmentation distiller for safely removing this augment."); return; } } - switch (in_augment->augment_action) - { - case 0: // Adding an augment - case 2: // Swapping augment - new_aug = user_inv.GetItem(EQ::invslot::slotCursor); + switch (in_augment->augment_action) { + case AugmentActions::Insert: + case AugmentActions::Swap: + new_aug = user_inv.GetItem(EQ::invslot::slotCursor); - if (!new_aug) // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x. - { - LogError("AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor"); - Message(Chat::Red, "Error: No augment found on cursor for inserting."); - return; - } - else - { - if (((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) && - (tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots))) - { - old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); - if (old_aug) - { - // An old augment was removed in order to be replaced with the new one (augment_action 2) - - CalcBonuses(); - - std::vector args; - args.push_back(old_aug); - parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - args.push_back(false); - parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args); - } - - tobe_auged->PutAugment(in_augment->augment_index, *new_aug); - tobe_auged->UpdateOrnamentationInfo(); - - aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) - { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else - { - Message(Chat::Red, "Error: Could not properly insert augmentation into augment slot %i. Aborting.", in_augment->augment_index); + if (!new_aug) { // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x. + LogError("AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor"); + Message(Chat::Red, "Error: No augment found on cursor for inserting."); + return; + } else { + if (!RuleB(Inventory, AllowMultipleOfSameAugment) && tobe_auged->ContainsAugmentByID(new_aug->GetID())) { + Message(Chat::Red, "Error: Cannot put multiple of the same augment in an item."); return; } - itemOneToPush = tobe_auged->Clone(); - if (old_aug) - { - itemTwoToPush = old_aug->Clone(); - } - - // Must push items after the items in inventory are deleted - necessary due to lore items... - if (itemOneToPush) - { - DeleteItemInInventory(item_slot, 0, true); - DeleteItemInInventory(EQ::invslot::slotCursor, new_aug->IsStackable() ? 1 : 0, true); - - if (solvent) - { - // Consume the augment distiller - DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); - } - - if (itemTwoToPush) - { - // This is a swap. Return the old aug to the player's cursor. - if (!PutItemInInventory(EQ::invslot::slotCursor, *itemTwoToPush, true)) - { - LogError("Problem returning old augment to player's cursor after augmentation swap"); - Message(Chat::Yellow, "Error: Failed to retrieve old augment after augmentation swap!"); - } - } - - if (PutItemInInventory(item_slot, *itemOneToPush, true)) - { - // Successfully added an augment to the item - + if ( + ((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) && + tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots) + ) { + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); + if (old_aug) { // An old augment was removed in order to be replaced with the new one (augment_action 2) CalcBonuses(); - if (mat != EQ::textures::materialInvalid) - { - SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + std::vector args; + args.push_back(old_aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + args.push_back(false); + parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args); + } + + tobe_auged->PutAugment(in_augment->augment_index, *new_aug); + tobe_auged->UpdateOrnamentationInfo(); + + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args); + } else { + Message( + Chat::Red, + fmt::format( + "Error: Could not properly insert augmentation into augment slot {}. Aborting.", + in_augment->augment_index + ).c_str() + ); + return; + } + + item_one_to_push = tobe_auged->Clone(); + if (old_aug) { + item_two_to_push = old_aug->Clone(); + } + + if (item_one_to_push) { // Must push items after the items in inventory are deleted - necessary due to lore items... + DeleteItemInInventory(item_slot, 0, true); + DeleteItemInInventory(EQ::invslot::slotCursor, new_aug->IsStackable() ? 1 : 0, true); + + if (solvent) { // Consume the augment distiller + DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); } + + if (item_two_to_push) { // This is a swap. Return the old aug to the player's cursor. + if (!PutItemInInventory(EQ::invslot::slotCursor, *item_two_to_push, true)) { + LogError("Problem returning old augment to player's cursor after augmentation swap"); + Message(Chat::Yellow, "Error: Failed to retrieve old augment after augmentation swap!"); + } + } + + if (PutItemInInventory(item_slot, *item_one_to_push, true)) { // Successfully added an augment to the item + CalcBonuses(); + if (material != EQ::textures::materialInvalid) { // Visible item augged while equipped. Send WC in case ornamentation changed. + SendWearChange(material); + } + } else { + Message(Chat::Red, "Error: No available slot for end result. Please free up the augment slot."); + } + } else { + Message(Chat::Red, "Error in cloning item for augment. Aborted."); } - else - { - Message(Chat::Red, "Error: No available slot for end result. Please free up the augment slot."); - } - } - else - { - Message(Chat::Red, "Error in cloning item for augment. Aborted."); + } else { + Message(Chat::Red, "Error: No available slot for augment in that item."); } } - else - { - Message(Chat::Red, "Error: No available slot for augment in that item."); + break; + case AugmentActions::Remove: + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + args.assign(1, tobe_auged); + args.push_back(false); + parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); + } else { + Message(Chat::Red, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index); + return; } - } - break; - case 1: // Removing augment safely (distiller) - aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) - { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - args.assign(1, tobe_auged); + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); + tobe_auged->UpdateOrnamentationInfo(); - args.push_back(false); + item_one_to_push = tobe_auged->Clone(); + if (old_aug) { + item_two_to_push = old_aug->Clone(); + } - parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else - { - Message(Chat::Red, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index); - return; - } + if (item_one_to_push && item_two_to_push) { + if (solvent) { + DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); // Consume the augment distiller + } - old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); - tobe_auged->UpdateOrnamentationInfo(); + DeleteItemInInventory(item_slot, 0, true); // Remove the augmented item - itemOneToPush = tobe_auged->Clone(); - if (old_aug) - itemTwoToPush = old_aug->Clone(); + if (!PutItemInInventory(item_slot, *item_one_to_push, true)) { // Replace it with the unaugmented item + LogError("Problem returning equipment item to player's inventory after safe augment removal"); + Message(Chat::Yellow, "Error: Failed to return item after de-augmentation!"); + } - if (itemOneToPush && itemTwoToPush) - { - // Consume the augment distiller - if (solvent) - DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); + CalcBonuses(); - // Remove the augmented item - DeleteItemInInventory(item_slot, 0, true); + if (material != EQ::textures::materialInvalid) { + SendWearChange(material); // Visible item augged while equipped. Send WC in case ornamentation changed. + } - // Replace it with the unaugmented item - if (!PutItemInInventory(item_slot, *itemOneToPush, true)) - { - LogError("Problem returning equipment item to player's inventory after safe augment removal"); - Message(Chat::Yellow, "Error: Failed to return item after de-augmentation!"); + // Drop the removed augment on the player's cursor + if (!PutItemInInventory(EQ::invslot::slotCursor, *item_two_to_push, true)) { + LogError("Problem returning augment to player's cursor after safe removal"); + Message(Chat::Yellow, "Error: Failed to return augment after removal from item!"); + return; + } + } + break; + case AugmentActions::Destroy: + // RoF client does not require an augmentation solvent for destroying an augmentation in an item. + // Augments can be destroyed with a right click -> Destroy at any time. + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + args.assign(1, tobe_auged); + args.push_back(true); + parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); + } else { + Message( + Chat::Red, + fmt::format( + "Error: Could not find augmentation to remove at index {}. Aborting.", + in_augment->augment_index + ).c_str() + ); + return; + } + + tobe_auged->DeleteAugment(in_augment->augment_index); + tobe_auged->UpdateOrnamentationInfo(); + + item_one_to_push = tobe_auged->Clone(); + if (item_one_to_push) { + DeleteItemInInventory(item_slot, 0, true); + + if (!PutItemInInventory(item_slot, *item_one_to_push, true)) { + LogError("Problem returning equipment item to player's inventory after augment deletion"); + Message(Chat::Yellow, "Error: Failed to return item after destroying augment!"); + } } CalcBonuses(); - if (mat != EQ::textures::materialInvalid) - { - SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + if (material != EQ::textures::materialInvalid) { + SendWearChange(material); } - - // Drop the removed augment on the player's cursor - if (!PutItemInInventory(EQ::invslot::slotCursor, *itemTwoToPush, true)) - { - LogError("Problem returning augment to player's cursor after safe removal"); - Message(Chat::Yellow, "Error: Failed to return augment after removal from item!"); - return; - } - } - break; - case 3: // Destroying augment (formerly done in birdbath/sealer with a solvent) - - // RoF client does not require an augmentation solvent for destroying an augmentation in an item. - // Augments can be destroyed with a right click -> Destroy at any time. - - aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) - { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - - args.push_back(true); - - parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else - { - Message(Chat::Red, "Error: Could not find augmentation to remove at index %i. Aborting."); - return; - } - - tobe_auged->DeleteAugment(in_augment->augment_index); - tobe_auged->UpdateOrnamentationInfo(); - - itemOneToPush = tobe_auged->Clone(); - if (itemOneToPush) - { - DeleteItemInInventory(item_slot, 0, true); - - if (!PutItemInInventory(item_slot, *itemOneToPush, true)) - { - LogError("Problem returning equipment item to player's inventory after augment deletion"); - Message(Chat::Yellow, "Error: Failed to return item after destroying augment!"); - } - } - - CalcBonuses(); - - if (mat != EQ::textures::materialInvalid) - { - SendWearChange(mat); - } - break; - default: // Unknown - LogInventory("Unrecognized augmentation action - cslot: [{}] aslot: [{}] cidx: [{}] aidx: [{}] act: [{}] dest: [{}]", - in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); - break; + break; + default: // Unknown + LogInventory( + "Unrecognized augmentation action - cslot: [{}] aslot: [{}] cidx: [{}] aidx: [{}] act: [{}] dest: [{}]", + in_augment->container_slot, + in_augment->augment_slot, + in_augment->container_index, + in_augment->augment_index, + in_augment->augment_action, + in_augment->dest_inst_id + ); + break; } - } - else - { - // Delegate to tradeskill object to perform combine - Object::HandleAugmentation(this, in_augment, m_tradeskill_object); + } else { + Object::HandleAugmentation(this, in_augment, m_tradeskill_object); // Delegate to tradeskill object to perform combine } return; } diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index 82d29e7f4..938aa1a0d 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -43,109 +43,93 @@ static const EQ::skills::SkillType TradeskillUnknown = EQ::skills::Skill1HBlunt; void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augment, Object *worldo) { - if (!user || !in_augment) - { + if (!user || !in_augment) { LogError("Client or AugmentItem_Struct not set in Object::HandleAugmentation"); return; } EQ::ItemInstance* container = nullptr; - if (worldo) - { + if (worldo) { container = worldo->m_inst; - } - else - { - // Check to see if they have an inventory container type 53 that is used for this. + } else { // Check to see if they have an inventory container type 53 that is used for this. EQ::InventoryProfile& user_inv = user->GetInv(); EQ::ItemInstance* inst = nullptr; inst = user_inv.GetItem(in_augment->container_slot); - if (inst) - { + if (inst) { const EQ::ItemData* item = inst->GetItem(); - if (item && inst->IsType(EQ::item::ItemClassBag) && item->BagType == 53) - { - // We have found an appropriate inventory augmentation sealer + if (item && inst->IsType(EQ::item::ItemClassBag) && item->BagType == EQ::item::BagTypeAugmentationSealer) { // We have found an appropriate inventory augmentation sealer container = inst; // Verify that no more than two items are in container to guarantee no inadvertant wipes. - uint8 itemsFound = 0; - for (uint8 i = EQ::invbag::SLOT_BEGIN; i < EQ::invtype::WORLD_SIZE; i++) - { + uint8 items_found = 0; + for (uint8 i = EQ::invbag::SLOT_BEGIN; i < EQ::invtype::WORLD_SIZE; i++) { const EQ::ItemInstance* inst = container->GetItem(i); - if (inst) - { - itemsFound++; + if (inst) { + items_found++; } } - if (itemsFound != 2) - { - user->Message(Chat::Red, "Error: Too many/few items in augmentation container."); + if (items_found < 2) { + user->Message(Chat::Red, "Error: Too few items in augmentation container."); + return; + } else if (items_found > 2) { + user->Message(Chat::Red, "Error: Too many items in augmentation container."); return; } } } } - if(!container) - { + if(!container) { LogError("Player tried to augment an item without a container set"); user->Message(Chat::Red, "Error: This item is not a container!"); return; } EQ::ItemInstance *tobe_auged = nullptr, *auged_with = nullptr; - int8 slot=-1; + int8 slot = -1; - // Verify 2 items in the augmentation device - if (container->GetItem(0) && container->GetItem(1)) - { + if (container->GetItem(0) && container->GetItem(1)) { // Verify 2 items in the augmentation device // Verify 1 item is augmentable and the other is not - if (container->GetItem(0)->IsAugmentable() && !container->GetItem(1)->IsAugmentable()) - { + if (container->GetItem(0)->IsAugmentable() && !container->GetItem(1)->IsAugmentable()) { tobe_auged = container->GetItem(0); auged_with = container->GetItem(1); - } - else if (!container->GetItem(0)->IsAugmentable() && container->GetItem(1)->IsAugmentable()) - { + } else if (!container->GetItem(0)->IsAugmentable() && container->GetItem(1)->IsAugmentable()) { tobe_auged = container->GetItem(1); auged_with = container->GetItem(0); - } - else - { + } else { // Either 2 augmentable items found or none found // This should never occur due to client restrictions, but prevent in case of a hack - user->Message(Chat::Red, "Error: Must be 1 augmentable item in the sealer"); + user->Message(Chat::Red, "Error: There must be 1 augmentable item in the sealer."); return; } - } - else - { - // This happens if the augment button is clicked more than once quickly while augmenting - if (!container->GetItem(0)) - { - user->Message(Chat::Red, "Error: No item in slot 0 of sealer"); + } else { // This happens if the augment button is clicked more than once quickly while augmenting + if (!container->GetItem(0)) { + user->Message(Chat::Red, "Error: No item in the first slot of sealer."); } - if (!container->GetItem(1)) - { - user->Message(Chat::Red, "Error: No item in slot 1 of sealer"); + + if (!container->GetItem(1)) { + user->Message(Chat::Red, "Error: No item in the second slot of sealer."); } return; } - bool deleteItems = false; + if (!RuleB(Inventory, AllowMultipleOfSameAugment) && tobe_auged->ContainsAugmentByID(auged_with->GetID())) { + user->Message(Chat::Red, "Error: Cannot put multiple of the same augment in an item."); + return; + } - EQ::ItemInstance *itemOneToPush = nullptr, *itemTwoToPush = nullptr; + bool delete_items = false; - // Adding augment - if (in_augment->augment_slot == -1) - { - if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) && - (tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots))) - { + EQ::ItemInstance *item_one_to_push = nullptr, *item_two_to_push = nullptr; + + if (in_augment->augment_slot == -1) { // Adding augment + if ( + ((slot = tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType())) != -1) && + tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots) + ) { tobe_auged->PutAugment(slot, *auged_with); EQ::ItemInstance *aug = tobe_auged->GetAugment(slot); @@ -158,20 +142,15 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme parse->EventItem(EVENT_AUGMENT_INSERT, user, aug, nullptr, "", slot, &args); } - itemOneToPush = tobe_auged->Clone(); - deleteItems = true; + item_one_to_push = tobe_auged->Clone(); + delete_items = true; + } else { + user->Message(Chat::Red, "Error: No available slot for augment."); } - else - { - user->Message(Chat::Red, "Error: No available slot for augment"); - } - } - else - { + } else { EQ::ItemInstance *old_aug = nullptr; - bool isSolvent = auged_with->GetItem()->ItemType == EQ::item::ItemTypeAugmentationSolvent; - if (!isSolvent && auged_with->GetItem()->ItemType != EQ::item::ItemTypeAugmentationDistiller) - { + bool is_solvent = auged_with->GetItem()->ItemType == EQ::item::ItemTypeAugmentationSolvent; + if (!is_solvent && auged_with->GetItem()->ItemType != EQ::item::ItemTypeAugmentationDistiller) { LogError("Player tried to remove an augment without a solvent or distiller"); user->Message(Chat::Red, "Error: Missing an augmentation solvent or distiller for removing this augment."); @@ -180,8 +159,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme EQ::ItemInstance *aug = tobe_auged->GetAugment(in_augment->augment_slot); if (aug) { - if (!isSolvent && auged_with->GetItem()->ID != aug->GetItem()->AugDistiller) - { + if (!is_solvent && auged_with->GetItem()->ID != aug->GetItem()->AugDistiller) { LogError("Player tried to safely remove an augment with the wrong distiller (item [{}] vs expected [{}])", auged_with->GetItem()->ID, aug->GetItem()->AugDistiller); user->Message(Chat::Red, "Error: Wrong augmentation distiller for safely removing this augment."); return; @@ -191,29 +169,27 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args); args.assign(1, tobe_auged); - args.push_back(&isSolvent); + args.push_back(&is_solvent); parse->EventItem(EVENT_AUGMENT_REMOVE, user, aug, nullptr, "", slot, &args); } - if (isSolvent) + if (is_solvent) { tobe_auged->DeleteAugment(in_augment->augment_slot); - else + } else { old_aug = tobe_auged->RemoveAugment(in_augment->augment_slot); + } - itemOneToPush = tobe_auged->Clone(); - if (old_aug) - itemTwoToPush = old_aug->Clone(); + item_one_to_push = tobe_auged->Clone(); + if (old_aug) { + item_two_to_push = old_aug->Clone(); + } - - - deleteItems = true; + delete_items = true; } - if (deleteItems) - { - if (worldo) - { + if (delete_items) { + if (worldo) { container->Clear(); auto outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct)); ClearObject_Struct *cos = (ClearObject_Struct *)outapp->pBuffer; @@ -221,34 +197,26 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme user->QueuePacket(outapp); safe_delete(outapp); database.DeleteWorldContainer(worldo->m_id, zone->GetZoneID()); - } - else - { - // Delete items in our inventory container... - for (uint8 i = EQ::invbag::SLOT_BEGIN; i < EQ::invtype::WORLD_SIZE; i++) - { + } else { // Delete items in our inventory container... + for (uint8 i = EQ::invbag::SLOT_BEGIN; i < EQ::invtype::WORLD_SIZE; i++) { const EQ::ItemInstance* inst = container->GetItem(i); - if (inst) - { + if (inst) { user->DeleteItemInInventory(EQ::InventoryProfile::CalcSlotId(in_augment->container_slot, i), 0, true); } } - // Explicitly mark container as cleared. - container->Clear(); + + container->Clear(); // Explicitly mark container as cleared. } } // Must push items after the items in inventory are deleted - necessary due to lore items... - if (itemOneToPush) - { - user->PushItemOnCursor(*itemOneToPush, true); + if (item_one_to_push) { + user->PushItemOnCursor(*item_one_to_push, true); } - if (itemTwoToPush) - { - user->PushItemOnCursor(*itemTwoToPush, true); + if (item_two_to_push) { + user->PushItemOnCursor(*item_two_to_push, true); } - } // Perform tradeskill combine