Skip to content

Commit fcf22b3

Browse files
authored
Merge pull request #69 from Olion17/master
spell_linked system from Zero
2 parents 9f812f6 + 898fcf4 commit fcf22b3

File tree

11 files changed

+230
-4
lines changed

11 files changed

+230
-4
lines changed

src/game/ChatCommands/Level3.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(char* /*args*/)
338338
HandleReloadSpellTargetPositionCommand((char*)"a");
339339
HandleReloadSpellThreatsCommand((char*)"a");
340340
HandleReloadSpellPetAurasCommand((char*)"a");
341+
HandleReloadSpellLinkedCommand((char*)"a");
341342
return true;
342343
}
343344

@@ -788,6 +789,14 @@ bool ChatHandler::HandleReloadSpellPetAurasCommand(char* /*args*/)
788789
return true;
789790
}
790791

792+
bool ChatHandler::HandleReloadSpellLinkedCommand(char* /*arg*/)
793+
{
794+
sLog.outString("Re-Loading spell linked table...");
795+
sSpellMgr.LoadSpellLinked();
796+
SendGlobalSysMessage("DB table `spell_linked` reloaded.", SEC_MODERATOR);
797+
return true;
798+
}
799+
791800
bool ChatHandler::HandleReloadPageTextsCommand(char* /*args*/)
792801
{
793802
sLog.outString("Re-Loading Page Texts...");

src/game/Object/SpellMgr.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,88 @@ void SpellMgr::LoadSpellBonuses()
16001600
sLog.outString();
16011601
}
16021602

1603+
void SpellMgr::LoadSpellLinked()
1604+
{
1605+
mSpellLinkedMap.clear(); // need for reload case
1606+
uint32 count = 0;
1607+
// 0 1 2 3
1608+
QueryResult* result = WorldDatabase.Query("SELECT entry, linked_entry, type, effect_mask FROM spell_linked");
1609+
if (!result)
1610+
{
1611+
BarGoLink bar(1);
1612+
bar.step();
1613+
sLog.outString();
1614+
sLog.outString(">> Spell linked definition not loaded - table empty");
1615+
return;
1616+
}
1617+
1618+
BarGoLink bar(result->GetRowCount());
1619+
do
1620+
{
1621+
Field *fields = result->Fetch();
1622+
bar.step();
1623+
uint32 entry = fields[0].GetUInt32();
1624+
uint32 linkedEntry = fields[1].GetUInt32();
1625+
1626+
SpellEntry const* spell = sSpellStore.LookupEntry(entry);
1627+
SpellEntry const* spell1 = sSpellStore.LookupEntry(linkedEntry);
1628+
if (!spell || !spell1)
1629+
{
1630+
sLog.outErrorDb("Spells %u or %u listed in `spell_linked` does not exist", entry, linkedEntry);
1631+
continue;
1632+
}
1633+
1634+
if (entry == linkedEntry)
1635+
{
1636+
sLog.outErrorDb("Spell %u linked with self!", entry);
1637+
continue;
1638+
}
1639+
1640+
uint32 first_id = GetFirstSpellInChain(entry);
1641+
1642+
if (first_id != entry)
1643+
{
1644+
sLog.outErrorDb("Spell %u listed in `spell_linked` is not first rank (%u) in chain", entry, first_id);
1645+
}
1646+
1647+
SpellLinkedEntry data;
1648+
1649+
data.spellId = entry;
1650+
data.linkedId = linkedEntry;
1651+
data.type = fields[2].GetUInt32();
1652+
data.effectMask = fields[3].GetUInt32();
1653+
1654+
mSpellLinkedMap.insert(SpellLinkedMap::value_type(entry, data));
1655+
1656+
++count;
1657+
1658+
} while (result->NextRow());
1659+
1660+
delete result;
1661+
1662+
sLog.outString();
1663+
sLog.outString(">> Loaded %u spell linked definitions", count);
1664+
}
1665+
1666+
SpellLinkedSet SpellMgr::GetSpellLinked(uint32 spell_id, SpellLinkedType type) const
1667+
{
1668+
SpellLinkedSet result;
1669+
1670+
SpellLinkedMapBounds const& bounds = GetSpellLinkedMapBounds(spell_id);
1671+
1672+
if (type < SPELL_LINKED_TYPE_MAX && bounds.first != bounds.second)
1673+
{
1674+
for (SpellLinkedMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
1675+
{
1676+
if (itr->second.type == type)
1677+
{
1678+
result.insert(itr->second.linkedId);
1679+
}
1680+
}
1681+
}
1682+
return result;
1683+
}
1684+
16031685
bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const* procSpell, uint32 procFlags, uint32 procExtra)
16041686
{
16051687
// No extra req need

src/game/Object/SpellMgr.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,32 @@ struct SpellTargetPosition
728728

729729
typedef UNORDERED_MAP<uint32, SpellTargetPosition> SpellTargetPositionMap;
730730

731+
// Spell linked types
732+
enum SpellLinkedType
733+
{
734+
SPELL_LINKED_TYPE_NONE = 0,
735+
SPELL_LINKED_TYPE_BOOST = 1,
736+
SPELL_LINKED_TYPE_PRECAST = 2,
737+
SPELL_LINKED_TYPE_TRIGGERED = 3,
738+
SPELL_LINKED_TYPE_PROC = 4,
739+
SPELL_LINKED_TYPE_REMOVEONCAST = 5,
740+
SPELL_LINKED_TYPE_REMOVEONREMOVE = 6,
741+
SPELL_LINKED_TYPE_CASTONREMOVE = 7,
742+
SPELL_LINKED_TYPE_MAX,
743+
};
744+
745+
struct SpellLinkedEntry
746+
{
747+
uint32 spellId;
748+
uint32 linkedId;
749+
uint32 type;
750+
uint32 effectMask;
751+
};
752+
753+
typedef std::multimap<uint32, SpellLinkedEntry> SpellLinkedMap;
754+
typedef std::pair<SpellLinkedMap::const_iterator, SpellLinkedMap::const_iterator> SpellLinkedMapBounds;
755+
typedef std::set<uint32> SpellLinkedSet;
756+
731757
// Spell pet auras
732758
class PetAura
733759
{
@@ -1123,6 +1149,13 @@ class SpellMgr
11231149
return mSpellAreaForAreaMap.equal_range(area_id);
11241150
}
11251151

1152+
SpellLinkedMapBounds GetSpellLinkedMapBounds(uint32 spell_id) const
1153+
{
1154+
return mSpellLinkedMap.equal_range(spell_id);
1155+
}
1156+
1157+
SpellLinkedSet GetSpellLinked(uint32 spell_id, SpellLinkedType type) const;
1158+
11261159
// Modifiers
11271160
public:
11281161
static SpellMgr& Instance();
@@ -1139,6 +1172,7 @@ class SpellMgr
11391172
void LoadSpellProcEvents();
11401173
void LoadSpellProcItemEnchant();
11411174
void LoadSpellBonuses();
1175+
void LoadSpellLinked();
11421176
void LoadSpellTargetPositions();
11431177
void LoadSpellThreats();
11441178
void LoadSkillLineAbilityMap();
@@ -1161,6 +1195,7 @@ class SpellMgr
11611195
SpellProcEventMap mSpellProcEventMap;
11621196
SpellProcItemEnchantMap mSpellProcItemEnchantMap;
11631197
SpellBonusMap mSpellBonusMap;
1198+
SpellLinkedMap mSpellLinkedMap;
11641199
SkillLineAbilityMap mSkillLineAbilityMap;
11651200
SkillRaceClassInfoMap mSkillRaceClassInfoMap;
11661201
SpellPetAuraMap mSpellPetAuraMap;

src/game/Object/Unit.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,14 @@ void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered,
12231223

12241224
spell->m_CastItem = castItem;
12251225
spell->prepare(&targets, triggeredByAura);
1226+
1227+
// Linked spells (RemoveOnCast chain)
1228+
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(spellInfo->Id, SPELL_LINKED_TYPE_REMOVEONCAST);
1229+
if (linkedSet.size() > 0)
1230+
{
1231+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
1232+
{ Victim->RemoveAurasDueToSpell(*itr); }
1233+
}
12261234
}
12271235

