using System;
using System.Linq;
using System.Collections.Generic;
public static class Consts
{
public const double eps = 0.001;
}
public class MyRotation: PaladinRotation
{
public MyRotation (bool hasDp, bool has4pc, double executionTime, double crit, double haste, int efGay)
:base (hasDp, has4pc, executionTime, crit, haste, efGay)
{
}
public override void Step()
{
// buff expires soon
if (FreeEF && FreeEF.Time <= Hasted(3))
{
CastEF();
}
else if (DP && DP.Time <= Hasted(3))
{
CastEF();
}
else if (FreeLoD && FreeLoD.Time <= Hasted(3))
{
CastLoD();
}
//capped
else if (HolyPower == 5)
{
CastEF();
}
//HS
else if (HS)
{
CastHS();
}
// buff expires soon if we wait 0.5s for HS
else if (DP && DP.Time <= Hasted(3) + 0.5)
{
CastEF();
}
else if (FreeEF && FreeEF.Time <= Hasted(3) + 0.5)
{
CastEF();
}
else if (FreeLoD && FreeLoD.Time <= Hasted(3) + 0.5)
{
CastLoD();
}
//wait 0.5s for HS
else if (HS.Time < 0.5)
{
CastNothing(HS.Time);
}
//free casts
else if (DP && DP.Time >= Hasted(1.5))
{
CastEF();
}
else if (FreeEF && FreeEF.Time >= Hasted(1.5))
{
CastEF();
}
else if (FreeLoD && FreeLoD.Time >= Hasted(1.5))
{
CastLoD();
}
//3 hp LoD
else if (HolyPower >= 3)
{
CastEF();
}
//IoL HL
else if (IoL)
{
CastHL();
}
//1-2hp EF
else if (EFGay > 0 && HolyPower >= EFGay)
{
CastEF();
}
//wait 1s for HS
else if (HS.Time < 1)
{
CastNothing(HS.Time);
}
//HL filler least priority
else
{
CastHL();
}
}
}
public class Timer
{
public Timer(List<Timer> timers, double defaultTime)
{
_defaultTime = defaultTime;
_active = false;
_time = 0;
timers.Add(this);
}
private bool _active;
private double _time;
private double _defaultTime;
public double Time
{
get
{
return _time;
}
}
protected bool Active
{
get
{
return _active;
}
}
public void Set()
{
_time = _defaultTime;
_active = true;
}
public void Reset()
{
_active = false;
_time = 0;
}
public
void Update
(double time) {
if(!_active) return;
if(_time < Consts.eps) Reset();
if (TimeoutHandler!=null) TimeoutHandler();
}
public Action TimeoutHandler;
}
public class Buff: Timer
{
public Buff
(List
<Timer
> timers
, double time): base
(timers
, time) {
}
public static implicit operator bool(Buff b)
{
return b.Active;
}
}
public class Cooldown: Timer
{
public Cooldown
(List
<Timer
> timers
, double time): base
(timers
, time) {
}
public static implicit operator bool(Cooldown cd)
{
return !cd.Active;
}
}
public class PaladinRotation
{
private List<Timer> _timers = new List<Timer>();
private double _time = 0;
private readonly double _maxTime;
protected readonly Buff FreeEF;
protected readonly Buff FreeLoD;
protected readonly Buff DoubleHS;
protected readonly Buff DP;
protected readonly Buff IoL;
protected readonly Cooldown HS;
protected int HolyPower = 0;
protected readonly bool Has4pc;
protected readonly bool HasDP;
protected readonly int EFGay;
protected readonly double Crit;
protected readonly double Haste;
protected readonly double _hasteMult;
private readonly Result _result = new Result();
public void CastHS()
{
if (!HS) throw new Exception("hs cd");
if (DoubleHS)
{
DoubleHS.Reset();
}
else
{
HS.Set();
}
if (HolyPower < 5) HolyPower++;
if (Roll(Crit * 2))
{
_result.HSCrits++;
IoL.Set();
}
AddTime(Hasted(1.5));
_result.HSCount++;
}
public void CastHL()
{
if(IoL)
{
IoL.Reset();
AddTime(Hasted(1));
if (Roll(10)) DoubleHS.Set();
AddTime(1 - Hasted(1));
_result.IoLHL++;
}
else
{
if (Roll(10)) DoubleHS.Set();
AddTime(Hasted(2.5));
}
_result.HLCount++;
}
public void CastEF()
{
if (FreeEF && FreeEF.Time >= Hasted(1.5))
{
FreeEF.Reset();
_result.EF3++;
if (HasDP && Roll(25)) DP.Set();
if (Has4pc && Roll(20)) FreeLoD.Set();
}
else if (DP && DP.Time >= Hasted(1.5))
{
DP.Reset();
_result.EF3++;
if (HasDP && Roll(25)) DP.Set();
if (Has4pc && Roll(20)) FreeLoD.Set();
}
else if (HolyPower >= 3)
{
HolyPower -= 3;
_result.EF3++;
if (HasDP && Roll(25)) DP.Set();
if (Has4pc && Roll(20)) FreeLoD.Set();
}
else if (EFGay > 0 && HolyPower >= EFGay)
{
switch(HolyPower)
{
case 1:
_result.EF1++;
if (HasDP && Roll(25/3.0)) DP.Set();
if (Has4pc && Roll(20)) FreeLoD.Set();
break;
case 2:
_result.EF2++;
if (HasDP && Roll(25*2/3.0)) DP.Set();
if (Has4pc && Roll(20)) FreeLoD.Set();
break;
default: throw new Exception("failed 1HP EF gay attempt"); break;
}
HolyPower = 0;
}
else
{
throw new Exception("1HP EF gay attempt");
}
AddTime(Hasted(1.5));
_result.EFCount++;
}
public void CastLoD()
{
if (FreeLoD && FreeLoD.Time >= Hasted(1.5))
{
FreeLoD.Reset();
}
else if (DP && DP.Time >= Hasted(1.5))
{
DP.Reset();
}
else if (HolyPower >= 3)
{
HolyPower -= 3;
}
else
{
throw new Exception("1HP LoD gay attempt");
}
AddTime(Hasted(1.5));
if (HasDP && Roll(25)) DP.Set();
if (Has4pc && Roll(25)) FreeEF.Set();
_result.LoDCount++;
}
public
void CastNothing
(double time) {
}
public bool Roll(double chance)
{
return RandomHelper.R.NextDouble() < chance / 100;
}
public
double Hasted
(double time) {
return time * _hasteMult
; }
public PaladinRotation(bool hasDp, bool has4pc, double executionTime, double crit, double haste, int efGay)
{
HasDP = hasDp;
Has4pc = has4pc;
EFGay = efGay;
_maxTime = executionTime;
Crit = crit;
Haste = haste;
_hasteMult = 1 / (1 + Haste / 100);
FreeEF = new Buff(_timers, 10);
FreeLoD = new Buff(_timers, 10);
DP = new Buff(_timers, 8);
DoubleHS = new Buff(_timers, 15);
IoL = new Buff(_timers, 15);
HS = new Cooldown(_timers, Hasted(6));
}
public
void AddTime
(double time) {
if (time <= Consts.
eps) throw new Exception
("time interval " + time.
ToString()); foreach (var timer in _timers)
{
}
_result.TotalTime = _time;
}
public virtual void Step()
{
}
public Result Execute()
{
while(_time < _maxTime) Step();
return _result;
}
}
public static class RandomHelper
{
public static void Init()
{
R = new Random();
}
public static Random R;
}
public class Result
{
public int LoDCount;
public int EFCount;
public int HSCount;
public int HLCount;
public double TotalTime;
public double WaitTime;
public int IoLHL;
public int HSCrits;
public int EF1;
public int EF2;
public int EF3;
public override string ToString()
{
return string.Format("LoD: {0}, EF: {1}, HS: {2}, HL: {3}", LoDCount, EFCount, HSCount, HLCount);
}
}
public class Test
{
public static void WriteResults(List<Result> results, double crit, double haste, double mastery)
{
var lods = results.Average(u=>u.LoDCount);
var ef1 = results.Average(u=>u.EF1);
var ef2 = results.Average(u=>u.EF2);
var ef3 = results.Average(u=>u.EF3);
var efs = ef3 + ef2*2/3.0 + ef1/3.0;
var hss = results.Average(u=>u.HSCount);
var hls = results.Average(u=>u.HLCount);
var hscrits = results.Average(u=>u.HSCrits);
var
time = results.
Average(u
=>u.
TotalTime); Console.WriteLine(string.Format("iter: {0} LoD: {1:F1}, EF: {2:F1}, HS: {3:F1}, HL: {4:F1}, IoLHL: {5:F1}, Time: {6:F2}s, Wait: {7:F2}s",
results.Count,
lods,
efs,
hss,
hls,
results.Average(u=>u.IoLHL),
results.Average(u=>u.WaitTime)
));
var mana = hss * 2352 + hls * 3300;
Console.WriteLine(string.Format("EF1: {0:F1}, EF2: {1:F1}, EF3: {2:F1}, mana: {3:F0}", ef1, ef2, ef3, mana));
var critmult = 1 + crit / 100;
var lodheal = 7398*6;
var hlheal = 25150;
var hsheal = 11736;
var efheal = 26619 + 1008*15*(1 + haste/100);
var masterymult = mastery / 100;
var healing = lods * (1 + 0.3*11/12.0 + masterymult) * critmult * lodheal +
(hss + hscrits) * (1 + 1 + masterymult) * hsheal +
hls * (1 + 1 + masterymult) * critmult * hlheal +
efs * (1 + 1 + masterymult) * critmult * efheal;
var hps
= healing
/ time; var hpm = healing / mana;
Console.WriteLine(string.Format("hps: {0:F0}, hpm: {1:F2}", hps, hpm));
}
public static void Main()
{
try
{
RandomHelper.Init();
List<Result> results1 = new List<Result>();
var crit = 25;
var haste = 25;
var mastery = 25;
Console.WriteLine ("10k iter, no DP, 4pc, 600s, 25% crit, 25% haste, no gay");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(false, true, 600, crit, haste, 0);
var result = rotation.Execute();
results1.Add(result);
}
WriteResults(results1, crit, haste, mastery);
results1 = new List<Result>();
Console.WriteLine ("10k iter, no DP, 4pc, 600s, 25% crit, 25% haste, 1hp gay");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(false, true, 600, crit, haste, 1);
var result = rotation.Execute();
results1.Add(result);
}
WriteResults(results1, crit, haste, mastery);
results1 = new List<Result>();
Console.WriteLine ("10k iter, no DP, 4pc, 600s, 25% crit, 25% haste, 2hp gay");
for (int i=0; i<10000; i++)
{
var rotation = new MyRotation(false, true, 600, crit, haste, 2);
var result = rotation.Execute();
results1.Add(result);
}
WriteResults(results1, crit, haste, mastery);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}