Skip to content
76 changes: 72 additions & 4 deletions engine/class_modules/sc_rogue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ class rogue_t : public player_t

// Set Bonuses
damage_buff_t* mid1_outlaw_4pc;
buff_t* mid2_outlaw_4pc;

} buffs;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 ============================================================
Expand Down Expand Up @@ -1992,6 +2005,11 @@ class rogue_action_t : public Base
int consume_cp = consumes_combo_points() ? as<int>( 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 = as<int>( p()->consume_cp_max() );
}

// Apply and Snapshot Supercharger Buffs
if ( p()->talent.rogue.supercharger->ok() && consumes_supercharger() )
{
Expand Down Expand Up @@ -2196,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:
Expand All @@ -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 );
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();
}
}
Expand Down Expand Up @@ -3543,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
Expand Down Expand Up @@ -5798,6 +5829,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
Expand Down Expand Up @@ -7547,8 +7579,13 @@ void actions::rogue_action_t<Base>::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 *= 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, 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() );
Expand All @@ -7569,7 +7606,8 @@ void actions::rogue_action_t<Base>::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<int>( max_spend ) );
// 2026-06-30 -- PTR TOCHECK: MID2 Outlaw 4pc does not contribute towards Deadly Pursuit
p()->buffs.deadly_pursuit_tracker->trigger( as<int>( cp_loss ) );
}
}

Expand Down Expand Up @@ -7810,6 +7848,12 @@ void actions::rogue_action_t<Base>::trigger_ruthlessness_cp( const action_state_
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
if ( p()->bugs && affected_by.mid2_outlaw_4pc && p()->buffs.mid2_outlaw_4pc->check() )
cp = std::max( 0, cp - as<int>( p()->consume_cp_max() ) );

if ( cp == 0 )
return;

Expand Down Expand Up @@ -8012,6 +8056,8 @@ void actions::rogue_action_t<Base>::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 );
}

template <typename Base>
Expand Down Expand Up @@ -8689,6 +8735,20 @@ void actions::rogue_action_t<Base>::trigger_echoing_reprimand( const action_stat
p()->active.echoing_reprimand->execute_on_target( state->target );
}

template <typename Base>
void actions::rogue_action_t<Base>::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 <typename Base>
void actions::rogue_action_t<Base>::trigger_secondary_poisoning( const action_state_t* state )
{
Expand Down Expand Up @@ -10125,6 +10185,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 ======================================================

Expand Down Expand Up @@ -10922,7 +10987,10 @@ void rogue_t::create_buffs()

// Set Bonus Items ========================================================

buffs.mid1_outlaw_4pc = make_buff<damage_buff_t>( this, "whirl_of_blades", set_bonuses.mid1_outlaw_4pc->effectN(2).trigger() );
buffs.mid1_outlaw_4pc = make_buff<damage_buff_t>( 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 =========================================
Expand Down
Loading