From ee15707c3b6dec88ef1dc09f4f1d2a49ef3ff74b Mon Sep 17 00:00:00 2001 From: soloxcx Date: Mon, 29 Jun 2026 14:06:47 -0500 Subject: [PATCH 1/7] [Outlaw] Add 12.1 changes and set bonus - Update Zero In proc behavior with daggers - Add MID2 set bonus for Outlaw --- engine/class_modules/sc_rogue.cpp | 83 ++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 9c985ee7fd1..87ed511c413 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -449,6 +449,7 @@ class rogue_t : public player_t // Set Bonuses damage_buff_t* mid1_outlaw_4pc; + buff_t* mid2_outlaw_4pc; } buffs; @@ -724,6 +725,8 @@ class rogue_t : public player_t const spell_data_t* rupture; // Assassination + Subtlety const spell_data_t* shadowstep; // Assassination + Subtlety, baseline charge increase passive + // Set Bonuses + const spell_data_t* mid2_outlaw_4pc_buff; } spec; // Talents @@ -1103,6 +1106,8 @@ class rogue_t : public player_t const spell_data_t* mid1_subtlety_2pc; const spell_data_t* mid1_subtlety_4pc; + const spell_data_t* mid2_outlaw_2pc; + const spell_data_t* mid2_outlaw_4pc; } set_bonuses; // Options @@ -1626,6 +1631,8 @@ class rogue_action_t : public Base bool mid1_assassination_4pc = false; bool mid1_subtlety_2pc = false; + bool mid2_outlaw_4pc = false; + damage_affect_data follow_the_blood; damage_affect_data mastery_executioner; damage_affect_data mastery_potent_assassin; @@ -1785,6 +1792,11 @@ class rogue_action_t : public Base { affected_by.mid1_subtlety_2pc = consumes_combo_points(); } + + if ( p->set_bonuses.mid2_outlaw_4pc->ok() ) + { + affected_by.mid2_outlaw_4pc = ab::data().affected_by( p->spec.mid2_outlaw_4pc_buff->effectN( 1 ) ); + } } void init() override @@ -1895,6 +1907,7 @@ class rogue_action_t : public Base register_consume_buff( p()->buffs.symbolic_victory, p()->buffs.symbolic_victory->is_affecting( &ab::data() ), nullptr, p()->bugs ? 0_ms : 1_ms, false, true ); // 2024-08-12 -- Consumed immediatey, does not work with Shadowy Finishers register_consume_buff( p()->buffs.the_rotten, p()->buffs.the_rotten->is_affecting_direct( &ab::data() ), nullptr, 1_ms, false, true ); + register_consume_buff( p()->buffs.mid2_outlaw_4pc, affected_by.mid2_outlaw_4pc ); } // Type Wrappers ============================================================ @@ -1992,6 +2005,11 @@ class rogue_action_t : public Base int consume_cp = consumes_combo_points() ? as( std::min( p()->current_cp(), p()->consume_cp_max() ) ) : 0; int effective_cp = consume_cp; + if ( affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) + { + effective_cp = p()->consume_cp_max(); + } + // Apply and Snapshot Supercharger Buffs if ( p()->talent.rogue.supercharger->ok() && consumes_supercharger() ) { @@ -2222,6 +2240,7 @@ class rogue_action_t : public Base bool trigger_deathstalkers_mark_debuff( const action_state_t* state, bool from_darkest_night = false ); void trigger_doomblade( const action_state_t* ); void trigger_echoing_reprimand( const action_state_t* state ); + void trigger_mid2_outlaw_4pc( const action_state_t* state ); void trigger_fatal_flourish( const action_state_t* ); void trigger_fatebound_coinflip( const action_state_t* state, fatebound_t::coinflip_e result, timespan_t delay = timespan_t::zero() ); void trigger_fatebound_edge_case( const action_state_t* state ); @@ -2608,6 +2627,11 @@ class rogue_action_t : public Base c *= 1.0 + p()->buffs.goremaws_bite->check_value(); } + if ( affected_by.mid2_outlaw_4pc ) + { + c *= 1.0 + p()->buffs.mid2_outlaw_4pc->check_value(); + } + return c; } @@ -3381,6 +3405,12 @@ struct melee_t : public rogue_attack_t if ( p()->talent.outlaw.zero_in->ok() && state->result == RESULT_CRIT ) { + if ( p()->is_ptr() && state->action->weapon->type == WEAPON_DAGGER ) + { + double chance = p()->talent.outlaw.zero_in->effectN( 2 ).percent(); + if ( p()->rng().roll( chance ) ) + return; + } p()->buffs.zero_in->trigger(); } } @@ -5766,6 +5796,13 @@ struct sinister_strike_t : public rogue_attack_t return ( secondary_trigger_type == secondary_trigger::SINISTER_STRIKE ) ? 1 : 0; } + void execute() override + { + rogue_attack_t::execute(); + // 2026-06-29 -- PTR TOCHECK: Sinister Strike can proc MID2 Outlaw 4pc on both hits + trigger_mid2_outlaw_4pc( execute_state ); + } + bool procs_main_gauche() const override { return true; } @@ -5798,6 +5835,7 @@ struct sinister_strike_t : public rogue_attack_t rogue_attack_t::execute(); trigger_unseen_blade( execute_state ); trigger_opportunity( execute_state, extra_attack ); + trigger_mid2_outlaw_4pc( execute_state ); } void impact( action_state_t* state ) override @@ -7547,8 +7585,13 @@ void actions::rogue_action_t::spend_combo_points( const action_state_t* st const auto rs = cast_state( state ); double max_spend = std::min( p()->current_cp(), p()->consume_cp_max() ); + double cp_loss = max_spend; + + if ( affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) + cp_loss = 0; + ab::stats->consume_resource( RESOURCE_COMBO_POINT, max_spend ); - p()->resource_loss( RESOURCE_COMBO_POINT, max_spend ); + p()->resource_loss( RESOURCE_COMBO_POINT, cp_loss ); p()->sim->print_log( "{} consumes {} {} for {} ({})", *p(), max_spend, util::resource_type_string( RESOURCE_COMBO_POINT ), *this, p()->current_cp() ); @@ -7806,6 +7849,10 @@ void actions::rogue_action_t::trigger_ruthlessness_cp( const action_state_ if ( !p()->talent.outlaw.ruthlessness->ok() || !affected_by.ruthlessness || is_secondary_action() ) return; + // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc does not trigger Ruthlessness + if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) + return; + if ( !ab::result_is_hit( state->result ) ) return; @@ -8012,6 +8059,8 @@ void actions::rogue_action_t::trigger_restless_blades( const action_state_ p()->cooldowns.killing_spree->adjust( v, false ); p()->cooldowns.roll_the_bones->adjust( v, false ); p()->cooldowns.sprint->adjust( v, false ); + + p()->sim->print_log( "{} triggered Restless Blades with {}s total cooldown reduction", *p(), v *= -1 ); } template @@ -8020,6 +8069,10 @@ void actions::rogue_action_t::trigger_hand_of_fate( const action_state_t* if ( !p()->talent.fatebound.hand_of_fate->ok() ) return; + // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc does not trigger Fatebound Coins + if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) + return; + if ( is_secondary_action() ) return; // You have to actually spend the CP to get the coin - no secondary action finishers grant flips @@ -8600,6 +8653,10 @@ void actions::rogue_action_t::trigger_scoundrel_strike( const action_state if ( !p()->talent.outlaw.gravedigger_2->ok() ) return; + // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc does not trigger Scoundrel Strike + if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) + return; + if ( !ab::result_is_hit( state->result ) ) return; @@ -8689,6 +8746,20 @@ void actions::rogue_action_t::trigger_echoing_reprimand( const action_stat p()->active.echoing_reprimand->execute_on_target( state->target ); } +template +void actions::rogue_action_t::trigger_mid2_outlaw_4pc( const action_state_t* state ) +{ + if ( !p()->is_ptr() ) + return; + + double chance = p()->set_bonuses.mid2_outlaw_4pc->effectN( 1 ).percent(); + + if ( !p()->rng().roll( chance ) ) + return; + + p()->buffs.mid2_outlaw_4pc->trigger(); +} + template void actions::rogue_action_t::trigger_secondary_poisoning( const action_state_t* state ) { @@ -10125,6 +10196,11 @@ void rogue_t::init_spells() set_bonuses.mid1_outlaw_4pc = sets->set( ROGUE_OUTLAW, MID1, B4 ); set_bonuses.mid1_subtlety_2pc = sets->set( ROGUE_SUBTLETY, MID1, B2 ); set_bonuses.mid1_subtlety_4pc = sets->set( ROGUE_SUBTLETY, MID1, B4 ); + + set_bonuses.mid2_outlaw_2pc = sets->set( ROGUE_OUTLAW, MID2, B2 ); + set_bonuses.mid2_outlaw_4pc = sets->set( ROGUE_OUTLAW, MID2, B4 ); + + spec.mid2_outlaw_4pc_buff = set_bonuses.mid2_outlaw_4pc->ok() ? set_bonuses.mid2_outlaw_4pc->effectN( 1 ).trigger() : spell_data_t::not_found(); // Register passives ====================================================== @@ -10922,7 +10998,10 @@ void rogue_t::create_buffs() // Set Bonus Items ======================================================== - buffs.mid1_outlaw_4pc = make_buff( this, "whirl_of_blades", set_bonuses.mid1_outlaw_4pc->effectN(2).trigger() ); + buffs.mid1_outlaw_4pc = make_buff( this, "whirl_of_blades", set_bonuses.mid1_outlaw_4pc->effectN( 2 ).trigger() ); + + buffs.mid2_outlaw_4pc = make_buff( this, "fang_strike", spec.mid2_outlaw_4pc_buff ) + ->set_default_value_from_effect_type( A_ADD_PCT_MODIFIER, P_RESOURCE_COST_1 ); } // rogue_t::invalidate_cache ========================================= From 8aac671dfb02e3a2059d3b24617b1f4b4b124b80 Mon Sep 17 00:00:00 2001 From: soloxcx Date: Mon, 29 Jun 2026 14:16:53 -0500 Subject: [PATCH 2/7] don't forget ambush --- engine/class_modules/sc_rogue.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 87ed511c413..87aa0fa7733 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -3573,6 +3573,7 @@ struct ambush_t : public rogue_attack_t { rogue_attack_t::execute(); trigger_blindside( execute_state ); + trigger_mid2_outlaw_4pc( execute_state ); } void impact( action_state_t* state ) override From bddca8e2be2db8009de090dd0b61d36205fe511f Mon Sep 17 00:00:00 2001 From: soloxcx Date: Tue, 30 Jun 2026 19:59:25 -0500 Subject: [PATCH 3/7] use spell data for CPs cost reduction, don't contribute towards deadly pursuit --- engine/class_modules/sc_rogue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 87aa0fa7733..4ad59662621 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -7589,7 +7589,7 @@ void actions::rogue_action_t::spend_combo_points( const action_state_t* st double cp_loss = max_spend; if ( affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) - cp_loss = 0; + cp_loss *= 1.0 + p()->spec.mid2_outlaw_4pc_buff->effectN( 2 ).percent(); ab::stats->consume_resource( RESOURCE_COMBO_POINT, max_spend ); p()->resource_loss( RESOURCE_COMBO_POINT, cp_loss ); @@ -7613,7 +7613,8 @@ void actions::rogue_action_t::spend_combo_points( const action_state_t* st else if ( p()->buffs.deadly_pursuit->check() ) p()->buffs.deadly_pursuit->refresh(); else - p()->buffs.deadly_pursuit_tracker->trigger( as( max_spend ) ); + // 2026-06-30 -- PTR TOCHECK: MID2 Outlaw 4pc does not contribute towards Deadly Pursuit + p()->buffs.deadly_pursuit_tracker->trigger( as( cp_loss ) ); } } From 25a82350e62d0cfaccab50f0185e07e9f790aa17 Mon Sep 17 00:00:00 2001 From: soloxcx Date: Thu, 2 Jul 2026 12:41:42 -0500 Subject: [PATCH 4/7] Update for PTR bugfixes, manually adjust ruthlessness --- engine/class_modules/sc_rogue.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 4ad59662621..56b481aab12 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -2007,7 +2007,7 @@ class rogue_action_t : public Base if ( affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) { - effective_cp = p()->consume_cp_max(); + effective_cp = as( p()->consume_cp_max() ); } // Apply and Snapshot Supercharger Buffs @@ -2214,7 +2214,7 @@ class rogue_action_t : public Base return 0.0; auto chance = ab::parry_chance(exp, target); - return std::max(0.0, chance); + return std::max( 0.0, chance ); } public: @@ -5797,13 +5797,6 @@ struct sinister_strike_t : public rogue_attack_t return ( secondary_trigger_type == secondary_trigger::SINISTER_STRIKE ) ? 1 : 0; } - void execute() override - { - rogue_attack_t::execute(); - // 2026-06-29 -- PTR TOCHECK: Sinister Strike can proc MID2 Outlaw 4pc on both hits - trigger_mid2_outlaw_4pc( execute_state ); - } - bool procs_main_gauche() const override { return true; } @@ -7851,14 +7844,17 @@ void actions::rogue_action_t::trigger_ruthlessness_cp( const action_state_ if ( !p()->talent.outlaw.ruthlessness->ok() || !affected_by.ruthlessness || is_secondary_action() ) return; - // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc does not trigger Ruthlessness - if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) - return; - if ( !ab::result_is_hit( state->result ) ) return; int cp = cast_state( state )->get_combo_points(); + + // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc can only trigger Ruthlessness if its effective CPs are + // boosted by Supercharger or Coup de Grace. For these cases the max CPs that can be + // consumed are subtracted out. + if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) + cp = std::max( 0, cp - as( p()->consume_cp_max() ) ); + if ( cp == 0 ) return; @@ -8655,10 +8651,6 @@ void actions::rogue_action_t::trigger_scoundrel_strike( const action_state if ( !p()->talent.outlaw.gravedigger_2->ok() ) return; - // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc does not trigger Scoundrel Strike - if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) - return; - if ( !ab::result_is_hit( state->result ) ) return; From 11a8f6621b73ef5cbe965e25aa1ca2351acc7f8b Mon Sep 17 00:00:00 2001 From: soloxcx Date: Thu, 2 Jul 2026 12:48:25 -0500 Subject: [PATCH 5/7] update comment --- engine/class_modules/sc_rogue.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 56b481aab12..26e0a7a481a 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -7850,8 +7850,7 @@ void actions::rogue_action_t::trigger_ruthlessness_cp( const action_state_ int cp = cast_state( state )->get_combo_points(); // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc can only trigger Ruthlessness if its effective CPs are - // boosted by Supercharger or Coup de Grace. For these cases the max CPs that can be - // consumed are subtracted out. + // boosted by Supercharger or Coup de Grace if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) cp = std::max( 0, cp - as( p()->consume_cp_max() ) ); From f9d43a7f1290d19d07d190565c7ec9a5ae40e5c8 Mon Sep 17 00:00:00 2001 From: soloxcx Date: Thu, 2 Jul 2026 12:49:24 -0500 Subject: [PATCH 6/7] update restless blades log --- engine/class_modules/sc_rogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 26e0a7a481a..36682c87cbf 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -8057,7 +8057,7 @@ void actions::rogue_action_t::trigger_restless_blades( const action_state_ p()->cooldowns.roll_the_bones->adjust( v, false ); p()->cooldowns.sprint->adjust( v, false ); - p()->sim->print_log( "{} triggered Restless Blades with {}s total cooldown reduction", *p(), v *= -1 ); + p()->sim->print_log( "{} triggered Restless Blades with {}s total cooldown reduction", *p(), v ); } template From a3d84c9141f09a84d50e6b9a7c40cd5176d5fc8c Mon Sep 17 00:00:00 2001 From: soloxcx Date: Thu, 2 Jul 2026 15:54:14 -0500 Subject: [PATCH 7/7] fatebound coin was bugfixed --- engine/class_modules/sc_rogue.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/engine/class_modules/sc_rogue.cpp b/engine/class_modules/sc_rogue.cpp index 36682c87cbf..5dc8330f15e 100644 --- a/engine/class_modules/sc_rogue.cpp +++ b/engine/class_modules/sc_rogue.cpp @@ -8066,10 +8066,6 @@ void actions::rogue_action_t::trigger_hand_of_fate( const action_state_t* if ( !p()->talent.fatebound.hand_of_fate->ok() ) return; - // 2026-06-29 -- PTR TOCHECK: MID2 Outlaw 4pc does not trigger Fatebound Coins - if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() ) - return; - if ( is_secondary_action() ) return; // You have to actually spend the CP to get the coin - no secondary action finishers grant flips