Skip to content

Commit

Permalink
[mr1291] implement spell_linked table for make DB link various types …
Browse files Browse the repository at this point in the history
…between spells. original idea by megamage (TC), but fully other realization and purpose.
  • Loading branch information
rsa committed Nov 25, 2011
1 parent e5aa3a0 commit c0446b0
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 1 deletion.
10 changes: 10 additions & 0 deletions sql_mr/custom_mangos_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,13 @@ CREATE TABLE IF NOT EXISTS `player_factionchange_spells` (
`commentH` varchar(255) DEFAULT NULL,
PRIMARY KEY (`race_A`,`alliance_id`,`race_H`,`horde_id`)
) DEFAULT CHARSET=UTF8;

-- Implement spell linked definitions storage
CREATE TABLE IF NOT EXISTS `spell_linked` (
`entry` int(10) unsigned NOT NULL COMMENT 'Spell entry',
`linked_entry` int(10) unsigned NOT NULL COMMENT 'Linked spell entry',
`type` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Type of link',
`effect_mask` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'mask of effect (NY)',
`comment` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`entry`,`linked_entry`,`type`)
) DEFAULT CHARSET=utf8 PACK_KEYS=0 COMMENT='Linked spells storage';
1 change: 1 addition & 0 deletions src/game/Chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },
{ "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL },
{ "spell_disabled", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellDisabledCommand, "", NULL },
{ "spell_linked", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLinkedCommand, "", NULL },
{ "anticheat", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAntiCheatCommand, "", NULL },

{ NULL, 0, false, NULL, "", NULL }
Expand Down
1 change: 1 addition & 0 deletions src/game/Chat.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ class MANGOS_DLL_SPEC ChatHandler
bool HandleReloadSpellThreatsCommand(char* args);
bool HandleReloadSpellPetAurasCommand(char* args);

bool HandleReloadSpellLinkedCommand(char* args);
bool HandleReloadSpellDisabledCommand(char* args);
bool HandleReloadAntiCheatCommand(char* args);

Expand Down
12 changes: 12 additions & 0 deletions src/game/Level3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(char* /*args*/)
HandleReloadSpellThreatsCommand((char*)"a");
HandleReloadSpellPetAurasCommand((char*)"a");
HandleReloadSpellDisabledCommand((char*)"a");
HandleReloadSpellLinkedCommand((char*)"a");
return true;
}

Expand Down Expand Up @@ -1114,6 +1115,17 @@ bool ChatHandler::HandleReloadSpellDisabledCommand(char* /*arg*/)
return true;
}

bool ChatHandler::HandleReloadSpellLinkedCommand(char* /*arg*/)
{
sLog.outString( "Re-Loading spell linked table...");

sSpellMgr.LoadSpellLinked();

SendGlobalSysMessage("DB table `spell_linked` reloaded.");

return true;
}

bool ChatHandler::HandleReloadAntiCheatCommand(char* /*arg*/)
{
sLog.outString( "Re-Loading anticheat config table...");
Expand Down
17 changes: 17 additions & 0 deletions src/game/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3723,6 +3723,23 @@ void Spell::cast(bool skipCheck)
break;
}

// Linked spells (precast chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(m_spellInfo->Id, SPELL_LINKED_TYPE_PRECAST);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
AddPrecastSpell(*itr);
}

// Linked spells (triggered chain)
linkedSet.clear();

This comment has been minimized.

Copy link
@boxa

boxa Nov 25, 2011

Member

not needed

This comment has been minimized.

Copy link
@rsa

rsa Nov 26, 2011

Author Member

:)

linkedSet = sSpellMgr.GetSpellLinked(m_spellInfo->Id, SPELL_LINKED_TYPE_TRIGGERED);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
AddTriggeredSpell(*itr);
}

