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
13 changes: 0 additions & 13 deletions engine/class_modules/warlock/sc_warlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ warlock_t::warlock_t( sim_t* sim, util::string_view name, race_e r )
eye_explosion_instanced_bug_cb( false ),
eye_explosion_instanced_bug_sb( false ),
eye_explosion_instanced_bug_rof( true ),
fel_armaments_extra_effect_bug( false ),
tyrant_antoran_armaments_target_mul( 1.0 )
{
cooldowns.haunt = get_cooldown( "haunt" );
Expand Down Expand Up @@ -268,14 +267,6 @@ warlock_t::warlock_t( sim_t* sim, util::string_view name, race_e r )
assert( ( buffs.hellbent_commander->check() == expected_stacks ) && "Incorrent Demon Count for Hellbent Commander" );
}

if ( bugs && talents.fel_armaments.ok() )
{
// On each Heartbeat, the player periodically applies a hidden Fel Armaments aura to the Felguard, triggering procs
auto active_pet = warlock_pet_list.active;
if ( active_pet && active_pet->pet_type == PET_FELGUARD )
trigger_aura_applied_callbacks( proc_data_entries.fel_armaments_2, active_pet );
}

for ( auto pet : active_pets )
{
auto lock_pet = dynamic_cast<warlock_pet_t*>( pet );
Expand Down Expand Up @@ -571,9 +562,6 @@ std::string warlock_t::create_profile( save_e stype )
if ( !eye_explosion_instanced_bug_rof )
profile_str +=
"warlock.eye_explosion_instanced_bug_rof=" + util::to_string( as<int>( eye_explosion_instanced_bug_rof ) ) + "\n";
if ( fel_armaments_extra_effect_bug )
profile_str +=
"warlock.fel_armaments_extra_effect_bug" + util::to_string( as<int>( fel_armaments_extra_effect_bug ) ) + "\n";
if ( tyrant_antoran_armaments_target_mul < 1.0 )
profile_str +=
"warlock.tyrant_antoran_armaments_target_mul=" + util::to_string( tyrant_antoran_armaments_target_mul ) + "\n";
Expand All @@ -596,7 +584,6 @@ void warlock_t::copy_from( player_t* source )
eye_explosion_instanced_bug_cb = p->eye_explosion_instanced_bug_cb;
eye_explosion_instanced_bug_sb = p->eye_explosion_instanced_bug_sb;
eye_explosion_instanced_bug_rof = p->eye_explosion_instanced_bug_rof;
fel_armaments_extra_effect_bug = p->fel_armaments_extra_effect_bug;
tyrant_antoran_armaments_target_mul = p->tyrant_antoran_armaments_target_mul;

rng_settings = p->rng_settings;
Expand Down
3 changes: 0 additions & 3 deletions engine/class_modules/warlock/sc_warlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ struct warlock_t : public parse_player_effects_t
player_talent_t rune_of_shadows;
player_talent_t carnivorous_stalkers; // Chance for Dreadstalkers to perform additional Dreadbites
player_talent_t fel_armaments;
const spell_data_t* fel_armaments_2; // Another effect of Fel Armaments that, due to a bug, is always active

player_talent_t imp_gang_boss;
const spell_data_t* imp_gang_boss_buff; // Buff on Wild Imps
Expand Down Expand Up @@ -795,7 +794,6 @@ struct warlock_t : public parse_player_effects_t
proc_data_t agony_energize;
proc_data_t demonbolt_energize;
proc_data_t incinerate_energize;
proc_data_t fel_armaments_2;
proc_data_t marked_soul;
} proc_data_entries;

Expand Down Expand Up @@ -1116,7 +1114,6 @@ struct warlock_t : public parse_player_effects_t
bool eye_explosion_instanced_bug_cb;
bool eye_explosion_instanced_bug_sb;
bool eye_explosion_instanced_bug_rof;
bool fel_armaments_extra_effect_bug;
double tyrant_antoran_armaments_target_mul;

