Skip to content
Open
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
78 changes: 73 additions & 5 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 Down Expand Up @@ -2608,6 +2626,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 +3404,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 +3572,7 @@ struct ambush_t : public rogue_attack_t
{
rogue_attack_t::execute();
trigger_blindside( execute_state );
p()->buffs.mid2_outlaw_4pc->trigger();
}

void impact( action_state_t* state ) override
Expand Down Expand Up @@ -5798,6 +5828,7 @@ struct sinister_strike_t : public rogue_attack_t
rogue_attack_t::execute();
trigger_unseen_blade( execute_state );
trigger_opportunity( execute_state, extra_attack );
p()->buffs.mid2_outlaw_4pc->trigger();
}

void impact( action_state_t* state ) override
Expand Down Expand Up @@ -7547,10 +7578,15 @@ 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 ),
p()->sim->print_log( "{} consumes {} {} for {} ({})", *p(), cp_loss, util::resource_type_string( RESOURCE_COMBO_POINT ),
*this, p()->current_cp() );
// Remove Supercharger Buffs
consume_supercharger( state );
Expand All @@ -7569,7 +7605,11 @@ 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
if ( cp_loss > 0 )
p()->buffs.deadly_pursuit_tracker->trigger( as<int>( cp_loss ) );
}
}
}

Expand Down Expand Up @@ -7810,6 +7850,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 +8058,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 @@ -10125,6 +10173,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->effectN( 1 ).trigger();

// Register passives ======================================================

Expand Down Expand Up @@ -10922,7 +10975,15 @@ 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_fallback( set_bonuses.mid2_outlaw_4pc->ok(), this, "fang_strike", spec.mid2_outlaw_4pc_buff )
->set_default_value_from_effect_type( A_ADD_PCT_MODIFIER, P_RESOURCE_COST_1 );

if ( set_bonuses.mid2_outlaw_4pc->ok() )
{
buffs.mid2_outlaw_4pc->set_chance( set_bonuses.mid2_outlaw_4pc->effectN( 1 ).percent() );
}
}

// rogue_t::invalidate_cache =========================================
Expand Down Expand Up @@ -11635,6 +11696,13 @@ class rogue_module_t : public module_t
.operation( hotfix::HOTFIX_SET )
.modifier( 15 )
.verification_value( 10 );

// 2026-07-10 -- PTR TOCHECK: MID2 Outlaw 4pc has a scripted 20% proc rate while spell data is 12%
hotfix::register_effect( "Rogue", "2026-07-10", "MID2 Outlaw 4pc Proc Chance", 1319250 )
.field( "base_value" )
.operation( hotfix::HOTFIX_SET )
.modifier( 20 )
.verification_value( 12 );
}

void register_actor_initializers( sim_t* ) const override {}
Expand Down
Loading