Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions data/sql/updates/db_world/2026_02_28_06.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- DB update 2026_02_28_05 -> 2026_02_28_06
DELETE FROM `spell_script_names` WHERE `spell_id` = 38132 AND `ScriptName` = 'spell_lady_vashj_tainted_core_paralyze';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(38132, 'spell_lady_vashj_tainted_core_paralyze');
2 changes: 2 additions & 0 deletions data/sql/updates/db_world/2026_02_28_07.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- DB update 2026_02_28_06 -> 2026_02_28_07
UPDATE `waypoint_data` SET `move_type` = 1 WHERE `id` = 1376110;
10 changes: 10 additions & 0 deletions data/sql/updates/db_world/2026_02_28_08.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- DB update 2026_02_28_07 -> 2026_02_28_08
-- Phase for accepting or having completed any of the "Rider of%" quests
DELETE FROM `spell_area` WHERE `spell` = 58863 AND `area` = 4520;
INSERT INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES
(58863, 4520, 13161, 0, 0, 0, 2, 1, 74, 11),
(58863, 4520, 13162, 0, 0, 0, 2, 1, 74, 11),
(58863, 4520, 13163, 0, 0, 0, 2, 1, 74, 11);

-- Make sure all prerequisites are completed
UPDATE `conditions` SET `ElseGroup` = 0 WHERE `SourceTypeOrReferenceId` = 19 AND `SourceEntry` IN (13161, 13162, 13163) AND `ConditionTypeOrReference` = 8 AND `ConditionValue1` IN (13146, 13147, 13160);
5 changes: 5 additions & 0 deletions data/sql/updates/db_world/2026_02_28_09.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- DB update 2026_02_28_08 -> 2026_02_28_09
-- Fingers of Frost buff: change SpellPhaseMask from 3 (CAST|HIT) to 1 (CAST only).
-- With !IsTriggered() removed from CAST proc blocks, triggered spells now fire
-- CAST procs, so HIT phase is no longer needed for triggered spell consumption.
UPDATE `spell_proc` SET `SpellPhaseMask` = 1 WHERE `SpellId` = 74396;
11 changes: 2 additions & 9 deletions src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,8 @@ void BattlegroundSA::DemolisherStartState(bool start)
if (!BgCreatures[0])
return;

// Only lock demolishers during warmup - they are attacker vehicles.
// Cannons/turrets are defender weapons and must remain usable from the start.
for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++)
if (Creature* dem = GetBGCreature(i))
{
Expand All @@ -727,15 +729,6 @@ void BattlegroundSA::DemolisherStartState(bool start)
dem->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
}

for (uint8 i = BG_SA_GUN_1; i <= BG_SA_GUN_10; i++)
if (Creature* gun = GetBGCreature(i))
{
if (start)
gun->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
else
gun->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
}

// xinef: enable first gates damaging at start
if (!start)
{
Expand Down
64 changes: 52 additions & 12 deletions src/server/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2559,11 +2559,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (effectUnit->IsAlive() != target->alive)
return;

// Xinef: absorb delayed projectiles for 500ms
if (getState() == SPELL_STATE_DELAYED && !m_spellInfo->IsTargetingArea() && !m_spellInfo->IsPositive() &&
(GameTime::GetGameTimeMS().count() - target->timeDelay) <= effectUnit->m_lastSanctuaryTime && GameTime::GetGameTimeMS().count() < (effectUnit->m_lastSanctuaryTime + 500) &&
effectUnit->FindMap() && !effectUnit->FindMap()->IsDungeon()
)
// Absorb delayed projectiles launched before Sanctuary (e.g. Vanish dodging a Frostbolt in flight)
if (getState() == SPELL_STATE_DELAYED && !m_spellInfo->IsPositive() &&
(GameTime::GetGameTimeMS().count() - target->timeDelay) <= effectUnit->m_lastSanctuaryTime)
return; // No missinfo in that case

// Absorb instant hostile spells on application within brief window after Sanctuary
if (getState() != SPELL_STATE_DELAYED && !m_spellInfo->IsPositive() &&
effectUnit->m_lastSanctuaryTime &&
GameTime::GetGameTimeMS().count() <= (effectUnit->m_lastSanctuaryTime + 400))
return; // No missinfo in that case

// Get original caster (if exist) and calculate damage/healing from him data
Expand Down Expand Up @@ -3952,6 +3956,44 @@ void Spell::_cast(bool skipCheck)
}
else
{
// CAST phase procs for non-channeled immediate spells
// (channeled spells handle this below to preserve spell mods)
// Note: triggered spells are allowed here; per-aura filtering via
// PROC_ATTR_TRIGGERED_CAN_PROC in SpellAuras.cpp handles rejection.
if (!m_spellInfo->IsChanneled() && m_originalCaster)
{
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
{
bool IsPositive = m_spellInfo->IsPositive();
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
{
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
}
else
{
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
}
}

uint32 hitMask = PROC_HIT_NORMAL;

for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
{
if (ihit->missCondition != SPELL_MISS_NONE)
continue;

if (!ihit->crit)
continue;

hitMask |= PROC_HIT_CRITICAL;
break;
}

Unit::ProcSkillsAndAuras(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, hitMask, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST);
}

// Immediate spell, no big deal
handle_immediate();
}
Expand Down Expand Up @@ -3981,13 +4023,11 @@ void Spell::_cast(bool skipCheck)
if (modOwner)
modOwner->SetSpellModTakingSpell(this, false);

