Skip to content
Open
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: 13 additions & 0 deletions engine/class_modules/sc_enemy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ struct enemy_t : public player_t
void demise() override;
double armor_coefficient( int level, tank_dummy_e diff );
std::unique_ptr<expr_t> create_expression( util::string_view expression_str ) override;

bool has_absorb() const override
{
return range::any_of( absorb_buff_list,
[]( const absorb_buff_t* ab ) { return ab->check_value() > 0; } );
}

double current_absorb_amount() const override
{
return range::accumulate( absorb_buff_list, 0.0,
[]( const absorb_buff_t* ab ) { return ab->check_value(); } );
}

timespan_t available() const override
{
return waiting_time;
Expand Down
3 changes: 3 additions & 0 deletions engine/player/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12090,6 +12090,9 @@ std::unique_ptr<expr_t> player_t::create_expression( util::string_view expressio
if ( expression_str == "is_enemy" )
return expr_t::create_constant( "is_enemy", is_enemy() );

if ( expression_str == "has_absorb" )
return make_fn_expr( expression_str, [ this ] { return has_absorb() ? 1.0 : 0.0; } );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An expression that yields the total amount of absorbs could also be useful, but it will be hard to avoid the trap that UnitGetTotalAbsorbs falls for given that there are multiple types of absorbs.


if ( expression_str == "attack_haste" )
return make_fn_expr( expression_str, [this] { return cache.attack_haste(); } );

Expand Down
4 changes: 4 additions & 0 deletions engine/player/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,10 @@ struct player_t : public actor_t
virtual void assess_damage_imminent_pre_absorb( school_e, result_amount_type, action_state_t* );
virtual void assess_damage_imminent( school_e, result_amount_type, action_state_t* );
virtual void do_damage( action_state_t* );

virtual bool has_absorb() const { return false; }
virtual double current_absorb_amount() const { return 0.0; }

virtual void assess_heal( school_e, result_amount_type, action_state_t* );
virtual void trigger_callbacks( proc_types, proc_types2, action_t* action, action_state_t* state,
proc_trigger_type_e pt_type = TRIGGER_ACTION );
Expand Down
104 changes: 104 additions & 0 deletions engine/sim/raid_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "action/heal.hpp"
#include "action/action.hpp"
#include "action/action_state.hpp"
#include "action/spell.hpp"
#include "buff/buff.hpp"
#include "dbc/dbc.hpp"
Expand Down Expand Up @@ -1667,6 +1668,88 @@ struct vulnerable_event_t final : public raid_event_t
}
};

// Absorb ===================================================================

struct absorb_event_t final : public raid_event_t
{
double amount;
std::string school_str;
player_t* target = nullptr;
std::string target_str;
school_e school;
absorb_buff_t* buff = nullptr;

absorb_event_t( sim_t* s, std::string_view options_str )
: raid_event_t( s, "absorb" ), amount( 0.0 ), school( SCHOOL_NONE )
{
add_option( opt_float( "amount", amount ) );
add_option( opt_string( "school", school_str ) );

if ( sim->fight_style == FIGHT_STYLE_DUNGEON_ROUTE )
add_option( opt_string( "target", target_str ) );
else
add_option( opt_func( "target", [ this ]( auto, auto, std::string_view v ) { return parse_target( v ); } ) );

parse_options( options_str );

if ( sim->fight_style == FIGHT_STYLE_DUNGEON_ROUTE )
target_str = "Pull_" + util::to_string( pull ) + "_" + target_str;

if ( !school_str.empty() )
{
school = util::parse_school_type( school_str );
if ( school == SCHOOL_NONE )
throw std::invalid_argument( fmt::format( "Unknown absorb raid event school '{}'", school_str ) );
}
}

bool parse_target( std::string_view value )
{
auto it = range::find_if( sim->target_list, [ &value ]( const player_t* t ) {
return util::str_compare_ci( value, t->name() );
} );

if ( it != sim->target_list.end() )
{
target = *it;
return true;
}
sim->error( "Unknown absorb raid event target '{}'", value );
return true;
}

void _start() override
{
if ( !buff )
{
if ( sim->fight_style == FIGHT_STYLE_DUNGEON_ROUTE )
{
target = sim->find_player( target_str );
if ( !target )
throw std::invalid_argument( fmt::format( "Unknown absorb raid event target '{}'", target_str ) );
}
else if ( !target )
{
target = sim->target;
}

buff = make_buff<absorb_buff_t>( target, fmt::format( "raid_event_absorb_{}", internal_id ) );
if ( school != SCHOOL_NONE )
buff->set_absorb_school( school );
}

// No amount => unbreakable; infinity makes consume() never reduce to 0.
double value = amount > 0 ? amount : std::numeric_limits<double>::infinity();
buff->trigger( 1, value, -1.0, timespan_t::max() );
}

void _finish() override
{
if ( buff )
buff->expire();
}
};

// Position Switch ==========================================================

struct position_event_t : public raid_event_t
Expand Down Expand Up @@ -2311,6 +2394,8 @@ std::unique_ptr<raid_event_t> raid_event_t::create( sim_t* sim, util::string_vie
return std::unique_ptr<raid_event_t>( new stun_event_t( sim, options_str ) );
if ( name == "vulnerable" )
return std::unique_ptr<raid_event_t>( new vulnerable_event_t( sim, options_str ) );
if ( name == "absorb" )
return std::unique_ptr<raid_event_t>( new absorb_event_t( sim, options_str ) );
if ( name == "position_switch" )
return std::unique_ptr<raid_event_t>( new position_event_t( sim, options_str ) );
if ( name == "flying" )
Expand Down Expand Up @@ -2414,6 +2499,25 @@ void raid_event_t::init( sim_t* sim )
}
throw sc_initialization_error( "DungeonRoute fight style requires at least one pull event with pull=1." );
}

bool has_absorb_event = range::any_of( sim->raid_events,
[]( const auto& e ) { return e->type == "absorb"; } );
if ( has_absorb_event )
{
for ( player_t* p : sim->player_no_pet_list )
{
p->assessor_out_damage.add( assessor::TARGET_DAMAGE + 1,
[]( result_amount_type, action_state_t* s ) {
if ( s->target && s->target->is_enemy() )
{
double absorbed = s->result_mitigated - s->result_absorbed;
if ( absorbed > 0 )
s->result_amount += absorbed;
}
return assessor::CONTINUE;
} );
}
}
}

void raid_event_t::reset( sim_t* sim )
Expand Down
Loading