12281236
void Unit::CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy)

src/game/WorldHandlers/Chat.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ ChatCommand* ChatHandler::getCommandTable()
559559
{ "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL },
560560
{ "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
561561
{ "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
562+
{ "spell_linked", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLinkedCommand, "", NULL },
562563
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
563564
{ "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
564565
{ "spell_proc_item_enchant", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcItemEnchantCommand, "", NULL },

src/game/WorldHandlers/Chat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ class ChatHandler
468468
bool HandleReloadSpellChainCommand(char* args);
469469
bool HandleReloadSpellElixirCommand(char* args);
470470
bool HandleReloadSpellLearnSpellCommand(char* args);
471+
bool HandleReloadSpellLinkedCommand(char* args);
471472
bool HandleReloadSpellProcEventCommand(char* args);
472473
bool HandleReloadSpellProcItemEnchantCommand(char* args);
473474
bool HandleReloadSpellScriptTargetCommand(char* args);

src/game/WorldHandlers/Spell.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,23 @@ void Spell::cast(bool skipCheck)
29422942
break;
29432943
}
29442944

2945+
// Linked spells (precast chain)
2946+
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(m_spellInfo->Id, SPELL_LINKED_TYPE_PRECAST);
2947+
if (linkedSet.size() > 0)
2948+
{
2949+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
2950+
{ AddPrecastSpell(*itr); }
2951+
}
2952+
2953+
// Linked spells (triggered chain)
2954+
linkedSet.clear();
2955+
linkedSet = sSpellMgr.GetSpellLinked(m_spellInfo->Id, SPELL_LINKED_TYPE_TRIGGERED);
2956+
if (linkedSet.size() > 0)
2957+
{
2958+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
2959+
{ AddTriggeredSpell(*itr); }
2960+
}
2961+
29452962
// traded items have trade slot instead of guid in m_itemTargetGUID
29462963
// set to real guid to be sent later to the client
29472964
m_targets.updateTradeSlotItem();
@@ -3927,7 +3944,7 @@ void Spell::TakeCastItem()
39273944

39283945
void Spell::TakePower()
39293946
{
3930-
if (m_CastItem || m_triggeredByAuraSpell)
3947+
if (m_CastItem || m_triggeredByAuraSpell || m_IsTriggeredSpell)
39313948
{ return; }
39323949

39333950
// health as power used
@@ -4720,6 +4737,7 @@ SpellCastResult Spell::CheckCast(bool strict)
47204737
}
47214738
}
47224739

4740+
if (!m_IsTriggeredSpell) // triggered spell does not use power
47234741
{
47244742
SpellCastResult castResult = CheckPower();
47254743
if (castResult != SPELL_CAST_OK)

src/game/WorldHandlers/SpellAuras.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7297,6 +7297,41 @@ void SpellAuraHolder::HandleSpellSpecificBoosts(bool apply)
72977297
uint32 spellId3 = 0;
72987298
uint32 spellId4 = 0;
72997299

7300+
// Linked spells (boost chain)
7301+
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_BOOST);
7302+
if (linkedSet.size() > 0)
7303+
{
7304+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
7305+
{
7306+
apply ?
7307+
m_target->CastSpell(m_target, *itr, true, NULL, NULL, GetCasterGuid()) :
7308+
m_target->RemoveAurasByCasterSpell(*itr, GetCasterGuid());
7309+
}
7310+
}
7311+
7312+
if (!apply)
7313+
{
7314+
// Linked spells (CastOnRemove chain)
7315+
linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_CASTONREMOVE);
7316+
if (linkedSet.size() > 0)
7317+
{
7318+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
7319+
{
7320+
m_target->CastSpell(m_target, *itr, true, NULL, NULL, GetCasterGuid());
7321+
}
7322+
}
7323+
7324+
// Linked spells (RemoveOnRemove chain)
7325+
linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_REMOVEONREMOVE);
7326+
if (linkedSet.size() > 0)
7327+
{
7328+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
7329+
{
7330+
m_target->RemoveAurasByCasterSpell(*itr, GetCasterGuid());
7331+
}
7332+
}
7333+
}
7334+
73007335
switch (GetSpellProto()->SpellFamilyName)
73017336
{
73027337
case SPELLFAMILY_MAGE:

src/game/WorldHandlers/UnitAuraProcHandler.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,23 @@ SpellAuraProcResult Unit::HandleDummyAuraProc(Unit* pVictim, uint32 damage, Aura
15591559
break;
15601560
}
15611561

1562+
if (!triggered_spell_id)
1563+
{
1564+
// Linked spells (Proc chain)
1565+
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(dummySpell->Id, SPELL_LINKED_TYPE_PROC);
1566+
if (linkedSet.size() > 0)
1567+
{
1568+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
1569+
{
1570+
if (target == NULL)
1571+
{ target = !(procFlag & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(*itr) ? this : pVictim; }
1572+
CastSpell(this, *itr, true, castItem, triggeredByAura);
1573+
if (cooldown && GetTypeId() == TYPEID_PLAYER)
1574+
{ ((Player*)this)->AddSpellCooldown(*itr, 0, time(NULL) + cooldown); }
1575+
}
1576+
}
1577+
}
1578+
15621579
// processed charge only counting case
15631580
if (!triggered_spell_id)
15641581
{ return SPELL_AURA_PROC_OK; }
@@ -2173,6 +2190,23 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
21732190
}
21742191
}
21752192

