Bonus hit chance auras should check equipped weapon.
Closes https://github.com/vmangos/core/issues/2306
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user