// traded items have trade slot instead of guid in m_itemTargetGUID
// set to real guid to be sent later to the client
m_targets.updateTradeSlotItem();
Expand Down
42 changes: 42 additions & 0 deletions src/game/SpellAuras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10463,6 +10463,37 @@ void SpellAuraHolder::HandleSpellSpecificBoosts(bool apply)
uint32 spellId3 = 0;
uint32 spellId4 = 0;

// Linked spells (boost chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_BOOST);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
{
apply ?
m_target->CastSpell(m_target, *itr, true, NULL, NULL, GetCasterGuid()) :
m_target->RemoveAurasByCasterSpell(*itr, GetCasterGuid());
}
}

if (!apply)
{
// Linked spells (CastOnRemove chain)
linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_CASTONREMOVE);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
m_target->CastSpell(m_target, *itr, true, NULL, NULL, GetCasterGuid());
}

// Linked spells (RemoveOnRemove chain)
linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_REMOVEONREMOVE);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
m_target->RemoveAurasByCasterSpell(*itr, GetCasterGuid());
}
}

switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
Expand Down Expand Up @@ -11413,6 +11444,16 @@ void SpellAuraHolder::HandleSpellSpecificBoostsForward(bool apply)

pCaster->ProcDamageAndSpell(m_target, procFlag, PROC_FLAG_NONE, procEx, 0, GetWeaponAttackType(GetSpellProto()), GetSpellProto());

// Linked spells (boostforward chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(GetId(), SPELL_LINKED_TYPE_BOOSTFORWARD);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
apply ?
m_target->CastSpell(m_target, *itr, true, NULL, NULL, GetCasterGuid()) :
m_target->RemoveAurasByCasterSpell(*itr, GetCasterGuid());
}

uint32 spellId1 = 0;
uint32 spellId2 = 0;
uint32 spellId3 = 0;
Expand Down Expand Up @@ -11505,6 +11546,7 @@ void SpellAuraHolder::HandleSpellSpecificBoostsForward(bool apply)
m_target->RemoveAurasByCasterSpell(spellId4, GetCasterGuid());
}


SetInUse(false);
}

Expand Down
81 changes: 81 additions & 0 deletions src/game/SpellMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,87 @@ void SpellMgr::LoadSpellBonuses()
sLog.outString( ">> Loaded %u extra spell bonus data", count);
}

void SpellMgr::LoadSpellLinked()
{
mSpellLinkedMap.clear(); // need for reload case
uint32 count = 0;
// 0 1 2 3
QueryResult* result = WorldDatabase.Query("SELECT entry, linked_entry, type, effect_mask FROM spell_linked");
if (!result)
{
BarGoLink bar(1);
bar.step();
sLog.outString();
sLog.outString(">> Spell linked definition not loaded - table empty");
return;
}

BarGoLink bar(result->GetRowCount());
do
{
Field *fields = result->Fetch();
bar.step();
uint32 entry = fields[0].GetUInt32();
uint32 linkedEntry = fields[1].GetUInt32();

SpellEntry const* spell = sSpellStore.LookupEntry(entry);
SpellEntry const* spell1 = sSpellStore.LookupEntry(linkedEntry);
if (!spell || !spell1)
{
sLog.outErrorDb("Spells %u or %u listed in `spell_linked` does not exist", entry, linkedEntry);
continue;
}

if (entry == linkedEntry)
{
sLog.outErrorDb("Spell %u linked with self!", entry);
continue;
}

uint32 first_id = GetFirstSpellInChain(entry);

if ( first_id != entry )
{
sLog.outErrorDb("Spell %u listed in `spell_linked` is not first rank (%u) in chain", entry, first_id);
}

SpellLinkedEntry data;

data.spellId = entry;
data.linkedId = linkedEntry;
data.type = fields[2].GetUInt32();
data.effectMask = fields[3].GetUInt32();

mSpellLinkedMap.insert(SpellLinkedMap::value_type(entry,data));

++count;

}
while (result->NextRow());

delete result;

sLog.outString();
sLog.outString( ">> Loaded %u spell linked definitions", count);
}

