protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return ( a.FingersOfFrostRegistered != b.FingersOfFrostRegistered || a.LatentFingersOfFrostWindow != b.LatentFingersOfFrostWindow || (a.DeepFreezeCooldown == 0 && (a.FingersOfFrostRegistered > 0 || a.LatentFingersOfFrostWindow)) != (b.DeepFreezeCooldown == 0 && (b.FingersOfFrostRegistered > 0 || b.LatentFingersOfFrostWindow)) || (!Tier10TwoPieceCollapsed && (a.Tier10TwoPieceDuration != b.Tier10TwoPieceDuration)) || a.BrainFreezeRegistered != b.BrainFreezeRegistered); }
protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return ( a.FingersOfFrostRegistered != b.FingersOfFrostRegistered || a.LatentFingersOfFrostWindow != b.LatentFingersOfFrostWindow || a.DeepFreezeCooldown != b.DeepFreezeCooldown || a.BrainFreezeRegistered != b.BrainFreezeRegistered); }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell FrB = null; Spell IL = null; Spell FB = null; Spell DF = null; int t10 = s.Tier10TwoPieceDuration > 0 ? 1 : 0; if (s.FingersOfFrostActual > 0) { FrB = this.FrB[1, t10]; } else { FrB = this.FrB[0, t10]; } if (s.FingersOfFrostActual > 0 || (useLatencyCombos && s.LatentFingersOfFrostWindow)) { IL = this.IL[1, t10]; FB = this.FB[1, t10]; } else { IL = this.IL[0, t10]; FB = this.FB[0, t10]; } if (s.DeepFreezeCooldown == 0.0f && (s.FingersOfFrostRegistered > 0 || (useLatencyCombos && s.LatentFingersOfFrostWindow))) { DF = this.DF[1, t10]; } if (FOF > 0 && BF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, true, Math.Max(0, s.FingersOfFrostActual - 1), 2, s.FingersOfFrostActual > 0, Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.Tier10TwoPieceDuration - FrB.CastTime) ), TransitionProbability = FOF * BF }); } if (FOF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, s.FingersOfFrostActual - 1), 2, s.FingersOfFrostActual > 0, Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.Tier10TwoPieceDuration - FrB.CastTime) ), TransitionProbability = FOF * (1 - BF) }); } if (BF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, true, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 0, Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.Tier10TwoPieceDuration - FrB.CastTime) ), TransitionProbability = (1 - FOF) * BF }); } list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 0, Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.Tier10TwoPieceDuration - FrB.CastTime) ), TransitionProbability = (1 - FOF) * (1 - BF) }); if (!fofInstantsOnLastChargeOnly || !(s.FingersOfFrostRegistered > 0) || (useLatencyCombos && s.LatentFingersOfFrostWindow && s.FingersOfFrostRegistered == 0) || (!useLatencyCombos && s.FingersOfFrostRegistered == 1)) { if (s.FingersOfFrostRegistered > 0 || (useLatencyCombos && s.LatentFingersOfFrostWindow)) { list.Add(new CycleControlledStateTransition() { Spell = IL, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, Math.Max(0, s.DeepFreezeCooldown - IL.CastTime), Math.Max(0, s.Tier10TwoPieceDuration - IL.CastTime) ), TransitionProbability = 1 }); } if (s.BrainFreezeRegistered) { if (ffbBrainFreeze) { // T8 not supported for FFB mode if (FOF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( false, false, Math.Max(0, s.FingersOfFrostActual - 1), 2, s.FingersOfFrostActual > 1, Math.Max(0, s.DeepFreezeCooldown - FB.CastTime), Math.Max(0, T10 ? 5.0f - FB.CastTime : s.Tier10TwoPieceDuration - FB.CastTime) ), TransitionProbability = FOF }); } list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( false, false, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, Math.Max(0, s.DeepFreezeCooldown - FB.CastTime), Math.Max(0, T10 ? 5.0f - FB.CastTime : s.Tier10TwoPieceDuration - FB.CastTime) ), TransitionProbability = 1 - FOF }); } else { if (T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( true, true, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, Math.Max(0, s.DeepFreezeCooldown - FB.CastTime), Math.Max(0, T10 ? 5.0f - FB.CastTime : s.Tier10TwoPieceDuration - FB.CastTime) ), TransitionProbability = T8 }); } list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( false, false, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, Math.Max(0, s.DeepFreezeCooldown - FB.CastTime), Math.Max(0, T10 ? 5.0f - FB.CastTime : s.Tier10TwoPieceDuration - FB.CastTime) ), TransitionProbability = 1 - T8 }); } } if (DF != null && deepFreeze) { list.Add(new CycleControlledStateTransition() { Spell = DF, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, Math.Max(0, deepFreezeCooldown - DF.CastTime), Math.Max(0, s.Tier10TwoPieceDuration - DF.CastTime) ), TransitionProbability = 1 }); } } return list; }
protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return (a.ScorchDuration != b.ScorchDuration || a.LivingBombDuration != b.LivingBombDuration || a.HotStreakCount != b.HotStreakCount || a.PyroDuration != b.PyroDuration || a.PyroRegistered != b.PyroRegistered || a.Tier10TwoPieceDuration != b.Tier10TwoPieceDuration); }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell FrB = null; Spell IL = null; Spell FB = null; Spell DF = null; if (s.FingersOfFrostActual > 0) { FrB = this.FrBS; } else { FrB = this.FrB; } if (s.FingersOfFrostActual > 0 || (useLatencyCombos && s.LatentFingersOfFrostWindow)) { IL = this.ILS; FB = this.FBS; } else { IL = this.IL; FB = this.FB; } if (!s.DeepFreezeCooldown && (s.FingersOfFrostRegistered > 0 || (useLatencyCombos && s.LatentFingersOfFrostWindow))) { DF = this.DFS; } if (FOF > 0 && BF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeDuration > FrB.CastTime, 15.0f, Math.Max(0, s.FingersOfFrostActual - 1), 2, s.FingersOfFrostActual > 0, s.DeepFreezeCooldown && s.FingersOfFrostActual > 0 ), TransitionProbability = FOF * BF }); } if (FOF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeDuration > FrB.CastTime, Math.Max(0.0f, s.BrainFreezeDuration - FrB.CastTime), Math.Max(0, s.FingersOfFrostActual - 1), 2, s.FingersOfFrostActual > 0, s.DeepFreezeCooldown && s.FingersOfFrostActual > 0 ), TransitionProbability = FOF * (1 - BF) }); } if (BF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeDuration > FrB.CastTime, 15.0f, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 0, s.DeepFreezeCooldown && s.FingersOfFrostActual > 0 ), TransitionProbability = (1 - FOF) * BF }); } list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeDuration > FrB.CastTime, Math.Max(0.0f, s.BrainFreezeDuration - FrB.CastTime), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 0, s.DeepFreezeCooldown && s.FingersOfFrostActual > 0 ), TransitionProbability = (1 - FOF) * (1 - BF) }); list.Add(new CycleControlledStateTransition() { Spell = IL, TargetState = GetState( s.BrainFreezeDuration > IL.CastTime, Math.Max(0.0f, s.BrainFreezeDuration - IL.CastTime), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, s.DeepFreezeCooldown && s.FingersOfFrostActual > 1 ), TransitionProbability = 1 }); if (s.BrainFreezeRegistered) { if (T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( s.BrainFreezeDuration > FB.CastTime, Math.Max(0.0f, s.BrainFreezeDuration - FB.CastTime), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, s.DeepFreezeCooldown && s.FingersOfFrostActual > 1 ), TransitionProbability = T8 }); } list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( false, 0.0f, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, s.DeepFreezeCooldown && s.FingersOfFrostActual > 1 ), TransitionProbability = 1 - T8 }); } if (DF != null && deepFreeze) { list.Add(new CycleControlledStateTransition() { Spell = DF, TargetState = GetState( s.BrainFreezeDuration > DF.CastTime, Math.Max(0.0f, s.BrainFreezeDuration - DF.CastTime), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), s.FingersOfFrostActual > 1, s.FingersOfFrostActual > 1 ), TransitionProbability = 1 }); } return list; }
// the states must form equivalence classes protected abstract bool CanStatesBeDistinguished(CycleState state1, CycleState state2);
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell Sc = this.Sc[s.Tier10TwoPieceDuration > 0 ? 1 : 0]; Spell FB = this.FB[s.Tier10TwoPieceDuration > 0 ? 1 : 0]; Spell LB = this.LB[s.Tier10TwoPieceDuration > 0 ? 1 : 0]; Spell Pyro = this.Pyro[s.Tier10TwoPieceDuration > 0 ? 1 : 0]; if (maintainScorch && s.ScorchDuration < Sc.CastTime) { // LB explosion and/or ticks can happen during the cast // account for all combinations of hot streak interaction float castTime = Sc.CastTime; int ticksLeft = Math.Max(0, (int)(s.LivingBombDuration / 3.0f)); int ticksLeftAfter = Math.Max(0, (int)((s.LivingBombDuration - castTime) / 3.0f)); int hotStreakEvents = ticksLeft - ticksLeftAfter; //if (!livingBombGlyph) { hotStreakEvents = 0; } bool explosion = false; if (ticksLeft > 0 && ticksLeftAfter == 0) { explosion = true; hotStreakEvents++; } for (int i = 0; i < (1 << (hotStreakEvents + 1)); i++) { int k = i; int hsc = s.HotStreakCount; float pd = Math.Max(0f, s.PyroDuration - castTime); bool pr = s.PyroDuration > castTime; float chance = 1.0f; for (int j = 0; j < hotStreakEvents; j++) { float crit = (j == hotStreakEvents - 1 && explosion) ? LB.CritRate : LBDotCritRate; if (k % 2 == 1) { chance *= crit; if (hsc == 1) { pd = 10.0f - (s.LivingBombDuration - ticksLeft * 3); pr = true; } hsc = (hsc + 1) % 2; } else { chance *= (1 - crit); hsc = 0; } k = k >> 1; } if (k % 2 == 1) { chance *= Sc.CritRate; if (hsc == 1) { pd = 10.0f; } hsc = (hsc + 1) % 2; } else { chance *= (1 - Sc.CritRate); hsc = 0; } list.Add(new CycleControlledStateTransition() { Spell = Sc, TargetState = GetState( 30.0f + Sc.CastTime, Math.Max(0f, s.LivingBombDuration - castTime), hsc, pd, pr, Math.Max(0.0f, s.Tier10TwoPieceDuration - Sc.CastTime) ), TransitionProbability = chance }); } } else if (s.LivingBombDuration <= 0f) { list.Add(new CycleControlledStateTransition() { Spell = LB, TargetState = GetState( Math.Max(0f, s.ScorchDuration - LB.CastTime), 12f - LB.CastTime, s.HotStreakCount, Math.Max(0f, s.PyroDuration - LB.CastTime), s.PyroDuration > LB.CastTime, Math.Max(0.0f, s.Tier10TwoPieceDuration - LB.CastTime) ), TransitionProbability = 1 }); } else if (s.PyroRegistered) { float castTime = Pyro.CastTime; int ticksLeft = Math.Max(0, (int)(s.LivingBombDuration / 3.0f)); int ticksLeftAfter = Math.Max(0, (int)((s.LivingBombDuration - castTime) / 3.0f)); int hotStreakEvents = ticksLeft - ticksLeftAfter; //if (!livingBombGlyph) { hotStreakEvents = 0; } bool explosion = false; if (ticksLeft > 0 && ticksLeftAfter == 0) { explosion = true; hotStreakEvents++; } for (int i = 0; i < (1 << hotStreakEvents); i++) { int k = i; int hsc = s.HotStreakCount; float pd1 = Math.Max(0f, s.PyroDuration - castTime); bool pr1 = s.PyroDuration > castTime; float pd2 = 0.0f; bool pr2 = false; float chance = 1.0f; for (int j = 0; j < hotStreakEvents; j++) { float crit = (j == hotStreakEvents - 1 && explosion) ? LB.CritRate : LBDotCritRate; if (k % 2 == 1) { chance *= crit; if (hsc == 1) { pd1 = 10.0f - (s.LivingBombDuration - ticksLeft * 3); pr1 = true; pd2 = 10.0f - (s.LivingBombDuration - ticksLeft * 3); pr2 = true; } hsc = (hsc + 1) % 2; } else { chance *= (1 - crit); hsc = 0; } k = k >> 1; } if (T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = Pyro, TargetState = GetState( Math.Max(0f, s.ScorchDuration - castTime), Math.Max(0f, s.LivingBombDuration - castTime), hsc, pd1, pr1, T10 ? Math.Max(0.0f, 5.0f - Pyro.CastTime) : 0f ), TransitionProbability = chance * T8 }); } list.Add(new CycleControlledStateTransition() { Spell = Pyro, TargetState = GetState( Math.Max(0f, s.ScorchDuration - castTime), Math.Max(0f, s.LivingBombDuration - castTime), hsc, pd2, pr2, T10 ? Math.Max(0.0f, 5.0f - Pyro.CastTime) : 0f ), TransitionProbability = chance * (1 - T8) }); } } else { float castTime = FB.CastTime; int ticksLeft = Math.Max(0, (int)(s.LivingBombDuration / 3.0f)); int ticksLeftAfter = Math.Max(0, (int)((s.LivingBombDuration - castTime) / 3.0f)); int hotStreakEvents = ticksLeft - ticksLeftAfter; //if (!livingBombGlyph) { hotStreakEvents = 0; } bool explosion = false; if (ticksLeft > 0 && ticksLeftAfter == 0) { explosion = true; hotStreakEvents++; } for (int i = 0; i < (1 << (hotStreakEvents + 1)); i++) { int k = i; int hsc = s.HotStreakCount; float pd = Math.Max(0f, s.PyroDuration - castTime); bool pr = s.PyroDuration > castTime; float chance = 1.0f; for (int j = 0; j < hotStreakEvents; j++) { float crit = (j == hotStreakEvents - 1 && explosion) ? LB.CritRate : LBDotCritRate; if (k % 2 == 1) { chance *= crit; if (hsc == 1) { pd = 10.0f - (s.LivingBombDuration - ticksLeft * 3); pr = true; } hsc = (hsc + 1) % 2; } else { chance *= (1 - crit); hsc = 0; } k = k >> 1; } if (k % 2 == 1) { chance *= FB.CritRate; if (hsc == 1) { pd = 10.0f; } hsc = (hsc + 1) % 2; } else { chance *= (1 - FB.CritRate); hsc = 0; } list.Add(new CycleControlledStateTransition() { Spell = FB, TargetState = GetState( Math.Max(0f, s.ScorchDuration - castTime), Math.Max(0f, s.LivingBombDuration - castTime), hsc, pd, pr, Math.Max(0.0f, s.Tier10TwoPieceDuration - FB.CastTime) ), TransitionProbability = chance }); } } return list; }
protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return (a.ArcaneBlastStack != b.ArcaneBlastStack || (!ABarCooldownCollapsed && a.ArcaneBarrageCooldown != b.ArcaneBarrageCooldown) || (((a.ArcaneBarrageCooldown > 0) != (b.ArcaneBarrageCooldown > 0)) && (a.MovementDuration > 0 || !instantsOnMovementOnly)) || a.MissileBarrageRegistered != b.MissileBarrageRegistered || (!Tier10TwoPieceCollapsed && a.Tier10TwoPieceDuration != b.Tier10TwoPieceDuration) || (!MBDurationCollapsed && a.MissileBarrageRegistered == true && b.MissileBarrageRegistered == true && a.MissileBarrageDuration != b.MissileBarrageDuration) || (a.MovementDuration != b.MovementDuration)); }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell AB = null; Spell AM = null; Spell ABar = null; switch (s.ArcaneBlastStack) { case 0: AB = AB0; ABar = ABar0; AM = (s.MissileBarrageDuration > 0) ? MBAM0 : AM0; break; case 1: AB = AB1; ABar = ABar1; AM = (s.MissileBarrageDuration > 0) ? MBAM1 : AM1; break; case 2: AB = AB2; ABar = ABar2; AM = (s.MissileBarrageDuration > 0) ? MBAM2 : AM2; break; case 3: AB = AB3; ABar = ABar3; AM = (s.MissileBarrageDuration > 0) ? MBAM3 : AM3; break; case 4: AB = AB4; ABar = ABar4; AM = (s.MissileBarrageDuration > 0) ? MBAM4 : AM4; break; } if (s.MovementDuration == 0.0f) { float d = (AB.CastTime - castingState.CalculationOptions.LatencyCast) / 2.0f; list.Add(new CycleControlledStateTransition() { Spell = ABNull, Pause = d, TargetState = GetState( s.MissileBarrageDuration > d, Math.Max(0.0f, s.MissileBarrageDuration - d), Math.Max(0.0f, s.ArcaneBarrageCooldown - d), s.ArcaneBlastDuration - d > 0 ? s.ArcaneBlastStack : 0, Math.Max(s.ArcaneBlastDuration - d, 0.0f), movementDuration ), TransitionProbability = ABI }); d = AB.CastTime - castingState.CalculationOptions.LatencyCast / 2.0f; if (MB > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, Pause = -castingState.CalculationOptions.LatencyCast / 2.0f, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, 15.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), 6.0f, movementDuration ), TransitionProbability = ABI2 * ABMB }); list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, 15.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), 6.0f, 0.0f ), TransitionProbability = ABI0 * ABMB }); } list.Add(new CycleControlledStateTransition() { Spell = AB, Pause = -castingState.CalculationOptions.LatencyCast / 2.0f, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AB.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), 6.0f, movementDuration ), TransitionProbability = ABI2 * (1.0f - ABMB) }); list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AB.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), 6.0f, 0.0f ), TransitionProbability = ABI0 * (1.0f - ABMB) }); //if (s.ArcaneBarrageCooldown == 0) { float p = (float)(1.0 - Math.Exp(-movementEventRate * (ABar0.CastTime + s.ArcaneBarrageCooldown))); if (MB > 0) { list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( true, 15.0f - ABar.CastTime, 3.0f - ABar.CastTime, 0, 0.0f, movementDuration - (ABar.CastTime + s.ArcaneBarrageCooldown) / 2.0f ), TransitionProbability = p * MB }); list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( true, 15.0f - ABar.CastTime, 3.0f - ABar.CastTime, 0, 0.0f, 0.0f ), TransitionProbability = (1 - p) * MB }); } list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( s.MissileBarrageDuration > ABar.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - ABar.CastTime), 3.0f - ABar.CastTime, 0, 0.0f, movementDuration - (ABar.CastTime + s.ArcaneBarrageCooldown) / 2.0f ), TransitionProbability = p * (1.0f - MB) }); list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( s.MissileBarrageDuration > ABar.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - ABar.CastTime), 3.0f - ABar.CastTime, 0, 0.0f, 0.0f ), TransitionProbability = (1 - p) * (1.0f - MB) }); } float[] I = (s.MissileBarrageDuration > 0) ? MBAMI : AMI; Spell[,] T = (s.MissileBarrageDuration > 0) ? MBAMT : AMT; for (int t = 0; t < 5; t++) { d = (t + 0.5f) * (AM.CastTime - castingState.CalculationOptions.LatencyChannel) / 5.0f; if (s.MissileBarrageDuration > 0 && T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = T[s.ArcaneBlastStack, t], Pause = -castingState.CalculationOptions.LatencyChannel + (AM.CastTime - castingState.CalculationOptions.LatencyChannel) / 10.0f, TargetState = GetState( s.MissileBarrageDuration > d, Math.Max(0.0f, s.MissileBarrageDuration - d), Math.Max(0.0f, s.ArcaneBarrageCooldown - d), 0, 0.0f, movementDuration ), TransitionProbability = I[t] * T8 }); } list.Add(new CycleControlledStateTransition() { Spell = T[s.ArcaneBlastStack, t], Pause = -castingState.CalculationOptions.LatencyChannel + (AM.CastTime - castingState.CalculationOptions.LatencyChannel) / 10.0f, TargetState = GetState( false, 0.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - d), 0, 0.0f, movementDuration ), TransitionProbability = I[t] * (s.MissileBarrageDuration > 0 ? 1.0f - T8 : 1.0f) }); } d = AM.CastTime - castingState.CalculationOptions.LatencyChannel / 2.0f; if (s.MissileBarrageDuration > 0 && T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, Pause = -castingState.CalculationOptions.LatencyChannel / 2, TargetState = GetState( s.MissileBarrageDuration > d, Math.Max(0.0f, s.MissileBarrageDuration - d), Math.Max(0.0f, s.ArcaneBarrageCooldown - d), 0, 0.0f, movementDuration ), TransitionProbability = I[5] * T8 }); } list.Add(new CycleControlledStateTransition() { Spell = AM, Pause = -castingState.CalculationOptions.LatencyChannel / 2, TargetState = GetState( false, 0.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - d), 0, 0.0f, movementDuration ), TransitionProbability = I[5] * (s.MissileBarrageDuration > 0 ? 1.0f - T8 : 1.0f) }); if (s.MissileBarrageDuration > 0 && T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( s.MissileBarrageDuration > AM.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AM.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, 0.0f, 0.0f ), TransitionProbability = T8 }); } list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( false, 0.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, 0.0f, 0.0f ), TransitionProbability = s.MissileBarrageDuration > 0 ? 1.0f - T8 : 1.0f }); } else { } return list; }
protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return (a.ArcaneBlastStack != b.ArcaneBlastStack || (!ABarCooldownCollapsed && a.ArcaneBarrageCooldown != b.ArcaneBarrageCooldown) || ((a.ArcaneBarrageCooldown > 0) != (b.ArcaneBarrageCooldown > 0)) || a.ArcaneMissilesRegistered != b.ArcaneMissilesRegistered || a.ArcaneBlastDuration != b.ArcaneBlastDuration); }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell AB = null; Spell AM = null; Spell ABar = null; AB = this.AB[s.ArcaneBlastStack, s.Tier10TwoPieceDuration > 0 ? 1 : 0]; ABar = this.ABar[s.ArcaneBlastStack, s.Tier10TwoPieceDuration - s.ArcaneBarrageCooldown > 0 ? 1 : 0]; if (s.MissileBarrageDuration > 0) { AM = this.MBAM[s.ArcaneBlastStack, s.Tier10TwoPieceDuration > 0 ? 1 : 0]; } else { AM = this.AM[s.ArcaneBlastStack, s.Tier10TwoPieceDuration > 0 ? 1 : 0]; } if (s.MovementDuration == 0.0f) { float move = (float)(1.0 - Math.Exp(-movementEventRate * AB.CastTime)); if (s.ArcaneBarrageCooldown > AB.CastTime) { move = 0.0f; } if (MB > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, 15.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), 0.0f ), TransitionProbability = ABMB * (1.0f - move) }); if (move > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, 15.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), movementDuration ), TransitionProbability = ABMB * move }); } } list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AB.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), 0.0f ), TransitionProbability = (1.0f - ABMB) * (1.0f - move) }); if (move > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AB.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), movementDuration ), TransitionProbability = (1.0f - ABMB) * move }); } move = (float)(1.0 - Math.Exp(-movementEventRate * AM.CastTime)); if (s.ArcaneBarrageCooldown > AM.CastTime) { move = 0.0f; } if (s.MissileBarrageDuration > 0 && T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( s.MissileBarrageDuration > AM.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AM.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - AM.CastTime), // cannot have 4T8 and 2T10 at the same time 0.0f ), TransitionProbability = T8 * (1.0f - move) }); if (move > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( s.MissileBarrageDuration > AM.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AM.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - AM.CastTime), // cannot have 4T8 and 2T10 at the same time movementDuration ), TransitionProbability = T8 * move }); } } list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( false, 0.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, Math.Max(0.0f, (s.MissileBarrageDuration > 0 && T10) ? 5.0f - channelLatency : s.Tier10TwoPieceDuration - AM.CastTime), 0.0f ), TransitionProbability = (s.MissileBarrageDuration > 0 ? 1.0f - T8 : 1.0f) * (1.0f - move) }); if (move > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( false, 0.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, Math.Max(0.0f, (s.MissileBarrageDuration > 0 && T10) ? 5.0f - channelLatency : s.Tier10TwoPieceDuration - AM.CastTime), movementDuration ), TransitionProbability = (s.MissileBarrageDuration > 0 ? 1.0f - T8 : 1.0f) * move }); } } if (ABarAllowed && (!ABarOnCooldownOnly || s.ArcaneBarrageCooldown == 0) && (s.MovementDuration > 0 || !instantsOnMovementOnly)) { float move = (float)(1.0 - Math.Exp(-movementEventRate * ABar.CastTime)); move = 0.0f; if (MB > 0) { list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( true, 15.0f - ABar.CastTime, 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), Math.Max(0.0f, s.MovementDuration - ABar.CastTime - s.ArcaneBarrageCooldown) ), TransitionProbability = MB * (1.0f - move) }); /*list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( true, 15.0f - ABar.CastTime, 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), movementDuration ), TransitionProbability = MB * move });*/ } list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( s.MissileBarrageDuration > ABar.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - ABar.CastTime), 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), Math.Max(0.0f, s.MovementDuration - ABar.CastTime - s.ArcaneBarrageCooldown) ), TransitionProbability = (1.0f - MB) * (1.0f - move) }); /*list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( s.MissileBarrageDuration > ABar.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - ABar.CastTime), 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), movementDuration ), TransitionProbability = (1.0f - MB) * move });*/ } if (s.MovementDuration > 0) { list.Add(new CycleControlledStateTransition() { Spell = null, Pause = s.MovementDuration, TargetState = GetState( s.MissileBarrageDuration > s.MovementDuration, Math.Max(0.0f, s.MissileBarrageDuration - s.MovementDuration), Math.Max(0.0f, s.ArcaneBarrageCooldown - s.MovementDuration), s.ArcaneBlastStack, Math.Max(0.0f, s.Tier10TwoPieceDuration - s.MovementDuration), 0.0f ), TransitionProbability = 1.0f }); } return list; }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell AB = null; Spell AM = null; Spell ABar = null; Spell AE = null; AB = this.AB[s.ArcaneBlastStack]; if (s.ArcaneBlastDuration > 0 && AB.CastTime > s.ArcaneBlastDuration) { AB = this.ABT[s.ArcaneBlastStack]; } AE = this.AE[s.ArcaneBlastStack]; ABar = this.ABar; //if (s.ArcaneMissilesRegistered) { AM = this.AM; } /*if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, AB.CastTime < s.ArcaneBlastDuration ? s.ArcaneBlastStack + 1 : 1), 6.0f, s.ArcaneMissilesProcced, true), TransitionProbability = AMProc }); }*/ // only use AB on full AB debuff duration or when it would run out if we delay //if (s.ArcaneBlastDuration == 0.0f || s.ArcaneBlastDuration == 6.0f || (s.ArcaneBlastDuration - AB.CastTime > 0 && s.ArcaneBlastDuration - AE.CastTime - AB.CastTime < 0)) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, (AB.CastTime < s.ArcaneBlastDuration) ? s.ArcaneBlastStack + 1 : 1), 6.0f, s.ArcaneMissilesProcced, s.ArcaneMissilesProcced), TransitionProbability = 1/*(1 - AMProc)*/ }); } /*if (s.ArcaneMissilesRegistered) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, 0.0f, false, false), TransitionProbability = 1.0f }); }*/ if (ABarAllowed && (!ABarOnCooldownOnly || s.ArcaneBarrageCooldown == 0.0)) { /*if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( ABar.Cooldown - ABar.CastTime, 0, 0.0f, true, true), TransitionProbability = AMProc }); }*/ /*list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( ABar.Cooldown - ABar.CastTime, 0, 0.0f, s.ArcaneMissilesProcced, s.ArcaneMissilesProcced), TransitionProbability = (1 - AMProc) });*/ } /*if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AE, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AE.CastTime), Math.Min(maxStack, AE.CastTime < s.ArcaneBlastDuration ? s.ArcaneBlastStack : 0), Math.Max(0.0f, s.ArcaneBlastDuration - AE.CastTime), true, true), TransitionProbability = AMProc }); }*/ list.Add(new CycleControlledStateTransition() { Spell = AE, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AE.CastTime), Math.Min(maxStack, AE.CastTime < s.ArcaneBlastDuration ? s.ArcaneBlastStack : 0), Math.Max(0.0f, s.ArcaneBlastDuration - AE.CastTime), s.ArcaneMissilesProcced, s.ArcaneMissilesProcced), TransitionProbability = 1/*(1 - AMProc)*/ }); if ((s.ArcaneBlastDuration == 0.0 || s.ArcaneBlastDuration == 6.0) && s.ArcaneBlastStack <= 1) { list.Add(new CycleControlledStateTransition() { Spell = Bliz, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - Bliz.CastTime), Math.Min(maxStack, Bliz.CastTime < s.ArcaneBlastDuration ? s.ArcaneBlastStack : 0), Math.Max(0.0f, s.ArcaneBlastDuration - Bliz.CastTime), s.ArcaneMissilesProcced, s.ArcaneMissilesProcced), TransitionProbability = 1 }); } return list; }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell AB = null; Spell AM = null; Spell ABar = null; Spell dwAB = null; int abStack = s.ArcaneBlastStack; if (s.DelayedABProc) { dwAB = this.DWAB[abStack]; abStack = Math.Min(maxStack, abStack + 1); } AB = this.AB[abStack]; ABar = this.ABar; if (s.ArcaneMissilesRegistered) { AM = this.AM; } float orbProc = flameOrb ? 1f - (float)Math.Pow(1 - AMProc, AB.CastTime) : 0; if (DelayProc > 0) { if (s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced || !flameOrb) { list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, true, true, true), TransitionProbability = DelayProc * legendary }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, true, true, false), TransitionProbability = DelayProc * (1 - legendary) }); } else { list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), true, true, true, true), TransitionProbability = DelayProc * orbProc * legendary }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), true, true, true, false), TransitionProbability = DelayProc * orbProc * (1 - legendary) }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), false, true, true, true), TransitionProbability = DelayProc * (1 - orbProc) * legendary }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), false, true, true, false), TransitionProbability = DelayProc * (1 - orbProc) * (1 - legendary) }); } } if (orbProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), true, true, false, true), TransitionProbability = orbProc * (1 - DelayProc) * legendary }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), true, true, false, false), TransitionProbability = orbProc * (1 - DelayProc) * (1 - legendary) }); } if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, true, false, true), TransitionProbability = AMProc * (1 - DelayProc) * (1 - orbProc) * legendary }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, true, false, false), TransitionProbability = AMProc * (1 - DelayProc) * (1 - orbProc) * (1 - legendary) }); } list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, false, true), TransitionProbability = (1 - AMProc) * (1 - DelayProc) * (1 - orbProc) * legendary }); list.Add(new CycleControlledStateTransition() { Spell = AB, DWSpell = dwAB, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, abStack + 1), s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, false, false), TransitionProbability = (1 - AMProc) * (1 - DelayProc) * (1 - orbProc) * (1 - legendary) }); if (s.ArcaneMissilesRegistered) { orbProc = flameOrb ? 1f - (float)Math.Pow(1 - AMProc, AM.CastTime) : 0; if (orbProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, DWSpell = dwAB != null ? DWAB[0] : null, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), dwAB != null ? 1 : 0, true, true, false, false), TransitionProbability = orbProc }); } list.Add(new CycleControlledStateTransition() { Spell = AM, DWSpell = dwAB != null ? DWAB[0] : null, TargetState = GetState( Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), dwAB != null ? 1 : 0, s.ArcaneMissilesDelayedProcced, s.ArcaneMissilesDelayedProcced, false, false), TransitionProbability = 1.0f - orbProc }); } if (ABarAllowed && (!ABarOnCooldownOnly || s.ArcaneBarrageCooldown == 0.0)) { orbProc = flameOrb ? 1f - (float)Math.Pow(1 - AMProc, ABar.CastTime) : 0; if (AMProc > 0 || orbProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = ABar, DWSpell = dwAB, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( ABar.Cooldown - ABar.CastTime, 0, true, true, false, false), TransitionProbability = 1 - (1 - AMProc) * (1 - orbProc) }); } list.Add(new CycleControlledStateTransition() { Spell = ABar, DWSpell = dwAB, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( ABar.Cooldown - ABar.CastTime, 0, s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, s.ArcaneMissilesProcced || s.ArcaneMissilesDelayedProcced, false, false), TransitionProbability = (1 - AMProc) * (1 - orbProc) }); } return list; }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell AB = null; Spell AM = null; Spell ABar = null; AB = this.AB[s.ArcaneBlastStack, s.Tier10TwoPieceDuration > 0 ? 1 : 0]; ABar = this.ABar[s.ArcaneBlastStack, s.Tier10TwoPieceDuration - s.ArcaneBarrageCooldown > 0 ? 1 : 0]; if (s.MissileBarrageDuration > 0) { AM = this.MBAM[s.ArcaneBlastStack, s.Tier10TwoPieceDuration > 0 ? 1 : 0]; } else { AM = this.AM[s.ArcaneBlastStack, s.Tier10TwoPieceDuration > 0 ? 1 : 0]; } if (MB > 0) { if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, 15.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), s.ArcaneMissilesProcced, true ), TransitionProbability = ABMB * AMProc }); } list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, 15.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), s.ArcaneMissilesProcced, s.ArcaneMissilesProcced ), TransitionProbability = ABMB * (1 - AMProc) }); } if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AB.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), s.ArcaneMissilesProcced, true ), TransitionProbability = (1.0f - ABMB) * AMProc }); } list.Add(new CycleControlledStateTransition() { Spell = AB, TargetState = GetState( s.MissileBarrageDuration > AB.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AB.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AB.CastTime), Math.Min(maxStack, s.ArcaneBlastStack + 1), Math.Max(0.0f, s.Tier10TwoPieceDuration - AB.CastTime), s.ArcaneMissilesProcced, s.ArcaneMissilesProcced ), TransitionProbability = (1.0f - ABMB) * (1 - AMProc) }); if (s.MissileBarrageDuration > 0 && T8 > 0) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( s.MissileBarrageDuration > AM.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - AM.CastTime), Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - AM.CastTime), // cannot have 4T8 and 2T10 at the same time false, false ), TransitionProbability = T8 }); } if (!beta || s.ArcaneMissilesRegistered || s.MissileBarrageRegistered) { list.Add(new CycleControlledStateTransition() { Spell = AM, TargetState = GetState( false, 0.0f, Math.Max(0.0f, s.ArcaneBarrageCooldown - AM.CastTime), 0, Math.Max(0.0f, (s.MissileBarrageDuration > 0 && T10) ? 5.0f - channelLatency : s.Tier10TwoPieceDuration - AM.CastTime), false, false ), TransitionProbability = s.MissileBarrageDuration > 0 ? 1.0f - T8 : 1.0f }); } if (ABarAllowed && (!ABarOnCooldownOnly || s.ArcaneBarrageCooldown == 0)) { if (MB > 0) { if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( true, 15.0f - ABar.CastTime, 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), s.ArcaneMissilesProcced, true ), TransitionProbability = MB * AMProc }); } list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( true, 15.0f - ABar.CastTime, 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), s.ArcaneMissilesProcced, s.ArcaneMissilesProcced ), TransitionProbability = MB * (1 - AMProc) }); } if (AMProc > 0) { list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( s.MissileBarrageDuration > ABar.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - ABar.CastTime), 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), s.ArcaneMissilesProcced, true ), TransitionProbability = (1.0f - MB) * AMProc }); } list.Add(new CycleControlledStateTransition() { Spell = ABar, Pause = s.ArcaneBarrageCooldown, TargetState = GetState( s.MissileBarrageDuration > ABar.CastTime, Math.Max(0.0f, s.MissileBarrageDuration - ABar.CastTime), 3.0f - ABar.CastTime, 0, Math.Max(0.0f, s.Tier10TwoPieceDuration - ABar.CastTime - s.ArcaneBarrageCooldown), s.ArcaneMissilesProcced, s.ArcaneMissilesProcced ), TransitionProbability = (1.0f - MB) * (1 - AMProc) }); } return list; }
protected override List<CycleControlledStateTransition> GetStateTransitions(CycleState state) { State s = (State)state; List<CycleControlledStateTransition> list = new List<CycleControlledStateTransition>(); Spell FrB = null; Spell IL = null; Spell FFB = null; Spell DF = null; FrB = this.FrB; if (s.FingersOfFrostActual > 0 || (s.FreezeCooldown == 0 && freeze)) { FFB = this.FFBF; } else { FFB = this.FFB; } if (s.FingersOfFrostRegistered > 0 || (s.FreezeCooldown == 0 && freeze)) { IL = this.IL; } if (s.DeepFreezeCooldown == 0.0f && (s.FingersOfFrostRegistered > 0 || (s.FreezeCooldown == 0 && freeze))) { DF = this.DF; } if (DF != null && deepFreeze) { if (s.FingersOfFrostRegistered > 0 || !freeze) { list.Add(new CycleControlledStateTransition() { Spell = DF, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, deepFreezeCooldown - DF.CastTime), Math.Max(0, s.FreezeCooldown - DF.CastTime) ), TransitionProbability = 1 }); } else { list.Add(new CycleControlledStateTransition() { Spell = DF, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, 1), Math.Max(0, 1), Math.Max(0, deepFreezeCooldown - DF.CastTime), Math.Max(0, freezeCooldown - DF.CastTime) ), TransitionProbability = 1 }); } } else { if (FOF > 0 && BF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, true, s.FingersOfFrostActual, Math.Min(2, s.FingersOfFrostActual + 1), Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.FreezeCooldown - FrB.CastTime) ), TransitionProbability = FOF * BF }); } if (FOF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, s.FingersOfFrostActual, Math.Min(2, s.FingersOfFrostActual + 1), Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.FreezeCooldown - FrB.CastTime) ), TransitionProbability = FOF * (1 - BF) }); } if (BF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, true, s.FingersOfFrostActual, s.FingersOfFrostActual, Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.FreezeCooldown - FrB.CastTime) ), TransitionProbability = (1 - FOF) * BF }); } list.Add(new CycleControlledStateTransition() { Spell = FrB, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, s.FingersOfFrostActual, s.FingersOfFrostActual, Math.Max(0, s.DeepFreezeCooldown - FrB.CastTime), Math.Max(0, s.FreezeCooldown - FrB.CastTime) ), TransitionProbability = (1 - FOF) * (1 - BF) }); if (IL != null) { if (s.FingersOfFrostRegistered > 0 || !freeze) { list.Add(new CycleControlledStateTransition() { Spell = IL, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.DeepFreezeCooldown - IL.CastTime), Math.Max(0, s.FreezeCooldown - IL.CastTime) ), TransitionProbability = 1 }); } else { list.Add(new CycleControlledStateTransition() { Spell = IL, TargetState = GetState( s.BrainFreezeProcced, s.BrainFreezeProcced, Math.Max(0, 1), Math.Max(0, 1), Math.Max(0, s.DeepFreezeCooldown - IL.CastTime), Math.Max(0, freezeCooldown - IL.CastTime) ), TransitionProbability = 1 }); } } if (s.BrainFreezeRegistered) { if (s.FingersOfFrostRegistered > 0 || !freeze) { if (FOF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FFB, TargetState = GetState( false, false, Math.Max(0, s.FingersOfFrostActual - 1) + 1, Math.Max(0, s.FingersOfFrostActual - 1) + 1, Math.Max(0, s.DeepFreezeCooldown - FFB.CastTime), Math.Max(0, s.FreezeCooldown - FFB.CastTime) ), TransitionProbability = FOF }); } list.Add(new CycleControlledStateTransition() { Spell = FFB, TargetState = GetState( false, false, Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.FingersOfFrostActual - 1), Math.Max(0, s.DeepFreezeCooldown - FFB.CastTime), Math.Max(0, s.FreezeCooldown - FFB.CastTime) ), TransitionProbability = 1 - FOF }); } else { if (FOF > 0) { list.Add(new CycleControlledStateTransition() { Spell = FFB, TargetState = GetState( false, false, Math.Max(0, 2 - 1) + 1, Math.Max(0, 2 - 1) + 1, Math.Max(0, s.DeepFreezeCooldown - FFB.CastTime), Math.Max(0, freezeCooldown - FFB.CastTime) ), TransitionProbability = FOF }); } list.Add(new CycleControlledStateTransition() { Spell = FFB, TargetState = GetState( false, false, Math.Max(0, 2 - 1), Math.Max(0, 2 - 1), Math.Max(0, s.DeepFreezeCooldown - FFB.CastTime), Math.Max(0, freezeCooldown - FFB.CastTime) ), TransitionProbability = 1 - FOF }); } } } return list; }
protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return (a.ArcaneBlastStack != b.ArcaneBlastStack || a.ArcaneBarrageCooldown != b.ArcaneBarrageCooldown || a.MissileBarrageRegistered != b.MissileBarrageRegistered || a.ArcaneBlastDuration != b.ArcaneBlastDuration || a.MovementDuration != b.MovementDuration /* || (a.MissileBarrageRegistered == true && b.MissileBarrageRegistered == true && a.MissileBarrageDuration != b.MissileBarrageDuration)*/); }
protected override bool CanStatesBeDistinguished(CycleState state1, CycleState state2) { State a = (State)state1; State b = (State)state2; return ( a.FingersOfFrostRegistered != b.FingersOfFrostRegistered || (a.DeepFreezeCooldown == 0 && (a.FingersOfFrostRegistered > 0)) != (b.DeepFreezeCooldown == 0 && (b.FingersOfFrostRegistered > 0)) || ((a.FreezeCooldown > 0) != (b.FreezeCooldown > 0)) || a.BrainFreezeRegistered != b.BrainFreezeRegistered); }
// the transition probabilities should be set as given the spell/pause is executed 100% // the transitions should all be spell transitions and at most one can be a state changing pause protected abstract List<CycleControlledStateTransition> GetStateTransitions(CycleState state);