public void Update(decimal timer, Keyboard keyboard, LogData log) { if (timer == 0) { gcdCounter = 0; } if (timer == NextGCD(heavyShotCdComp)) { gcdCounter++; } // Opener: if (gcdCounter <= 9) { if (NextGCD(heavyShotCdComp) <= timer) { // GCD: opener switch (gcdCounter) { case 1: UseSkill(skillControlComp, SkillName.Stormbite); break; case 2: UseSkill(skillControlComp, SkillName.CausticBite); break; case 3: UseSkill(skillControlComp, SkillName.StraightShot); break; case 4: UseSkill(skillControlComp, SkillName.IronJaws); break; case 5: UseSkill(skillControlComp, SkillName.HeavyShot); break; case 6: case 7: case 8: if (IsStatusActive(modStateComponent, StatusName.StraighterShot)) { UseSkill(skillControlComp, SkillName.RefulgentArrow); } else { UseSkill(skillControlComp, SkillName.HeavyShot); } break; case 9: UseSkill(skillControlComp, SkillName.IronJaws); break; } } else if (timer < NextGCD(heavyShotCdComp)) { // oGCD: opener switch (gcdCounter) { case 1: if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } else if (CooldownLeft(rsCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.RagingStrikes); } else { ReleaseSkill(skillControlComp); } break; case 2: if (CooldownLeft(wmCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.TheWanderersMinuet); } else if (CooldownLeft(eaCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } else { ReleaseSkill(skillControlComp); } break; case 3: case 4: case 5: case 6: case 7: if (Repertoire(brdComp) == 3 && CooldownLeft(ppCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.PitchPerfect); } else if (IsStatusActive(modStateComponent, StatusName.StraighterShot) && CooldownLeft(barrageCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Barrage); } else if (CooldownLeft(eaCooldownComp, timer) <= 0 && CooldownLeft(barrageCooldownComp, timer) > 0 && !IsStatusActive(modStateComponent, StatusName.Barrage) && NoClip(timer)) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } else if (CooldownLeft(swCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Sidewinder); } else if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } else { ReleaseSkill(skillControlComp); } break; case 8: if (Repertoire(brdComp) == 3 && CooldownLeft(ppCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.PitchPerfect); } else if (CooldownLeft(eaCooldownComp, timer) <= 0 && CooldownLeft(barrageCooldownComp, timer) > 0 && !IsStatusActive(modStateComponent, StatusName.Barrage) && NoClip(timer)) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } else if (CooldownLeft(swCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Sidewinder); } else if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } else { ReleaseSkill(skillControlComp); } break; case 9: if (Repertoire(brdComp) == 3 && CooldownLeft(ppCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.PitchPerfect); } else if (CooldownLeft(barrageCooldownComp, timer) <= 0 && !IsStatusActive(modStateComponent, StatusName.StraighterShot)) { UseSkill(skillControlComp, SkillName.Barrage); } else if ((IsStatusActive(modStateComponent, StatusName.Barrage) && !IsStatusActive(modStateComponent, StatusName.StraighterShot) && CooldownLeft(eaCooldownComp, timer) <= 0) || (CooldownLeft(barrageCooldownComp, timer) > 0 && NoClip(timer) && CooldownLeft(eaCooldownComp, timer) <= 0)) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } else { ReleaseSkill(skillControlComp); } break; } } } else { if (TimeLeftOnSong(brdComp, SongName.TheWanderersMinuet, timer) > 0) { if (NextGCD(heavyShotCdComp) <= timer) { // GCD: Base structure if (!IsDoTActive(targOtComp, DotName.Stormbite)) { UseSkill(skillControlComp, SkillName.CausticBite); } else if (!IsDoTActive(targOtComp, DotName.CausticBite)) { UseSkill(skillControlComp, SkillName.Stormbite); } else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && (TimeLeftOnDot(targOtComp, DotName.CausticBite, timer) <= 3m || TimeLeftOnDot(targOtComp, DotName.Stormbite, timer) <= 3m)) { UseSkill(skillControlComp, SkillName.IronJaws); } else if (IsStatusActive(modStateComponent, StatusName.StraighterShot) && CooldownLeft(barrageCooldownComp, timer) >= 10m) { UseSkill(skillControlComp, SkillName.RefulgentArrow); } else if (!IsStatusActive(modStateComponent, StatusName.StraightShot) || TimeLeftOnStatus(modStateComponent, StatusName.StraightShot, timer) <= 5m) { UseSkill(skillControlComp, SkillName.StraightShot); } else { UseSkill(skillControlComp, SkillName.HeavyShot); } } else if (timer < NextGCD(heavyShotCdComp)) { // oGCD: Base structure // Mage's Ballad if (TimeLeftOnSong(brdComp, SongName.TheWanderersMinuet, timer) <= 2m && NoClip(timer)) { UseSkill(skillControlComp, SkillName.MagesBallad); } // Raging Strikes else if (CooldownLeft(rsCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.RagingStrikes); } // Pitch Perfect else if ((Repertoire(brdComp) == 3 || (IsSongActive(brdComp, SongName.TheWanderersMinuet) && TimeLeftOnSong(brdComp, SongName.TheWanderersMinuet, timer) <= 2m)) && CooldownLeft(ppCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.PitchPerfect); } // Barrage else if ((IsStatusActive(modStateComponent, StatusName.StraighterShot) || IsStatusActive(modStateComponent, StatusName.RagingStrikes) && TimeLeftOnStatus(modStateComponent, StatusName.RagingStrikes, timer) <= 3m) && CooldownLeft(barrageCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Barrage); } // Bloodletter else if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } // Empyreal Arrow else if (IsStatusActive(modStateComponent, StatusName.RagingStrikes) && TimeLeftOnStatus(modStateComponent, StatusName.RagingStrikes, timer) <= 15m && IsStatusActive(modStateComponent, StatusName.Barrage) && CooldownLeft(eaCooldownComp, timer) <= 0 /* CAN CLIP */) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } // Empyreal Arrow else if ((IsStatusActive(modStateComponent, StatusName.RagingStrikes) && TimeLeftOnStatus(modStateComponent, StatusName.RagingStrikes, timer) > 15m) || !IsStatusActive(modStateComponent, StatusName.RagingStrikes) && CooldownLeft(eaCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } // Sidewinder else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && CooldownLeft(swCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Sidewinder); } else { ReleaseSkill(skillControlComp); } } else { ReleaseSkill(skillControlComp); } } else if (TimeLeftOnSong(brdComp, SongName.MagesBallad, timer) > 0) { if (NextGCD(heavyShotCdComp) <= timer) { // GCD: Base structure if (!IsDoTActive(targOtComp, DotName.Stormbite)) { UseSkill(skillControlComp, SkillName.CausticBite); } else if (!IsDoTActive(targOtComp, DotName.CausticBite)) { UseSkill(skillControlComp, SkillName.Stormbite); } else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && (TimeLeftOnDot(targOtComp, DotName.CausticBite, timer) <= 3m || TimeLeftOnDot(targOtComp, DotName.Stormbite, timer) <= 3m)) { UseSkill(skillControlComp, SkillName.IronJaws); } else if (IsStatusActive(modStateComponent, StatusName.StraighterShot) && CooldownLeft(barrageCooldownComp, timer) >= 10m) { UseSkill(skillControlComp, SkillName.RefulgentArrow); } else if (!IsStatusActive(modStateComponent, StatusName.StraightShot) || TimeLeftOnStatus(modStateComponent, StatusName.StraightShot, timer) <= 5m) { UseSkill(skillControlComp, SkillName.StraightShot); } else { UseSkill(skillControlComp, SkillName.HeavyShot); } } else if (timer < NextGCD(heavyShotCdComp)) { // oGCD: Base structure // Army's Paeon if (CooldownLeft(apCooldownComp, timer) <= 0 && CooldownLeft(wmCooldownComp, timer) <= 20 && CooldownLeft(mbCooldownComp, timer) <= 50 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.ArmysPaeon); } // Bloodletter else if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } // Empyreal Arrow else if (CooldownLeft(blCooldownComp, timer) > 3m && CooldownLeft(eaCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } // Sidewinder else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && CooldownLeft(swCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Sidewinder); } else { ReleaseSkill(skillControlComp); } } else { ReleaseSkill(skillControlComp); } } else if (TimeLeftOnSong(brdComp, SongName.ArmysPaeon, timer) > 0) { if (NextGCD(heavyShotCdComp) <= timer) { // GCD: Base structure if (!IsDoTActive(targOtComp, DotName.Stormbite)) { UseSkill(skillControlComp, SkillName.CausticBite); } else if (!IsDoTActive(targOtComp, DotName.CausticBite)) { UseSkill(skillControlComp, SkillName.Stormbite); } else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && (TimeLeftOnDot(targOtComp, DotName.CausticBite, timer) <= 3m || TimeLeftOnDot(targOtComp, DotName.Stormbite, timer) <= 3m)) { UseSkill(skillControlComp, SkillName.IronJaws); } else if (IsStatusActive(modStateComponent, StatusName.StraighterShot) && CooldownLeft(barrageCooldownComp, timer) >= 10m) { UseSkill(skillControlComp, SkillName.RefulgentArrow); } else if (!IsStatusActive(modStateComponent, StatusName.StraightShot) || TimeLeftOnStatus(modStateComponent, StatusName.StraightShot, timer) <= 5m || ((TimeLeftOnStatus(modStateComponent, StatusName.StraightShot, timer) - CooldownLeft(rsCooldownComp, timer) - 20m) <= ((NextGCD(heavyShotCdComp) - timer + Constants.AnimationLock)) && CooldownLeft(rsCooldownComp, timer) <= ((NextGCD(heavyShotCdComp) - timer + Constants.AnimationLock)) && (CooldownLeft(wmCooldownComp, timer) <= ((NextGCD(heavyShotCdComp) - timer + Constants.AnimationLock)) && CooldownLeft(mbCooldownComp, timer) <= 30 + ((NextGCD(heavyShotCdComp) - timer + Constants.AnimationLock)) && CooldownLeft(apCooldownComp, timer) <= 60 + ((NextGCD(heavyShotCdComp) - timer + Constants.AnimationLock))))) { UseSkill(skillControlComp, SkillName.StraightShot); } else { UseSkill(skillControlComp, SkillName.HeavyShot); } } else if (timer < NextGCD(heavyShotCdComp)) { // oGCD: Base structure // Wanderer's Minuet if (CooldownLeft(wmCooldownComp, timer) <= 0m && CooldownLeft(mbCooldownComp, timer) <= 30 && CooldownLeft(apCooldownComp, timer) <= 60 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.TheWanderersMinuet); } // Bloodletter else if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } // Empyreal Arrow else if (CooldownLeft(blCooldownComp, timer) > 3m && CooldownLeft(eaCooldownComp, timer) <= 0 && NoClip(timer) && TimeLeftOnSong(brdComp, SongName.ArmysPaeon, timer) > 15) { UseSkill(skillControlComp, SkillName.EmpyrealArrow); } // Sidewinder else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && CooldownLeft(swCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Sidewinder); } else { ReleaseSkill(skillControlComp); } } else { ReleaseSkill(skillControlComp); } } else { if (NextGCD(heavyShotCdComp) <= timer) { // GCD: Base structure if (!IsDoTActive(targOtComp, DotName.Stormbite)) { UseSkill(skillControlComp, SkillName.CausticBite); } else if (!IsDoTActive(targOtComp, DotName.CausticBite)) { UseSkill(skillControlComp, SkillName.Stormbite); } else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && (TimeLeftOnDot(targOtComp, DotName.CausticBite, timer) <= 3m || TimeLeftOnDot(targOtComp, DotName.Stormbite, timer) <= 3m)) { UseSkill(skillControlComp, SkillName.IronJaws); } else if (IsStatusActive(modStateComponent, StatusName.StraighterShot) && CooldownLeft(barrageCooldownComp, timer) >= 10m) { UseSkill(skillControlComp, SkillName.RefulgentArrow); } else if (!IsStatusActive(modStateComponent, StatusName.StraightShot) || TimeLeftOnStatus(modStateComponent, StatusName.StraightShot, timer) <= 5m) { UseSkill(skillControlComp, SkillName.StraightShot); } else { UseSkill(skillControlComp, SkillName.HeavyShot); } } else if (timer < NextGCD(heavyShotCdComp)) { // oGCD: Base structure // The Wanderer's Minuet if (IsSongActive(brdComp, SongName.None) && CooldownLeft(wmCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.TheWanderersMinuet); } // Mage's Ballad else if (IsSongActive(brdComp, SongName.None) && CooldownLeft(mbCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.MagesBallad); } // Army's Paeon else if (IsSongActive(brdComp, SongName.None) && CooldownLeft(apCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.ArmysPaeon); } // Bloodletter else if (CooldownLeft(blCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Bloodletter); } // Sidewinder else if (IsDoTActive(targOtComp, DotName.CausticBite) && IsDoTActive(targOtComp, DotName.Stormbite) && CooldownLeft(swCooldownComp, timer) <= 0 && NoClip(timer)) { UseSkill(skillControlComp, SkillName.Sidewinder); } else { ReleaseSkill(skillControlComp); } } else { ReleaseSkill(skillControlComp); } } } }
public void Update(decimal timer, Keyboard keyboard, LogData log) { foreach (SkillControlComponent skillControlComp in skillControlComponents) { // User Entity entity = skillControlComp.Parent; AnimationLockComponent animLockComp = animationLockComponents.Find(x => x.Parent == entity); if (timer - animLockComp.Start >= Constants.AnimationLock) { foreach (SkillName s in skillControlComp.SkillControlList) { if (skillControlComp.SkillControlDictionary[s] == true) { // Skill components SkillBaseComponent skillBaseComp = skillBaseComponents.Find(x => x.Name == s); if (skillBaseComp != null) { // Skill Entity skill = skillBaseComp.Parent; CooldownComponent cdComp = cooldownComponents.Find(x => x.Parent == skill); // Checking if skill is on cooldown if (cdComp.UsableAt <= timer) { ModifierStateComponent modStateComp = modifierStateComponents.Find(x => x.Parent == entity); BardComponent brdComp = bardComponents.Find(x => x.Parent == entity); // Determining conditional use bool isUsable = true; foreach (UseConditionComponent useCondComp in useConditionComponents.FindAll(x => x.Parent == skill)) { if (!useCondComp.Function(modStateComp, brdComp)) { isUsable = false; break; } } if (isUsable) { // User Components AttributesComponent attComp = attributesComponents.Find(x => x.Parent == entity); // Skill list List <Entity> skillList = brdComp.SkillList; // Target components TargetComponent targComp = targetComponents.Find(x => x.Parent == entity); HealthComponent targHealthComp = healthComponents.Find(x => x.Parent == targComp.Target); ModifierStateComponent targModStateComp = modifierStateComponents.Find(x => x.Parent == targComp.Target); OverTimeStateComponent targOtComp = overtimeStateComponents.Find(x => x.Parent == targComp.Target); // More skill components PotencyComponent potComp = potencyComponents.Find(x => x.Parent == skill); ConditionalPotencyComponent condPotComp = conditionalPotencyComponents.Find(x => x.Parent == skill); decimal recast; if (potComp != null || condPotComp != null) { // If the skill is offensive decimal wdMod = 1; decimal apMod = 1; decimal detMod = 1; decimal tenMod = 1; decimal ssMod = 1; decimal traitMod = 1; decimal critMod1 = 1; decimal dhitMod1 = 1; decimal critMod2 = 1; decimal dhitMod2 = 1; decimal critMod3 = 1; decimal dhitMod3 = 1; decimal critChance; decimal dhitChance; Dictionary <DamageModifierType, decimal> modifiersDictionary; Dictionary <AttributeType, decimal> chancesDictionary; // Calculates weapon damage modifier wdMod = CombatFormulas.WeaponDamageMod(attComp.AttributesDictionary[AttributeType.WeaponDamage]); // Calculates attack power modifier if (brdComp.Job == Job.Paladin || brdComp.Job == Job.Warrior || brdComp.Job == Job.DarkKnight || brdComp.Job == Job.Monk || brdComp.Job == Job.Dragoon || brdComp.Job == Job.Samurai) { apMod = CombatFormulas.AttackPowerDamageMod(attComp.AttributesDictionary[AttributeType.Strenght] + modStateComp.BuffDictionary[AttributeType.Strenght]); } else if (brdComp.Job == Job.Ninja || brdComp.Job == Job.Bard || brdComp.Job == Job.Machinist) { apMod = CombatFormulas.AttackPowerDamageMod(attComp.AttributesDictionary[AttributeType.Dexterity] + modStateComp.BuffDictionary[AttributeType.Dexterity]); } else if (brdComp.Job == Job.BlackMage || brdComp.Job == Job.Summoner || brdComp.Job == Job.RedMage) { apMod = CombatFormulas.AttackPowerDamageMod(attComp.AttributesDictionary[AttributeType.Intelligence] + modStateComp.BuffDictionary[AttributeType.Intelligence]); } else if (brdComp.Job == Job.WhiteMage || brdComp.Job == Job.Scholar || brdComp.Job == Job.Astrologian) { apMod = CombatFormulas.AttackPowerDamageMod(attComp.AttributesDictionary[AttributeType.Mind] + modStateComp.BuffDictionary[AttributeType.Mind]); } // Calculates determination modifier detMod = CombatFormulas.DeterminationDamageMod(attComp.AttributesDictionary[AttributeType.Determination] + modStateComp.BuffDictionary[AttributeType.Determination]); // Calculates tenacity modifier tenMod = CombatFormulas.TenacityDamageMod(attComp.AttributesDictionary[AttributeType.Tenacity] + modStateComp.BuffDictionary[AttributeType.Tenacity]); // Calculates speed modifier if (brdComp.Job == Job.BlackMage || brdComp.Job == Job.Summoner || brdComp.Job == Job.RedMage || brdComp.Job == Job.WhiteMage || brdComp.Job == Job.Scholar || brdComp.Job == Job.Astrologian) { ssMod = CombatFormulas.SpeedDamageMod(attComp.AttributesDictionary[AttributeType.SpellSpeed] + modStateComp.BuffDictionary[AttributeType.SpellSpeed]); } else { ssMod = CombatFormulas.SpeedDamageMod(attComp.AttributesDictionary[AttributeType.SkillSpeed] + modStateComp.BuffDictionary[AttributeType.SkillSpeed]); } // Calculates trait modifier if (brdComp.Job == Job.Ninja || brdComp.Job == Job.Bard || brdComp.Job == Job.Machinist) { traitMod = 1.2m; } else if (brdComp.Job == Job.BlackMage || brdComp.Job == Job.Summoner || brdComp.Job == Job.RedMage || brdComp.Job == Job.WhiteMage || brdComp.Job == Job.Scholar || brdComp.Job == Job.Astrologian) { traitMod = 1.3m; } // Checks for straighter shot guaranteed crit Enabler straighterShot = modStateComp.EnablerList.Find(x => x.Name == StatusName.StraighterShot); if (skillBaseComp.Name == SkillName.StraightShot && straighterShot != null) { critChance = 100; modStateComp.EnablerList.Remove(straighterShot); } else { critChance = CombatFormulas.CriticalHitRate(attComp.AttributesDictionary[AttributeType.CriticalHit]) + modStateComp.BuffDictionary[AttributeType.CriticalHitRate]; } dhitChance = CombatFormulas.DirectHitRate(attComp.AttributesDictionary[AttributeType.DirectHit]) + modStateComp.BuffDictionary[AttributeType.DirectHitRate]; // Calculates crit modifier critMod1 = CombatFormulas.CriticalHitDamageMod(attComp.AttributesDictionary[AttributeType.CriticalHit] + modStateComp.BuffDictionary[AttributeType.CriticalHit]); critMod2 = critMod1; critMod3 = critMod1; // Calculates dhit modifier dhitMod1 = CombatFormulas.DirectHitDamageMod(attComp.AttributesDictionary[AttributeType.DirectHit] + modStateComp.BuffDictionary[AttributeType.DirectHit]); dhitMod2 = dhitMod1; dhitMod3 = dhitMod1; // Compilates the chances into a dictionary: chancesDictionary = new Dictionary <AttributeType, decimal> { { AttributeType.CriticalHitRate, critChance }, { AttributeType.DirectHitRate, dhitChance } }; // Compilates all the modifiers into a dictionary: modifiersDictionary = new Dictionary <DamageModifierType, decimal> { { DamageModifierType.WeaponDamageModifier, wdMod }, { DamageModifierType.AttackPowerModifier, apMod }, { DamageModifierType.DeterminationModifier, detMod }, { DamageModifierType.TenacityModifier, tenMod }, { DamageModifierType.TraitModifier, traitMod }, { DamageModifierType.SpeedModifier, ssMod }, { DamageModifierType.CriticalModifier, critMod1 }, { DamageModifierType.DirectModifier, dhitMod1 } }; decimal totalDamage1 = 0; decimal totalDamage2 = 0; decimal totalDamage3 = 0; decimal potMod = 1; int potency = 0; // Determining potency: if (potComp != null) { potency = potComp.Amount; } else if (condPotComp != null) { potency = condPotComp.Function(entity, targOtComp, brdComp); } // Starts calculating potency modifier from base potency potMod = CombatFormulas.PotencyMod(potency); // If not critical hit, modifier is 1 if ((int)(critChance * 10) < rng.Next(1, 1000)) { critMod1 = 1; } // If not direct hit, modifier is 1 if ((int)(dhitChance * 10) < rng.Next(1, 1000)) { dhitMod1 = 1; } totalDamage1 = CombatFormulas.DirectDamage(potMod, wdMod, apMod, detMod, tenMod, traitMod, critMod1, dhitMod1, modStateComp.BuffList); // Checks for barrage Enabler barrage = modStateComp.EnablerList.Find(x => x.Name == StatusName.Barrage); if (skillBaseComp.Type == SkillType.Weaponskill && barrage != null) { // Rolls crit and dhit for two more hits // If not critical hit, modifier is 1 if ((int)(critChance * 10) < rng.Next(1, 1000)) { critMod2 = 1; } // If not direct hit, modifier is 1 if ((int)(dhitChance * 10) < rng.Next(1, 1000)) { dhitMod2 = 1; } // If not critical hit, modifier is 1 if ((int)(critChance * 10) < rng.Next(1, 1000)) { critMod3 = 1; } // If not direct hit, modifier is 1 if ((int)(dhitChance * 10) < rng.Next(1, 1000)) { dhitMod3 = 1; } // Calculates two more hits totalDamage2 = CombatFormulas.DirectDamage(potMod, wdMod, apMod, detMod, tenMod, traitMod, critMod2, dhitMod2, modStateComp.BuffList); totalDamage3 = CombatFormulas.DirectDamage(potMod, wdMod, apMod, detMod, tenMod, traitMod, critMod3, dhitMod3, modStateComp.BuffList); // Inflicts damage on target's health component targHealthComp.Amount -= totalDamage2; targHealthComp.Amount -= totalDamage3; targHealthComp.DamageTaken += totalDamage2; targHealthComp.DamageTaken += totalDamage3; // Removes the effect of barrage modStateComp.EnablerList.Remove(barrage); } // Inflicts damage on target's health component targHealthComp.Amount -= totalDamage1; targHealthComp.DamageTaken += totalDamage1; // Adds the damage to the log, if it exists if (log != null) { // If skill is a GCD if (skillBaseComp.Name == SkillName.HeavyShot || skillBaseComp.Name == SkillName.StraightShot || skillBaseComp.Name == SkillName.CausticBite || skillBaseComp.Name == SkillName.Stormbite || skillBaseComp.Name == SkillName.IronJaws || skillBaseComp.Name == SkillName.RefulgentArrow || skillBaseComp.Name == SkillName.VenomousBite || skillBaseComp.Name == SkillName.Windbite) { log.Log.Rows.Add(LogActionType.GCD, timer, skillBaseComp.Name.ToString(), totalDamage1, critMod1 > 1, dhitMod1 > 1, false); if (skillBaseComp.Type == SkillType.Weaponskill && barrage != null) { log.Log.Rows.Add(LogActionType.GCD, timer, skillBaseComp.Name.ToString(), totalDamage2, critMod2 > 1, dhitMod2 > 1, true); log.Log.Rows.Add(LogActionType.GCD, timer, skillBaseComp.Name.ToString(), totalDamage3, critMod3 > 1, dhitMod3 > 1, true); } } // Otherwise, it's an oGCD else { log.Log.Rows.Add(LogActionType.oGCD, timer, skillBaseComp.Name.ToString(), totalDamage1, critMod1 > 1, dhitMod1 > 1, false); if (skillBaseComp.Type == SkillType.Weaponskill && barrage != null) { log.Log.Rows.Add(LogActionType.oGCD, timer, skillBaseComp.Name.ToString(), totalDamage2, critMod2 > 1, dhitMod2 > 1, true); log.Log.Rows.Add(LogActionType.oGCD, timer, skillBaseComp.Name.ToString(), totalDamage3, critMod3 > 1, dhitMod3 > 1, true); } } } // Logic for over time effects foreach (DotEffectComponent dotEffectComp in dotEffectComponents.FindAll(x => x.Parent == skill)) { DoT d = targOtComp.DotList.Find(x => x.UserSource == entity && x.Name == dotEffectComp.Name); // If there's already the same DoT applied, reapplies it if (d != null) { d = new DoT(targComp.Target, entity, modifiersDictionary, chancesDictionary, modStateComp.BuffList, dotEffectComp.Name, dotEffectComp.Potency, dotEffectComp.Duration, timer, true); } //Otherwise, adds the dot else { targOtComp.DotList.Add(new DoT(targComp.Target, entity, modifiersDictionary, chancesDictionary, modStateComp.BuffList, dotEffectComp.Name, dotEffectComp.Potency, dotEffectComp.Duration, timer, false)); } } // Logic for straighter shot effects foreach (StraighterShotEffectComponent ssEffectComp in straighterShotEffectComponents.FindAll(x => x.Parent == skill)) { // Effect is granted with a chance if ((int)(ssEffectComp.Probability * 10) > rng.Next(0, 1000)) { Enabler e = modStateComp.EnablerList.Find(x => x.User == entity && x.Name == ssEffectComp.Name); // If there's already the same enabler applied, refresh the timer if (e != null) { e.Start = timer; } // Otherwise, adds the enabler else { modStateComp.EnablerList.Add(new Enabler(entity, ssEffectComp.Name, ssEffectComp.Duration, timer)); } } } // Logic for iron jaws effects foreach (IronJawsEffectComponent ijEffectComp in ironJawsEffectComponents.FindAll(x => x.Parent == skill)) { for (int i = 0; i < targOtComp.DotList.Count; i++) { DotEffectComponent ijDotEffectComp = ijEffectComp.DotList.Find(x => x.Name == targOtComp.DotList[i].Name); // If the dot is present, reapplies it if (ijDotEffectComp != null) { targOtComp.DotList[i] = new DoT(targComp.Target, entity, modifiersDictionary, chancesDictionary, modStateComp.BuffList, ijDotEffectComp.Name, ijDotEffectComp.Potency, ijDotEffectComp.Duration, timer, true); } } } // Logic for song effects foreach (SongComponent songComp in songComponents.FindAll(x => x.Parent == skill)) { // Logic for ending AP buff Buff apEffect = null; ModifierStateComponent brdModComp = modifierStateComponents.Find(x => x.Parent == brdComp.Parent); if (brdModComp != null) { apEffect = brdModComp.BuffList.Find(x => x.Name == StatusName.ArmysPaeon); } if (apEffect != null) { brdModComp.BuffDictionary[apEffect.Type] -= apEffect.Modifier; brdModComp.BuffList.Remove(apEffect); } // Logic for resetting repertoire brdComp.Repertoire = 0; // Applying the song brdComp.Song = songComp.Song; brdComp.SongStart = timer; brdComp.SongDuration = songComp.Duration; } // Logic for enhanced empyreal arrow effects foreach (EnhancedEmpyrealArrowComponent eaComp in enhancedEmpyrealArrowComponents.FindAll(x => x.Parent == skill)) { if (brdComp.Song != SongName.None) { if (brdComp.Song == SongName.TheWanderersMinuet && brdComp.Repertoire < 3) { brdComp.Repertoire++; } else if (brdComp.Song == SongName.MagesBallad) { brdComp.Repertoire++; } else if (brdComp.Song == SongName.ArmysPaeon && brdComp.Repertoire < 4) { brdComp.Repertoire++; } } } // Logic for consuming repertoire foreach (UsesRepertoireComponent repComp in usesRepertoireComponents.FindAll(x => x.Parent == skill)) { brdComp.Repertoire = 0; } // Logic for consuming enabler foreach (UsesEnablerComponent enComp in usesEnablerComponents.FindAll(x => x.Parent == skill)) { Enabler e = modStateComp.EnablerList.Find(x => x.Name == enComp.Name); if (e != null) { modStateComp.EnablerList.Remove(e); } } } // Activates animation lock animLockComp.Start = timer; // Adjusts cooldown if (skillBaseComp.Type == SkillType.Weaponskill) { recast = CombatFormulas.SpeedRecast ( attComp.AttributesDictionary[AttributeType.SkillSpeed] + modStateComp.BuffDictionary[AttributeType.SkillSpeed], cdComp.BaseRecast, modStateComp.BuffDictionary[AttributeType.Arrow], modStateComp.BuffDictionary[AttributeType.Haste], modStateComp.BuffDictionary[AttributeType.FeyWind], modStateComp.BuffDictionary[AttributeType.SpeedType1], modStateComp.BuffDictionary[AttributeType.SpeedType2], modStateComp.BuffDictionary[AttributeType.RiddleOfFire], modStateComp.BuffDictionary[AttributeType.AstralUmbral] ); } else if (skillBaseComp.Type == SkillType.Spell) { recast = CombatFormulas.SpeedRecast ( attComp.AttributesDictionary[AttributeType.SpellSpeed] + modStateComp.BuffDictionary[AttributeType.SpellSpeed], cdComp.BaseRecast, modStateComp.BuffDictionary[AttributeType.Arrow], modStateComp.BuffDictionary[AttributeType.Haste], modStateComp.BuffDictionary[AttributeType.FeyWind], modStateComp.BuffDictionary[AttributeType.SpeedType1], modStateComp.BuffDictionary[AttributeType.SpeedType2], modStateComp.BuffDictionary[AttributeType.RiddleOfFire], modStateComp.BuffDictionary[AttributeType.AstralUmbral] ); } else { recast = cdComp.BaseRecast; } // Logic for cooldown foreach (Entity sharedSkill in cdComp.SharedCooldownList) { CooldownComponent c = cooldownComponents.Find(x => x.Parent == sharedSkill); c.Start = timer; c.UsableAt = c.Start + recast; } // Logic for buff effects foreach (StatusEffectComponent statusComp in statusEffectComponents.FindAll(x => x.Parent == skill)) { Buff b = modStateComp.BuffList.Find(x => x.UserSource == entity && x.Name == statusComp.Name); // If there's already the same buff applied, refresh the timer if (b != null) { b.Start = timer; } // Otherwise, adds the buff else { if (statusComp.Actor == ActorType.Self) { modStateComp.BuffList.Add(new Buff(entity, entity, statusComp.Name, statusComp.Type, statusComp.Duration, timer, statusComp.Modifier, false)); } else if (statusComp.Actor == ActorType.Target) { modStateComp.BuffList.Add(new Buff(targComp.Target, entity, statusComp.Name, statusComp.Type, statusComp.Duration, timer, statusComp.Modifier, false)); } } } // Logic for generic buff effects foreach (GenericStatusEffectComponent genStatusComp in genericStatusEffectComponents.FindAll(x => x.Parent == skill)) { Enabler e = modStateComp.EnablerList.Find(x => x.User == entity && x.Name == genStatusComp.Name); // If there's already the same enabler applied, refresh the timer if (e != null) { e.Start = timer; } // Otherwise, adds the enabler else { modStateComp.EnablerList.Add(new Enabler(entity, genStatusComp.Name, genStatusComp.Duration, timer)); } } } } } break; } } } } }
public void Update(decimal timer, Keyboard keyboard, LogData log) { if (!(timer <= NextGCD(heavyShotCdComp) - Constants.AnimationLock) || NextGCD(heavyShotCdComp) <= 0m) { if (targOtComp.DotList.Find(x => x.Name == DotName.Stormbite && x.UserSource == player && x.Duration - timer + x.Start < 4m) != null || targOtComp.DotList.Find(x => x.Name == DotName.CausticBite && x.UserSource == player && x.Duration - timer + x.Start < 4m) != null) { UseKey(keyboard, Keys.Num5); } else if (modStateComponent.EnablerList.Find(x => x.Name == StatusName.StraighterShot) != null) { UseKey(keyboard, Keys.F3); } else if (modStateComponent.BuffList.Find(x => x.IsActive && x.Name == StatusName.StraightShot) == null) { UseKey(keyboard, Keys.Num2); } else if (targOtComp.DotList.Find(x => x.IsActive == true && x.Name == DotName.Stormbite && x.UserSource == player) == null) { UseKey(keyboard, Keys.Num3); } else if (targOtComp.DotList.Find(x => x.IsActive == true && x.Name == DotName.CausticBite && x.UserSource == player) == null) { UseKey(keyboard, Keys.Num4); } else { UseKey(keyboard, Keys.Num1); } } else { if (brdComp.Song != SongName.TheWanderersMinuet && wmCooldownComp.UsableAt <= timer && apCooldownComp.UsableAt - timer <= 60m && onOpener == false) { UseKey(keyboard, Keys.M1); } else if (brdComp.Song != SongName.MagesBallad && mbCooldownComp.UsableAt <= timer && wmCooldownComp.UsableAt - timer <= 50m && onOpener == false) { UseKey(keyboard, Keys.M2); } else if (brdComp.Song != SongName.ArmysPaeon && apCooldownComp.UsableAt <= timer && mbCooldownComp.UsableAt - timer <= 50m && wmCooldownComp.UsableAt - timer <= 20m && onOpener == false) { UseKey(keyboard, Keys.M3); } else if ((brdComp.Song == SongName.TheWanderersMinuet && brdComp.Repertoire == 3 && ppCooldownComp.UsableAt <= timer) || (brdComp.Song == SongName.TheWanderersMinuet && timer - wmCooldownComp.Start >= 28m && ppCooldownComp.UsableAt <= timer)) { UseKey(keyboard, Keys.T); } else if (blCooldownComp.UsableAt <= timer) { UseKey(keyboard, Keys.R); } else if (rsCooldownComp.UsableAt <= timer) { UseKey(keyboard, Keys.F1); } else if (brdComp.Song != SongName.TheWanderersMinuet && wmCooldownComp.UsableAt <= timer && apCooldownComp.UsableAt - timer <= 60m && onOpener == true) { onOpener = false; UseKey(keyboard, Keys.M1); } else if (modStateComponent.EnablerList.Find(x => x.Name == StatusName.StraighterShot) != null && barrageCooldownComp.UsableAt <= timer && !(targOtComp.DotList.Find(x => x.Name == DotName.Stormbite && x.Duration - timer + x.Start < 4m) != null || targOtComp.DotList.Find(x => x.Name == DotName.CausticBite && x.Duration - timer + x.Start < 4m) != null)) { UseKey(keyboard, Keys.F2); } else if (!(modStateComponent.EnablerList.Find(x => x.Name == StatusName.StraighterShot) != null && modStateComponent.EnablerList.Find(x => x.Name == StatusName.Barrage) != null) && eaCooldownComp.UsableAt <= timer) { UseKey(keyboard, Keys.Num6); } else if ((targOtComp.DotList.Find(x => x.IsActive == true && x.Name == DotName.Stormbite && x.UserSource == player) != null && targOtComp.DotList.Find(x => x.IsActive == true && x.Name == DotName.CausticBite && x.UserSource == player) != null) && swCooldownComp.UsableAt <= timer) { UseKey(keyboard, Keys.Num7); } } }
public void Update(decimal timer, Keyboard keyboard, LogData log) { foreach (OverTimeStateComponent otStateComp in overtimeStateComponents) { // Gets the HealthComponent of the entity inflicted by the over time effect HealthComponent healthComp = healthComponents.Find(x => x.Parent == otStateComp.Parent); foreach (DoT dot in otStateComp.DotList) { // Remove the DoT if it's expired if (timer - dot.Start > dot.Duration) { toBeRemoved.Add(dot); } else { // Activates if not active if (!dot.IsActive) { dot.IsActive = true; dot.LastTick = timer; } else { // Executes the damage if (((timer - otStateComp.Offset) % (3m) == 0) && (timer - dot.LastTick >= 3m)) { decimal critMod = 1; decimal dhitMod = 1; bool hasCrit = false; if ((int)(dot.UsersChancesDictionary[AttributeType.CriticalHitRate] * 10) > rng.Next(0, 1000)) { critMod = dot.UsersModifiersDictionary[DamageModifierType.CriticalModifier]; // For repertoire hasCrit = true; } if ((int)(dot.UsersChancesDictionary[AttributeType.DirectHitRate] * 10) > rng.Next(0, 1000)) { dhitMod = dot.UsersModifiersDictionary[DamageModifierType.DirectModifier]; } decimal dotTick = CombatFormulas.DoTDamage ( CombatFormulas.PotencyMod(dot.Potency), dot.UsersModifiersDictionary[DamageModifierType.WeaponDamageModifier], dot.UsersModifiersDictionary[DamageModifierType.AttackPowerModifier], dot.UsersModifiersDictionary[DamageModifierType.DeterminationModifier], dot.UsersModifiersDictionary[DamageModifierType.TenacityModifier], dot.UsersModifiersDictionary[DamageModifierType.TraitModifier], dot.UsersModifiersDictionary[DamageModifierType.SpeedModifier], critMod, dhitMod, dot.UsersBuffList ); healthComp.Amount -= dotTick; healthComp.DamageTaken += dotTick; // Adds the damage to the log, if it exists if (log != null) { log.Log.Rows.Add(LogActionType.DoT, timer, dot.Name.ToString(), dotTick, critMod > 1, dhitMod > 1, false); } dot.LastTick = timer; // Handles repertoire if ((dot.Name == DotName.CausticBite || dot.Name == DotName.Stormbite) && hasCrit) { // Gets the BardComponent of the entity that applied the over time effect foreach (BardComponent brdComp in bardComponents.FindAll(x => x.Parent == dot.UserSource)) { if (brdComp.Song == SongName.TheWanderersMinuet && brdComp.Repertoire < 3) { brdComp.Repertoire++; } else if (brdComp.Song == SongName.MagesBallad) { brdComp.Repertoire++; } else if (brdComp.Song == SongName.ArmysPaeon && brdComp.Repertoire < 4) { brdComp.Repertoire++; } } } } } } } foreach (DoT dot in toBeRemoved) { otStateComp.DotList.Remove(dot); } toBeRemoved = new List <DoT>(); } }
public void Update(decimal timer, Keyboard keyboard, LogData log) { foreach (AutoAttackComponent aaComp in autoAttackComponents) { AttributesComponent attComp = attributesComponents.Find(x => x.Parent == aaComp.Parent); ModifierStateComponent modStateComp = modifiterStateComponents.Find(x => x.Parent == aaComp.Parent); BardComponent brdComp = bardComponents.Find(x => x.Parent == aaComp.Parent); TargetComponent targComp = targetComponents.Find(x => x.Parent == aaComp.Parent); HealthComponent targHealthComp = healthComponents.Find(x => x.Parent == targComp.Target); // To assure autos start right away if (aaComp.NextAuto == 0) { aaComp.NextAuto = timer; } // Inflict auto attack damage every X seconds, where X is the weapon delay if (timer == aaComp.NextAuto) { decimal potMod = 1; decimal aaMod = 1; decimal apMod = 1; decimal detMod = 1; decimal tenMod = 1; decimal ssMod = 1; decimal critMod = 1; decimal dhitMod = 1; decimal critChance; decimal dhitChance; decimal totalDamage; // Starts calculating potency modifier from base potency potMod = CombatFormulas.PotencyMod(aaComp.Potency); // Calculates auto attack modifier aaMod = CombatFormulas.AutoAttackMod(attComp.AttributesDictionary[AttributeType.WeaponDamage], attComp.AttributesDictionary[AttributeType.WeaponDelay]); // Calculates attack power modifier (every job uses str, except dex-based jobs) if (brdComp.Job == Job.Ninja || brdComp.Job == Job.Bard || brdComp.Job == Job.Machinist) { apMod = CombatFormulas.AttackPowerDamageMod(attComp.AttributesDictionary[AttributeType.Dexterity] + modStateComp.BuffDictionary[AttributeType.Dexterity]); } else { apMod = CombatFormulas.AttackPowerDamageMod(attComp.AttributesDictionary[AttributeType.Strenght] + modStateComp.BuffDictionary[AttributeType.Strenght]); } // Calculates determination modifier detMod = CombatFormulas.DeterminationDamageMod(attComp.AttributesDictionary[AttributeType.Determination] + modStateComp.BuffDictionary[AttributeType.Determination]); // Calculates tenacity modifier tenMod = CombatFormulas.TenacityDamageMod(attComp.AttributesDictionary[AttributeType.Tenacity] + modStateComp.BuffDictionary[AttributeType.Tenacity]); // Calculates speed modifier (even casters use sks for this) ssMod = CombatFormulas.SpeedDamageMod(attComp.AttributesDictionary[AttributeType.SkillSpeed] + modStateComp.BuffDictionary[AttributeType.SkillSpeed]); critChance = CombatFormulas.CriticalHitRate(attComp.AttributesDictionary[AttributeType.CriticalHit]) + modStateComp.BuffDictionary[AttributeType.CriticalHitRate]; dhitChance = CombatFormulas.DirectHitRate(attComp.AttributesDictionary[AttributeType.DirectHit]) + modStateComp.BuffDictionary[AttributeType.DirectHitRate]; // Calculates crit modifier // If not critical hit, modifier is 1 if ((int)(critChance * 10) < rng.Next(1, 1000)) { critMod = 1; } else { critMod = CombatFormulas.CriticalHitDamageMod(attComp.AttributesDictionary[AttributeType.CriticalHit] + modStateComp.BuffDictionary[AttributeType.CriticalHit]); } // Calculates dhit modifier // If not direct hit, modifier is 1 if ((int)(dhitChance * 10) < rng.Next(1, 1000)) { dhitMod = 1; } else { dhitMod = CombatFormulas.DirectHitDamageMod(attComp.AttributesDictionary[AttributeType.DirectHit] + modStateComp.BuffDictionary[AttributeType.DirectHit]); } totalDamage = CombatFormulas.AutoAttackDamage(potMod, aaMod, apMod, detMod, tenMod, 1, ssMod, critMod, dhitMod, modStateComp.BuffList); // Inflicts damage on target's health component targHealthComp.Amount -= totalDamage; targHealthComp.DamageTaken += totalDamage; // Adds the damage to the log, if it exists if (log != null) { log.Log.Rows.Add(LogActionType.AutoAttack, timer, "Auto attack", totalDamage, critMod > 1, dhitMod > 1, false); } // Sets next auto aaComp.NextAuto += attComp.AttributesDictionary[AttributeType.WeaponDelay]; } } }
static void Main(string[] args) { while (true) { LogData logData = new LogData(); DataTable dpsTable = new DataTable("DPS"); List <string> ariyalaSets = new List <string>(); int numberOfSets = 0; int numberOfRuns = 0; decimal simulationTarget = 0; List <AttributesDictionary> listOfAttDicts = new List <AttributesDictionary>(); AttributesDictionary singleAttDict = new AttributesDictionary(); bool validSetNumber = true; bool validCode = true; bool validRunsNumber = true; bool validSimulationTarget = true; SimulationParameters simulationParameter = SimulationParameters.Invalid; SimulationType simulationType = SimulationType.Invalid; // Asks for type of simulation do { Console.WriteLine("\nEnter 'V' for a single verbose run, or 'M' for multiple runs:"); try { char typeChar = Console.ReadLine()[0]; if (typeChar == 'V') { simulationType = SimulationType.Verbose; } else if (typeChar == 'M') { simulationType = SimulationType.Multiple; } else { throw new InvalidDataException("Invalid type of simulation."); } } catch (Exception e) { Console.WriteLine(e.Message); simulationType = SimulationType.Invalid; } }while (simulationType == SimulationType.Invalid); // Multiple simulation if (simulationType == SimulationType.Multiple) { // Asks for number of gearsets do { Console.WriteLine("\nInput the number of gearsets:"); try { int.TryParse(Console.ReadLine(), out numberOfSets); if (numberOfSets <= 0) { throw new InvalidDataException("Number must be greater than zero."); } validSetNumber = true; } catch (Exception e) { Console.WriteLine(e.Message); validSetNumber = false; } }while (!validSetNumber); // Instantiates the HTML scraper for Ariyala AriyalaScraper scraper = new AriyalaScraper(); // Iterates over each gearset for (int i = 0; i < numberOfSets; i++) { do { Console.WriteLine("\nEnter the Ariyala link or code #{0}:", i + 1); try { string ariyalaCode = Console.ReadLine(); listOfAttDicts.Add(scraper.GetAriyalaSet(ariyalaCode)); validCode = true; } catch (Exception e) { Console.WriteLine(e.Message); validCode = false; } }while (!validCode); } // Closes the browser scraper.Dispose(); // Asks for number of simulations do { Console.WriteLine("\nInput the number of simulations:"); try { int.TryParse(Console.ReadLine(), out numberOfRuns); if (numberOfRuns <= 0) { throw new InvalidDataException("Number must be greater than zero."); } validRunsNumber = true; } catch (Exception e) { Console.WriteLine(e.Message); validRunsNumber = false; } }while (!validRunsNumber); // Asks for type of simulation do { Console.WriteLine("\nEnter 'D' for damage target, or 'T' for time target:"); try { char targetChar = Console.ReadLine()[0]; if (targetChar == 'D') { simulationParameter = SimulationParameters.DamageTarget; } else if (targetChar == 'T') { simulationParameter = SimulationParameters.TimeTarget; } else { throw new InvalidDataException("Invalid type of simulation."); } } catch (Exception e) { Console.WriteLine(e.Message); simulationParameter = SimulationParameters.Invalid; } }while (simulationParameter == SimulationParameters.Invalid); // Asks for target of simulation (seconds or total damage) do { try { if (simulationParameter == SimulationParameters.DamageTarget) { Console.WriteLine("\nInput the total damage target:"); decimal.TryParse(Console.ReadLine(), out simulationTarget); } else if (simulationParameter == SimulationParameters.TimeTarget) { Console.WriteLine("\nInput the time target (in seconds):"); decimal.TryParse(Console.ReadLine(), out simulationTarget); } if (simulationTarget <= 0) { throw new InvalidDataException("Value must be greater than zero."); } validSimulationTarget = true; } catch (Exception e) { Console.WriteLine(e.Message); validSimulationTarget = false; } }while (!validSimulationTarget); // Main loop for (int k = 0; k < numberOfSets; k++) { List <decimal> results = new List <decimal>(); Engine engine = new Engine(listOfAttDicts[k]); Stopwatch timer = new Stopwatch(); // Simulates each gearset timer.Start(); for (int i = 0; i < numberOfRuns; i++) { results.Add(engine.Simulate(simulationParameter, simulationTarget)); engine.Reinitialize(); } timer.Stop(); Console.WriteLine("\nAverage DPS: {0:0.00}\nMax: {1:0.00}\nMin: {2:0.00}", results.Average(), results.Max(), results.Min()); Console.WriteLine("\nSimulation time: {0}", timer.ElapsedMilliseconds.MilliToSeconds()); // Writes to CSV Console.WriteLine("\nWriting to CSV."); StreamWriter stream = new StreamWriter(Environment.CurrentDirectory + k.ToString() + @".csv"); CsvWriter csvWriter = new CsvWriter(stream); timer.Restart(); foreach (decimal d in results) { csvWriter.WriteRecord((double)d); csvWriter.NextRecord(); } timer.Stop(); Console.WriteLine("\nWrite time: {0}", timer.ElapsedMilliseconds.MilliToSeconds()); stream.Dispose(); } } // Single verbose simulation else { // Instantiates the HTML scraper for Ariyala AriyalaScraper scraper = new AriyalaScraper(); // Asks for an Ariyala code do { Console.WriteLine("\nEnter the Ariyala link or code:"); try { string ariyalaCode = Console.ReadLine(); singleAttDict = scraper.GetAriyalaSet(ariyalaCode); validCode = true; } catch (Exception e) { Console.WriteLine(e.Message); validCode = false; } }while (!validCode); // Closes the browser scraper.Dispose(); // Asks for type of simulation do { Console.WriteLine("\nEnter 'D' for damage target, or 'T' for time target:"); try { char targetChar = Console.ReadLine()[0]; if (targetChar == 'D') { simulationParameter = SimulationParameters.DamageTarget; } else if (targetChar == 'T') { simulationParameter = SimulationParameters.TimeTarget; } else { throw new InvalidDataException("Invalid type of simulation."); } } catch (Exception e) { Console.WriteLine(e.Message); simulationParameter = SimulationParameters.Invalid; } }while (simulationParameter == SimulationParameters.Invalid); // Asks for target of simulation (seconds or total damage) do { try { if (simulationParameter == SimulationParameters.DamageTarget) { Console.WriteLine("\nInput the total damage target:"); decimal.TryParse(Console.ReadLine(), out simulationTarget); } else if (simulationParameter == SimulationParameters.TimeTarget) { Console.WriteLine("\nInput the time target (in seconds):"); decimal.TryParse(Console.ReadLine(), out simulationTarget); } if (simulationTarget <= 0) { throw new InvalidDataException("Value must be greater than zero."); } validSimulationTarget = true; } catch (Exception e) { Console.WriteLine(e.Message); validSimulationTarget = false; } }while (!validSimulationTarget); // Main loop decimal result = 0; Engine engine = new Engine(singleAttDict); Stopwatch timer = new Stopwatch(); timer.Start(); result = engine.Simulate(simulationParameter, simulationTarget, logData); engine.Reinitialize(); timer.Stop(); List <string> logStrings = logData.GetLog(); foreach (string s in logStrings) { Console.Write(s); } Console.WriteLine("\nDPS: {0:0.00}", result); Console.WriteLine("\nSimulation time: {0}", timer.ElapsedMilliseconds.MilliToSeconds()); } } }