From 5962dc3d0c6ec9e33a910d7b8b85875eb54f2816 Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 17:23:48 +1100 Subject: [PATCH 1/7] Update ItemUsageValue.cpp --- src/strategy/values/ItemUsageValue.cpp | 32 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/strategy/values/ItemUsageValue.cpp b/src/strategy/values/ItemUsageValue.cpp index 5c5e38e1..fbf9ccda 100644 --- a/src/strategy/values/ItemUsageValue.cpp +++ b/src/strategy/values/ItemUsageValue.cpp @@ -256,20 +256,42 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto) // Check weapon case separately to keep things a bit cleaner bool have2HWeapon = false; bool isValidTGWeapon = false; + if (dstSlot == EQUIPMENT_SLOT_MAINHAND) { Item* currentWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); have2HWeapon = currentWeapon && currentWeapon->GetTemplate()->InventoryType == INVTYPE_2HWEAPON; - isValidTGWeapon = itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || - itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || - itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2; - - if (bot->CanDualWield() && ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon))) + + // Determine if the new weapon is a valid Titan Grip weapon + isValidTGWeapon = (itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || + itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || + itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2); + + // If the bot can Titan Grip, ignore any 2H weapon that isn't a 2H sword, mace, or axe. + if (bot->CanTitanGrip()) + { + // If this weapon is 2H but not one of the valid TG weapon types, do not equip it at all. + if (itemProto->InventoryType == INVTYPE_2HWEAPON && !isValidTGWeapon) + { + return ITEM_USAGE_NONE; + } + } + + // Now handle the logic for equipping and possible offhand slots + // If the bot can Dual Wield and: + // - The weapon is not 2H and we currently don't have a 2H weapon equipped + // OR + // - The bot can Titan Grip and it is a valid TG weapon + // Then we can consider the offhand slot as well. + if (bot->CanDualWield() && + ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || + (bot->CanTitanGrip() && isValidTGWeapon))) { possibleSlots = 2; } } + for (uint8 i = 0; i < possibleSlots; i++) { bool shouldEquipInSlot = shouldEquip; From ea9bd181027e88b00281178de124e7ac1ae0532a Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 17:57:16 +1100 Subject: [PATCH 2/7] Enhanced dual-wield logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description of Changes: Implemented logic to ensure the strongest weapon is always placed in the main hand for dual-wielding or Titan Grip-capable bots. When equipping a new weapon, the code now compares the new weapon’s score with the currently equipped main-hand and off-hand weapons. If the new weapon is the strongest, it goes into the main hand. The previous main-hand weapon may be moved to the off-hand if it is allowed (e.g., not a main-hand-only weapon) and provides a performance improvement. Titan Grip conditions are accounted for, allowing valid two-handed weapons (2H axes, maces, swords) to be placed in the off-hand as well. --- src/strategy/actions/EquipAction.cpp | 106 ++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/strategy/actions/EquipAction.cpp b/src/strategy/actions/EquipAction.cpp index f9258d77..8fcc55d2 100644 --- a/src/strategy/actions/EquipAction.cpp +++ b/src/strategy/actions/EquipAction.cpp @@ -99,7 +99,111 @@ void EquipAction::EquipItem(Item* item) itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2; } - + + // New logic: Ensure strongest weapon is in main hand for dual wield/Titan Grip scenarios + bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON); + bool canDualWieldOrTG = (bot->CanDualWield() || (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); + if (isWeapon && canDualWieldOrTG && dstSlot == EQUIPMENT_SLOT_MAINHAND && + ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon))) + { + // Compare current mainhand and offhand weapons to the new item + Item* mainHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + Item* offHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + + StatsWeightCalculator calculator(bot); + calculator.SetItemSetBonus(false); + calculator.SetOverflowPenalty(false); + + float newItemScore = calculator.CalculateItem(itemId); + float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f; + float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f; + + // Determine if new weapon is best + bool newIsBest = (newItemScore > mainHandScore && newItemScore > offHandScore); + bool betterThanOff = (newItemScore > offHandScore) && !newIsBest; + + // Check that the new item can go main hand + bool canGoMain = (itemProto->InventoryType == INVTYPE_WEAPON || + itemProto->InventoryType == INVTYPE_WEAPONMAINHAND || + (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); + + // Check Titan Grip offhand eligibility + bool canTGOff = false; + if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON) + { + // Titan Grip allows 2H axes, maces, swords in offhand + canTGOff = (isValidTGWeapon); + } + + // Check that the new item can go off hand + bool canGoOff = (itemProto->InventoryType == INVTYPE_WEAPON || + itemProto->InventoryType == INVTYPE_WEAPONOFFHAND || + canTGOff); + + // Check what the main hand item can do if we move it + bool mainHandCanGoOff = false; + if (mainHandItem) + { + const ItemTemplate* mhProto = mainHandItem->GetTemplate(); + bool mhIsValidTG = (bot->CanTitanGrip() && mhProto->InventoryType == INVTYPE_2HWEAPON && + (mhProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || + mhProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || + mhProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2)); + mainHandCanGoOff = (mhProto->InventoryType == INVTYPE_WEAPON || + mhProto->InventoryType == INVTYPE_WEAPONOFFHAND || + (mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG)); + } + + // If new weapon is best of all three, put it in main hand + if (newIsBest && canGoMain) + { + // Equip new weapon in main hand + { + WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid newItemGuid = item->GetGUID(); + eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_MAINHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); + } + + // If there was a main hand item, try to move it to offhand if it improves offhand + if (mainHandItem && mainHandCanGoOff) + { + // Only move if it's better than the current offhand or offhand is empty + if (!offHandItem || mainHandScore > offHandScore) + { + WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid oldMHGuid = mainHandItem->GetGUID(); + offhandPacket << oldMHGuid << uint8(EQUIPMENT_SLOT_OFFHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); + } + } + + std::ostringstream out; + out << "equipping " << chat->FormatItem(itemProto) << " as the best weapon in main hand"; + botAI->TellMaster(out); + return; + } + else if (betterThanOff && canGoOff) + { + // Equip the new weapon in offhand + WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid newItemGuid = item->GetGUID(); + eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); + + std::ostringstream out; + out << "equipping " << chat->FormatItem(itemProto) << " in offhand"; + botAI->TellMaster(out); + return; + } + else + { + // Not an improvement or can't place it properly, do nothing + return; + } + } + + // Existing logic below - do not remove or modify existing comments if (dstSlot == EQUIPMENT_SLOT_FINGER1 || dstSlot == EQUIPMENT_SLOT_TRINKET1 || (dstSlot == EQUIPMENT_SLOT_MAINHAND && bot->CanDualWield() && From a9eb41600da8d4ee7e84d4f10d173799a6bb6676 Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 18:07:02 +1100 Subject: [PATCH 3/7] Update EquipAction.cpp --- src/strategy/actions/EquipAction.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/strategy/actions/EquipAction.cpp b/src/strategy/actions/EquipAction.cpp index 8fcc55d2..08f0d3da 100644 --- a/src/strategy/actions/EquipAction.cpp +++ b/src/strategy/actions/EquipAction.cpp @@ -154,7 +154,7 @@ void EquipAction::EquipItem(Item* item) (mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG)); } - // If new weapon is best of all three, put it in main hand + // If new weapon is best of all three, put it in main hand// If new weapon is best of all three, put it in main hand if (newIsBest && canGoMain) { // Equip new weapon in main hand @@ -164,7 +164,7 @@ void EquipAction::EquipItem(Item* item) eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_MAINHAND); bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); } - + // If there was a main hand item, try to move it to offhand if it improves offhand if (mainHandItem && mainHandCanGoOff) { @@ -177,7 +177,7 @@ void EquipAction::EquipItem(Item* item) bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); } } - + std::ostringstream out; out << "equipping " << chat->FormatItem(itemProto) << " as the best weapon in main hand"; botAI->TellMaster(out); @@ -185,12 +185,21 @@ void EquipAction::EquipItem(Item* item) } else if (betterThanOff && canGoOff) { + // If offhand is empty, just verify logic: + // Since newIsBest is false, the main hand is already equal or better than the new weapon. + // Thus, equipping this weapon in offhand is safe and correct. + if (!offHandItem) + { + // No additional main hand check needed because if it were better than main hand, + // newIsBest would have triggered above. + } + // Equip the new weapon in offhand WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); ObjectGuid newItemGuid = item->GetGUID(); eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND); bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); - + std::ostringstream out; out << "equipping " << chat->FormatItem(itemProto) << " in offhand"; botAI->TellMaster(out); From f8da773ce1843cd03d82303692bee34b709d5676 Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 18:21:28 +1100 Subject: [PATCH 4/7] Update EquipAction.cpp --- src/strategy/actions/EquipAction.cpp | 76 +++++++++++++--------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/src/strategy/actions/EquipAction.cpp b/src/strategy/actions/EquipAction.cpp index 08f0d3da..1274cc14 100644 --- a/src/strategy/actions/EquipAction.cpp +++ b/src/strategy/actions/EquipAction.cpp @@ -91,22 +91,29 @@ void EquipAction::EquipItem(Item* item) uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true); bool have2HWeapon = false; bool isValidTGWeapon = false; - if (dstSlot == EQUIPMENT_SLOT_MAINHAND) + + if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON) + { + isValidTGWeapon = (itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || + itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || + itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2); + } + + // Check if we currently have a 2H weapon in main hand { Item* currentWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); have2HWeapon = currentWeapon && currentWeapon->GetTemplate()->InventoryType == INVTYPE_2HWEAPON; - isValidTGWeapon = itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || - itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || - itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2; } - // New logic: Ensure strongest weapon is in main hand for dual wield/Titan Grip scenarios bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON); bool canDualWieldOrTG = (bot->CanDualWield() || (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); - if (isWeapon && canDualWieldOrTG && dstSlot == EQUIPMENT_SLOT_MAINHAND && - ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon))) + + // Perform best-weapon logic if this is a weapon and the bot can dual wield or Titan Grip + if (isWeapon && canDualWieldOrTG && + ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || + (bot->CanTitanGrip() && isValidTGWeapon))) { - // Compare current mainhand and offhand weapons to the new item + // Compare new item to mainhand and offhand regardless of initial dstSlot Item* mainHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); Item* offHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); @@ -118,29 +125,24 @@ void EquipAction::EquipItem(Item* item) float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f; float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f; - // Determine if new weapon is best bool newIsBest = (newItemScore > mainHandScore && newItemScore > offHandScore); bool betterThanOff = (newItemScore > offHandScore) && !newIsBest; - // Check that the new item can go main hand bool canGoMain = (itemProto->InventoryType == INVTYPE_WEAPON || itemProto->InventoryType == INVTYPE_WEAPONMAINHAND || (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); - // Check Titan Grip offhand eligibility bool canTGOff = false; if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON) { - // Titan Grip allows 2H axes, maces, swords in offhand - canTGOff = (isValidTGWeapon); + // Titan Grip allows certain 2H weapons in offhand + canTGOff = isValidTGWeapon; } - // Check that the new item can go off hand bool canGoOff = (itemProto->InventoryType == INVTYPE_WEAPON || itemProto->InventoryType == INVTYPE_WEAPONOFFHAND || canTGOff); - // Check what the main hand item can do if we move it bool mainHandCanGoOff = false; if (mainHandItem) { @@ -149,14 +151,18 @@ void EquipAction::EquipItem(Item* item) (mhProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || mhProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || mhProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2)); + mainHandCanGoOff = (mhProto->InventoryType == INVTYPE_WEAPON || mhProto->InventoryType == INVTYPE_WEAPONOFFHAND || (mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG)); } - // If new weapon is best of all three, put it in main hand// If new weapon is best of all three, put it in main hand + // Decide final equip slot based on comparison if (newIsBest && canGoMain) { + // Equip in main hand + dstSlot = EQUIPMENT_SLOT_MAINHAND; + // Equip new weapon in main hand { WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); @@ -164,11 +170,10 @@ void EquipAction::EquipItem(Item* item) eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_MAINHAND); bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); } - + // If there was a main hand item, try to move it to offhand if it improves offhand if (mainHandItem && mainHandCanGoOff) { - // Only move if it's better than the current offhand or offhand is empty if (!offHandItem || mainHandScore > offHandScore) { WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); @@ -177,7 +182,7 @@ void EquipAction::EquipItem(Item* item) bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); } } - + std::ostringstream out; out << "equipping " << chat->FormatItem(itemProto) << " as the best weapon in main hand"; botAI->TellMaster(out); @@ -185,21 +190,14 @@ void EquipAction::EquipItem(Item* item) } else if (betterThanOff && canGoOff) { - // If offhand is empty, just verify logic: - // Since newIsBest is false, the main hand is already equal or better than the new weapon. - // Thus, equipping this weapon in offhand is safe and correct. - if (!offHandItem) - { - // No additional main hand check needed because if it were better than main hand, - // newIsBest would have triggered above. - } - - // Equip the new weapon in offhand + // Equip in offhand + dstSlot = EQUIPMENT_SLOT_OFFHAND; + WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); ObjectGuid newItemGuid = item->GetGUID(); eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND); bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); - + std::ostringstream out; out << "equipping " << chat->FormatItem(itemProto) << " in offhand"; botAI->TellMaster(out); @@ -207,12 +205,14 @@ void EquipAction::EquipItem(Item* item) } else { - // Not an improvement or can't place it properly, do nothing + // Not an improvement, do nothing and return return; } } - // Existing logic below - do not remove or modify existing comments + // If we reach here, either not a dual-wield scenario, not a better weapon scenario, + // or the item isn't a weapon. Fall back to existing logic. + if (dstSlot == EQUIPMENT_SLOT_FINGER1 || dstSlot == EQUIPMENT_SLOT_TRINKET1 || (dstSlot == EQUIPMENT_SLOT_MAINHAND && bot->CanDualWield() && @@ -231,8 +231,7 @@ void EquipAction::EquipItem(Item* item) StatsWeightCalculator calculator(bot); calculator.SetItemSetBonus(false); calculator.SetOverflowPenalty(false); - - // float newItemScore = calculator.CalculateItem(itemId); + float equippedItemScore[2] = { equippedItemScore[0] = calculator.CalculateItem(equippedItems[0]->GetTemplate()->ItemId), equippedItemScore[1] = calculator.CalculateItem(equippedItems[1]->GetTemplate()->ItemId) @@ -244,22 +243,18 @@ void EquipAction::EquipItem(Item* item) dstSlot++; } } - else // No item equipped in slot 2, equip in that slot instead of replacing first item + else // No item equipped in slot 2, equip in that slot { dstSlot++; } } } + // Perform the final equip if no special logic applied WorldPacket packet(CMSG_AUTOEQUIP_ITEM_SLOT, 2); ObjectGuid itemguid = item->GetGUID(); - packet << itemguid << dstSlot; bot->GetSession()->HandleAutoEquipItemSlotOpcode(packet); - - // WorldPacket packet(CMSG_AUTOEQUIP_ITEM, 2); - // packet << bagIndex << slot; - // bot->GetSession()->HandleAutoEquipItemOpcode(packet); } } @@ -268,6 +263,7 @@ void EquipAction::EquipItem(Item* item) botAI->TellMaster(out); } + bool EquipUpgradesAction::Execute(Event event) { if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot)) From 34c0759c905694bfe5e013e6ccb9a8075b5364b0 Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 18:28:28 +1100 Subject: [PATCH 5/7] Update EquipAction.cpp --- src/strategy/actions/EquipAction.cpp | 65 ++++++++++++---------------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/src/strategy/actions/EquipAction.cpp b/src/strategy/actions/EquipAction.cpp index 1274cc14..2fec22a4 100644 --- a/src/strategy/actions/EquipAction.cpp +++ b/src/strategy/actions/EquipAction.cpp @@ -89,6 +89,8 @@ void EquipAction::EquipItem(Item* item) if (!equippedBag) { uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true); + + bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON); bool have2HWeapon = false; bool isValidTGWeapon = false; @@ -105,15 +107,13 @@ void EquipAction::EquipItem(Item* item) have2HWeapon = currentWeapon && currentWeapon->GetTemplate()->InventoryType == INVTYPE_2HWEAPON; } - bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON); bool canDualWieldOrTG = (bot->CanDualWield() || (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); - // Perform best-weapon logic if this is a weapon and the bot can dual wield or Titan Grip - if (isWeapon && canDualWieldOrTG && - ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || - (bot->CanTitanGrip() && isValidTGWeapon))) + // Run best-weapon logic only if it's a weapon and can dual wield or Titan Grip. + // Remove conditions that previously restricted running this logic based on dstSlot. + // We'll always check if this new weapon is better, and then decide final slot. + if (isWeapon && canDualWieldOrTG) { - // Compare new item to mainhand and offhand regardless of initial dstSlot Item* mainHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); Item* offHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); @@ -125,9 +125,6 @@ void EquipAction::EquipItem(Item* item) float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f; float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f; - bool newIsBest = (newItemScore > mainHandScore && newItemScore > offHandScore); - bool betterThanOff = (newItemScore > offHandScore) && !newIsBest; - bool canGoMain = (itemProto->InventoryType == INVTYPE_WEAPON || itemProto->InventoryType == INVTYPE_WEAPONMAINHAND || (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); @@ -135,7 +132,6 @@ void EquipAction::EquipItem(Item* item) bool canTGOff = false; if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON) { - // Titan Grip allows certain 2H weapons in offhand canTGOff = isValidTGWeapon; } @@ -157,12 +153,11 @@ void EquipAction::EquipItem(Item* item) (mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG)); } - // Decide final equip slot based on comparison - if (newIsBest && canGoMain) + // First priority: If new weapon is better than main hand and can be equipped in main hand, + // do that. + if (canGoMain && newItemScore > mainHandScore && + ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon))) { - // Equip in main hand - dstSlot = EQUIPMENT_SLOT_MAINHAND; - // Equip new weapon in main hand { WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); @@ -171,48 +166,43 @@ void EquipAction::EquipItem(Item* item) bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); } - // If there was a main hand item, try to move it to offhand if it improves offhand - if (mainHandItem && mainHandCanGoOff) + // If we had a main hand item, consider moving it to offhand if beneficial + if (mainHandItem && mainHandCanGoOff && + (!offHandItem || mainHandScore > offHandScore)) { - if (!offHandItem || mainHandScore > offHandScore) - { - WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); - ObjectGuid oldMHGuid = mainHandItem->GetGUID(); - offhandPacket << oldMHGuid << uint8(EQUIPMENT_SLOT_OFFHAND); - bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); - } + WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid oldMHGuid = mainHandItem->GetGUID(); + offhandPacket << oldMHGuid << uint8(EQUIPMENT_SLOT_OFFHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); } std::ostringstream out; - out << "equipping " << chat->FormatItem(itemProto) << " as the best weapon in main hand"; + out << "equipping " << chat->FormatItem(itemProto) << " in main hand as an upgrade"; botAI->TellMaster(out); return; } - else if (betterThanOff && canGoOff) + // If not better than main hand, check if it's better than offhand + else if (canGoOff && newItemScore > offHandScore) { // Equip in offhand - dstSlot = EQUIPMENT_SLOT_OFFHAND; - WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); ObjectGuid newItemGuid = item->GetGUID(); eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND); bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); std::ostringstream out; - out << "equipping " << chat->FormatItem(itemProto) << " in offhand"; + out << "equipping " << chat->FormatItem(itemProto) << " in offhand as an upgrade"; botAI->TellMaster(out); return; } else { - // Not an improvement, do nothing and return + // No improvement, do nothing return; } } - // If we reach here, either not a dual-wield scenario, not a better weapon scenario, - // or the item isn't a weapon. Fall back to existing logic. - + // If not a special dual-wield/TG scenario or no improvement found, fall back to original logic if (dstSlot == EQUIPMENT_SLOT_FINGER1 || dstSlot == EQUIPMENT_SLOT_TRINKET1 || (dstSlot == EQUIPMENT_SLOT_MAINHAND && bot->CanDualWield() && @@ -233,8 +223,8 @@ void EquipAction::EquipItem(Item* item) calculator.SetOverflowPenalty(false); float equippedItemScore[2] = { - equippedItemScore[0] = calculator.CalculateItem(equippedItems[0]->GetTemplate()->ItemId), - equippedItemScore[1] = calculator.CalculateItem(equippedItems[1]->GetTemplate()->ItemId) + calculator.CalculateItem(equippedItems[0]->GetTemplate()->ItemId), + calculator.CalculateItem(equippedItems[1]->GetTemplate()->ItemId) }; // Second item is worse than first, equip candidate item in second slot @@ -243,14 +233,14 @@ void EquipAction::EquipItem(Item* item) dstSlot++; } } - else // No item equipped in slot 2, equip in that slot + else { + // No item in second slot, equip there dstSlot++; } } } - // Perform the final equip if no special logic applied WorldPacket packet(CMSG_AUTOEQUIP_ITEM_SLOT, 2); ObjectGuid itemguid = item->GetGUID(); packet << itemguid << dstSlot; @@ -263,7 +253,6 @@ void EquipAction::EquipItem(Item* item) botAI->TellMaster(out); } - bool EquipUpgradesAction::Execute(Event event) { if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot)) From 0c16f308db60f4f1688f939eade82c62be2e897d Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 18:41:32 +1100 Subject: [PATCH 6/7] Update EquipAction.cpp --- src/strategy/actions/EquipAction.cpp | 333 ++++++++++++++------------- 1 file changed, 179 insertions(+), 154 deletions(-) diff --git a/src/strategy/actions/EquipAction.cpp b/src/strategy/actions/EquipAction.cpp index 2fec22a4..19a39661 100644 --- a/src/strategy/actions/EquipAction.cpp +++ b/src/strategy/actions/EquipAction.cpp @@ -65,182 +65,206 @@ void EquipAction::EquipItem(Item* item) uint8 slot = item->GetSlot(); const ItemTemplate* itemProto = item->GetTemplate(); uint32 itemId = itemProto->ItemId; + uint8 invType = itemProto->InventoryType; - if (itemProto->InventoryType == INVTYPE_AMMO) + // Handle ammunition separately + if (invType == INVTYPE_AMMO) { bot->SetAmmo(itemId); + std::ostringstream out; + out << "equipping " << chat->FormatItem(itemProto); + botAI->TellMaster(out); + return; } - else + + // Handle bags first + bool equippedBag = false; + if (itemProto->Class == ITEM_CLASS_CONTAINER) { - bool equippedBag = false; - if (itemProto->Class == ITEM_CLASS_CONTAINER) + // Attempt to equip as a bag + Bag* pBag = reinterpret_cast(item); + uint8 newBagSlot = GetSmallestBagSlot(); + if (newBagSlot > 0) { - Bag* pBag = (Bag*)&item; - uint8 newBagSlot = GetSmallestBagSlot(); - if (newBagSlot > 0) + uint16 src = ((bagIndex << 8) | slot); + uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | newBagSlot); + bot->SwapItem(src, dst); + equippedBag = true; + } + } + + // If we didn't equip as a bag, try to equip as gear + if (!equippedBag) + { + uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true); + + // Check if the item is a weapon and whether the bot can dual wield or use Titan Grip + bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON); + bool canTitanGrip = bot->CanTitanGrip(); + bool canDualWield = bot->CanDualWield(); + + bool isTwoHander = (invType == INVTYPE_2HWEAPON); + bool isValidTGWeapon = false; + if (canTitanGrip && isTwoHander) + { + // Titan Grip-valid 2H weapon subclasses: Axe2, Mace2, Sword2 + isValidTGWeapon = (itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || + itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || + itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2); + } + + // Check if the main hand currently has a 2H weapon equipped + Item* currentMHItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + bool have2HWeaponEquipped = (currentMHItem && currentMHItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON); + + bool canDualWieldOrTG = (canDualWield || (canTitanGrip && isTwoHander)); + + // If this is a weapon and we can dual wield or Titan Grip, check if we can improve main/off-hand setup + if (isWeapon && canDualWieldOrTG) + { + // Fetch current main hand and offhand items + Item* mainHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + Item* offHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + + // Set up the stats calculator once and reuse results for performance + StatsWeightCalculator calculator(bot); + calculator.SetItemSetBonus(false); + calculator.SetOverflowPenalty(false); + + // Calculate item scores once and store them + float newItemScore = calculator.CalculateItem(itemId); + float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f; + float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f; + + // Determine where this weapon can go + bool canGoMain = (invType == INVTYPE_WEAPON || + invType == INVTYPE_WEAPONMAINHAND || + (canTitanGrip && isTwoHander)); + + bool canTGOff = false; + if (canTitanGrip && isTwoHander && isValidTGWeapon) + canTGOff = true; + + bool canGoOff = (invType == INVTYPE_WEAPON || + invType == INVTYPE_WEAPONOFFHAND || + canTGOff); + + // Check if the main hand item can go to offhand if needed + bool mainHandCanGoOff = false; + if (mainHandItem) { - uint16 src = ((bagIndex << 8) | slot); - uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | newBagSlot); - bot->SwapItem(src, dst); - equippedBag = true; + const ItemTemplate* mhProto = mainHandItem->GetTemplate(); + bool mhIsValidTG = false; + if (canTitanGrip && mhProto->InventoryType == INVTYPE_2HWEAPON) + { + mhIsValidTG = (mhProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || + mhProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || + mhProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2); + } + + mainHandCanGoOff = (mhProto->InventoryType == INVTYPE_WEAPON || + mhProto->InventoryType == INVTYPE_WEAPONOFFHAND || + (mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG)); + } + + // Priority 1: Replace main hand if the new weapon is strictly better + // and if conditions allow (e.g. no conflicting 2H logic) + bool betterThanMH = (newItemScore > mainHandScore); + bool mhConditionOK = ((invType != INVTYPE_2HWEAPON && !have2HWeaponEquipped) || + (canTitanGrip && isValidTGWeapon)); + + if (canGoMain && betterThanMH && mhConditionOK) + { + // Equip new weapon in main hand + { + WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid newItemGuid = item->GetGUID(); + eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_MAINHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); + } + + // Try moving old main hand weapon to offhand if beneficial + if (mainHandItem && mainHandCanGoOff && (!offHandItem || mainHandScore > offHandScore)) + { + const ItemTemplate* oldMHProto = mainHandItem->GetTemplate(); + + WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid oldMHGuid = mainHandItem->GetGUID(); + offhandPacket << oldMHGuid << uint8(EQUIPMENT_SLOT_OFFHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); + + std::ostringstream moveMsg; + moveMsg << "moving " << chat->FormatItem(oldMHProto) << " to offhand"; + botAI->TellMaster(moveMsg); + } + + std::ostringstream out; + out << "equipping " << chat->FormatItem(itemProto) << " in main hand as an upgrade"; + botAI->TellMaster(out); + return; + } + + // Priority 2: If not better than main hand, check if better than offhand + else if (canGoOff && newItemScore > offHandScore) + { + // Equip in offhand + WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); + ObjectGuid newItemGuid = item->GetGUID(); + eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND); + bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); + + std::ostringstream out; + out << "equipping " << chat->FormatItem(itemProto) << " in offhand as an upgrade"; + botAI->TellMaster(out); + return; + } + else + { + // No improvement, do nothing + return; } } - if (!equippedBag) + // If not a special dual-wield/TG scenario or no improvement found, fall back to original logic + if (dstSlot == EQUIPMENT_SLOT_FINGER1 || + dstSlot == EQUIPMENT_SLOT_TRINKET1 || + (dstSlot == EQUIPMENT_SLOT_MAINHAND && canDualWield && + ((invType != INVTYPE_2HWEAPON && !have2HWeaponEquipped) || (canTitanGrip && isValidTGWeapon)))) { - uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true); + // Handle ring/trinket dual-slot logic + Item* const equippedItems[2] = { + bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot), + bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot + 1) + }; - bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON); - bool have2HWeapon = false; - bool isValidTGWeapon = false; - - if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON) + if (equippedItems[0]) { - isValidTGWeapon = (itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || - itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || - itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2); - } - - // Check if we currently have a 2H weapon in main hand - { - Item* currentWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - have2HWeapon = currentWeapon && currentWeapon->GetTemplate()->InventoryType == INVTYPE_2HWEAPON; - } - - bool canDualWieldOrTG = (bot->CanDualWield() || (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); - - // Run best-weapon logic only if it's a weapon and can dual wield or Titan Grip. - // Remove conditions that previously restricted running this logic based on dstSlot. - // We'll always check if this new weapon is better, and then decide final slot. - if (isWeapon && canDualWieldOrTG) - { - Item* mainHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - Item* offHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - - StatsWeightCalculator calculator(bot); - calculator.SetItemSetBonus(false); - calculator.SetOverflowPenalty(false); - - float newItemScore = calculator.CalculateItem(itemId); - float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f; - float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f; - - bool canGoMain = (itemProto->InventoryType == INVTYPE_WEAPON || - itemProto->InventoryType == INVTYPE_WEAPONMAINHAND || - (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON)); - - bool canTGOff = false; - if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON) + if (equippedItems[1]) { - canTGOff = isValidTGWeapon; - } + // Both slots are full - pick the worst item to replace + StatsWeightCalculator calc(bot); + calc.SetItemSetBonus(false); + calc.SetOverflowPenalty(false); - bool canGoOff = (itemProto->InventoryType == INVTYPE_WEAPON || - itemProto->InventoryType == INVTYPE_WEAPONOFFHAND || - canTGOff); + float firstItemScore = calc.CalculateItem(equippedItems[0]->GetTemplate()->ItemId); + float secondItemScore = calc.CalculateItem(equippedItems[1]->GetTemplate()->ItemId); - bool mainHandCanGoOff = false; - if (mainHandItem) - { - const ItemTemplate* mhProto = mainHandItem->GetTemplate(); - bool mhIsValidTG = (bot->CanTitanGrip() && mhProto->InventoryType == INVTYPE_2HWEAPON && - (mhProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 || - mhProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 || - mhProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2)); - - mainHandCanGoOff = (mhProto->InventoryType == INVTYPE_WEAPON || - mhProto->InventoryType == INVTYPE_WEAPONOFFHAND || - (mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG)); - } - - // First priority: If new weapon is better than main hand and can be equipped in main hand, - // do that. - if (canGoMain && newItemScore > mainHandScore && - ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon))) - { - // Equip new weapon in main hand + // If the second slot is worse, place the new item there + if (firstItemScore > secondItemScore) { - WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); - ObjectGuid newItemGuid = item->GetGUID(); - eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_MAINHAND); - bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); - } - - // If we had a main hand item, consider moving it to offhand if beneficial - if (mainHandItem && mainHandCanGoOff && - (!offHandItem || mainHandScore > offHandScore)) - { - WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); - ObjectGuid oldMHGuid = mainHandItem->GetGUID(); - offhandPacket << oldMHGuid << uint8(EQUIPMENT_SLOT_OFFHAND); - bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); - } - - std::ostringstream out; - out << "equipping " << chat->FormatItem(itemProto) << " in main hand as an upgrade"; - botAI->TellMaster(out); - return; - } - // If not better than main hand, check if it's better than offhand - else if (canGoOff && newItemScore > offHandScore) - { - // Equip in offhand - WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2); - ObjectGuid newItemGuid = item->GetGUID(); - eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND); - bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); - - std::ostringstream out; - out << "equipping " << chat->FormatItem(itemProto) << " in offhand as an upgrade"; - botAI->TellMaster(out); - return; - } - else - { - // No improvement, do nothing - return; - } - } - - // If not a special dual-wield/TG scenario or no improvement found, fall back to original logic - if (dstSlot == EQUIPMENT_SLOT_FINGER1 || - dstSlot == EQUIPMENT_SLOT_TRINKET1 || - (dstSlot == EQUIPMENT_SLOT_MAINHAND && bot->CanDualWield() && - ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon)))) - { - Item* const equippedItems[2] = { - bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot), - bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot + 1) - }; - - if (equippedItems[0]) - { - if (equippedItems[1]) - { - // Both slots are full - determine worst item to replace - StatsWeightCalculator calculator(bot); - calculator.SetItemSetBonus(false); - calculator.SetOverflowPenalty(false); - - float equippedItemScore[2] = { - calculator.CalculateItem(equippedItems[0]->GetTemplate()->ItemId), - calculator.CalculateItem(equippedItems[1]->GetTemplate()->ItemId) - }; - - // Second item is worse than first, equip candidate item in second slot - if (equippedItemScore[0] > equippedItemScore[1]) - { - dstSlot++; - } - } - else - { - // No item in second slot, equip there dstSlot++; } } + else + { + // Second slot empty, use it + dstSlot++; + } } + } + // Equip the item in the chosen slot + { WorldPacket packet(CMSG_AUTOEQUIP_ITEM_SLOT, 2); ObjectGuid itemguid = item->GetGUID(); packet << itemguid << dstSlot; @@ -253,6 +277,7 @@ void EquipAction::EquipItem(Item* item) botAI->TellMaster(out); } + bool EquipUpgradesAction::Execute(Event event) { if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot)) From d77dbb65e548ede02358140d100aa2cfc01c4779 Mon Sep 17 00:00:00 2001 From: avirar Date: Sat, 14 Dec 2024 18:52:57 +1100 Subject: [PATCH 7/7] Enhanced dual wield logic in EquipItem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented logic to ensure the strongest weapon is always placed in the main hand for dual-wielding or Titan Grip-capable bots. When equipping a new weapon, the code now compares the new weapon’s score with the currently equipped main-hand and off-hand weapons. If the new weapon is the strongest, it goes into the main hand. The previous main-hand weapon may be moved to the off-hand if it is allowed (e.g., not a main-hand-only weapon) and provides a performance improvement. Titan Grip conditions are accounted for, allowing valid two-handed weapons (2H axes, maces, swords) to be placed in the off-hand as well. --- src/strategy/actions/EquipAction.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategy/actions/EquipAction.cpp b/src/strategy/actions/EquipAction.cpp index 19a39661..9ea2a797 100644 --- a/src/strategy/actions/EquipAction.cpp +++ b/src/strategy/actions/EquipAction.cpp @@ -194,12 +194,12 @@ void EquipAction::EquipItem(Item* item) bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket); std::ostringstream moveMsg; - moveMsg << "moving " << chat->FormatItem(oldMHProto) << " to offhand"; + moveMsg << "Main hand upgrade found. Moving " << chat->FormatItem(oldMHProto) << " to offhand"; botAI->TellMaster(moveMsg); } std::ostringstream out; - out << "equipping " << chat->FormatItem(itemProto) << " in main hand as an upgrade"; + out << "Equipping " << chat->FormatItem(itemProto) << " in main hand"; botAI->TellMaster(out); return; } @@ -214,7 +214,7 @@ void EquipAction::EquipItem(Item* item) bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket); std::ostringstream out; - out << "equipping " << chat->FormatItem(itemProto) << " in offhand as an upgrade"; + out << "Equipping " << chat->FormatItem(itemProto) << " in offhand"; botAI->TellMaster(out); return; }