Advertisement
Guest User

RaidSim Spell.cpp

a guest
Sep 14th, 2016
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.31 KB | None | 0 0
  1. // ==========================================================================
  2. // Dedmonwakeen's DPS-DPM Simulator.
  3. // Send questions to natehieter@gmail.com
  4. // ==========================================================================
  5.  
  6. #include <time.h>
  7. #include <wow_sim.h>
  8.  
  9. // ==========================================================================
  10. // Spell
  11. // ==========================================================================
  12.  
  13. // spell_t::spell_t ==========================================================
  14.  
  15. spell_t::spell_t( player_t*          p,
  16.                   const std::string& n,
  17.                   int8_t             s,
  18.                   int8_t             t ) :
  19.   sim(p->sim), player(p), name_str(n), next(0), chained_spell(0),
  20.   type(p->type), school(s), tree(t), rank_index(0), rank(0),
  21.   base_dd(-1), dd(0), dd_dmg_bonus_mod(0),
  22.   base_dot(-1), dot(0), dot_tick(0), dot_dmg_bonus_mod(0),
  23.   base_multiplier(1.0), base_hit_adder(0), base_crit_adder(0), crit_bonus(0.50), base_penetration(0),
  24.   base_cast_time(0), base_duration(0), base_mana_cost(0),
  25.   cooldown(0), cooldown_group(n), cooldown_ready(0), dot_ready(0),
  26.   num_ticks(0), ticks_remaining(0),
  27.   channeled(false), may_crit(false), binary(false), aoe(false),
  28.   trigger_gcd(true), may_cast(true), hit_on_cast(true),
  29.   hit(false), crit(false), resist(false),
  30.   event(0), stats(0)
  31. {
  32.   report_t::trace( sim, "Player %s creates spell %s", p -> name(), name() );
  33.   spell_t** last = &( p -> spell_list );
  34.   while( *last ) last = &( (*last) -> next );
  35.   *last = this;
  36.   stats = new spell_stats_t( this );
  37. }  
  38.  
  39. // spell_t::parse_options ====================================================
  40.  
  41. void spell_t::parse_options( option_t*          options,
  42.                  const std::string& options_str )
  43. {
  44.   if( options_str.empty()     ) return;
  45.   if( options_str.size() == 0 ) return;
  46.  
  47.   std::vector<std::string> splits;
  48.  
  49.   int size = wow_string_split( splits, options_str, "-" );
  50.  
  51.   for( int i=0; i < size; i++ )
  52.   {
  53.     static std::string n;
  54.     static std::string v;
  55.  
  56.     if( 2 != wow_string_split( splits[ i ], "_", "S S", &n, &v ) )
  57.     {
  58.       printf( "wow_spell: %s: Unexpected parameter '%s'.  Expected format: name=value\n", name(), splits[ i ].c_str() );
  59.       assert( false );
  60.     }
  61.    
  62.     if( ! option_t::parse( options, n, v ) )
  63.     {
  64.       printf( "wow_spell: %s: Unexpected parameter '%s'.\n", name(), n.c_str() );
  65.       assert( false );
  66.     }
  67.   }
  68. }
  69.  
  70. // spell_t::choose_rank ======================================================
  71.  
  72. spell_rank_t* spell_t::choose_rank( spell_rank_t* rank_list )
  73. {
  74.    for( int i=0; rank_list[ i ].level; i++ )
  75.    {
  76.      if( ( rank_index <= 0 && player -> level >= rank_list[ i ].level ) ||
  77.          ( rank_index >  0 &&      rank_index == rank_list[ i ].index  ) )
  78.        return &( rank_list[ i ] );
  79.    }
  80.  
  81.    return 0;
  82. }
  83.    
  84. // spell_t::level_based_miss_chance ==========================================
  85.  
  86. double spell_t::level_based_miss_chance( int8_t player,
  87.                                         int8_t target )
  88. {
  89.    int8_t diff = target - player;
  90.    if( diff <= -3 ) return 0.01;
  91.    if( diff == -2 ) return 0.02;
  92.    if( diff == -1 ) return 0.03;
  93.    if( diff ==  0 ) return 0.04;
  94.    if( diff == +1 ) return 0.05;
  95.    if( diff == +2 ) return 0.06;
  96.    if( diff == +3 ) return 0.17;
  97.    if( diff == +4 ) return 0.28;
  98.    if( diff == +5 ) return 0.39;
  99.    if( diff == +6 ) return 0.50;
  100.    if( diff == +7 ) return 0.61;
  101.    if( diff == +8 ) return 0.72;
  102.    if( diff == +9 ) return 0.83;
  103.    return 0.94;
  104. }
  105.  
  106. // spell_t::cast_time ========================================================
  107.  
  108. double spell_t::cast_time()
  109. {
  110.   if( base_cast_time == 0 ) return 0;
  111.   double t = base_cast_time - player -> buffs.cast_time_reduction;
  112.   if( t < 0 ) t = 0;
  113.   t *= player -> haste;
  114.   if( player -> buffs.mystical_skyfire ) t *= 0.5;
  115.   if( player -> buffs.bloodlust        ) t *= 0.7;
  116.   report_t::debug( sim, "spell_t::cast_time: %s %.1f", name(), t );
  117.   return t;
  118. }
  119.  
  120. // spell_t::duration =========================================================
  121.  
  122. double spell_t::duration()
  123. {
  124.   double t = base_duration;
  125.   if( channeled )
  126.   {
  127.     t *= player -> haste;
  128.     if( player -> buffs.mystical_skyfire ) t *= 0.5;
  129.     if( player -> buffs.bloodlust        ) t *= 0.7;
  130.   }
  131.   report_t::debug( sim, "spell_t::duration: %s %.1f", name(), t );
  132.   return t;
  133. }
  134.  
  135. // spell_t::mana_cost ========================================================
  136.  
  137. double spell_t::mana_cost()
  138. {
  139.    double m = base_mana_cost - player -> buffs.mana_cost_reduction;
  140.    if( m < 0 ) m = 0;
  141.    report_t::debug( sim, "spell_t::mana_cost: %s %.0f", name(), m );
  142.    return m;
  143. }
  144.    
  145. // spell_t::player_buff ======================================================
  146.  
  147. void spell_t::player_buff()
  148. {
  149.   // This is for temporary buffs only.  Permanent buffs are handled in spell constructor.
  150.  
  151.    player_t* p = player;
  152.  
  153.    player_multiplier = 1.0;
  154.    player_hit_adder   = p -> hit_adder;
  155.    player_crit_adder  = p -> crit_adder;
  156.    player_dmg_bonus   = p -> dmg_bonus[ SPELL_SCHOOL_MAX ] + p -> dmg_bonus[ school ];
  157.    player_penetration = p -> penetration;
  158.    
  159.    if( p -> buffs.power_infusion ) player_multiplier *= 1.20;
  160.    if( p -> buffs.moonkin_aura   ) player_crit_adder += 0.05;
  161.    if( p -> buffs.totem_of_wrath )
  162.    {
  163.      player_hit_adder  += 0.03;
  164.      player_crit_adder += 0.03;
  165.    }
  166.    player_dmg_bonus += p -> buffs.wrath_of_air;
  167.  
  168.    if( school == SCHOOL_HOLY )
  169.    {
  170.      if( p -> buffs.sanctity_aura ) player_multiplier *= 1.12;
  171.    }
  172.  
  173.    // Despite the 3% number on the tool-tip, this is the current mechanics.
  174.    player_crit_bonus = ( p -> gear.chaotic_skyfire ) ? 1.09 : 1.0;
  175.  
  176.    report_t::debug( sim, "spell_t::player_buff: %s hit=%.2f crit=%.2f dmg_bonus=%.2f",
  177.             name(), player_hit_adder, player_crit_adder, player_dmg_bonus );
  178. }
  179.  
  180. // spell_t::target_debuff =====================================================
  181.  
  182. void spell_t::target_debuff()
  183. {
  184.    target_t* t = sim -> target;
  185.    
  186.    target_multiplier = 1.0;
  187.    target_hit_adder  = 0;
  188.    target_crit_adder = 0;
  189.    target_dmg_bonus  = 0;
  190.    target_resistance = t -> resistance[ school ];
  191.  
  192.    if( school == SCHOOL_SHADOW )
  193.    {
  194.       target_multiplier *= 1.0 + ( t -> debuffs.curse_of_shadows * 0.01 );
  195.       target_multiplier *= 1.0 + ( t -> debuffs.shadow_weaving   * 0.01 );
  196.       if( t -> debuffs.shadow_vulnerability )
  197.       {
  198.     target_multiplier *= 1.20;
  199.     sim -> isb_up++;
  200.       }
  201.       else sim -> isb_down++;
  202.       if( t -> debuffs.curse_of_shadows ) target_resistance -= 88;
  203.    }
  204.    else if( school == SCHOOL_ARCANE )
  205.    {
  206.       target_multiplier *= 1.0 + ( t -> debuffs.curse_of_shadows * 0.01 );      
  207.       if( t -> debuffs.curse_of_shadows ) target_resistance -= 88;
  208.    }
  209.    else if( school == SCHOOL_FROST )
  210.    {
  211.       target_multiplier *= 1.0 + ( t -> debuffs.curse_of_elements * 0.01 );
  212.       target_crit_adder += ( t -> debuffs.winters_chill  * 0.01 );
  213.    }
  214.    else if( school == SCHOOL_FIRE )
  215.    {
  216.       target_multiplier *= 1.0 + ( t -> debuffs.curse_of_elements  * 0.01 );
  217.       target_multiplier *= 1.0 + ( t -> debuffs.fire_vulnerability * 0.01 );
  218.    }
  219.    else if( school == SCHOOL_HOLY )
  220.    {
  221.      if( t -> debuffs.judgement_of_crusader ) target_dmg_bonus += 218;
  222.    }      
  223.    target_multiplier *= 1.0 + ( t -> debuffs.misery * 0.01 );
  224.  
  225.    report_t::debug( sim, "spell_t::target_debuff: %s multiplier=%.2f hit=%.2f crit=%.2f dmg_bonus=%.2f %.0f",
  226.             name(), target_multiplier, target_hit_adder, target_crit_adder, target_dmg_bonus, target_resistance );
  227. }
  228.    
  229. // spell_t::resistance =======================================================
  230.  
  231. double spell_t::resistance( bool resist_binary )
  232. {
  233.   double resist_rating = target_resistance - base_penetration - player_penetration;
  234.  
  235.   if( resist_rating < 0 ) resist_rating = 0;
  236.  
  237.   if( ! resist_binary && sim -> target -> level > player -> level )
  238.   {
  239.     double min_rating = 8 * ( sim -> target -> level - player -> level );
  240.     if( resist_rating < min_rating ) resist_rating = min_rating;
  241.   }
  242.  
  243.   return ( resist_rating / ( player -> level * 5.0 ) );
  244. }
  245.  
  246. // spell_t::cast =============================================================
  247.  
  248. bool spell_t::cast()
  249. {
  250.   report_t::log( sim, "Player %s casts spell %s", player -> name(), name() );
  251.  
  252.   resist = false;
  253.   hit    = false;
  254.   crit   = false;
  255.  
  256.   player_t* p = player;
  257.   target_t* t = sim -> target;
  258.  
  259.   report_t::debug( sim, "spell_t::cast: %s multiplier=%.2f hit=%.2f crit=%.2f",
  260.            name(), base_multiplier, base_hit_adder, base_crit_adder );
  261.  
  262.   player_buff();
  263.   target_debuff();
  264.      
  265.   p -> mana_loss( mana_cost() );
  266.  
  267.   double resist_multiplier = 1.0;
  268.  
  269.   if( hit_on_cast )
  270.   {
  271.     double miss_chance = level_based_miss_chance( p -> level, t -> level );
  272.     miss_chance -= ( base_hit_adder + player_hit_adder + target_hit_adder );
  273.     if( wow_random( std::max( miss_chance, (double) 0.01 ) ) )
  274.     {
  275.       resist = true;
  276.       resist_callback();
  277.       return false;
  278.     }
  279.  
  280.     bool   resist_binary = binary || num_ticks;
  281.     double resist_chance = resistance( resist_binary );
  282.  
  283.     if( resist_binary )
  284.     {
  285.       if( wow_random( resist_chance ) )
  286.       {
  287.     resist = true;
  288.     resist_callback();
  289.     return false;
  290.       }
  291.     }
  292.     else resist_multiplier = 1.0 - resist_chance;
  293.  
  294.     hit = true;
  295.   }
  296.  
  297.   double dmg_bonus = player_dmg_bonus + target_dmg_bonus;
  298.    
  299.   if( base_dd < 0 ) base_dd = average_dd();
  300.   if( base_dd > 0 )
  301.   {      
  302.     double dmg_multiplier = base_multiplier * player_multiplier * target_multiplier * resist_multiplier;
  303.  
  304.     dd = ( base_dd + dd_dmg_bonus_mod * dmg_bonus ) * dmg_multiplier;
  305.  
  306.     if( may_crit )
  307.     {
  308.       double crit_chance = base_crit_adder + player_crit_adder + target_crit_adder;
  309.       if( wow_random( crit_chance ) )
  310.       {
  311.     double bonus = crit_bonus * player_crit_bonus;
  312.     dd *= ( 1.0 + bonus );
  313.     crit = true;
  314.     crit_callback();
  315.       }          
  316.     }
  317.     assess_damage( dd, DMG_DIRECT );
  318.   }
  319.  
  320.   if( base_dot < 0 ) base_dot = rank -> dot;
  321.   if( base_dot > 0 )
  322.   {
  323.     double dmg_multiplier = base_multiplier * player_multiplier;        
  324.     dot = ( base_dot + dot_dmg_bonus_mod * dmg_bonus ) * dmg_multiplier;
  325.   }
  326.  
  327.   cast_callback();
  328.  
  329.   return true;
  330. }
  331.    
  332. // spell_t::tick =============================================================
  333.  
  334. void spell_t::tick()
  335. {
  336.   report_t::trace( sim, "Spell %s ticks (%d)", name(), current_tick() );
  337.  
  338.   resist = false;
  339.   hit    = false;
  340.   crit   = false;
  341.  
  342.   if( dot > 0 )
  343.   {
  344.     target_debuff();
  345.      
  346.     if( ! hit_on_cast )
  347.     {
  348.       double miss_chance = level_based_miss_chance( player -> level, sim -> target -> level );
  349.       miss_chance -= ( base_hit_adder + player_hit_adder + target_hit_adder );
  350.       if( wow_random( std::max( miss_chance, (double) 0.01 ) ) )
  351.       {
  352.     resist = true;
  353.     resist_callback();
  354.     return;
  355.       }
  356.  
  357.       hit = true;
  358.     }
  359.  
  360.     dot_tick = ( dot / num_ticks ) * target_multiplier;
  361.      
  362.     if( ! binary ) dot_tick *= ( 1.0 - resistance( false ) );
  363.  
  364.     if( may_crit && channeled )
  365.     {
  366.       double crit_chance = ( base_crit_adder + player_crit_adder + target_crit_adder );
  367.       if( wow_random( crit_chance ) )
  368.       {
  369.     double bonus = crit_bonus * player_crit_bonus;
  370.     dot_tick *= ( 1.0 + bonus );
  371.     crit = true;
  372.     crit_callback();
  373.       }    
  374.     }
  375.     assess_damage( dot_tick, DMG_TICK );
  376.   }
  377.  
  378.   tick_callback();
  379. }  
  380.  
  381. // spell_t::assess_damage ====================================================
  382.  
  383. void spell_t::assess_damage( double  amount,
  384.                              int8_t dmg_type )
  385. {
  386.    report_t::log( sim, "%s 's %s %shits %s for %.0f %s damage",
  387.           player -> name(), name(),
  388.           crit ? "critically " : "",
  389.           sim -> target -> name(), amount,
  390.           wow_spell_school_string( school ) );
  391.  
  392.    player -> sim -> target -> assess_damage( amount, school, dmg_type );
  393.  
  394.    stats -> add( amount, dmg_type, crit );
  395. }
  396.  
  397. // spell_t::ready ============================================================
  398.  
  399. bool spell_t::ready()
  400. {
  401.   if( dot_ready > sim -> current_time + cast_time() )
  402.     return false;
  403.  
  404.   if( cooldown_ready > sim -> current_time )
  405.     return false;
  406.  
  407.   if( mana_cost() > player -> mana )
  408.     return false;
  409.  
  410.   return true;
  411. }
  412.  
  413. // spell_t::start_callback ==================================================
  414.  
  415. void spell_t::start_callback()
  416. {
  417.   report_t::trace( sim, "Player %s starts casting %s %.2f", player -> name(), name(), cast_time() );
  418.  
  419.   stats -> total_casts++;
  420. }
  421.  
  422. // spell_t::cast_callback ===================================================
  423.  
  424. void spell_t::cast_callback()
  425. {
  426.   player_t* p = player;
  427.  
  428.   report_t::debug( sim, "Player %s: spell_t::cast_callback", p -> name() );
  429.  
  430.   if( mana_cost() > 0 ) p -> last_cast = sim -> current_time;
  431.  
  432.   if( cooldown > 0 )
  433.   {
  434.     p -> share_cooldown( cooldown_group, cooldown );
  435.   }
  436.  
  437.   if( num_ticks > 0 )
  438.   {
  439.     if( ! channeled )
  440.     {
  441.       // Cannot stack multiple DoTs of the same name on the same target.
  442.       dot_ready = sim -> current_time + duration() + 0.01;
  443.       p -> share_dot( this );
  444.     }
  445.     new spell_tick_event_t( sim, this, 0 );
  446.   }
  447.  
  448.   trinket_t::trigger_talisman_of_ascendance( this );
  449.   trinket_t::trigger_zandalarian_hero_charm( this );
  450.  
  451.   trinket_t::clear_mystical_skyfire( this );
  452.  
  453.   enchant_t::trigger_spellsurge( this );
  454.  
  455.   if( hit ) hit_callback();
  456. }
  457.  
  458. // spell_t::tick_callback ===================================================
  459.  
  460. void spell_t::tick_callback()
  461. {
  462.   player_t* p = player;
  463.  
  464.   report_t::debug( sim, "Player %s: spell_t::tick_callback", p -> name() );
  465.  
  466.   stats -> total_ticks++;
  467.  
  468.   trinket_t::trigger_darkmoon_wrath( this );
  469.  
  470.   if( hit ) hit_callback();
  471. }
  472.  
  473. // spell_t::hit_callback ====================================================
  474.  
  475. void spell_t::hit_callback()
  476. {
  477.   player_t* p = player;
  478.  
  479.   report_t::debug( sim, "Player %s: spell_t::hit_callback", p -> name() );
  480.  
  481.   if( harmful() )
  482.   {
  483.     if( sim -> target -> debuffs.judgement_of_wisdom )
  484.     {
  485.       if( wow_random( 0.50 ) ) p -> mana_gain( 74, "jow" );
  486.     }
  487.   }
  488.    
  489.   trinket_t::trigger_darkmoon_crusade ( this );
  490.   trinket_t::trigger_darkmoon_wrath   ( this );
  491.   trinket_t::trigger_elder_scribes    ( this );
  492.   trinket_t::trigger_eternal_sage     ( this );
  493.   trinket_t::trigger_mark_of_defiance ( this );
  494.   trinket_t::trigger_mystical_skyfire ( this );
  495.   trinket_t::trigger_quagmirrans_eye  ( this );
  496.   trinket_t::trigger_spellstrike      ( this );
  497.   trinket_t::trigger_violet_eye       ( this );
  498.   trinket_t::trigger_wrath_of_cenarius( this );
  499.  
  500. }
  501.  
  502. // spell_t::crit_callback ===================================================
  503.  
  504. void spell_t::crit_callback()
  505. {
  506.   report_t::debug( sim, "Player %s: spell_t::crit_callback", player -> name() );
  507.  
  508.   trinket_t::clear_darkmoon_wrath( this );
  509.  
  510.   trinket_t::trigger_lightning_capacitor         ( this );
  511.   trinket_t::trigger_sextant_of_unstable_currents( this );
  512.   trinket_t::trigger_shiffars_nexus_horn         ( this );
  513. }
  514.  
  515. // spell_t::resist_callback ==================================================
  516.  
  517. void spell_t::resist_callback()
  518. {
  519.   report_t::trace( sim, "Player %s spell %s is resisted", player -> name(), name() );
  520.  
  521.   if( mana_cost() > 0 ) player -> last_cast = sim -> current_time;
  522.  
  523.   if( cooldown > 0 )
  524.   {
  525.     player -> share_cooldown( cooldown_group, cooldown );
  526.   }
  527.  
  528.   trinket_t::clear_mystical_skyfire( this );
  529.  
  530.   trinket_t::trigger_eye_of_magtheridon( this );
  531. }
  532.  
  533. // spell_t::reset ============================================================
  534.  
  535. void spell_t::reset()
  536. {
  537.   report_t::debug( sim, "spell_t::reset: %s", name() );
  538.   ticks_remaining = 0;
  539.   cooldown_ready = 0;
  540.   dot_ready = 0;
  541. }  
  542.    
  543. // spell_t::average_dd =======================================================
  544.  
  545. double spell_t::average_dd()
  546. {
  547.   if( sim -> average_dmg )
  548.   {
  549.     return ( rank -> dd_min + rank -> dd_max ) / 2.0;
  550.   }
  551.   else
  552.   {
  553.     double delta = rank -> dd_max - rank -> dd_min;
  554.  
  555.     return rank -> dd_min + delta * wow_random();
  556.   }
  557. }
  558.  
  559. // spell_t::name =============================================================
  560.  
  561. const char* spell_t::chained_name()
  562. {
  563.   if( ! chained_spell ) return name_str.c_str();
  564.  
  565.   static std::string buffer;
  566.  
  567.   buffer = chained_spell -> name_str + "-" + name_str;
  568.  
  569.   return buffer.c_str();
  570. }
  571.  
  572. // ==========================================================================
  573. // spell_t::create_spell
  574. // ==========================================================================
  575.  
  576. spell_t* spell_t::create_spell( player_t*          p,
  577.                                 const std::string& name,
  578.                                 const std::string& options )
  579. {
  580.   report_t::debug( p -> sim, "spell_t::create_spell: %s %s %s", p -> name(), name.c_str(), options.c_str() );
  581.  
  582.   spell_t* s = trinket_t::create_spell( p, name, options );
  583.  
  584.   if( ! s ) s = consumable_t::create_spell( p, name, options );
  585.  
  586.   if( ! s )
  587.   {
  588.     switch( p -> type )
  589.     {
  590.     case DRUID:   s =   druid_spell_t::create_spell( p, name, options ); break;
  591.     case MAGE:    s =    mage_spell_t::create_spell( p, name, options ); break;
  592.     case PRIEST:  s =  priest_spell_t::create_spell( p, name, options ); break;
  593.     case SHAMAN:  s =  shaman_spell_t::create_spell( p, name, options ); break;
  594.     case WARLOCK: s = warlock_spell_t::create_spell( p, name, options ); break;
  595.     }
  596.   }
  597.  
  598.   return s;
  599. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement