aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/latest.sql13
-rw-r--r--src/game/Player.cpp94
-rw-r--r--src/game/Player.h2
-rw-r--r--src/game/SpellMgr.cpp52
-rw-r--r--src/game/SpellMgr.h19
-rw-r--r--src/game/Unit.cpp44
-rw-r--r--src/game/World.cpp3
7 files changed, 191 insertions, 36 deletions
diff --git a/sql/updates/latest.sql b/sql/updates/latest.sql
new file mode 100644
index 00000000000..0a25eaefc46
--- /dev/null
+++ b/sql/updates/latest.sql
@@ -0,0 +1,13 @@
+CREATE TABLE `spell_enchant_proc_data` (
+ `entry` INT(10) UNSIGNED NOT NULL,
+ `customChance` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `PPMChance` FLOAT UNSIGNED NOT NULL DEFAULT '0',
+ `procEx` FLOAT UNSIGNED NOT NULL DEFAULT '0'
+) ENGINE=MYISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Spell enchant proc data';
+
+INSERT INTO spell_enchant_proc_data (`entry`, `customChance`, `PPMChance`,`procEx`) VALUES (2, 0, 8.8,0);
+INSERT INTO spell_enchant_proc_data (`entry`, `customChance`, `PPMChance`,`procEx`) VALUES (12, 0, 8.8,0);
+INSERT INTO spell_enchant_proc_data (`entry`, `customChance`, `PPMChance`,`procEx`) VALUES (524, 0, 8.8,0);
+INSERT INTO spell_enchant_proc_data (`entry`, `customChance`, `PPMChance`,`procEx`) VALUES (1667, 0, 8.8,0);
+INSERT INTO spell_enchant_proc_data (`entry`, `customChance`, `PPMChance`,`procEx`) VALUES (1668, 0, 8.8,0);
+INSERT INTO spell_enchant_proc_data (`entry`, `customChance`, `PPMChance`,`procEx`) VALUES (2635, 0, 8.8,0);
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 341742dd3b1..18426621300 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -6991,7 +6991,7 @@ void Player::UpdateEquipSpellsAtFormChange()
}
}
-void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType)
+void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo)
{
if(!item || item->IsBroken())
return;
@@ -7000,46 +7000,53 @@ void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attTy
if(!proto)
return;
+ Unit * Target = damageInfo->target;
+ WeaponAttackType attType = damageInfo->attackType;
+
if (!Target || Target == this )
return;
- for (int i = 0; i < 5; i++)
+ // Can do effect if any damage done to target
+ if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
- _Spell const& spellData = proto->Spells[i];
+ for (int i = 0; i < 5; i++)
+ {
+ _Spell const& spellData = proto->Spells[i];
- // no spell
- if(!spellData.SpellId )
- continue;
+ // no spell
+ if(!spellData.SpellId )
+ continue;
- // wrong triggering type
- if(spellData.SpellTrigger != ITEM_SPELLTRIGGER_CHANCE_ON_HIT)
- continue;
+ // wrong triggering type
+ if(spellData.SpellTrigger != ITEM_SPELLTRIGGER_CHANCE_ON_HIT)
+ continue;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId);
- if(!spellInfo)
- {
- sLog.outError("WORLD: unknown Item spellid %i", spellData.SpellId);
- continue;
- }
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId);
+ if(!spellInfo)
+ {
+ sLog.outError("WORLD: unknown Item spellid %i", spellData.SpellId);
+ continue;
+ }
- // not allow proc extra attack spell at extra attack
- if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
- return;
+ // not allow proc extra attack spell at extra attack
+ if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
+ return;
- float chance = spellInfo->procChance;
+ float chance = spellInfo->procChance;
- if(spellData.SpellPPMRate)
- {
- uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate);
- }
- else if(chance > 100.0f)
- {
- chance = GetWeaponProcChance();
- }
+ if(spellData.SpellPPMRate)
+ {
+ uint32 WeaponSpeed = GetAttackTime(attType);
+ chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate);
+ }
+ else if(chance > 100.0f)
+ {
+ chance = GetWeaponProcChance();
+ }
- if (roll_chance_f(chance))
- CastSpell(Target, spellInfo->Id, true, item);
+ if (roll_chance_f(chance))
+ CastSpell(Target, spellInfo->Id, true, item);
+ }
}
// item combat enchantments
@@ -7053,6 +7060,21 @@ void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attTy
if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
continue;
+ SpellEnchantProcEntry const* entry = spellmgr.GetSpellEnchantProcEvent(enchant_id);
+
+ if (entry && entry->procEx)
+ {
+ // Check hit/crit/dodge/parry requirement
+ if((entry->procEx & damageInfo->procEx) == 0)
+ continue;
+ }
+ else
+ {
+ // Can do effect if any damage done to target
+ if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
+ continue;
+ }
+
SpellEntry const *spellInfo = sSpellStore.LookupEntry(pEnchant->spellid[s]);
if (!spellInfo)
{
@@ -7061,6 +7083,18 @@ void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attTy
}
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
+
+ if (entry && entry->PPMChance)
+ {
+ uint32 WeaponSpeed = GetAttackTime(attType);
+ chance = GetPPMProcChance(WeaponSpeed, entry->PPMChance);
+ }
+ else if (entry && entry->customChance)
+ chance = entry->customChance;
+
+ // Apply spell mods
+ ApplySpellMod(pEnchant->spellid[s],SPELLMOD_CHANCE_OF_SUCCESS,chance);
+
if (roll_chance_f(chance))
{
if(IsPositiveSpell(pEnchant->spellid[s]))
diff --git a/src/game/Player.h b/src/game/Player.h
index 7d530a57228..fbe365173dc 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -1797,7 +1797,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void ApplyItemEquipSpell(Item *item, bool apply, bool form_change = false);
void ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change = false);
void UpdateEquipSpellsAtFormChange();
- void CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType);
+ void CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo);
void SendInitWorldStates(bool force = false, uint32 forceZoneId = 0);
void SendUpdateWorldState(uint32 Field, uint32 Value);
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 8e01742587c..3a22efd71d6 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -1330,6 +1330,58 @@ void SpellMgr::LoadSpellThreats()
sLog.outString();
}
+void SpellMgr::LoadSpellEnchantProcData()
+{
+ mSpellEnchantProcEventMap.clear(); // need for reload case
+
+ uint32 count = 0;
+
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx");
+ if( !result )
+ {
+
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell enchant proc event conditions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ uint32 enchantId = fields[0].GetUInt32();
+
+ SpellItemEnchantmentEntry const *ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
+ if (!ench)
+ {
+ sLog.outErrorDb("Enchancment %u listed in `spell_enchant_proc_data` does not exist", enchantId);
+ continue;
+ }
+
+ SpellEnchantProcEntry spe;
+
+ spe.customChance = fields[1].GetUInt32();
+ spe.PPMChance = fields[2].GetFloat();
+ spe.procEx = fields[3].GetUInt32();
+
+ mSpellEnchantProcEventMap[enchantId] = spe;
+
+ ++count;
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString( ">> Loaded %u enchant proc data definitions", count);
+}
+
bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
{
SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index 70b81403a52..749abab0efb 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -564,6 +564,15 @@ struct SpellProcEventEntry
typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap;
+struct SpellEnchantProcEntry
+{
+ uint32 customChance;
+ float PPMChance;
+ uint32 procEx;
+};
+
+typedef UNORDERED_MAP<uint32, SpellEnchantProcEntry> SpellEnchantProcEventMap;
+
#define ELIXIR_BATTLE_MASK 0x1
#define ELIXIR_GUARDIAN_MASK 0x2
#define ELIXIR_FLASK_MASK (ELIXIR_BATTLE_MASK|ELIXIR_GUARDIAN_MASK)
@@ -785,6 +794,14 @@ class SpellMgr
static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
+ SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const
+ {
+ SpellEnchantProcEventMap::const_iterator itr = mSpellEnchantProcEventMap.find(enchId);
+ if( itr != mSpellEnchantProcEventMap.end( ) )
+ return &itr->second;
+ return NULL;
+ }
+
// Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const
{
@@ -986,6 +1003,7 @@ class SpellMgr
void LoadSpellPetAuras();
void LoadSpellCustomAttr();
void LoadSpellLinked();
+ void LoadSpellEnchantProcData();
private:
SpellScriptTarget mSpellScriptTarget;
@@ -1002,6 +1020,7 @@ class SpellMgr
SpellPetAuraMap mSpellPetAuraMap;
SpellCustomAttribute mSpellCustomAttr;
SpellLinkedMap mSpellLinkedMap;
+ SpellEnchantProcEventMap mSpellEnchantProcEventMap;
};
#define spellmgr SpellMgr::Instance()
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index cac26755d3f..a4963e37d5b 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -1611,15 +1611,49 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
}
}
- // If not miss
- if (!(damageInfo->HitInfo & HITINFO_MISS))
+ if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
{
- if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
{
- for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
- ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i), pVictim, damageInfo->attackType);
+ EquipmentSlots slot = (EquipmentSlots)i;
+ // For weapon slots check if valid attack type and if weapon useable
+ if (i == EQUIPMENT_SLOT_MAINHAND
+ || i == EQUIPMENT_SLOT_OFFHAND
+ || i == EQUIPMENT_SLOT_RANGED)
+ {
+ switch (damageInfo->attackType)
+ {
+ case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
+ case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
+ case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
+ }
+ // offhand item cannot proc from main hand hit etc
+ if (slot != i)
+ slot=EQUIPMENT_SLOT_END;
+ else
+ {
+ // Check if item is useable (forms or disarm)
+ if (damageInfo->attackType == BASE_ATTACK)
+ {
+ if (!((Player*)this)->IsUseEquipedWeapon(true))
+ slot=EQUIPMENT_SLOT_END;
+ }
+ else
+ {
+ if (((Player*)this)->IsInFeralForm())
+ slot=EQUIPMENT_SLOT_END;
+ }
+ }
+ }
+ // If usable, try to cast item spell
+ if(slot!=EQUIPMENT_SLOT_END)
+ (((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i), &damageInfo);
}
+ }
+ // Do effect if any damage done to target
+ if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
+ {
// victim's damage shield
std::set<Aura*> alreadyDone;
uint32 removedAuras = pVictim->m_removedAuras;
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 5edd15fa472..a58103ef437 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -1150,6 +1150,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading NPC Texts..." );
objmgr.LoadGossipText();
+ sLog.outString( "Loading Enchant Spells Proc datas...");
+ spellmgr.LoadSpellEnchantProcData();
+
sLog.outString( "Loading Item Random Enchantments Table..." );
LoadRandomEnchantmentsTable();