2193+
if (!trigger_spell_id)
2194+
{
2195+
// Linked spells (Proc chain)
2196+
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(auraSpellInfo->Id, SPELL_LINKED_TYPE_PROC);
2197+
if (linkedSet.size() > 0)
2198+
{
2199+
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
2200+
{
2201+
if (target == NULL)
2202+
{ target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(*itr) ? this : pVictim; }
2203+
CastSpell(target, *itr, true, castItem, triggeredByAura);
2204+
if (cooldown && GetTypeId() == TYPEID_PLAYER)
2205+
{ ((Player*)this)->AddSpellCooldown(*itr, 0, time(NULL) + cooldown); }
2206+
}
2207+
}
2208+
}
2209+
21762210
if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
21772211
{ return SPELL_AURA_PROC_FAILED; }
21782212

src/game/WorldHandlers/World.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,9 @@ void World::SetInitialWorldSettings()
10671067
sLog.outString("Loading Spell Proc Item Enchant...");
10681068
sSpellMgr.LoadSpellProcItemEnchant(); // must be after LoadSpellChains
10691069

1070+
sLog.outString("Loading Spell Linked definitions...");
1071+
sSpellMgr.LoadSpellLinked(); // must be after LoadSpellChains
1072+
10701073
sLog.outString("Loading Aggro Spells Definitions...");
10711074
sSpellMgr.LoadSpellThreats();
10721075

0 commit comments

Comments
 (0)