From f33aba3a7276ac64fe2fcf6d6c7d58e9766071aa Mon Sep 17 00:00:00 2001 From: pinepinepine Date: Mon, 23 Mar 2026 18:06:20 -0400 Subject: [PATCH 1/2] infused --- engine/class_modules/sc_mage.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/engine/class_modules/sc_mage.cpp b/engine/class_modules/sc_mage.cpp index 3bdd7c9ade8..ebe7e5a73c6 100644 --- a/engine/class_modules/sc_mage.cpp +++ b/engine/class_modules/sc_mage.cpp @@ -414,6 +414,7 @@ struct mage_t final : public player_t accumulated_rng_t* clearcasting; accumulated_rng_t* spellfire_spheres; accumulated_rng_t* augury_abounds; + accumulated_rng_t* infused_splinters; } accumulated_rng; // Sample data @@ -917,7 +918,7 @@ struct mage_t final : public player_t void trigger_freezing( player_t* target, int stacks, proc_t* source, double chance = 1.0 ); int trigger_shatter( player_t* target, action_t* action, int max_consumption, shatter_source_t* source, bool fof = false ); void trigger_icicle( int count = 1, bool grant_buff = true ); - void trigger_arcane_salvo( proc_t* source, int stacks = 1, double chance = 1.0 ); + void trigger_arcane_salvo( proc_t* source, int stacks = 1, double chance = 1.0, bool predictable = true ); }; namespace pets { @@ -5274,7 +5275,6 @@ struct splinter_t final : public mage_spell_t add_child( controlled_instincts ); } - freezing_chance = p->talents.infused_splinters->effectN( 2 ).percent(); freezing_stacks = as( p->talents.infused_splinters->effectN( 4 ).base_value() ); } @@ -5289,6 +5289,9 @@ struct splinter_t final : public mage_spell_t void impact( action_state_t* s ) override { + auto infused_outcome = p()->accumulated_rng.infused_splinters->trigger(); + freezing_chance = infused_outcome; + mage_spell_t::impact( s ); if ( !result_is_hit( s->result ) ) @@ -5301,7 +5304,7 @@ struct splinter_t final : public mage_spell_t } p()->trigger_arcane_salvo( salvo_source, as( p()->talents.infused_splinters->effectN( 3 ).base_value() ), - p()->talents.infused_splinters->effectN( 1 ).percent() ); + infused_outcome, false ); auto cd = p()->specialization() == MAGE_FROST ? p()->cooldowns.frozen_orb : p()->cooldowns.arcane_orb; // TODO: This is actually 300 ms (rather than 250), not sure how @@ -6539,6 +6542,9 @@ void mage_t::init_rng() accumulated_rng.augury_abounds = get_accumulated_rng( "augury_abounds", prd::find_constant( augury_chance, options.augury_blp_threshold ), options.augury_blp_threshold ); + + double infused_chance = talents.infused_splinters->effectN( specialization() == MAGE_ARCANE ? 1 : 2 ).percent(); + accumulated_rng.infused_splinters = get_accumulated_rng( "infused_splinters", prd::find_constant( infused_chance ) ); } void mage_t::init_finished() @@ -7113,7 +7119,7 @@ void mage_t::trigger_cinderstorm( player_t* target ) } } -void mage_t::trigger_arcane_salvo( proc_t* source, int stacks, double chance ) +void mage_t::trigger_arcane_salvo( proc_t* source, int stacks, double chance, bool predictable ) { if ( !talents.arcane_salvo->ok() || stacks <= 0 ) return; @@ -7125,7 +7131,7 @@ void mage_t::trigger_arcane_salvo( proc_t* source, int stacks, double chance ) buff->trigger( stacks ); int new_stacks = buff->check(); - if ( chance >= 1.0 ) + if ( chance >= 1.0 && predictable ) buff->predict(); if ( buff->at_max_stacks() && old_stacks < new_stacks ) From f56eced5fa7ea0057eb8acad303e5fc768284976 Mon Sep 17 00:00:00 2001 From: pinepinepine Date: Tue, 24 Mar 2026 16:11:46 -0400 Subject: [PATCH 2/2] options --- engine/class_modules/sc_mage.cpp | 8 +++++++- engine/sim/proc_rng.hpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/engine/class_modules/sc_mage.cpp b/engine/class_modules/sc_mage.cpp index ebe7e5a73c6..4ab3bcd40ec 100644 --- a/engine/class_modules/sc_mage.cpp +++ b/engine/class_modules/sc_mage.cpp @@ -370,6 +370,7 @@ struct mage_t final : public player_t unsigned clearcasting_blp_threshold = 0; unsigned sphere_blp_threshold = 11; unsigned augury_blp_threshold = 21; + unsigned infused_blp_threshold = 10; bool il_requires_freezing = false; bool il_sort_by_freezing = true; bool randomize_si_target = false; @@ -5779,6 +5780,7 @@ void mage_t::create_options() add_option( opt_uint( "mage.clearcasting_blp_threshold", options.clearcasting_blp_threshold ) ); add_option( opt_uint( "mage.sphere_blp_threshold", options.sphere_blp_threshold ) ); add_option( opt_uint( "mage.augury_blp_threshold", options.augury_blp_threshold ) ); + add_option( opt_uint( "mage.infused_blp_threshold", options.infused_blp_threshold ) ); add_option( opt_bool( "mage.il_requires_freezing", options.il_requires_freezing ) ); add_option( opt_bool( "mage.il_sort_by_freezing", options.il_sort_by_freezing ) ); add_option( opt_bool( "mage.randomize_si_target", options.randomize_si_target ) ); @@ -6544,7 +6546,11 @@ void mage_t::init_rng() options.augury_blp_threshold ); double infused_chance = talents.infused_splinters->effectN( specialization() == MAGE_ARCANE ? 1 : 2 ).percent(); - accumulated_rng.infused_splinters = get_accumulated_rng( "infused_splinters", prd::find_constant( infused_chance ) ); + // Thresholds may be uncapped (particularily Frost's). + // It's incredibly rare to reach 10/20: out of their (very) few instances, they've respectively shown a 100% success rate. + const unsigned infused_cap = specialization() == MAGE_ARCANE ? options.infused_blp_threshold : options.infused_blp_threshold * 2; + accumulated_rng.infused_splinters = get_accumulated_rng( + "infused_splinters", prd::find_constant( infused_chance, infused_cap ), infused_cap ); } void mage_t::init_finished() diff --git a/engine/sim/proc_rng.hpp b/engine/sim/proc_rng.hpp index 8187fecebaa..3e26d4c9b8e 100644 --- a/engine/sim/proc_rng.hpp +++ b/engine/sim/proc_rng.hpp @@ -244,7 +244,7 @@ constexpr double find_constant( double p, unsigned K = 0 ) // % success = proc_chance * trigger_count // // where trigger_count is the number of trigger attempts since the last success, including the current attempt. -// Thefirst trigger attempt after a successful proc will have a trigger count of 1. +// The first trigger attempt after a successful proc will have a trigger count of 1. // // cap is an optional parameter that sets the maximum number of attempts before the proc is guaranteed. If set // to a nonzero value, it guarantees a proc when trigger_count == cap (even if proc_chance * trigger_count < 1).