// Handle procs on cast - only for non-triggered spells
// Triggered spells (from auras, items, etc.) should not fire CAST phase procs
// as they are not player-initiated casts. This prevents issues like Arcane Potency
// charges being consumed by periodic damage effects (e.g., Blizzard ticks).
// Must be called AFTER handle_immediate() so spell mods (like Missile Barrage's
// duration reduction) are applied before the aura is consumed by the proc.
if (m_originalCaster && !IsTriggered())
// CAST phase procs for delayed and channeled spells
// Note: triggered spells are allowed here; per-aura filtering via
// PROC_ATTR_TRIGGERED_CAN_PROC in SpellAuras.cpp handles rejection.
if ((m_spellState == SPELL_STATE_DELAYED || m_spellInfo->IsChanneled())
&& m_originalCaster)
{
uint32 procAttacker = m_procAttacker;
if (!procAttacker)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ struct boss_razorscale : public BossAI
CommanderGUID.Clear();
bGroundPhase = false;
flyTimes = 0;
me->SetAnimTier(AnimTier::Fly);
}

void AttackStart(Unit* who) override
Expand Down Expand Up @@ -610,7 +611,7 @@ class npc_ulduar_expedition_commander : public CreatureScript
{
razorscale->AI()->AttackStart(player);
razorscale->GetMotionMaster()->MoveIdle();
razorscale->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_INIT, 588.0f, -178.0f, 490.0f, FORCED_MOVEMENT_NONE, 0.f, 0.f, false, false);
razorscale->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_INIT, CORDS_AIR.GetPositionX(), CORDS_AIR.GetPositionY(), CORDS_AIR.GetPositionZ(), FORCED_MOVEMENT_NONE, 0.f, 0.f, false, false, MOTION_SLOT_ACTIVE, AnimTier::Fly);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,26 @@ class spell_lady_vashj_summons : public SpellScript
}
};

// Spell 38132 - Paralyze (applied to player when looting Tainted Core item 31088)
class spell_lady_vashj_tainted_core_paralyze : public AuraScript
{
PrepareAuraScript(spell_lady_vashj_tainted_core_paralyze);

void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
return;

if (Player* player = GetTarget()->ToPlayer())
player->DestroyItemCount(ITEM_TAINTED_CORE, -1, true);
}

void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_lady_vashj_tainted_core_paralyze::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_ROOT, AURA_EFFECT_HANDLE_REAL);
}
};

void AddSC_boss_lady_vashj()
{
RegisterSerpentShrineAI(boss_lady_vashj);
Expand All @@ -409,4 +429,5 @@ void AddSC_boss_lady_vashj()
RegisterSpellScript(spell_lady_vashj_summon_sporebat);
RegisterSpellScript(spell_lady_vashj_spore_drop_effect);
RegisterSpellScript(spell_lady_vashj_summons);
RegisterSpellScript(spell_lady_vashj_tainted_core_paralyze);
}
18 changes: 3 additions & 15 deletions src/server/scripts/Spells/spell_mage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,23 +958,11 @@ class spell_mage_fingers_of_frost : public AuraScript

void PrepareProc(ProcEventInfo& eventInfo)
{
// Block channeled spells (e.g. Blizzard channel start) from consuming charges.
// All other filtering is handled by SpellPhaseMask=1 (CAST only) in spell_proc.
if (Spell const* spell = eventInfo.GetProcSpell())
{
bool isTriggered = spell->IsTriggered();
bool isCastPhase = (eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST) != 0;
bool isChanneled = spell->GetSpellInfo()->IsChanneled();
bool prevent = false;

if (isTriggered)
prevent = false;
else if (isChanneled)
prevent = true;
else if (!isCastPhase)
prevent = true;

if (prevent)
if (spell->GetSpellInfo()->IsChanneled())
PreventDefaultAction();
}
}

void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
Expand Down
2 changes: 1 addition & 1 deletion src/server/scripts/Spells/spell_shaman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ class spell_sha_frozen_power : public AuraScript
if (GetTarget()->GetDistance(target) < 15.0f)
return false;

return roll_chance_i(GetEffect(EFFECT_0)->GetAmount());
return roll_chance_i(GetEffect(EFFECT_1)->GetAmount());
}

void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
Expand Down
Loading