warlock_t( sim_t* sim, util::string_view name, race_e r );
Expand Down
65 changes: 37 additions & 28 deletions engine/class_modules/warlock/sc_warlock_actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1426,13 +1426,7 @@ using namespace helpers;
initial_stacks += ( int )( p()->talents.sudden_onset->effectN( 2 ).base_value() );

if ( active_4pc<MID1>() )
{
// NOTE: 2026-04-24 Tier set is only applying 1 additional stack to Agony on initial cast if Sudden Onset is not talented (bug?)
if ( p()->bugs && !p()->talents.sudden_onset.ok() )
initial_stacks += ( int )( p()->tier.wl_affliction_12_0_class_set_4pc->effectN( 1 ).base_value() * 0.5 );
else
initial_stacks += ( int )( p()->tier.wl_affliction_12_0_class_set_4pc->effectN( 1 ).base_value() );
}
initial_stacks += ( int )( p()->tier.wl_affliction_12_0_class_set_4pc->effectN( 1 ).base_value() );

int delta_stacks = initial_stacks - td( execute_state->target )->dots.agony->current_stack();

Expand Down Expand Up @@ -1470,19 +1464,27 @@ using namespace helpers;

void execute() override
{
// NOTE: 2026-02-20 Currently ingame a UA applied by Fatal Echoes also processes/consumes the UA 'execute' effects:
// NOTE: 2026-04-29 Currently ingame a UA applied by Fatal Echoes also processes/consumes some UA 'execute' effects:
// - Succulent Soul: consumes a stack and triggers its effects (Demonic Soul dmg and Manifested Avarice rng proc)
// - Cull the Weak: reduces the cooldown of Dark Harvest
// - Shard Instability: consumes a stack but does nothing (bug?) because the Fatal Echoes UA is already free and instant
// - Hellcaller Blackened Soul: increments wither stacks
// - Hellcaller Blackened Soul: increments Wither stacks
// - Shard Instability: unaffected; Fatal Echoes does not consume a stack of this buff

warlock_spell_t::execute();

if ( p()->talents.cull_the_weak.ok() )
p()->cooldowns.dark_harvest->adjust( -p()->talents.cull_the_weak->effectN( 1 ).time_value() );

// Seems that Shard Instability buff takes effect (and is consumed) even if it is obtained while Unstable Affliction is being cast (bug?)
p()->buffs.shard_instability->decrement();
// NOTE: 2026-04-29 If Shard Instability buff is gained during the casting of Unstable Affliction, that UA cast benefits from the cost
// reduction but does not consume the effect (bug?). As expected, a Fatal Echoes UA proc does not consume it either.
if ( p()->talents.shard_instability.ok() && time_to_execute == 0_ms && !is_fatal_echoes_execute )
{
// NOTE: 2026-04-29 Unstable Affliction consumes all Shard Instability stacks at once (bug)
if ( p()->bugs )
p()->buffs.shard_instability->expire();
else
p()->buffs.shard_instability->decrement();
}

if ( soul_harvester() && p()->buffs.succulent_soul->check() )
{
Expand Down Expand Up @@ -1539,14 +1541,19 @@ using namespace helpers;
{
p()->procs.fatal_echoes->occur();
make_event( sim, 1_ms, [ this, t = d->target ] {
const bool prev_ua_ticking = td( t )->dots.unstable_affliction->is_ticking();
this->set_target( t );
this->is_fatal_echoes_execute = true;
this->execute();
this->is_fatal_echoes_execute = false;
// When UA is applied by Fatal Echoes, Cascading Calamity is also triggered
if ( p()->talents.cascading_calamity.ok() && !prev_ua_ticking )
p()->buffs.cascading_calamity->trigger();
// NOTE: 2026-04-29 Fatal Echoes proc needs a Soul Shard to trigger (bug)
if ( !p()->bugs || p()->resources.current[ RESOURCE_SOUL_SHARD ] >= 1.0 )
{
const bool prev_ua_ticking = td( t )->dots.unstable_affliction->is_ticking();
this->set_target( t );
this->time_to_execute = 0_ms;
this->is_fatal_echoes_execute = true;
this->execute();
this->is_fatal_echoes_execute = false;
// When UA is applied by Fatal Echoes, Cascading Calamity is also triggered
if ( p()->talents.cascading_calamity.ok() && !prev_ua_ticking )
p()->buffs.cascading_calamity->trigger();
}
} );
}
}
Expand Down Expand Up @@ -1585,7 +1592,8 @@ using namespace helpers;

double cost_pct_multiplier() const override
{
if ( is_fatal_echoes_execute )
// NOTE: 2026-04-29 Fatal Echoes proc consumes a Soul Shard (bug)
if ( !p()->bugs && is_fatal_echoes_execute )
return 0.0;

return warlock_spell_t::cost_pct_multiplier();
Expand Down Expand Up @@ -1920,8 +1928,8 @@ using namespace helpers;
base_dd_min = base_dd_max = 0;
spell_power_mod.direct = 0;

// NOTE: 2026-02-20 DoT (Malefic Grasp) extra ticks are not affected by Death's Embrace (bug?)
affected_by.deaths_embrace = !p->bugs && p->talents.deaths_embrace.ok();
// DoT (Malefic Grasp) extra ticks are affected by Death's Embrace
affected_by.deaths_embrace = p->talents.deaths_embrace.ok();
}

void impact( action_state_t* s ) override
Expand Down Expand Up @@ -2013,7 +2021,7 @@ using namespace helpers;
extra_tick_mul( p->talents.malefic_grasp_2->effectN( 2 ).percent() )
{
channeled = true;
// NOTE: 2026-02-20 Malefic Grasp extra ticks are not affected by Death's Embrace (bug?)
// NOTE: 2026-04-29 Malefic Grasp ticks are not affected by Death's Embrace (bug?)
affected_by.deaths_embrace = !p->bugs && p->talents.deaths_embrace.ok();

if ( p->talents.cunning_cruelty.ok() )
Expand Down Expand Up @@ -2080,8 +2088,7 @@ using namespace helpers;

if ( soul_harvester() && p()->buffs.nightfall->check() )
{
// NOTE: 2026-03-21 Malefic Grasp consumes Nightfall without triggering Wicked Reaping (bug)
if ( !p()->bugs && p()->hero.wicked_reaping.ok() )
if ( p()->hero.wicked_reaping.ok() )
p()->proc_actions.wicked_reaping->execute_on_target( target );

if ( p()->hero.quietus.ok() && p()->hero.shared_fate.ok() )
Expand Down Expand Up @@ -5081,7 +5088,7 @@ using namespace helpers;
struct summon_mother_of_chaos_t : public warlock_spell_t
{
summon_mother_of_chaos_t( warlock_t* p )
: warlock_spell_t( "Summon Mother of Chaos (Summon)", p, p->hero.summon_mother )
: warlock_spell_t( "Summon Mother of Chaos", p, p->hero.summon_mother )
{
harmful = may_crit = false;
background = true;
Expand Down Expand Up @@ -5322,11 +5329,13 @@ using namespace helpers;
dot->decrement( 1 );
assert( ( dot->is_ticking() && dot->current_stack() > 0 ) && "UA stack decrement event should not cancel the DoT" );

// NOTE: 2026-04-29 Fatal Echoes proc needs a Soul Shard to trigger (bug)
// if ( p->talents.fatal_echoes.ok() && !target->is_sleeping() && dot->is_ticking() && dot->current_stack() > 0 && p->prd_rng.fatal_echoes->trigger() )
if ( p->talents.fatal_echoes.ok() && !target->is_sleeping() && p->prd_rng.fatal_echoes->trigger() )
if ( p->talents.fatal_echoes.ok() && !target->is_sleeping() && p->prd_rng.fatal_echoes->trigger() && ( !p->bugs || p->resources.current[ RESOURCE_SOUL_SHARD ] >= 1.0 ) )
{
p->procs.fatal_echoes->occur();
dot->current_action->set_target( target );
dot->current_action->time_to_execute = 0_ms;
debug_cast<unstable_affliction_t*>( dot->current_action )->is_fatal_echoes_execute = true;
dot->current_action->execute();
debug_cast<unstable_affliction_t*>( dot->current_action )->is_fatal_echoes_execute = false;
Expand Down
8 changes: 0 additions & 8 deletions engine/class_modules/warlock/sc_warlock_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,6 @@ namespace warlock
// NOTE: 2026-02-17 Mark of Perotharn is being applied twice in what appears to be a bug
if ( bugs )
parse_passive_effects( hero.mark_of_perotharn, true );

// NOTE: 2026-03-21 An additional effect of Fel Armaments talent is applied even if the talent is not selected (bug)
if ( demonology() && bugs && ( talents.fel_armaments.ok() || fel_armaments_extra_effect_bug ) )
parse_passive_effects( talents.fel_armaments_2, true );
}

void warlock_t::init_spells_affliction()
Expand Down Expand Up @@ -287,7 +283,6 @@ namespace warlock
talents.carnivorous_stalkers = find_talent_spell( talent_tree::SPECIALIZATION, "Carnivorous Stalkers" ); // Should be ID 386194;

talents.fel_armaments = find_talent_spell( talent_tree::SPECIALIZATION, "Fel Armaments" ); // Should be ID 1263935
talents.fel_armaments_2 = conditional_spell_lookup( warlock_base.demonology_warlock->ok() && bugs, 1263938 ); // Always active due to a bug

talents.imp_gang_boss = find_talent_spell( talent_tree::SPECIALIZATION, "Imp Gang Boss" ); // Should be ID 1250768

Expand Down Expand Up @@ -685,7 +680,6 @@ namespace warlock
proc_data_entries.agony_energize = talents.agony_energize;
proc_data_entries.demonbolt_energize = talents.demonbolt_energize;
proc_data_entries.incinerate_energize = warlock_base.incinerate_energize;
proc_data_entries.fel_armaments_2 = talents.fel_armaments_2;
proc_data_entries.marked_soul = hero.marked_soul;
}

Expand Down Expand Up @@ -1636,8 +1630,6 @@ namespace warlock
add_option( opt_deprecated( "eye_explosion_instanced_bug_sb", "warlock.eye_explosion_instanced_bug_sb" ) );
add_option( opt_bool( "warlock.eye_explosion_instanced_bug_rof", eye_explosion_instanced_bug_rof ) );
add_option( opt_deprecated( "eye_explosion_instanced_bug_rof", "warlock.eye_explosion_instanced_bug_rof" ) );
add_option( opt_bool( "warlock.fel_armaments_extra_effect_bug", fel_armaments_extra_effect_bug ) );
add_option( opt_deprecated( "fel_armaments_extra_effect_bug", "warlock.fel_armaments_extra_effect_bug" ) );
add_option( opt_float( "warlock.tyrant_antoran_armaments_target_mul", tyrant_antoran_armaments_target_mul, 0.0, 1.0 ));
add_option( opt_deprecated( "tyrant_antoran_armaments_target_mul", "warlock.tyrant_antoran_armaments_target_mul" ) );

Expand Down
2 changes: 1 addition & 1 deletion engine/class_modules/warlock/sc_warlock_pets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ struct desperate_soul_t : public warlock_pet_t
{
int wraths;

desperate_soul_t( warlock_t*, util::string_view = "desperate_souls" );
desperate_soul_t( warlock_t*, util::string_view = "desperate_soul" );
void arise() override;
action_t* create_action( util::string_view , util::string_view ) override;
};
Expand Down