SpellLinkedSet SpellMgr::GetSpellLinked(uint32 spell_id, SpellLinkedType type) const
{
SpellLinkedSet result;

SpellLinkedMapBounds const& bounds = GetSpellLinkedMapBounds(spell_id);

if (type < SPELL_LINKED_TYPE_MAX && bounds.first != bounds.second)
{
for (SpellLinkedMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
{
if (itr->second.type == type)
result.insert(itr->second.linkedId);
}
}
return result;
}

bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra)
{
// No extra req need
Expand Down
36 changes: 36 additions & 0 deletions src/game/SpellMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,33 @@ struct SpellTargetPosition

typedef UNORDERED_MAP<uint32, SpellTargetPosition> SpellTargetPositionMap;

// Spell linked types
enum SpellLinkedType
{
SPELL_LINKED_TYPE_NONE = 0,
SPELL_LINKED_TYPE_BOOST = 1,
SPELL_LINKED_TYPE_BOOSTFORWARD = 2,
SPELL_LINKED_TYPE_PRECAST = 3,
SPELL_LINKED_TYPE_TRIGGERED = 4,
SPELL_LINKED_TYPE_PROC = 5,
SPELL_LINKED_TYPE_REMOVEONCAST = 6,
SPELL_LINKED_TYPE_REMOVEONREMOVE = 7,
SPELL_LINKED_TYPE_CASTONREMOVE = 8,
SPELL_LINKED_TYPE_MAX,
};

struct SpellLinkedEntry
{
uint32 spellId;
uint32 linkedId;
uint32 type;
uint32 effectMask;
};

typedef std::multimap<uint32, SpellLinkedEntry> SpellLinkedMap;
typedef std::pair<SpellLinkedMap::const_iterator,SpellLinkedMap::const_iterator> SpellLinkedMapBounds;
typedef std::set<uint32> SpellLinkedSet;

// Spell pet auras
class PetAura
{
Expand Down Expand Up @@ -1223,6 +1250,13 @@ class SpellMgr
return mSpellAreaForAreaMap.equal_range(area_id);
}

SpellLinkedMapBounds GetSpellLinkedMapBounds(uint32 spell_id) const
{
return mSpellLinkedMap.equal_range(spell_id);
}

SpellLinkedSet GetSpellLinked(uint32 spell_id, SpellLinkedType type) const;

// Modifiers
public:
static SpellMgr& Instance();
Expand All @@ -1238,6 +1272,7 @@ class SpellMgr
void LoadSpellProcEvents();
void LoadSpellProcItemEnchant();
void LoadSpellBonuses();
void LoadSpellLinked();
void LoadSpellTargetPositions();
void LoadSpellThreats();
void LoadSkillLineAbilityMap();
Expand All @@ -1261,6 +1296,7 @@ class SpellMgr
SpellProcEventMap mSpellProcEventMap;
SpellProcItemEnchantMap mSpellProcItemEnchantMap;
SpellBonusMap mSpellBonusMap;
SpellLinkedMap mSpellLinkedMap;
SkillLineAbilityMap mSkillLineAbilityMap;
SkillRaceClassInfoMap mSkillRaceClassInfoMap;
SpellPetAuraMap mSpellPetAuraMap;
Expand Down
9 changes: 9 additions & 0 deletions src/game/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,15 @@ void Unit::CastSpell(Unit* Victim, SpellEntry const *spellInfo, bool triggered,
targets.setUnitTarget( Victim );
spell->m_CastItem = castItem;
spell->prepare(&targets, triggeredByAura);

// Linked spells (RemoveOnCast chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(spellInfo->Id, SPELL_LINKED_TYPE_REMOVEONCAST);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
Victim->RemoveAurasDueToSpell(*itr);
}

}

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)
Expand Down
35 changes: 35 additions & 0 deletions src/game/UnitAuraProcHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3380,6 +3380,23 @@ SpellAuraProcResult Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura
break;
}

