Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 87219cb4eb | |||
| da17074a63 |
+21
@@ -0,0 +1,21 @@
|
||||
-- Fractured / Paragon: multidot Devouring Plague clone (spell IDs 951000-951008).
|
||||
-- Spell rows live in the patched client Spell.dbc (see fractured-tooling
|
||||
-- from-workspace-root/_patch_spell_dbc_paragon_multidot_devouring_plague.py).
|
||||
-- Deploy the same Spell.dbc into the worldserver `data/dbc/` folder OR import
|
||||
-- equivalent `spell_dbc` rows from a full exporter; stock SQL cannot express
|
||||
-- the SpellEntryfmt NA padding columns safely in one INSERT here.
|
||||
|
||||
DELETE FROM `spell_ranks` WHERE `first_spell_id` = 951000;
|
||||
INSERT INTO `spell_ranks` (`first_spell_id`,`spell_id`,`rank`) VALUES
|
||||
(951000,951000,1),
|
||||
(951000,951001,2),
|
||||
(951000,951002,3),
|
||||
(951000,951003,4),
|
||||
(951000,951004,5),
|
||||
(951000,951005,6),
|
||||
(951000,951006,7),
|
||||
(951000,951007,8),
|
||||
(951000,951008,9);
|
||||
|
||||
DELETE FROM `paragon_spell_ae_cost` WHERE `spell_id` IN (2944,951000);
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`,`ae_cost`) VALUES (951000, 1);
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
-- Fractured / Paragon: spellbook tab for multidot Devouring Plague (951000 chain).
|
||||
-- Shadow priest skill line (78); ClassMask 2064 matches mod-paragon SLA overlay.
|
||||
-- Client: patched SkillLineAbility.dbc in patch-enUS-4 from the same script.
|
||||
|
||||
DELETE FROM `skilllineability_dbc` WHERE `ID` IN (1951000, 1951001, 1951002, 1951003, 1951004, 1951005, 1951006, 1951007, 1951008);
|
||||
INSERT INTO `skilllineability_dbc` (`ID`,`SkillLine`,`Spell`,`RaceMask`,`ClassMask`,`ExcludeRace`,`ExcludeClass`,`MinSkillLineRank`,`SupercededBySpell`,`AcquireMethod`,`TrivialSkillLineRankHigh`,`TrivialSkillLineRankLow`,`CharacterPoints_1`,`CharacterPoints_2`) VALUES
|
||||
(1951000,78,951000,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951001,78,951001,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951002,78,951002,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951003,78,951003,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951004,78,951004,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951005,78,951005,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951006,78,951006,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951007,78,951007,0,2064,0,0,1,0,0,0,0,0,0),
|
||||
(1951008,78,951008,0,2064,0,0,1,0,0,0,0,0,0);
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
-- Fractured / Paragon: Character Advancement stance/presence clones (951010-951015).
|
||||
-- Client: patched Spell.dbc + SpellShapeshiftForm.dbc + SkillLineAbility.dbc in patch-enUS-4.MPQ.
|
||||
-- Server: copy Spell.dbc + SpellShapeshiftForm.dbc into `data/dbc/` (SpellShapeshiftForm is not in stock MPQ); SkillLineAbility is DB-driven on server.
|
||||
|
||||
DELETE FROM `paragon_spell_ae_cost` WHERE `spell_id` IN (951010,951011,951012,951013,951014,951015);
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`,`ae_cost`) VALUES
|
||||
(951010, 1),
|
||||
(951011, 1),
|
||||
(951012, 1),
|
||||
(951013, 1),
|
||||
(951014, 1),
|
||||
(951015, 1);
|
||||
|
||||
DELETE FROM `skilllineability_dbc` WHERE `ID` IN (1951020,1951021,1951022,1951023,1951024,1951025);
|
||||
INSERT INTO `skilllineability_dbc` (`ID`,`SkillLine`,`Spell`,`RaceMask`,`ClassMask`,`ExcludeRace`,`ExcludeClass`,`MinSkillLineRank`,`SupercededBySpell`,`AcquireMethod`,`TrivialSkillLineRankHigh`,`TrivialSkillLineRankLow`,`CharacterPoints_1`,`CharacterPoints_2`) VALUES
|
||||
(1951020,26,951010,0,2049,0,0,1,0,2,0,0,0,0),
|
||||
(1951021,257,951011,0,2049,0,0,1,0,0,0,0,0,0),
|
||||
(1951022,256,951012,0,2049,0,0,1,0,0,0,0,0,0),
|
||||
(1951023,770,951013,0,2080,0,0,1,0,2,0,0,0,0),
|
||||
(1951024,771,951014,0,2080,0,0,1,0,0,0,0,0,0),
|
||||
(1951025,772,951015,0,2080,0,0,1,0,0,0,0,0,0);
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
-- Fractured / Paragon: run spell_dk_presence on Character Advancement DK presence clones (951013-951015).
|
||||
-- Spell.dbc sets SpellFamilyName=0 on these rows (see fractured-tooling/_patch_spell_dbc_paragon_stance_presence_clones.py)
|
||||
-- so the stock client does not map them onto DK stance buttons; core still needs the aura script for Improved Presence.
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` IN (951013, 951014, 951015);
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(951013, 'spell_dk_presence'),
|
||||
(951014, 'spell_dk_presence'),
|
||||
(951015, 'spell_dk_presence');
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
-- Fractured / Paragon: Character Advancement stance/presence clones — spellbook + client bits.
|
||||
-- 1) SkillLineAbility: DK presence clones belong on 770/771/772 (Blood/Frost/Unholy tabs), not 760 (General).
|
||||
-- (760 was an experiment; stance bar visibility is driven by Spell.dbc AttributesEx2 USE_SHAPESHIFT_BAR.)
|
||||
-- 2) Idempotent if rows already match.
|
||||
|
||||
UPDATE `skilllineability_dbc` SET `SkillLine` = 770 WHERE `ID` = 1951023 AND `Spell` = 951013;
|
||||
UPDATE `skilllineability_dbc` SET `SkillLine` = 771 WHERE `ID` = 1951024 AND `Spell` = 951014;
|
||||
UPDATE `skilllineability_dbc` SET `SkillLine` = 772 WHERE `ID` = 1951025 AND `Spell` = 951015;
|
||||
@@ -584,6 +584,37 @@ void RevokeBlockedSpellsForPlayer(Player* pl)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Same migration for meta-skill cascade spells. Earlier builds
|
||||
// (and this one until just now) revoked the rune-enchant spells
|
||||
// (Razorice, Cinderglacier, Rune of the Fallen Crusader, ...)
|
||||
// when a Paragon learned Runeforging via the panel, because
|
||||
// they're active spells and the default classifier treats
|
||||
// unknown active cascades as leaks. New policy: anything on
|
||||
// SKILL_RUNEFORGING is part of the Runeforging meta-skill
|
||||
// package and stays. Drop the revoked row and, if we have a
|
||||
// still-owned parent (typically Runeforging itself, 53428),
|
||||
// re-record as a child so refund/unlearn still cleans them up.
|
||||
bool isMetaSkillRevoke = false;
|
||||
{
|
||||
auto bounds = sSpellMgr->GetSkillLineAbilityMapBounds(sid);
|
||||
for (auto it = bounds.first; it != bounds.second; ++it)
|
||||
{
|
||||
if (it->second->SkillLine == SKILL_RUNEFORGING)
|
||||
{
|
||||
isMetaSkillRevoke = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isMetaSkillRevoke)
|
||||
{
|
||||
if (parent && ownedPanelSpells.count(parent))
|
||||
passiveMigrate.emplace_back(parent, sid);
|
||||
passiveStaleAll.push_back(sid);
|
||||
++migrated;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allowed.count(sid))
|
||||
{
|
||||
stale.push_back(sid);
|
||||
@@ -753,11 +784,57 @@ void RevokeBlockedSpellsForPlayer(Player* pl)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allowlist for ACTIVE spells we explicitly want kept as
|
||||
// panel_spell_children, even though the general policy is "actives in
|
||||
// children = legacy garbage, drop them" (see
|
||||
// PruneSkillLineCascadeChildrenFromDb).
|
||||
//
|
||||
// The original kAttached set was 100% passives (Frost Fever, Blood
|
||||
// Plague, Forceful Deflection, Runic Focus). For those, "passive ==
|
||||
// keep" was a perfect proxy. Runeforging changed that: the 8 basic
|
||||
// rune-enchant spells (53344, 53343, 53341, 53331, 53342, 53323,
|
||||
// 54447, 54446) are ACTIVE casts that we DO want to attach to the
|
||||
// Runeforging panel purchase so:
|
||||
// * The Lua-substitute Runeforge UI can cast them (HasActiveSpell).
|
||||
// * Refunding Runeforging cleans them up via the standard
|
||||
// panel_spell_children unlearn path.
|
||||
//
|
||||
// Without this allowlist, PruneSkillLineCascadeChildrenFromDb runs
|
||||
// immediately after PanelLearnSpellChain attaches them, sees them as
|
||||
// non-passive, drops them, and inserts panel_spell_revoked rows --
|
||||
// stranding the player with no usable runeforging menu.
|
||||
//
|
||||
// Every entry here MUST also appear in PanelLearnSpellChain::kAttached
|
||||
// AND in OnPlayerLogin's kFixup list (or a shared source if those ever
|
||||
// get factored out). The pair ordering is (parentHead, attachedSpell),
|
||||
// matching kAttached / kFixup.
|
||||
struct IntentionalActiveAttached { uint32 parent; uint32 child; };
|
||||
static IntentionalActiveAttached const kIntentionalActiveAttached[] = {
|
||||
{ 53428, 53344 }, // Runeforging -> Rune of the Fallen Crusader
|
||||
{ 53428, 53343 }, // Runeforging -> Rune of Razorice
|
||||
{ 53428, 53341 }, // Runeforging -> Rune of Cinderglacier
|
||||
{ 53428, 53331 }, // Runeforging -> Rune of Lichbane
|
||||
{ 53428, 53342 }, // Runeforging -> Rune of Spellshattering
|
||||
{ 53428, 53323 }, // Runeforging -> Rune of Swordshattering
|
||||
{ 53428, 54447 }, // Runeforging -> Rune of Spellbreaking
|
||||
{ 53428, 54446 }, // Runeforging -> Rune of Swordbreaking
|
||||
};
|
||||
|
||||
[[nodiscard]] static bool IsIntentionalActiveAttachedChild(uint32 parent, uint32 child)
|
||||
{
|
||||
for (auto const& e : kIntentionalActiveAttached)
|
||||
if (e.parent == parent && e.child == child)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Current policy: cascade-granted passives stick as panel_spell_children;
|
||||
// only actives get revoked. This pass exists to scrub *legacy* rows that
|
||||
// older logic inserted incorrectly — specifically, any active spell that
|
||||
// ended up in panel_spell_children from a build that classified things
|
||||
// differently. Passive children are always retained.
|
||||
// differently. Passive children are always retained, as are entries
|
||||
// whitelisted via kIntentionalActiveAttached (Runeforging rune-enchants
|
||||
// are active casts that we deliberately attach as children).
|
||||
static void PruneSkillLineCascadeChildrenFromDb(Player* pl, uint32 lowGuid)
|
||||
{
|
||||
if (!pl)
|
||||
@@ -776,6 +853,8 @@ static void PruneSkillLineCascadeChildrenFromDb(Player* pl, uint32 lowGuid)
|
||||
SpellInfo const* info = sSpellMgr->GetSpellInfo(child);
|
||||
if (info && info->IsPassive())
|
||||
continue; // passives always stay
|
||||
if (IsIntentionalActiveAttachedChild(parent, child))
|
||||
continue; // intentional active attachment
|
||||
// Active in children -> legacy garbage. Drop the row, revoke the
|
||||
// spell, and persist into panel_spell_revoked so the login sweep
|
||||
// catches future cascade re-fires.
|
||||
@@ -1228,13 +1307,45 @@ void PanelLearnSpellChain(Player* pl, uint32 baseSpellId)
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
if (dep->IsPassive())
|
||||
// Meta-skill cascade carve-out. Runeforging (776) is a
|
||||
// CLASS-category skill that, once granted, is supposed to
|
||||
// cascade ALL its rune-enchant spells (Rune of the Fallen
|
||||
// Crusader, Razorice, Cinderglacier, Lichbane, Spell-/
|
||||
// Sword-shattering, Spell-/Sword-breaking, Stoneskin
|
||||
// Gargoyle, Nerubian Carapace) for the player to choose
|
||||
// from at a runeforge anvil. Those rune-enchants are
|
||||
// ACTIVE spells, so the default policy below would
|
||||
// revoke them and the player would learn Runeforging
|
||||
// for nothing. Treat the whole cluster the same way we
|
||||
// treat passive deps: persist as children of the panel
|
||||
// purchase so refund/unlearn drops them too, but do NOT
|
||||
// revoke them.
|
||||
//
|
||||
// Detection: walk the dep's own SkillLineAbility entries
|
||||
// and check for SKILL_RUNEFORGING. This auto-handles all
|
||||
// 10 rune-enchant spells without an ID-by-ID allowlist.
|
||||
bool isMetaSkillCascade = false;
|
||||
{
|
||||
auto bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
|
||||
for (auto it = bounds.first; it != bounds.second; ++it)
|
||||
{
|
||||
if (it->second->SkillLine == SKILL_RUNEFORGING)
|
||||
{
|
||||
isMetaSkillCascade = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dep->IsPassive() || isMetaSkillCascade)
|
||||
{
|
||||
DbInsertPanelSpellChild(lowGuid, trackId, spellId);
|
||||
if (diag)
|
||||
LOG_INFO("module",
|
||||
"[paragon-diag] +{} (passive dep, kept as child of {})",
|
||||
spellId, trackId);
|
||||
"[paragon-diag] +{} ({} dep, kept as child of {})",
|
||||
spellId,
|
||||
isMetaSkillCascade ? "meta-skill" : "passive",
|
||||
trackId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1301,6 +1412,34 @@ void PanelLearnSpellChain(Player* pl, uint32 baseSpellId)
|
||||
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive entry)
|
||||
{ 45477, 61455 }, // Icy Touch -> Runic Focus (parry from spell power)
|
||||
{ 45902, 49410 }, // Blood Strike -> Forceful Deflection (parry from strength)
|
||||
|
||||
// Runeforging -> 8 basic rune-enchants. The
|
||||
// SkillLineAbility rows for these (skill 776) all ship
|
||||
// with AcquireMethod = 0 in the DBC (i.e. NOT auto-learn-
|
||||
// on-skill-grant). For stock DKs the engine's hardcoded
|
||||
// runeforging UI hand-rolls the cast for whichever rune
|
||||
// the player picks, but for our Lua-substitute UI the
|
||||
// server's HandleCastSpellOpcode / HasActiveSpell gate
|
||||
// rejects the cast unless the spell is in the spellbook.
|
||||
// Force-attach them as panel children so:
|
||||
// 1. The player actually owns the spells (cast works).
|
||||
// 2. Refunding Runeforging cleans them up via the
|
||||
// standard panel_spell_children unlearn path.
|
||||
// The two ADVANCED runes (Stoneskin Gargoyle 62158 and
|
||||
// Nerubian Carapace 70164) are intentionally NOT listed:
|
||||
// retail gates them behind item drops from heroic
|
||||
// dungeons / Naxx / ICC, and our SkillLineAbility rows
|
||||
// for them already use AcquireMethod=0 so the player
|
||||
// gets them when they pick up the appropriate item, not
|
||||
// for free with Runeforging itself.
|
||||
{ 53428, 53344 }, // Runeforging -> Rune of the Fallen Crusader
|
||||
{ 53428, 53343 }, // Runeforging -> Rune of Razorice
|
||||
{ 53428, 53341 }, // Runeforging -> Rune of Cinderglacier
|
||||
{ 53428, 53331 }, // Runeforging -> Rune of Lichbane
|
||||
{ 53428, 53342 }, // Runeforging -> Rune of Spellshattering
|
||||
{ 53428, 53323 }, // Runeforging -> Rune of Swordshattering
|
||||
{ 53428, 54447 }, // Runeforging -> Rune of Spellbreaking
|
||||
{ 53428, 54446 }, // Runeforging -> Rune of Swordbreaking
|
||||
};
|
||||
|
||||
// Self-heal: a previous build of mod-paragon (briefly shipped)
|
||||
@@ -2256,9 +2395,21 @@ void PushSpellSnapshot(Player* pl)
|
||||
continue;
|
||||
}
|
||||
|
||||
SpellInfo const* info = sSpellMgr->GetSpellInfo(sid);
|
||||
if (info && info->HasAttribute(SPELL_ATTR0_DO_NOT_DISPLAY))
|
||||
continue;
|
||||
// Note: we deliberately do NOT filter SPELL_ATTR0_DO_NOT_DISPLAY
|
||||
// here. Earlier builds did, on the theory that hidden spells
|
||||
// shouldn't appear in the spellbook-style Overview tab. That
|
||||
// turned out to be wrong: cascade-granted hidden passives
|
||||
// (Forceful Deflection, Frost Fever, ...) live in
|
||||
// panel_spell_children, not in panel_spells -- so the only
|
||||
// entries that ever land in this query are the chain heads
|
||||
// the player explicitly purchased. Those MUST appear in the
|
||||
// Overview even if their DBC entry is hidden, because they
|
||||
// are the player's actual purchases (e.g. Runeforging 53428
|
||||
// is hidden in the DBC but is the entire Runeforging panel
|
||||
// purchase). Filtering them out left chars whose only buy
|
||||
// was Runeforging with an empty Overview tab -- looked like
|
||||
// a regression but was actually the existing snapshot logic
|
||||
// mismatching the panel's user-facing semantics.
|
||||
|
||||
std::string token = (first ? "" : ",") + std::to_string(sid);
|
||||
if (buf.size() + token.size() > kSnapshotChunkBudget)
|
||||
@@ -4018,6 +4169,24 @@ public:
|
||||
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive)
|
||||
{ 45477, 61455 }, // Icy Touch -> Runic Focus
|
||||
{ 45902, 49410 }, // Blood Strike -> Forceful Deflection
|
||||
|
||||
// Runeforging -> 8 basic rune-enchants. Mirror of
|
||||
// PanelLearnSpellChain::kAttached: the SLA rows for
|
||||
// these (skill 776) ship with AcquireMethod=0 so the
|
||||
// engine's normal cascade never grants them, and for
|
||||
// the substitute Lua runeforging UI to actually be
|
||||
// able to cast them HasActiveSpell needs to return
|
||||
// true. Existing Paragon characters that bought
|
||||
// Runeforging before this fix landed get them
|
||||
// retro-granted on their next login.
|
||||
{ 53428, 53344 }, // Runeforging -> Fallen Crusader
|
||||
{ 53428, 53343 }, // Runeforging -> Razorice
|
||||
{ 53428, 53341 }, // Runeforging -> Cinderglacier
|
||||
{ 53428, 53331 }, // Runeforging -> Lichbane
|
||||
{ 53428, 53342 }, // Runeforging -> Spellshattering
|
||||
{ 53428, 53323 }, // Runeforging -> Swordshattering
|
||||
{ 53428, 54447 }, // Runeforging -> Spellbreaking
|
||||
{ 53428, 54446 }, // Runeforging -> Swordbreaking
|
||||
};
|
||||
for (auto const& lf : kFixup)
|
||||
{
|
||||
|
||||
@@ -12048,7 +12048,20 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
|
||||
// weapon, language, and racial skill cascades stay enabled so things
|
||||
// like recipe auto-learn, weapon proficiencies, and racial perks
|
||||
// still work.
|
||||
if (getClass() == CLASS_PARAGON)
|
||||
//
|
||||
// Carve-out: SKILL_RUNEFORGING (776) is a CLASS-category skill but
|
||||
// behaves like a profession in this context — the player buys ONE
|
||||
// panel ability (Runeforging, spell 53428) and the rune-enchant
|
||||
// spells (Rune of the Fallen Crusader, Razorice, Cinderglacier, ...)
|
||||
// are supposed to come along for the ride via the standard SLA
|
||||
// cascade, exactly the same way they do for a stock DK. Without
|
||||
// this carve-out, the early-return below blocks the cascade and a
|
||||
// Paragon who buys Runeforging gets the skill but no actual rune
|
||||
// options at the runeforge anvil. The cascade only fires once per
|
||||
// skill-grant for 776 (it's not on UpdateSkillsForLevel) so the
|
||||
// "leaking back into the spellbook" concern that motivates the
|
||||
// early-return doesn't apply to this skill.
|
||||
if (getClass() == CLASS_PARAGON && skill_id != SKILL_RUNEFORGING)
|
||||
{
|
||||
if (SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill_id))
|
||||
if (sl->categoryId == SKILL_CATEGORY_CLASS)
|
||||
|
||||
@@ -151,6 +151,11 @@ bool IsFracturedExclusiveStanceSpell(uint32 spellId)
|
||||
case 71: // Defensive Stance
|
||||
case 2458: // Berserker Stance
|
||||
|
||||
// -- Paragon Advancement warrior stance clones (951010-951012).
|
||||
case 951010:
|
||||
case 951011:
|
||||
case 951012:
|
||||
|
||||
// -- Druid combat forms (engine-shapeshifts).
|
||||
case 5487: // Bear Form
|
||||
case 9634: // Dire Bear Form
|
||||
@@ -189,6 +194,11 @@ bool IsFracturedExclusiveStanceSpell(uint32 spellId)
|
||||
case 48263: // Frost Presence
|
||||
case 48265: // Unholy Presence
|
||||
|
||||
// -- Paragon Advancement DK presence clones (951013-951015).
|
||||
case 951013:
|
||||
case 951014:
|
||||
case 951015:
|
||||
|
||||
// -- Hunter Aspects (combat). Like presences, these are regular
|
||||
// auras stock AC, not engine-shapeshifts; rank-1 ids cover all
|
||||
// ranks via GetFirstRankSpell. Cheetah / Pack are the utility
|
||||
|
||||
@@ -99,7 +99,13 @@ enum ShapeshiftForm
|
||||
FORM_FLIGHT = 0x1D,
|
||||
FORM_STEALTH = 0x1E,
|
||||
FORM_MOONKIN = 0x1F,
|
||||
FORM_SPIRITOFREDEMPTION = 0x20
|
||||
FORM_SPIRITOFREDEMPTION = 0x20,
|
||||
|
||||
// Fractured / Paragon: Character Advancement warrior stance clones (Spell.dbc
|
||||
// MOD_SHAPESHIFT -> SpellShapeshiftForm 33-35, BonusActionBar=0, no client bar swap).
|
||||
FORM_PARAGON_BATTLE_STANCE = 33,
|
||||
FORM_PARAGON_DEFENSIVE_STANCE = 34,
|
||||
FORM_PARAGON_BERSERKER_STANCE = 35,
|
||||
};
|
||||
|
||||
enum ShapeshiftFlags
|
||||
|
||||
@@ -1373,12 +1373,15 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
|
||||
HotWSpellId = 24899;
|
||||
break;
|
||||
case FORM_BATTLESTANCE:
|
||||
case FORM_PARAGON_BATTLE_STANCE:
|
||||
spellId = 21156;
|
||||
break;
|
||||
case FORM_DEFENSIVESTANCE:
|
||||
case FORM_PARAGON_DEFENSIVE_STANCE:
|
||||
spellId = 7376;
|
||||
break;
|
||||
case FORM_BERSERKERSTANCE:
|
||||
case FORM_PARAGON_BERSERKER_STANCE:
|
||||
spellId = 7381;
|
||||
break;
|
||||
case FORM_MOONKIN:
|
||||
@@ -1995,7 +1998,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
|
||||
/*** UNIT MODEL ***/
|
||||
/**********************/
|
||||
|
||||
void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
static void Fractured_ApplyShapeshiftFormFromAuraEffect(AuraEffect const* aurEff, AuraApplication const* aurApp, uint8 mode, bool apply, ShapeshiftForm form)
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK))
|
||||
return;
|
||||
@@ -2004,8 +2007,6 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
|
||||
uint32 modelid = 0;
|
||||
Powers PowerType = POWER_MANA;
|
||||
ShapeshiftForm form = ShapeshiftForm(GetMiscValue());
|
||||
|
||||
switch (form)
|
||||
{
|
||||
case FORM_CAT: // 0x01
|
||||
@@ -2019,6 +2020,9 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
case FORM_BATTLESTANCE: // 0x11
|
||||
case FORM_DEFENSIVESTANCE: // 0x12
|
||||
case FORM_BERSERKERSTANCE: // 0x13
|
||||
case FORM_PARAGON_BATTLE_STANCE:
|
||||
case FORM_PARAGON_DEFENSIVE_STANCE:
|
||||
case FORM_PARAGON_BERSERKER_STANCE:
|
||||
PowerType = POWER_RAGE;
|
||||
break;
|
||||
|
||||
@@ -2049,10 +2053,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
case FORM_SPIRITOFREDEMPTION: // 0x20
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("spells.aura.effect", "Auras: Unknown Shapeshift Type: {}", GetMiscValue());
|
||||
LOG_ERROR("spells.aura.effect", "Auras: Unknown Shapeshift Type: {}", aurEff->GetMiscValue());
|
||||
}
|
||||
|
||||
modelid = target->GetModelForForm(form, GetId());
|
||||
modelid = target->GetModelForForm(form, aurEff->GetId());
|
||||
|
||||
if (apply)
|
||||
{
|
||||
@@ -2087,8 +2091,8 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
|
||||
// remove other shapeshift before applying a new one
|
||||
// xinef: rogue shouldnt be wrapped by this check (shadow dance vs stealth)
|
||||
if (GetSpellInfo()->SpellFamilyName != SPELLFAMILY_ROGUE)
|
||||
target->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT, ObjectGuid::Empty, GetBase());
|
||||
if (aurEff->GetSpellInfo()->SpellFamilyName != SPELLFAMILY_ROGUE)
|
||||
target->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT, ObjectGuid::Empty, aurEff->GetBase());
|
||||
|
||||
// stop handling the effect if it was removed by linked event
|
||||
if (aurApp->GetRemoveMode())
|
||||
@@ -2112,13 +2116,13 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
if (AuraEffect const* dummy = target->GetDummyAuraEffect(SPELLFAMILY_DRUID, 238, 0))
|
||||
FurorChance = std::max(dummy->GetAmount(), 0);
|
||||
|
||||
switch (GetMiscValue())
|
||||
switch (aurEff->GetMiscValue())
|
||||
{
|
||||
case FORM_CAT:
|
||||
{
|
||||
int32 basePoints = int32(std::min(oldPower, FurorChance));
|
||||
target->SetPower(POWER_ENERGY, 0);
|
||||
target->CastCustomSpell(target, 17099, &basePoints, nullptr, nullptr, true, nullptr, this);
|
||||
target->CastCustomSpell(target, 17099, &basePoints, nullptr, nullptr, true, nullptr, aurEff);
|
||||
break;
|
||||
}
|
||||
case FORM_BEAR:
|
||||
@@ -2192,13 +2196,16 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
case FORM_BATTLESTANCE:
|
||||
case FORM_DEFENSIVESTANCE:
|
||||
case FORM_BERSERKERSTANCE:
|
||||
case FORM_PARAGON_BATTLE_STANCE:
|
||||
case FORM_PARAGON_DEFENSIVE_STANCE:
|
||||
case FORM_PARAGON_BERSERKER_STANCE:
|
||||
{
|
||||
uint32 Rage_val = 0;
|
||||
// Defensive Tactics
|
||||
if (form == FORM_DEFENSIVESTANCE)
|
||||
if (form == FORM_DEFENSIVESTANCE || form == FORM_PARAGON_DEFENSIVE_STANCE)
|
||||
{
|
||||
if (AuraEffect const* aurEff = target->IsScriptOverriden(m_spellInfo, 831))
|
||||
Rage_val += aurEff->GetAmount() * 10;
|
||||
if (AuraEffect const* scriptEff = target->IsScriptOverriden(aurEff->GetSpellInfo(), 831))
|
||||
Rage_val += scriptEff->GetAmount() * 10;
|
||||
}
|
||||
// Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch)
|
||||
if (target->IsPlayer())
|
||||
@@ -2238,7 +2245,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
|
||||
// adding/removing linked auras
|
||||
// add/remove the shapeshift aura's boosts
|
||||
HandleShapeshiftBoosts(target, apply);
|
||||
aurEff->HandleShapeshiftBoosts(target, apply);
|
||||
|
||||
if (target->IsPlayer())
|
||||
target->ToPlayer()->InitDataForForm();
|
||||
@@ -2246,8 +2253,8 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
if (target->IsClass(CLASS_DRUID, CLASS_CONTEXT_ABILITY))
|
||||
{
|
||||
// Dash
|
||||
if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8))
|
||||
aurEff->RecalculateAmount();
|
||||
if (AuraEffect* dashSpeedEff = target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8))
|
||||
dashSpeedEff->RecalculateAmount();
|
||||
|
||||
// Disarm handling
|
||||
// If druid shifts while being disarmed we need to deal with that since forms aren't affected by disarm
|
||||
@@ -2281,6 +2288,11 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form);
|
||||
if (!shapeInfo)
|
||||
{
|
||||
LOG_ERROR("spells.aura.effect", "Fractured_ApplyShapeshiftFormFromAuraEffect: missing SpellShapeshiftForm {}", uint32(form));
|
||||
return;
|
||||
}
|
||||
// Learn spells for shapeshift form - no need to send action bars or add spells to spellbook
|
||||
for (uint8 i = 0; i < MAX_SHAPESHIFT_SPELLS; ++i)
|
||||
{
|
||||
@@ -2294,6 +2306,11 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
{
|
||||
Fractured_ApplyShapeshiftFormFromAuraEffect(this, aurApp, mode, apply, ShapeshiftForm(GetMiscValue()));
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK))
|
||||
@@ -5174,6 +5191,20 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
// Fractured: Paragon warrior stance clones (951010-951012) use SPELL_AURA_DUMMY on Spell.dbc **effect2**
|
||||
// (misc = Paragon SpellShapeshiftForm 33-35). Effect1 is a separate DUMMY for the buff strip; passive stats
|
||||
// (e.g. armor pen / threat) live on Effect3. **AttributesEx** clears SPELL_ATTR1_NO_AURA_ICON (DBC + SpellInfoCorrections)
|
||||
// so the client shows an aura icon — stock Warrior stances keep that bit set on purpose.
|
||||
if (GetAuraType() == SPELL_AURA_DUMMY && m_effIndex == 1)
|
||||
{
|
||||
uint32 const sid = GetSpellInfo()->Id;
|
||||
if (sid == 951010 || sid == 951011 || sid == 951012)
|
||||
{
|
||||
Fractured_ApplyShapeshiftFormFromAuraEffect(this, aurApp, mode, apply, ShapeshiftForm(GetMiscValue()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & AURA_EFFECT_HANDLE_REAL)
|
||||
{
|
||||
// pet auras
|
||||
|
||||
@@ -7860,6 +7860,36 @@ SpellCastResult Spell::CheckSpellFocus()
|
||||
// check spell focus object
|
||||
if (m_spellInfo->RequiresSpellFocus)
|
||||
{
|
||||
// Fractured / Paragon: skip the GO proximity check for Paragon
|
||||
// casters when the spell is a runeforge enchant (skill line 776).
|
||||
// Paragons get a Runeforge tab in the Character Advancement
|
||||
// panel that lets them apply rune-enchants from anywhere in the
|
||||
// world -- no need to fly back to Acherus or find the nearest
|
||||
// Eastern Plaguelands anvil. The skill-line gate keeps the
|
||||
// bypass tightly scoped: only the 10 SkillLineAbility-tagged
|
||||
// rune-enchant spells qualify, every other spell that uses
|
||||
// SpellFocusObject (Enchanting bench, Cooking fire, Lockpicking
|
||||
// anvil, etc.) keeps its requirement intact.
|
||||
//
|
||||
// DK / other class casters are unchanged -- this carve-out
|
||||
// intentionally checks getClass() == CLASS_PARAGON rather than
|
||||
// IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY) (which
|
||||
// would also return true for Paragons via mod-paragon's hook).
|
||||
// Stock DK behavior must stay vanilla; the QoL bypass is a
|
||||
// class-12 feature only.
|
||||
if (m_caster && m_caster->IsPlayer()
|
||||
&& m_caster->ToPlayer()->getClass() == CLASS_PARAGON)
|
||||
{
|
||||
auto bounds = sSpellMgr->GetSkillLineAbilityMapBounds(m_spellInfo->Id);
|
||||
for (auto it = bounds.first; it != bounds.second; ++it)
|
||||
{
|
||||
if (it->second->SkillLine == SKILL_RUNEFORGING)
|
||||
{
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CellCoord p(Acore::ComputeCellCoord(m_caster->GetPositionX(), m_caster->GetPositionY()));
|
||||
Cell cell(p);
|
||||
|
||||
|
||||
@@ -2147,6 +2147,10 @@ SpellSpecificType SpellInfo::LoadSpellSpecific() const
|
||||
{
|
||||
case SPELLFAMILY_GENERIC:
|
||||
{
|
||||
// Fractured / Paragon: DK presence advancement clones (SpellFamilyName=0 in Spell.dbc for client UX).
|
||||
if (Id == 951013 || Id == 951014 || Id == 951015)
|
||||
return SPELL_SPECIFIC_PRESENCE;
|
||||
|
||||
// Food / Drinks (mostly)
|
||||
if (AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED)
|
||||
{
|
||||
|
||||
@@ -5427,11 +5427,13 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
2457, // Battle Stance
|
||||
71, // Defensive Stance
|
||||
2458, // Berserker Stance
|
||||
951010, 951011, 951012, // Paragon advancement warrior stance clones
|
||||
|
||||
// Death Knight Presences.
|
||||
48266, // Blood Presence
|
||||
48263, // Frost Presence
|
||||
48265, // Unholy Presence
|
||||
951013, 951014, 951015, // Paragon advancement DK presence clones (SpellFamily GENERIC in Spell.dbc)
|
||||
|
||||
// Hunter Aspects -- every rank, since AC stores the per-rank
|
||||
// SpellInfo as separate objects and `Category` lives on each.
|
||||
@@ -5485,14 +5487,33 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
2457, // Battle Stance
|
||||
71, // Defensive Stance
|
||||
2458, // Berserker Stance
|
||||
951010, 951011, 951012, // Paragon advancement warrior stance clones
|
||||
48266, // Blood Presence
|
||||
48263, // Frost Presence
|
||||
48265, // Unholy Presence
|
||||
951013, 951014, 951015, // Paragon advancement DK presence clones (SpellFamily GENERIC in Spell.dbc)
|
||||
}, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx6 &= ~SPELL_ATTR6_ALLOW_WHILE_RIDING_VEHICLE;
|
||||
});
|
||||
|
||||
// Fractured / Paragon: advancement warrior stance clones — strip SPELL_ATTR1_NO_AURA_ICON
|
||||
// (copied from stock 2457/71/2458). Stock Warrior stances intentionally hide from the default aura bar;
|
||||
// these clones are meant to show a cancellable buff icon instead. Client Spell.dbc is patched in tandem via
|
||||
// fractured-tooling/_patch_spell_dbc_paragon_stance_presence_clones.py.
|
||||
ApplySpellFix({ 951010, 951011, 951012 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx &= ~SPELL_ATTR1_NO_AURA_ICON;
|
||||
});
|
||||
|
||||
// Fractured / Paragon: advancement DK presence clones — strip SPELL_ATTR2_USE_SHAPESHIFT_BAR (0x10) copied
|
||||
// from 48266/48263/48265. That client-only bit is what parks a spell on the secondary stance bar above the
|
||||
// action bar; SkillLine / SpellFamily alone do not remove it. Spellbook tabs still come from SkillLines 770/771/772.
|
||||
ApplySpellFix({ 951013, 951014, 951015 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx2 &= ~SPELL_ATTR2_USE_SHAPESHIFT_BAR;
|
||||
});
|
||||
|
||||
// Fractured: strip reagent requirements from every player-class spell at
|
||||
// load time. Filtered by SpellFamilyName != 0 so that profession spells
|
||||
// (cooking, alchemy, enchanting, blacksmithing, jewelcrafting, leatherworking,
|
||||
|
||||
@@ -66,6 +66,9 @@ enum DeathKnightSpells
|
||||
SPELL_DK_ITEM_T8_MELEE_4P_BONUS = 64736,
|
||||
SPELL_DK_MASTER_OF_GHOULS = 52143,
|
||||
SPELL_DK_BLOOD_PLAGUE = 55078,
|
||||
// Fractured / Paragon: stock Priest Devouring Plague vs Character Advancement multidot clone
|
||||
SPELL_PRIEST_DEVOURING_PLAGUE_R1 = 2944,
|
||||
SPELL_PARAGON_MULTIDOT_DEVOURING_PLAGUE_R1 = 951000,
|
||||
SPELL_DK_RAISE_DEAD_USE_REAGENT = 48289,
|
||||
SPELL_DK_RUNIC_POWER_ENERGIZE = 49088,
|
||||
SPELL_DK_SCENT_OF_BLOOD = 50422,
|
||||
@@ -107,6 +110,10 @@ enum DeathKnightSpells
|
||||
SPELL_DK_RUNE_STRIKE_OFF_HAND_R1 = 66217,
|
||||
SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 = 66215,
|
||||
SPELL_DK_KILLING_MACHINE = 51124,
|
||||
// Fractured / Paragon: Character Advancement DK presence clones (SpellFamily GENERIC in Spell.dbc).
|
||||
SPELL_PARAGON_ADV_BLOOD_PRESENCE = 951013,
|
||||
SPELL_PARAGON_ADV_FROST_PRESENCE = 951014,
|
||||
SPELL_PARAGON_ADV_UNHOLY_PRESENCE = 951015,
|
||||
};
|
||||
|
||||
enum DeathKnightSpellIcons
|
||||
@@ -126,6 +133,21 @@ enum Misc
|
||||
NPC_RISEN_ALLY = 30230
|
||||
};
|
||||
|
||||
inline bool Fractured_UnitHasBloodPresenceAura(Unit const* unit)
|
||||
{
|
||||
return unit->HasAura(SPELL_DK_BLOOD_PRESENCE) || unit->HasAura(SPELL_PARAGON_ADV_BLOOD_PRESENCE);
|
||||
}
|
||||
|
||||
inline bool Fractured_UnitHasFrostPresenceAura(Unit const* unit)
|
||||
{
|
||||
return unit->HasAura(SPELL_DK_FROST_PRESENCE) || unit->HasAura(SPELL_PARAGON_ADV_FROST_PRESENCE);
|
||||
}
|
||||
|
||||
inline bool Fractured_UnitHasUnholyPresenceAura(Unit const* unit)
|
||||
{
|
||||
return unit->HasAura(SPELL_DK_UNHOLY_PRESENCE) || unit->HasAura(SPELL_PARAGON_ADV_UNHOLY_PRESENCE);
|
||||
}
|
||||
|
||||
// 50526 - Wandering Plague
|
||||
class spell_dk_wandering_plague : public SpellScript
|
||||
{
|
||||
@@ -1797,8 +1819,11 @@ class spell_dk_improved_blood_presence : public AuraScript
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_DK_BLOOD_PRESENCE,
|
||||
SPELL_PARAGON_ADV_BLOOD_PRESENCE,
|
||||
SPELL_DK_FROST_PRESENCE,
|
||||
SPELL_PARAGON_ADV_FROST_PRESENCE,
|
||||
SPELL_DK_UNHOLY_PRESENCE,
|
||||
SPELL_PARAGON_ADV_UNHOLY_PRESENCE,
|
||||
SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED
|
||||
});
|
||||
}
|
||||
@@ -1806,14 +1831,14 @@ class spell_dk_improved_blood_presence : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (target->HasAnyAuras(SPELL_DK_FROST_PRESENCE, SPELL_DK_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED))
|
||||
if (target->HasAnyAuras(SPELL_DK_FROST_PRESENCE, SPELL_DK_UNHOLY_PRESENCE, SPELL_PARAGON_ADV_FROST_PRESENCE, SPELL_PARAGON_ADV_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED))
|
||||
target->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED, SPELLVALUE_BASE_POINT1, aurEff->GetAmount(), target, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target->HasAura(SPELL_DK_BLOOD_PRESENCE))
|
||||
if (!Fractured_UnitHasBloodPresenceAura(target))
|
||||
target->RemoveAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED);
|
||||
}
|
||||
|
||||
@@ -1834,8 +1859,11 @@ class spell_dk_improved_frost_presence : public AuraScript
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_DK_BLOOD_PRESENCE,
|
||||
SPELL_PARAGON_ADV_BLOOD_PRESENCE,
|
||||
SPELL_DK_FROST_PRESENCE,
|
||||
SPELL_PARAGON_ADV_FROST_PRESENCE,
|
||||
SPELL_DK_UNHOLY_PRESENCE,
|
||||
SPELL_PARAGON_ADV_UNHOLY_PRESENCE,
|
||||
SPELL_DK_FROST_PRESENCE_TRIGGERED
|
||||
});
|
||||
}
|
||||
@@ -1843,14 +1871,14 @@ class spell_dk_improved_frost_presence : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (target->HasAnyAuras(SPELL_DK_BLOOD_PRESENCE, SPELL_DK_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_FROST_PRESENCE_TRIGGERED))
|
||||
if (target->HasAnyAuras(SPELL_DK_BLOOD_PRESENCE, SPELL_DK_UNHOLY_PRESENCE, SPELL_PARAGON_ADV_BLOOD_PRESENCE, SPELL_PARAGON_ADV_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_FROST_PRESENCE_TRIGGERED))
|
||||
target->CastCustomSpell(SPELL_DK_FROST_PRESENCE_TRIGGERED, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), target, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target->HasAura(SPELL_DK_FROST_PRESENCE))
|
||||
if (!Fractured_UnitHasFrostPresenceAura(target))
|
||||
target->RemoveAura(SPELL_DK_FROST_PRESENCE_TRIGGERED);
|
||||
}
|
||||
|
||||
@@ -1871,8 +1899,11 @@ class spell_dk_improved_unholy_presence : public AuraScript
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_DK_BLOOD_PRESENCE,
|
||||
SPELL_PARAGON_ADV_BLOOD_PRESENCE,
|
||||
SPELL_DK_FROST_PRESENCE,
|
||||
SPELL_PARAGON_ADV_FROST_PRESENCE,
|
||||
SPELL_DK_UNHOLY_PRESENCE,
|
||||
SPELL_PARAGON_ADV_UNHOLY_PRESENCE,
|
||||
SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED,
|
||||
SPELL_DK_UNHOLY_PRESENCE_TRIGGERED
|
||||
});
|
||||
@@ -1881,14 +1912,14 @@ class spell_dk_improved_unholy_presence : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (target->HasAura(SPELL_DK_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED))
|
||||
if (Fractured_UnitHasUnholyPresenceAura(target) && !target->HasAura(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED))
|
||||
{
|
||||
// Not listed as any effect, only base points set in dbc
|
||||
int32 basePoints = GetSpellInfo()->Effects[EFFECT_1].CalcValue();
|
||||
target->CastCustomSpell(target, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED, &basePoints, &basePoints, &basePoints, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
if (target->HasAnyAuras(SPELL_DK_BLOOD_PRESENCE, SPELL_DK_FROST_PRESENCE) && !target->HasAura(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED))
|
||||
if (target->HasAnyAuras(SPELL_DK_BLOOD_PRESENCE, SPELL_DK_FROST_PRESENCE, SPELL_PARAGON_ADV_BLOOD_PRESENCE, SPELL_PARAGON_ADV_FROST_PRESENCE) && !target->HasAura(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED))
|
||||
target->CastCustomSpell(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), target, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
@@ -1898,7 +1929,7 @@ class spell_dk_improved_unholy_presence : public AuraScript
|
||||
|
||||
target->RemoveAura(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED);
|
||||
|
||||
if (!target->HasAura(SPELL_DK_UNHOLY_PRESENCE))
|
||||
if (!Fractured_UnitHasUnholyPresenceAura(target))
|
||||
target->RemoveAura(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED);
|
||||
}
|
||||
|
||||
@@ -1939,12 +1970,12 @@ class spell_dk_pestilence : public SpellScript
|
||||
// and Unit::GetDiseasesByCaster already counts it for Paragon callers
|
||||
// (see Unit.cpp), so it is conceptually a disease; stock Pestilence
|
||||
// just hard-codes Blood Plague + Frost Fever and so silently drops it.
|
||||
// GetAuraOfRankedSpell with the rank-1 id (2944) covers every rank of
|
||||
// GetAuraOfRankedSpell with the rank-1 id (2944 / 951000) covers every rank of
|
||||
// Devouring Plague the player has on the target -- we re-cast that
|
||||
// exact same rank so the spread copy carries the caster's actual
|
||||
// damage tier rather than always rank 1. Stock DKs cannot cast
|
||||
// Devouring Plague at all, so the GetAuraOfRankedSpell will return
|
||||
// null for them and this branch is a no-op there.
|
||||
// Devouring Plague at all, so both lookups return null for them and
|
||||
// this branch is a no-op there.
|
||||
bool const paragonSpread = IsParagonWildcardCaller(caster);
|
||||
|
||||
// Spread on others
|
||||
@@ -1958,11 +1989,17 @@ class spell_dk_pestilence : public SpellScript
|
||||
if (target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
|
||||
caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true);
|
||||
|
||||
// Fractured / Paragon: Devouring Plague spread.
|
||||
// Fractured / Paragon: Devouring Plague spread (stock 2944 chain or
|
||||
// Character Advancement multidot clone 951000 chain).
|
||||
if (paragonSpread)
|
||||
if (Aura const* dp = target->GetAuraOfRankedSpell(2944 /* Devouring Plague r1 */, caster->GetGUID()))
|
||||
{
|
||||
Aura const* dp = target->GetAuraOfRankedSpell(SPELL_PRIEST_DEVOURING_PLAGUE_R1, caster->GetGUID());
|
||||
if (!dp)
|
||||
dp = target->GetAuraOfRankedSpell(SPELL_PARAGON_MULTIDOT_DEVOURING_PLAGUE_R1, caster->GetGUID());
|
||||
if (dp)
|
||||
caster->CastSpell(hitUnit, dp->GetId(), true);
|
||||
}
|
||||
}
|
||||
// Refresh on target
|
||||
else if (caster->GetAura(SPELL_DK_GLYPH_OF_DISEASE))
|
||||
{
|
||||
@@ -1985,10 +2022,15 @@ class spell_dk_pestilence : public SpellScript
|
||||
|
||||
// Fractured / Paragon: Devouring Plague Glyph-of-Disease refresh.
|
||||
if (paragonSpread)
|
||||
if (Aura* dp = target->GetAuraOfRankedSpell(2944 /* Devouring Plague r1 */, caster->GetGUID()))
|
||||
{
|
||||
Aura* dp = target->GetAuraOfRankedSpell(SPELL_PRIEST_DEVOURING_PLAGUE_R1, caster->GetGUID());
|
||||
if (!dp)
|
||||
dp = target->GetAuraOfRankedSpell(SPELL_PARAGON_MULTIDOT_DEVOURING_PLAGUE_R1, caster->GetGUID());
|
||||
if (dp)
|
||||
dp->RefreshDuration();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
@@ -2010,6 +2052,9 @@ class spell_dk_presence : public AuraScript
|
||||
SPELL_DK_BLOOD_PRESENCE,
|
||||
SPELL_DK_FROST_PRESENCE,
|
||||
SPELL_DK_UNHOLY_PRESENCE,
|
||||
SPELL_PARAGON_ADV_BLOOD_PRESENCE,
|
||||
SPELL_PARAGON_ADV_FROST_PRESENCE,
|
||||
SPELL_PARAGON_ADV_UNHOLY_PRESENCE,
|
||||
SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1,
|
||||
SPELL_DK_IMPROVED_FROST_PRESENCE_R1,
|
||||
SPELL_DK_IMPROVED_UNHOLY_PRESENCE_R1,
|
||||
@@ -2024,7 +2069,7 @@ class spell_dk_presence : public AuraScript
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
|
||||
if (GetId() == SPELL_DK_BLOOD_PRESENCE)
|
||||
if (GetId() == SPELL_DK_BLOOD_PRESENCE || GetId() == SPELL_PARAGON_ADV_BLOOD_PRESENCE)
|
||||
target->CastSpell(target, SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED, true);
|
||||
else if (AuraEffect const* impAurEff = target->GetAuraEffectOfRankedSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1, EFFECT_0))
|
||||
if (!target->HasAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED))
|
||||
@@ -2035,7 +2080,7 @@ class spell_dk_presence : public AuraScript
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
|
||||
if (GetId() == SPELL_DK_FROST_PRESENCE)
|
||||
if (GetId() == SPELL_DK_FROST_PRESENCE || GetId() == SPELL_PARAGON_ADV_FROST_PRESENCE)
|
||||
target->CastSpell(target, SPELL_DK_FROST_PRESENCE_TRIGGERED, true);
|
||||
else if (AuraEffect const* impAurEff = target->GetAuraEffectOfRankedSpell(SPELL_DK_IMPROVED_FROST_PRESENCE_R1, EFFECT_0))
|
||||
if (!target->HasAura(SPELL_DK_FROST_PRESENCE_TRIGGERED))
|
||||
@@ -2046,12 +2091,12 @@ class spell_dk_presence : public AuraScript
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
|
||||
if (GetId() == SPELL_DK_UNHOLY_PRESENCE)
|
||||
if (GetId() == SPELL_DK_UNHOLY_PRESENCE || GetId() == SPELL_PARAGON_ADV_UNHOLY_PRESENCE)
|
||||
target->CastSpell(target, SPELL_DK_UNHOLY_PRESENCE_TRIGGERED, true);
|
||||
|
||||
if (AuraEffect const* impAurEff = target->GetAuraEffectOfRankedSpell(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_R1, EFFECT_0))
|
||||
{
|
||||
if (GetId() == SPELL_DK_UNHOLY_PRESENCE)
|
||||
if (GetId() == SPELL_DK_UNHOLY_PRESENCE || GetId() == SPELL_PARAGON_ADV_UNHOLY_PRESENCE)
|
||||
{
|
||||
// Not listed as any effect, only base points set
|
||||
int32 bp = impAurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue();
|
||||
|
||||
Reference in New Issue
Block a user