From 20cf73bf35864ee8d7ceab6abb52bc8c42617fe7 Mon Sep 17 00:00:00 2001 From: Frankie-hz <105882754+Frankie-hz@users.noreply.github.com> Date: Fri, 8 May 2026 00:14:23 -0400 Subject: [PATCH] [cpp] Allows dualWield to be changed on the fly --- src/map/attackround.cpp | 2 +- src/map/entities/battleentity.cpp | 10 ++++++++++ src/map/entities/battleentity.h | 1 + src/map/lua/lua_baseentity.cpp | 2 +- src/map/utils/battleutils.cpp | 2 +- src/map/utils/mobutils.cpp | 17 ++++++----------- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/map/attackround.cpp b/src/map/attackround.cpp index 17e8361bdb7..98524462d22 100644 --- a/src/map/attackround.cpp +++ b/src/map/attackround.cpp @@ -76,7 +76,7 @@ CAttackRound::CAttackRound(CBattleEntity* attacker, CBattleEntity* defender) } } - if (PSub && attacker->m_dualWield) + if (PSub && attacker->IsDualWielding()) { CreateAttacks(PSub, LEFTATTACK); } diff --git a/src/map/entities/battleentity.cpp b/src/map/entities/battleentity.cpp index 28f1f890ada..e480a1665a4 100644 --- a/src/map/entities/battleentity.cpp +++ b/src/map/entities/battleentity.cpp @@ -109,6 +109,16 @@ CBattleEntity::~CBattleEntity() TracyZoneScoped; } +bool CBattleEntity::IsDualWielding() +{ + if (objtype == TYPE_MOB) + { + return static_cast(this)->getMobMod(MOBMOD_DUAL_WIELD) != 0; + } + + return m_dualWield; +} + auto CBattleEntity::isDead() const -> bool { return (health.hp <= 0 || status == STATUS_TYPE::DISAPPEAR || PAI->IsCurrentState() || PAI->IsCurrentState()); diff --git a/src/map/entities/battleentity.h b/src/map/entities/battleentity.h index e55b9c1dbd2..7648e976068 100644 --- a/src/map/entities/battleentity.h +++ b/src/map/entities/battleentity.h @@ -379,6 +379,7 @@ class CBattleEntity : public CBaseEntity void UpdateHealth(); // recalculation of the maximum amount of hp and mp, as well as adjusting their current values uint8 UpdateSpeed(bool run = false) override; + bool IsDualWielding(); uint32 GetWeaponDelay(bool tp); // returns delay of combined weapons float GetMeleeRange(const CBattleEntity* Target) const; // returns the distance considered to be within melee range of the entity virtual float GetRangedAttackRange(); // returns the maximum valid distance for a ranged attack diff --git a/src/map/lua/lua_baseentity.cpp b/src/map/lua/lua_baseentity.cpp index 8776407313b..8bf41a9feff 100644 --- a/src/map/lua/lua_baseentity.cpp +++ b/src/map/lua/lua_baseentity.cpp @@ -12987,7 +12987,7 @@ bool CLuaBaseEntity::isDualWielding() CBattleEntity* PBattleEntity = dynamic_cast(m_PBaseEntity); if (PBattleEntity) { - return PBattleEntity->m_dualWield; + return PBattleEntity->IsDualWielding(); } else { diff --git a/src/map/utils/battleutils.cpp b/src/map/utils/battleutils.cpp index 2c8fba2ee58..4beff9d3661 100644 --- a/src/map/utils/battleutils.cpp +++ b/src/map/utils/battleutils.cpp @@ -630,7 +630,7 @@ int32 CalculateEnspellDamage(CBattleEntity* PAttacker, CBattleEntity* PDefender, runeDPS = PWeapon->getDPS(); } - if (PAttacker->m_dualWield) + if (PAttacker->IsDualWielding()) { runeDPS /= 2; // DPS is divided evenly between hands derived from mainhand only } diff --git a/src/map/utils/mobutils.cpp b/src/map/utils/mobutils.cpp index 84d2f2b0164..78353bfb448 100644 --- a/src/map/utils/mobutils.cpp +++ b/src/map/utils/mobutils.cpp @@ -847,17 +847,6 @@ void CalculateMobStats(CMobEntity* PMob, bool recover) ((CItemWeapon*)PMob->m_Weapons[SLOT_MAIN])->resetDelay(); } - PMob->m_dualWield = false; - - // Deprecate MOBMOD_DUAL_WIELD later, replace if check with value from DB - if (PMob->getMobMod(MOBMOD_DUAL_WIELD)) - { - PMob->m_dualWield = true; - // if mob is going to dualWield then need to have sub slot - // assume it is the same damage as the main slot - static_cast(PMob->m_Weapons[SLOT_SUB])->setDamage(GetWeaponDamage(PMob, SLOT_MAIN)); - } - uint16 fSTR = GetBaseToRank(PMob->strRank, mLvl); uint16 fDEX = GetBaseToRank(PMob->dexRank, mLvl); uint16 fVIT = GetBaseToRank(PMob->vitRank, mLvl); @@ -1010,6 +999,12 @@ void CalculateMobStats(CMobEntity* PMob, bool recover) } SetupJob(PMob); + + // If a mob is going to dual wield, then it needs to have a sub slot. + // Assume it is the same damage as the main slot. + // Ordering matters. This has to come after SetupJob + static_cast(PMob->m_Weapons[SLOT_SUB])->setDamage(PMob->IsDualWielding() ? GetWeaponDamage(PMob, SLOT_MAIN) : 0); + SetupRoaming(PMob); // All beastmen drop gil