if (!triggered_spell_id)
{
// Linked spells (Proc chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(dummySpell->Id, SPELL_LINKED_TYPE_PROC);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
{
if (target == NULL)
target = !(procFlag & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(*itr) ? this : pVictim;
CastSpell(this, *itr, true, castItem, triggeredByAura);

This comment has been minimized.

Copy link
@boxa

boxa Nov 25, 2011

Member

CastSpell(target ?

This comment has been minimized.

Copy link
@rsa

rsa Nov 26, 2011

Author Member

yes, thx.

if (cooldown && GetTypeId()==TYPEID_PLAYER)
((Player*)this)->AddSpellCooldown(*itr,0,time(NULL) + cooldown);
}
}
}

// processed charge only counting case
if (!triggered_spell_id)
return SPELL_AURA_PROC_OK;
Expand Down Expand Up @@ -4411,6 +4428,23 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit *pVictim, uint32 d
}
}

if (!trigger_spell_id)
{
// Linked spells (Proc chain)
SpellLinkedSet linkedSet = sSpellMgr.GetSpellLinked(auraSpellInfo->Id, SPELL_LINKED_TYPE_PROC);
if (linkedSet.size() > 0)
{
for (SpellLinkedSet::const_iterator itr = linkedSet.begin(); itr != linkedSet.end(); ++itr)
{
if (target == NULL)
target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(*itr) ? this : pVictim;
CastSpell(target, *itr, true, castItem, triggeredByAura);
if (cooldown && GetTypeId()==TYPEID_PLAYER)
((Player*)this)->AddSpellCooldown(*itr,0,time(NULL) + cooldown);
}
}
}

if (cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
return SPELL_AURA_PROC_FAILED;

Expand All @@ -4422,6 +4456,7 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit *pVictim, uint32 d
if (!target || (target != this && !target->isAlive()))
return SPELL_AURA_PROC_FAILED;


if (SpellEntry const* triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id))
{
if (basepoints[EFFECT_INDEX_0] || basepoints[EFFECT_INDEX_1] || basepoints[EFFECT_INDEX_2])
Expand Down
3 changes: 3 additions & 0 deletions src/game/World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Spell Proc Item Enchant..." );
sSpellMgr.LoadSpellProcItemEnchant(); // must be after LoadSpellChains

sLog.outString( "Loading Spell Linked definitions..." );
sSpellMgr.LoadSpellLinked(); // must be after LoadSpellChains

sLog.outString( "Loading Aggro Spells Definitions...");
sSpellMgr.LoadSpellThreats();

Expand Down
2 changes: 1 addition & 1 deletion src/shared/revision_R2.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef __REVISION_R2_H__
#define __REVISION_R2_H__
#define REVISION_R2 "1290"
#define REVISION_R2 "1291"
#endif // __REVISION_R2_H__

7 comments on commit c0446b0

@michalpolko
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so who signs up for moving shitloads of code into this new table? :D

P.S. I really like the idea, good job :)

@rsa
Copy link
Member Author

@rsa rsa commented on c0446b0 Nov 25, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not my idea. but my realization (awaiting bugs :)

@Inquisitor
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's f...ing awesome

@Reamer
Copy link

@Reamer Reamer commented on c0446b0 Nov 25, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All spellspecificboost can copy in this table right?
What still (more spell Code)?

@rsa
Copy link
Member Author

@rsa rsa commented on c0446b0 Nov 25, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not all, approx 1/2. only if target spell = target linked spell and caster = caster linked.
but some other spells may be moved in this table with other (not _BOOST) link_type. also - from proc methods...

@boxa
Copy link
Member

@boxa boxa commented on c0446b0 Nov 25, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

excellent thing! tnx RSA

@tibbi
Copy link

@tibbi tibbi commented on c0446b0 Dec 16, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.