From 4543311d5d5d8c3d177b684ada0212781cef11c0 Mon Sep 17 00:00:00 2001 From: WinterSolstice8 <60417494+wintersolstice8@users.noreply.github.com> Date: Thu, 2 Apr 2026 11:08:44 -0600 Subject: [PATCH] [core] Filter additional bad equip packets Also emit the "you cant dual wield that" message when appropriate --- src/map/enums/msg_basic.h | 1 + src/map/utils/charutils.cpp | 85 ++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/map/enums/msg_basic.h b/src/map/enums/msg_basic.h index b492c688907..3390bb7dc49 100644 --- a/src/map/enums/msg_basic.h +++ b/src/map/enums/msg_basic.h @@ -63,6 +63,7 @@ enum class MsgBasic : uint16_t LoseSight = 36, // You lose sight of . TooFarForExp = 37, // You are too far from the battle to gain experience. SkillGain = 38, // 's skill rises X points. + NeedDualWield = 39, // You need the Dual Wield ability to equip as a sub-weapon CannotInThisArea = 40, // cannot use in this area ReadiesWeaponskill = 43, // readies . SpikesEffectDmg = 44, // 's spikes deal damage to diff --git a/src/map/utils/charutils.cpp b/src/map/utils/charutils.cpp index 85b9ffbd4f6..18f0b81fb4e 100644 --- a/src/map/utils/charutils.cpp +++ b/src/map/utils/charutils.cpp @@ -3140,7 +3140,72 @@ void EquipItem(CCharEntity* PChar, uint8 slotID, uint8 equipSlotID, uint8 contai return; } - // if player attempts to change thier ranged weapon during a ranged state then prevent equip + // slotID of zero = unequip + if (slotID > 0) + { + // skip the rest of the function if we are trying to equip the same item to a different slot + switch (static_cast(equipSlotID)) + { + case SLOT_MAIN: + { + auto PSub = PChar->getEquip(SLOT_SUB); + if (PItem == PSub) + { + return; + } + break; + } + case SLOT_SUB: + { + auto PMain = PChar->getEquip(SLOT_MAIN); + if (PItem == PMain) + { + return; + } + break; + } + case SLOT_EAR1: + { + auto PEar2 = PChar->getEquip(SLOT_EAR2); + if (PItem == PEar2) + { + return; + } + break; + } + case SLOT_EAR2: + { + auto PEar1 = PChar->getEquip(SLOT_EAR1); + if (PItem == PEar1) + { + return; + } + break; + } + case SLOT_RING1: + { + auto PRing2 = PChar->getEquip(SLOT_RING2); + if (PItem == PRing2) + { + return; + } + break; + } + case SLOT_RING2: + { + auto PRing1 = PChar->getEquip(SLOT_RING1); + if (PItem == PRing1) + { + return; + } + break; + } + default: + break; + } + } + + // if player attempts to change their ranged weapon during a ranged state then prevent equip // this prevents players from starting a RA with short delay x-bow and ending with high dmg longbow if (equipSlotID == SLOT_RANGED || (equipSlotID == SLOT_AMMO && !PChar->getEquip(SLOT_RANGED))) { @@ -3154,12 +3219,30 @@ void EquipItem(CCharEntity* PChar, uint8 slotID, uint8 equipSlotID, uint8 contai { auto PItemWeapon = dynamic_cast(PItem); auto PMainItem = dynamic_cast(PChar->getEquip(SLOT_MAIN)); + if (PItemWeapon && PItemWeapon->getSkillType() == SKILL_NONE && (!PMainItem || !PMainItem->isTwoHanded())) { PChar->pushPacket(PChar, PChar, 0, 0, MsgBasic::Requires2HForGrip); return; } + if (PItemWeapon && PItemWeapon->getSkillType() != SKILL_NONE) + { + // Don't attempt to equip item in equip menu if you don't have dual wield trait (client sees BLU, THF, DNC, NIN, /DNC or /NIN etc as able to equip sub weapons even if sub is too low or no trait on BLU) + if (!PChar->hasTrait(TRAIT_DUAL_WIELD)) + { + PChar->pushPacket(PChar, PChar, PItemWeapon->getID(), 0, MsgBasic::NeedDualWield); + return; + } + + // Don't allow Dual Wield injections to offhand when you dont have a mainahdn (this was visual only) + // Don't allow non-shields in offhand with no weapon + if ((PMainItem && PMainItem->isTwoHanded()) || !PMainItem) + { + return; + } + } + // Disallow everything but shields if you're using H2H // Equipping a shield will unequip the H2H weapon and you will go barefisted with a shield if (PMainItem && PMainItem->getSkillType() == SKILL_HAND_TO_HAND)