Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==========================================================================
- // Dedmonwakeen's DPS-DPM Simulator.
- // Send questions to natehieter@gmail.com
- // ==========================================================================
- #include <time.h>
- #include <wow_sim.h>
- // ==========================================================================
- // Spell
- // ==========================================================================
- // spell_t::spell_t ==========================================================
- spell_t::spell_t( player_t* p,
- const std::string& n,
- int8_t s,
- int8_t t ) :
- sim(p->sim), player(p), name_str(n), next(0), chained_spell(0),
- type(p->type), school(s), tree(t), rank_index(0), rank(0),
- base_dd(-1), dd(0), dd_dmg_bonus_mod(0),
- base_dot(-1), dot(0), dot_tick(0), dot_dmg_bonus_mod(0),
- base_multiplier(1.0), base_hit_adder(0), base_crit_adder(0), crit_bonus(0.50), base_penetration(0),
- base_cast_time(0), base_duration(0), base_mana_cost(0),
- cooldown(0), cooldown_group(n), cooldown_ready(0), dot_ready(0),
- num_ticks(0), ticks_remaining(0),
- channeled(false), may_crit(false), binary(false), aoe(false),
- trigger_gcd(true), may_cast(true), hit_on_cast(true),
- hit(false), crit(false), resist(false),
- event(0), stats(0)
- {
- report_t::trace( sim, "Player %s creates spell %s", p -> name(), name() );
- spell_t** last = &( p -> spell_list );
- while( *last ) last = &( (*last) -> next );
- *last = this;
- stats = new spell_stats_t( this );
- }
- // spell_t::parse_options ====================================================
- void spell_t::parse_options( option_t* options,
- const std::string& options_str )
- {
- if( options_str.empty() ) return;
- if( options_str.size() == 0 ) return;
- std::vector<std::string> splits;
- int size = wow_string_split( splits, options_str, "-" );
- for( int i=0; i < size; i++ )
- {
- static std::string n;
- static std::string v;
- if( 2 != wow_string_split( splits[ i ], "_", "S S", &n, &v ) )
- {
- printf( "wow_spell: %s: Unexpected parameter '%s'. Expected format: name=value\n", name(), splits[ i ].c_str() );
- assert( false );
- }
- if( ! option_t::parse( options, n, v ) )
- {
- printf( "wow_spell: %s: Unexpected parameter '%s'.\n", name(), n.c_str() );
- assert( false );
- }
- }
- }
- // spell_t::choose_rank ======================================================
- spell_rank_t* spell_t::choose_rank( spell_rank_t* rank_list )
- {
- for( int i=0; rank_list[ i ].level; i++ )
- {
- if( ( rank_index <= 0 && player -> level >= rank_list[ i ].level ) ||
- ( rank_index > 0 && rank_index == rank_list[ i ].index ) )
- return &( rank_list[ i ] );
- }
- return 0;
- }
- // spell_t::level_based_miss_chance ==========================================
- double spell_t::level_based_miss_chance( int8_t player,
- int8_t target )
- {
- int8_t diff = target - player;
- if( diff <= -3 ) return 0.01;
- if( diff == -2 ) return 0.02;
- if( diff == -1 ) return 0.03;
- if( diff == 0 ) return 0.04;
- if( diff == +1 ) return 0.05;
- if( diff == +2 ) return 0.06;
- if( diff == +3 ) return 0.17;
- if( diff == +4 ) return 0.28;
- if( diff == +5 ) return 0.39;
- if( diff == +6 ) return 0.50;
- if( diff == +7 ) return 0.61;
- if( diff == +8 ) return 0.72;
- if( diff == +9 ) return 0.83;
- return 0.94;
- }
- // spell_t::cast_time ========================================================
- double spell_t::cast_time()
- {
- if( base_cast_time == 0 ) return 0;
- double t = base_cast_time - player -> buffs.cast_time_reduction;
- if( t < 0 ) t = 0;
- t *= player -> haste;
- if( player -> buffs.mystical_skyfire ) t *= 0.5;
- if( player -> buffs.bloodlust ) t *= 0.7;
- report_t::debug( sim, "spell_t::cast_time: %s %.1f", name(), t );
- return t;
- }
- // spell_t::duration =========================================================
- double spell_t::duration()
- {
- double t = base_duration;
- if( channeled )
- {
- t *= player -> haste;
- if( player -> buffs.mystical_skyfire ) t *= 0.5;
- if( player -> buffs.bloodlust ) t *= 0.7;
- }
- report_t::debug( sim, "spell_t::duration: %s %.1f", name(), t );
- return t;
- }
- // spell_t::mana_cost ========================================================
- double spell_t::mana_cost()
- {
- double m = base_mana_cost - player -> buffs.mana_cost_reduction;
- if( m < 0 ) m = 0;
- report_t::debug( sim, "spell_t::mana_cost: %s %.0f", name(), m );
- return m;
- }
- // spell_t::player_buff ======================================================
- void spell_t::player_buff()
- {
- // This is for temporary buffs only. Permanent buffs are handled in spell constructor.
- player_t* p = player;
- player_multiplier = 1.0;
- player_hit_adder = p -> hit_adder;
- player_crit_adder = p -> crit_adder;
- player_dmg_bonus = p -> dmg_bonus[ SPELL_SCHOOL_MAX ] + p -> dmg_bonus[ school ];
- player_penetration = p -> penetration;
- if( p -> buffs.power_infusion ) player_multiplier *= 1.20;
- if( p -> buffs.moonkin_aura ) player_crit_adder += 0.05;
- if( p -> buffs.totem_of_wrath )
- {
- player_hit_adder += 0.03;
- player_crit_adder += 0.03;
- }
- player_dmg_bonus += p -> buffs.wrath_of_air;
- if( school == SCHOOL_HOLY )
- {
- if( p -> buffs.sanctity_aura ) player_multiplier *= 1.12;
- }
- // Despite the 3% number on the tool-tip, this is the current mechanics.
- player_crit_bonus = ( p -> gear.chaotic_skyfire ) ? 1.09 : 1.0;
- report_t::debug( sim, "spell_t::player_buff: %s hit=%.2f crit=%.2f dmg_bonus=%.2f",
- name(), player_hit_adder, player_crit_adder, player_dmg_bonus );
- }
- // spell_t::target_debuff =====================================================
- void spell_t::target_debuff()
- {
- target_t* t = sim -> target;
- target_multiplier = 1.0;
- target_hit_adder = 0;
- target_crit_adder = 0;
- target_dmg_bonus = 0;
- target_resistance = t -> resistance[ school ];
- if( school == SCHOOL_SHADOW )
- {
- target_multiplier *= 1.0 + ( t -> debuffs.curse_of_shadows * 0.01 );
- target_multiplier *= 1.0 + ( t -> debuffs.shadow_weaving * 0.01 );
- if( t -> debuffs.shadow_vulnerability )
- {
- target_multiplier *= 1.20;
- sim -> isb_up++;
- }
- else sim -> isb_down++;
- if( t -> debuffs.curse_of_shadows ) target_resistance -= 88;
- }
- else if( school == SCHOOL_ARCANE )
- {
- target_multiplier *= 1.0 + ( t -> debuffs.curse_of_shadows * 0.01 );
- if( t -> debuffs.curse_of_shadows ) target_resistance -= 88;
- }
- else if( school == SCHOOL_FROST )
- {
- target_multiplier *= 1.0 + ( t -> debuffs.curse_of_elements * 0.01 );
- target_crit_adder += ( t -> debuffs.winters_chill * 0.01 );
- }
- else if( school == SCHOOL_FIRE )
- {
- target_multiplier *= 1.0 + ( t -> debuffs.curse_of_elements * 0.01 );
- target_multiplier *= 1.0 + ( t -> debuffs.fire_vulnerability * 0.01 );
- }
- else if( school == SCHOOL_HOLY )
- {
- if( t -> debuffs.judgement_of_crusader ) target_dmg_bonus += 218;
- }
- target_multiplier *= 1.0 + ( t -> debuffs.misery * 0.01 );
- report_t::debug( sim, "spell_t::target_debuff: %s multiplier=%.2f hit=%.2f crit=%.2f dmg_bonus=%.2f %.0f",
- name(), target_multiplier, target_hit_adder, target_crit_adder, target_dmg_bonus, target_resistance );
- }
- // spell_t::resistance =======================================================
- double spell_t::resistance( bool resist_binary )
- {
- double resist_rating = target_resistance - base_penetration - player_penetration;
- if( resist_rating < 0 ) resist_rating = 0;
- if( ! resist_binary && sim -> target -> level > player -> level )
- {
- double min_rating = 8 * ( sim -> target -> level - player -> level );
- if( resist_rating < min_rating ) resist_rating = min_rating;
- }
- return ( resist_rating / ( player -> level * 5.0 ) );
- }
- // spell_t::cast =============================================================
- bool spell_t::cast()
- {
- report_t::log( sim, "Player %s casts spell %s", player -> name(), name() );
- resist = false;
- hit = false;
- crit = false;
- player_t* p = player;
- target_t* t = sim -> target;
- report_t::debug( sim, "spell_t::cast: %s multiplier=%.2f hit=%.2f crit=%.2f",
- name(), base_multiplier, base_hit_adder, base_crit_adder );
- player_buff();
- target_debuff();
- p -> mana_loss( mana_cost() );
- double resist_multiplier = 1.0;
- if( hit_on_cast )
- {
- double miss_chance = level_based_miss_chance( p -> level, t -> level );
- miss_chance -= ( base_hit_adder + player_hit_adder + target_hit_adder );
- if( wow_random( std::max( miss_chance, (double) 0.01 ) ) )
- {
- resist = true;
- resist_callback();
- return false;
- }
- bool resist_binary = binary || num_ticks;
- double resist_chance = resistance( resist_binary );
- if( resist_binary )
- {
- if( wow_random( resist_chance ) )
- {
- resist = true;
- resist_callback();
- return false;
- }
- }
- else resist_multiplier = 1.0 - resist_chance;
- hit = true;
- }
- double dmg_bonus = player_dmg_bonus + target_dmg_bonus;
- if( base_dd < 0 ) base_dd = average_dd();
- if( base_dd > 0 )
- {
- double dmg_multiplier = base_multiplier * player_multiplier * target_multiplier * resist_multiplier;
- dd = ( base_dd + dd_dmg_bonus_mod * dmg_bonus ) * dmg_multiplier;
- if( may_crit )
- {
- double crit_chance = base_crit_adder + player_crit_adder + target_crit_adder;
- if( wow_random( crit_chance ) )
- {
- double bonus = crit_bonus * player_crit_bonus;
- dd *= ( 1.0 + bonus );
- crit = true;
- crit_callback();
- }
- }
- assess_damage( dd, DMG_DIRECT );
- }
- if( base_dot < 0 ) base_dot = rank -> dot;
- if( base_dot > 0 )
- {
- double dmg_multiplier = base_multiplier * player_multiplier;
- dot = ( base_dot + dot_dmg_bonus_mod * dmg_bonus ) * dmg_multiplier;
- }
- cast_callback();
- return true;
- }
- // spell_t::tick =============================================================
- void spell_t::tick()
- {
- report_t::trace( sim, "Spell %s ticks (%d)", name(), current_tick() );
- resist = false;
- hit = false;
- crit = false;
- if( dot > 0 )
- {
- target_debuff();
- if( ! hit_on_cast )
- {
- double miss_chance = level_based_miss_chance( player -> level, sim -> target -> level );
- miss_chance -= ( base_hit_adder + player_hit_adder + target_hit_adder );
- if( wow_random( std::max( miss_chance, (double) 0.01 ) ) )
- {
- resist = true;
- resist_callback();
- return;
- }
- hit = true;
- }
- dot_tick = ( dot / num_ticks ) * target_multiplier;
- if( ! binary ) dot_tick *= ( 1.0 - resistance( false ) );
- if( may_crit && channeled )
- {
- double crit_chance = ( base_crit_adder + player_crit_adder + target_crit_adder );
- if( wow_random( crit_chance ) )
- {
- double bonus = crit_bonus * player_crit_bonus;
- dot_tick *= ( 1.0 + bonus );
- crit = true;
- crit_callback();
- }
- }
- assess_damage( dot_tick, DMG_TICK );
- }
- tick_callback();
- }
- // spell_t::assess_damage ====================================================
- void spell_t::assess_damage( double amount,
- int8_t dmg_type )
- {
- report_t::log( sim, "%s 's %s %shits %s for %.0f %s damage",
- player -> name(), name(),
- crit ? "critically " : "",
- sim -> target -> name(), amount,
- wow_spell_school_string( school ) );
- player -> sim -> target -> assess_damage( amount, school, dmg_type );
- stats -> add( amount, dmg_type, crit );
- }
- // spell_t::ready ============================================================
- bool spell_t::ready()
- {
- if( dot_ready > sim -> current_time + cast_time() )
- return false;
- if( cooldown_ready > sim -> current_time )
- return false;
- if( mana_cost() > player -> mana )
- return false;
- return true;
- }
- // spell_t::start_callback ==================================================
- void spell_t::start_callback()
- {
- report_t::trace( sim, "Player %s starts casting %s %.2f", player -> name(), name(), cast_time() );
- stats -> total_casts++;
- }
- // spell_t::cast_callback ===================================================
- void spell_t::cast_callback()
- {
- player_t* p = player;
- report_t::debug( sim, "Player %s: spell_t::cast_callback", p -> name() );
- if( mana_cost() > 0 ) p -> last_cast = sim -> current_time;
- if( cooldown > 0 )
- {
- p -> share_cooldown( cooldown_group, cooldown );
- }
- if( num_ticks > 0 )
- {
- if( ! channeled )
- {
- // Cannot stack multiple DoTs of the same name on the same target.
- dot_ready = sim -> current_time + duration() + 0.01;
- p -> share_dot( this );
- }
- new spell_tick_event_t( sim, this, 0 );
- }
- trinket_t::trigger_talisman_of_ascendance( this );
- trinket_t::trigger_zandalarian_hero_charm( this );
- trinket_t::clear_mystical_skyfire( this );
- enchant_t::trigger_spellsurge( this );
- if( hit ) hit_callback();
- }
- // spell_t::tick_callback ===================================================
- void spell_t::tick_callback()
- {
- player_t* p = player;
- report_t::debug( sim, "Player %s: spell_t::tick_callback", p -> name() );
- stats -> total_ticks++;
- trinket_t::trigger_darkmoon_wrath( this );
- if( hit ) hit_callback();
- }
- // spell_t::hit_callback ====================================================
- void spell_t::hit_callback()
- {
- player_t* p = player;
- report_t::debug( sim, "Player %s: spell_t::hit_callback", p -> name() );
- if( harmful() )
- {
- if( sim -> target -> debuffs.judgement_of_wisdom )
- {
- if( wow_random( 0.50 ) ) p -> mana_gain( 74, "jow" );
- }
- }
- trinket_t::trigger_darkmoon_crusade ( this );
- trinket_t::trigger_darkmoon_wrath ( this );
- trinket_t::trigger_elder_scribes ( this );
- trinket_t::trigger_eternal_sage ( this );
- trinket_t::trigger_mark_of_defiance ( this );
- trinket_t::trigger_mystical_skyfire ( this );
- trinket_t::trigger_quagmirrans_eye ( this );
- trinket_t::trigger_spellstrike ( this );
- trinket_t::trigger_violet_eye ( this );
- trinket_t::trigger_wrath_of_cenarius( this );
- }
- // spell_t::crit_callback ===================================================
- void spell_t::crit_callback()
- {
- report_t::debug( sim, "Player %s: spell_t::crit_callback", player -> name() );
- trinket_t::clear_darkmoon_wrath( this );
- trinket_t::trigger_lightning_capacitor ( this );
- trinket_t::trigger_sextant_of_unstable_currents( this );
- trinket_t::trigger_shiffars_nexus_horn ( this );
- }
- // spell_t::resist_callback ==================================================
- void spell_t::resist_callback()
- {
- report_t::trace( sim, "Player %s spell %s is resisted", player -> name(), name() );
- if( mana_cost() > 0 ) player -> last_cast = sim -> current_time;
- if( cooldown > 0 )
- {
- player -> share_cooldown( cooldown_group, cooldown );
- }
- trinket_t::clear_mystical_skyfire( this );
- trinket_t::trigger_eye_of_magtheridon( this );
- }
- // spell_t::reset ============================================================
- void spell_t::reset()
- {
- report_t::debug( sim, "spell_t::reset: %s", name() );
- ticks_remaining = 0;
- cooldown_ready = 0;
- dot_ready = 0;
- }
- // spell_t::average_dd =======================================================
- double spell_t::average_dd()
- {
- if( sim -> average_dmg )
- {
- return ( rank -> dd_min + rank -> dd_max ) / 2.0;
- }
- else
- {
- double delta = rank -> dd_max - rank -> dd_min;
- return rank -> dd_min + delta * wow_random();
- }
- }
- // spell_t::name =============================================================
- const char* spell_t::chained_name()
- {
- if( ! chained_spell ) return name_str.c_str();
- static std::string buffer;
- buffer = chained_spell -> name_str + "-" + name_str;
- return buffer.c_str();
- }
- // ==========================================================================
- // spell_t::create_spell
- // ==========================================================================
- spell_t* spell_t::create_spell( player_t* p,
- const std::string& name,
- const std::string& options )
- {
- report_t::debug( p -> sim, "spell_t::create_spell: %s %s %s", p -> name(), name.c_str(), options.c_str() );
- spell_t* s = trinket_t::create_spell( p, name, options );
- if( ! s ) s = consumable_t::create_spell( p, name, options );
- if( ! s )
- {
- switch( p -> type )
- {
- case DRUID: s = druid_spell_t::create_spell( p, name, options ); break;
- case MAGE: s = mage_spell_t::create_spell( p, name, options ); break;
- case PRIEST: s = priest_spell_t::create_spell( p, name, options ); break;
- case SHAMAN: s = shaman_spell_t::create_spell( p, name, options ); break;
- case WARLOCK: s = warlock_spell_t::create_spell( p, name, options ); break;
- }
- }
- return s;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement