Bonus hit chance auras should check equipped weapon.

Closes https://github.com/vmangos/core/issues/2306
This commit is contained in:
ratkosrb
2023-11-26 17:43:56 +02:00
parent 73dc96ec9f
commit 4bf4864f8b
16 changed files with 97 additions and 62 deletions
+2 -2
View File
@@ -1157,13 +1157,13 @@ bool ChatHandler::HandleNpcAddWeaponCommand(char* args)
return true;
}
if (uiSlotId > VIRTUAL_ITEM_SLOT_2)
if (uiSlotId > RANGED_ATTACK)
{
PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST, uiSlotId);
return true;
}
pCreature->SetVirtualItem(VirtualItemSlot(uiSlotId), uiItemId);
pCreature->SetVirtualItem(WeaponAttackType(uiSlotId), uiItemId);
PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT, uiItemId, pItemProto->Name1, uiSlotId);
return true;
+3 -3
View File
@@ -711,15 +711,15 @@ bool Map::ScriptCommand_SetEquipment(ScriptInfo const& script, WorldObject* sour
// main hand
if (script.setEquipment.slot[0] >= 0)
pSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, script.setEquipment.slot[0]);
pSource->SetVirtualItem(BASE_ATTACK, script.setEquipment.slot[0]);
// off hand
if (script.setEquipment.slot[1] >= 0)
pSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, script.setEquipment.slot[1]);
pSource->SetVirtualItem(OFF_ATTACK, script.setEquipment.slot[1]);
// ranged
if (script.setEquipment.slot[2] >= 0)
pSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, script.setEquipment.slot[2]);
pSource->SetVirtualItem(RANGED_ATTACK, script.setEquipment.slot[2]);
return false;
}
+23 -3
View File
@@ -1880,7 +1880,7 @@ void Creature::LoadEquipment(uint32 equipmentId, bool force)
if (force)
{
for (uint8 i = 0; i < MAX_VIRTUAL_ITEM_SLOT; ++i)
SetVirtualItem(VirtualItemSlot(i), 0);
SetVirtualItem(WeaponAttackType(i), 0);
m_equipmentId = 0;
}
return;
@@ -1892,7 +1892,7 @@ void Creature::LoadEquipment(uint32 equipmentId, bool force)
if (EquipmentEntry const* pEquipEntry = pEquipTemplate->ChooseEquipmentEntry())
{
for (uint8 i = 0; i < MAX_VIRTUAL_ITEM_SLOT; ++i)
SetVirtualItem(VirtualItemSlot(i), pEquipEntry->item[i]);
SetVirtualItem(WeaponAttackType(i), pEquipEntry->item[i]);
}
}
}
@@ -4059,7 +4059,7 @@ uint32 Creature::GetDBTableGUIDLow() const
return 0;
}
void Creature::SetVirtualItem(VirtualItemSlot slot, uint32 item_id)
void Creature::SetVirtualItem(WeaponAttackType slot, uint32 item_id)
{
if (item_id == 0)
{
@@ -4085,6 +4085,26 @@ void Creature::SetVirtualItem(VirtualItemSlot slot, uint32 item_id)
SetByteValue(UNIT_VIRTUAL_ITEM_INFO + (slot * 2) + 1, VIRTUAL_ITEM_INFO_1_OFFSET_SHEATH, proto->Sheath);
}
uint32 Creature::GetVirtualItemDisplayId(WeaponAttackType slot) const
{
return GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + slot);
}
uint32 Creature::GetVirtualItemClass(WeaponAttackType slot) const
{
return GetByteValue(UNIT_VIRTUAL_ITEM_INFO + (slot * 2) + 0, VIRTUAL_ITEM_INFO_0_OFFSET_CLASS);
}
uint32 Creature::GetVirtualItemSubclass(WeaponAttackType slot) const
{
return GetByteValue(UNIT_VIRTUAL_ITEM_INFO + (slot * 2) + 0, VIRTUAL_ITEM_INFO_0_OFFSET_SUBCLASS);
}
uint32 Creature::GetVirtualItemInventoryType(WeaponAttackType slot) const
{
return GetByteValue(UNIT_VIRTUAL_ITEM_INFO + (slot * 2) + 0, VIRTUAL_ITEM_INFO_0_OFFSET_INVENTORYTYPE);
}
void Creature::JoinCreatureGroup(Creature* leader, float dist, float angle, uint32 options)
{
if (CreatureGroup* myGroup = GetCreatureGroup())
+5 -1
View File
@@ -514,7 +514,11 @@ class Creature : public Unit
void RegenerateHealth();
void RegenerateMana();
void SetVirtualItem(VirtualItemSlot slot, uint32 item_id);
void SetVirtualItem(WeaponAttackType slot, uint32 item_id);
uint32 GetVirtualItemDisplayId(WeaponAttackType slot) const;
uint32 GetVirtualItemClass(WeaponAttackType slot) const;
uint32 GetVirtualItemSubclass(WeaponAttackType slot) const;
uint32 GetVirtualItemInventoryType(WeaponAttackType slot) const;
void ResetDamageTakenOrigin()
{
-7
View File
@@ -598,13 +598,6 @@ struct TrainerSpellData
#define MAX_VENDOR_ITEMS 128 // Limitation in item count field size in SMSG_LIST_INVENTORY
enum VirtualItemSlot
{
VIRTUAL_ITEM_SLOT_0 = 0,
VIRTUAL_ITEM_SLOT_1 = 1,
VIRTUAL_ITEM_SLOT_2 = 2,
};
#define MAX_VIRTUAL_ITEM_SLOT 3
enum VirtualItemInfoByteOffset
+11 -7
View File
@@ -965,22 +965,20 @@ bool Item::IsBoundByEnchant() const
return false;
}
bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo, uint32 itemClass, uint32 itemSubClass, uint32 itemInventoryType)
{
ItemPrototype const* proto = GetProto();
if (spellInfo->EquippedItemClass != -1) // -1 == any item class
{
// Ustaag <Nostalrius> : ajout exception pour le spell Enchant Cloak - Minor Agility
// prob de DB : spellInfo->EquippedItemClass == 2 alors qu'il devrait etre == 4
if (spellInfo->Id == 13419 && proto->InventoryType == INVTYPE_CLOAK)
if (spellInfo->Id == 13419 && itemInventoryType == INVTYPE_CLOAK)
return true;
if ((spellInfo->EquippedItemClass != int32(proto->Class)) && spellInfo->Id != 13419)
if ((spellInfo->EquippedItemClass != int32(itemClass)) && spellInfo->Id != 13419)
return false; // wrong item class
if (spellInfo->EquippedItemSubClassMask != 0) // 0 == any subclass
{
if ((spellInfo->EquippedItemSubClassMask & (1 << proto->SubClass)) == 0)
if ((spellInfo->EquippedItemSubClassMask & (1 << itemSubClass)) == 0)
return false; // subclass not present in mask
}
}
@@ -990,13 +988,19 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
// and special code (Titan's Grip, Windfury Attack). Check clearly not applicable for Lava Lash.
if (spellInfo->EquippedItemInventoryTypeMask != 0 && (spellInfo->Targets & TARGET_FLAG_ITEM)) // 0 == any inventory type
{
if ((spellInfo->EquippedItemInventoryTypeMask & (1 << proto->InventoryType)) == 0)
if ((spellInfo->EquippedItemInventoryTypeMask & (1 << itemInventoryType)) == 0)
return false; // inventory type not present in mask
}
return true;
}
bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
{
ItemPrototype const* proto = GetProto();
return IsFitToSpellRequirements(spellInfo, proto->Class, proto->SubClass, proto->InventoryType);
}
bool Item::IsTargetValidForItemUse(Unit* pUnitTarget)
{
ItemRequiredTargetMapBounds bounds = sObjectMgr.GetItemRequiredTargetMapBounds(GetProto()->ItemId);
+1
View File
@@ -292,6 +292,7 @@ class Item : public Object
void SetInTrade(bool b = true) { mb_in_trade = b; }
bool IsInTrade() const { return mb_in_trade; }
static bool IsFitToSpellRequirements(SpellEntry const* spellInfo, uint32 itemClass, uint32 itemSubClass, uint32 itemInventoryType);
bool IsFitToSpellRequirements(SpellEntry const* spellInfo) const;
bool IsTargetValidForItemUse(Unit* pUnitTarget);
bool IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const;
+1 -4
View File
@@ -345,10 +345,7 @@ float SpellCaster::MeleeSpellMissChance(Unit* pVictim, WeaponAttackType attType,
modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, hitChance, spellPtr);
// Bonuses from attacker aura and ratings
if (attType == RANGED_ATTACK)
hitChance += pUnit->m_modRangedHitChance;
else
hitChance += pUnit->m_modMeleeHitChance;
hitChance += pUnit->GetBonusHitChanceFromAuras(attType);
}
// There is some code in 1.12 that explicitly adds a modifier that causes the first 1% of +hit gained from
+34 -7
View File
@@ -146,8 +146,6 @@ Unit::Unit()
m_createResistance = 0;
m_attacking = nullptr;
m_modMeleeHitChance = 0.0f;
m_modRangedHitChance = 0.0f;
m_modSpellHitChance = 0.0f;
m_baseSpellCritChance = 5;
@@ -2545,6 +2543,39 @@ bool Unit::IsEffectResist(SpellEntry const* spell, int eff) const
return false;
}
float Unit::GetBonusHitChanceFromAuras(WeaponAttackType attType) const
{
float chance = 0.0f;
AuraList const& mTotalAuraList = GetAurasByType(SPELL_AURA_MOD_HIT_CHANCE);
for (auto const& i : mTotalAuraList)
{
SpellEntry const* pSpellEntry = i->GetSpellProto();
if (pSpellEntry->EquippedItemClass >= 0)
{
if (Player const* pPlayer = ToPlayer())
{
Item* pWeapon = pPlayer->GetWeaponForAttack(attType);
if (!pWeapon)
continue;
if (!pWeapon->IsFitToSpellRequirements(pSpellEntry))
continue;
}
else if (Creature const* pCreature = ToCreature())
{
if (!pCreature->GetVirtualItemDisplayId(attType))
continue;
if (!Item::IsFitToSpellRequirements(pSpellEntry, pCreature->GetVirtualItemClass(attType), pCreature->GetVirtualItemSubclass(attType), pCreature->GetVirtualItemInventoryType(attType)))
continue;
}
}
chance += i->GetModifier()->m_amount;
}
return chance;
}
float Unit::MeleeMissChanceCalc(Unit const* pVictim, WeaponAttackType attType) const
{
if (!pVictim || !pVictim->IsStandingUp())
@@ -2585,11 +2616,7 @@ float Unit::MeleeMissChanceCalc(Unit const* pVictim, WeaponAttackType attType) c
missChance *= levelDiffMultiplier;
// Hit chance bonus from attacker based on ratings and auras
float hitChance = 0.0f;
if (attType == RANGED_ATTACK)
hitChance = m_modRangedHitChance;
else
hitChance = m_modMeleeHitChance;
float hitChance = GetBonusHitChanceFromAuras(attType);
// There is some code in 1.12 that explicitly adds a modifier that causes the first 1% of +hit gained from
// talents or gear to be ignored against monsters with more than 10 Defense Skill above the attacking player’s Weapon Skill.
+1 -2
View File
@@ -378,8 +378,6 @@ class Unit : public SpellCaster
float GetRegenMPPerSpirit() const;
public:
// Data
float m_modMeleeHitChance;
float m_modRangedHitChance;
float m_modSpellHitChance;
int32 m_baseSpellCritChance;
float m_threatModifier[MAX_SPELL_SCHOOL];
@@ -1000,6 +998,7 @@ class Unit : public SpellCaster
ObjectGuid const& GetReactiveTarget(ReactiveType reactive) const { return m_reactiveTarget[reactive]; }
void UpdateReactives(uint32 p_time);
float GetBonusHitChanceFromAuras(WeaponAttackType attType) const;
float MeleeMissChanceCalc(Unit const* pVictim, WeaponAttackType attType) const;
void CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK);
void UnitDamaged(ObjectGuid from, uint32 damage) { m_damageTakenHistory[from] += damage; m_lastDamageTaken = 0; }
+1 -10
View File
@@ -114,7 +114,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS] =
&Aura::HandleAuraModBlockPercent, // 51 SPELL_AURA_MOD_BLOCK_PERCENT
&Aura::HandleAuraModCritPercent, // 52 SPELL_AURA_MOD_CRIT_PERCENT
&Aura::HandlePeriodicLeech, // 53 SPELL_AURA_PERIODIC_LEECH
&Aura::HandleModHitChance, // 54 SPELL_AURA_MOD_HIT_CHANCE
&Aura::HandleNoImmediateEffect, // 54 SPELL_AURA_MOD_HIT_CHANCE implemented in Unit::GetBonusHitChanceFromAuras
&Aura::HandleModSpellHitChance, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE
&Aura::HandleAuraTransform, // 56 SPELL_AURA_TRANSFORM
&Aura::HandleModSpellCritChance, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE
@@ -5225,15 +5225,6 @@ void Aura::HandleAuraModCritPercent(bool apply, bool Real)
}
}
void Aura::HandleModHitChance(bool apply, bool /*Real*/)
{
Unit* target = GetTarget();
if (GetId() != 22780) // [Ranged Hit Bonus +3] as stated in name ...
target->m_modMeleeHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
target->m_modRangedHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
}
void Aura::HandleModSpellHitChance(bool apply, bool /*Real*/)
{
GetTarget()->m_modSpellHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
-1
View File
@@ -374,7 +374,6 @@ class Aura
void HandleAuraModBlockPercent(bool Apply, bool Real);
void HandleAuraModCritPercent(bool Apply, bool Real);
void HandlePeriodicLeech(bool Apply, bool Real);
void HandleModHitChance(bool Apply, bool Real);
void HandleModSpellHitChance(bool Apply, bool Real);
void HandleAuraModScale(bool Apply, bool Real);
void HandlePeriodicManaLeech(bool Apply, bool Real);
@@ -65,14 +65,14 @@ struct boss_warmastervooneAI : public ScriptedAI
{
case 0:
{
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 12348);
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
m_creature->SetVirtualItem(BASE_ATTACK, 12348);
m_creature->SetVirtualItem(OFF_ATTACK, 0);
break;
}
case 1:
{
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0);
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
m_creature->SetVirtualItem(BASE_ATTACK, 0);
m_creature->SetVirtualItem(OFF_ATTACK, 0);
m_creature->CastSpell(m_creature, SPELL_UNARMED_PASSIVE, true);
break;
}
@@ -167,17 +167,17 @@ struct boss_mr_smiteAI : public ScriptedAI
if (m_creature->GetHealthPercent() < 33.0f)
{
// It's Hammer, go Hammer!
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, EQUIP_ID_HAMMER);
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
m_creature->SetVirtualItem(BASE_ATTACK, EQUIP_ID_HAMMER);
m_creature->SetVirtualItem(OFF_ATTACK, 0);
m_creature->SetVirtualItem(RANGED_ATTACK, 0);
DoCastSpellIfCan(m_creature, SPELL_SMITE_HAMMER);
}
else
{
// It's double Axe.
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, EQUIP_ID_AXE);
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, EQUIP_ID_AXE);
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
m_creature->SetVirtualItem(BASE_ATTACK, EQUIP_ID_AXE);
m_creature->SetVirtualItem(OFF_ATTACK, EQUIP_ID_AXE);
m_creature->SetVirtualItem(RANGED_ATTACK, 0);
}
m_creature->SetStandState(UNIT_STAND_STATE_STAND);
@@ -87,7 +87,7 @@ struct npc_daphne_stilwellAI : public npc_escortAI
switch (uiPoint)
{
case 4:
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 6946);
m_creature->SetVirtualItem(BASE_ATTACK, 6946);
m_creature->SetSheath(SHEATH_STATE_RANGED);
m_creature->HandleEmoteCommand(EMOTE_STATE_USESTANDING_NOSHEATHE);
break;
+4 -4
View File
@@ -2132,20 +2132,20 @@ struct npc_anachronos_the_ancientAI : public ScriptedAI
m_uiEventTimer = 15000;
break;
case 40:
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, ITEM_SCEPTER_OF_THE_SHIFTING_SANDS);
m_creature->SetVirtualItem(BASE_ATTACK, ITEM_SCEPTER_OF_THE_SHIFTING_SANDS);
if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_uiFandralGUID))
DoScriptText(EMOTE_ANACHRONOS_SCEPTER, m_creature, pFandral);
m_uiEventTimer = 1500;
break;
case 41:
m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0);
m_creature->SetVirtualItem(BASE_ATTACK, 0);
m_creature->HandleEmote(EMOTE_ONESHOT_BEG);
m_uiEventTimer = 1500;
break;
case 42:
if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_uiFandralGUID))
{
pFandral->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, ITEM_SCEPTER_OF_THE_SHIFTING_SANDS);
pFandral->SetVirtualItem(BASE_ATTACK, ITEM_SCEPTER_OF_THE_SHIFTING_SANDS);
pFandral->SetStandState(UNIT_STAND_STATE_STAND);
DoScriptText(SAY_FANDRAL_EPILOGUE_4, pFandral);
}
@@ -2161,7 +2161,7 @@ struct npc_anachronos_the_ancientAI : public ScriptedAI
{
pFandral->CastSpell(pFandral, SPELL_SHATTER_HAMMER, false);
DoScriptText(EMOTE_FANDRAL_SHATTER, pFandral);
pFandral->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0);
pFandral->SetVirtualItem(BASE_ATTACK, 0);
}
m_uiEventTimer = 3000;
break;