diff --git a/src/game/Commands/CreatureCommands.cpp b/src/game/Commands/CreatureCommands.cpp index f9906b2e6..e044908a3 100644 --- a/src/game/Commands/CreatureCommands.cpp +++ b/src/game/Commands/CreatureCommands.cpp @@ -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; diff --git a/src/game/Maps/ScriptCommands.cpp b/src/game/Maps/ScriptCommands.cpp index c9eb5902f..3669b71c2 100644 --- a/src/game/Maps/ScriptCommands.cpp +++ b/src/game/Maps/ScriptCommands.cpp @@ -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; } diff --git a/src/game/Objects/Creature.cpp b/src/game/Objects/Creature.cpp index dbdb8df58..7b21622ed 100644 --- a/src/game/Objects/Creature.cpp +++ b/src/game/Objects/Creature.cpp @@ -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()) diff --git a/src/game/Objects/Creature.h b/src/game/Objects/Creature.h index 3846b2f67..5511327fa 100644 --- a/src/game/Objects/Creature.h +++ b/src/game/Objects/Creature.h @@ -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() { diff --git a/src/game/Objects/CreatureDefines.h b/src/game/Objects/CreatureDefines.h index 8377a54d1..02335396b 100644 --- a/src/game/Objects/CreatureDefines.h +++ b/src/game/Objects/CreatureDefines.h @@ -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 diff --git a/src/game/Objects/Item.cpp b/src/game/Objects/Item.cpp index 07a62bd8f..325e759fd 100644 --- a/src/game/Objects/Item.cpp +++ b/src/game/Objects/Item.cpp @@ -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 : 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); diff --git a/src/game/Objects/Item.h b/src/game/Objects/Item.h index fb8e8c181..0e6eeeb9d 100644 --- a/src/game/Objects/Item.h +++ b/src/game/Objects/Item.h @@ -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; diff --git a/src/game/Objects/SpellCaster.cpp b/src/game/Objects/SpellCaster.cpp index 32bee1ffe..31a9d34bb 100644 --- a/src/game/Objects/SpellCaster.cpp +++ b/src/game/Objects/SpellCaster.cpp @@ -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 diff --git a/src/game/Objects/Unit.cpp b/src/game/Objects/Unit.cpp index d29a8499f..0319a0e90 100644 --- a/src/game/Objects/Unit.cpp +++ b/src/game/Objects/Unit.cpp @@ -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. diff --git a/src/game/Objects/Unit.h b/src/game/Objects/Unit.h index 5e1024bf7..1b983ceef 100644 --- a/src/game/Objects/Unit.h +++ b/src/game/Objects/Unit.h @@ -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; } diff --git a/src/game/Spells/SpellAuras.cpp b/src/game/Spells/SpellAuras.cpp index e57674980..c8e3517a7 100644 --- a/src/game/Spells/SpellAuras.cpp +++ b/src/game/Spells/SpellAuras.cpp @@ -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); diff --git a/src/game/Spells/SpellAuras.h b/src/game/Spells/SpellAuras.h index 810021014..6dedd199a 100644 --- a/src/game/Spells/SpellAuras.h +++ b/src/game/Spells/SpellAuras.h @@ -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); diff --git a/src/scripts/eastern_kingdoms/burning_steppes/blackrock_spire/boss_warmaster_voone.cpp b/src/scripts/eastern_kingdoms/burning_steppes/blackrock_spire/boss_warmaster_voone.cpp index e86431cc5..3375782fe 100644 --- a/src/scripts/eastern_kingdoms/burning_steppes/blackrock_spire/boss_warmaster_voone.cpp +++ b/src/scripts/eastern_kingdoms/burning_steppes/blackrock_spire/boss_warmaster_voone.cpp @@ -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; } diff --git a/src/scripts/eastern_kingdoms/westfall/deadmines/boss_mr_smite.cpp b/src/scripts/eastern_kingdoms/westfall/deadmines/boss_mr_smite.cpp index 6a73fb720..709b56693 100644 --- a/src/scripts/eastern_kingdoms/westfall/deadmines/boss_mr_smite.cpp +++ b/src/scripts/eastern_kingdoms/westfall/deadmines/boss_mr_smite.cpp @@ -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); diff --git a/src/scripts/eastern_kingdoms/westfall/westfall.cpp b/src/scripts/eastern_kingdoms/westfall/westfall.cpp index 6b3fd3892..10823cd0f 100644 --- a/src/scripts/eastern_kingdoms/westfall/westfall.cpp +++ b/src/scripts/eastern_kingdoms/westfall/westfall.cpp @@ -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; diff --git a/src/scripts/kalimdor/silithus/silithus.cpp b/src/scripts/kalimdor/silithus/silithus.cpp index 42243b4d4..c3115bc15 100644 --- a/src/scripts/kalimdor/silithus/silithus.cpp +++ b/src/scripts/kalimdor/silithus/silithus.cpp @@ -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;