public Engine(AttributesDictionary playerAttributes) { _systems = new List <ISystem>(); _entities = new List <Entity>(); // Sets up a keyboard to watch for inputs keyboard = new Keyboard(); // Initializing player entities player = new Entity(); // Initializing enemy entities enemy = new Entity(); // Initializing skill entities heavyShot = new Entity(); straightShot = new Entity(); causticBite = new Entity(); stormBite = new Entity(); ironJaws = new Entity(); refulgentArrow = new Entity(); bloodletter = new Entity(); empyrealArrow = new Entity(); pitchPerfect = new Entity(); sidewinder = new Entity(); ragingStrikes = new Entity(); barrage = new Entity(); theWanderersMinuet = new Entity(); magesBallad = new Entity(); armysPaeon = new Entity(); // Shared cooldown lists gcdSkillList = new List <Entity> { heavyShot, straightShot, causticBite, stormBite, ironJaws, refulgentArrow }; riverOfBloodSkillList = new List <Entity> { bloodletter, //rainOfDeath }; // Adding components to skills heavyShot.AddComponents(new List <Component> { new SkillBaseComponent(heavyShot, SkillName.HeavyShot, SkillType.Weaponskill), new CooldownComponent(heavyShot, 2.5m, gcdSkillList), new PotencyComponent(heavyShot, 150), new StraighterShotEffectComponent(heavyShot, StatusName.StraighterShot, 10m, 20) }); straightShot.AddComponents(new List <Component> { new SkillBaseComponent(straightShot, SkillName.StraightShot, SkillType.Weaponskill), new CooldownComponent(straightShot, 2.5m, gcdSkillList), new PotencyComponent(straightShot, 140), new StatusEffectComponent(straightShot, AttributeType.CriticalHitRate, StatusName.StraightShot, ActorType.Self, 30, 10) }); causticBite.AddComponents(new List <Component> { new SkillBaseComponent(causticBite, SkillName.CausticBite, SkillType.Weaponskill), new CooldownComponent(causticBite, 2.5m, gcdSkillList), new PotencyComponent(causticBite, 120), new DotEffectComponent(causticBite, DotName.CausticBite, 30m, 45) }); stormBite.AddComponents(new List <Component> { new SkillBaseComponent(stormBite, SkillName.Stormbite, SkillType.Weaponskill), new CooldownComponent(stormBite, 2.5m, gcdSkillList), new PotencyComponent(stormBite, 120), new DotEffectComponent(stormBite, DotName.Stormbite, 30m, 55) }); ironJaws.AddComponents(new List <Component> { new SkillBaseComponent(ironJaws, SkillName.IronJaws, SkillType.Weaponskill), new CooldownComponent(ironJaws, 2.5m, gcdSkillList), new PotencyComponent(ironJaws, 100), new IronJawsEffectComponent(ironJaws, new List <DotEffectComponent> { (DotEffectComponent)stormBite.Components.Find(x => x is DotEffectComponent), (DotEffectComponent)causticBite.Components.Find(x => x is DotEffectComponent) }) }); refulgentArrow.AddComponents(new List <Component> { new SkillBaseComponent(refulgentArrow, SkillName.RefulgentArrow, SkillType.Weaponskill), new CooldownComponent(refulgentArrow, 2.5m, gcdSkillList), new PotencyComponent(refulgentArrow, 300), new UseConditionComponent(refulgentArrow, ConditionalFunctions.IsRefulgentArrowUsable), new UsesEnablerComponent(refulgentArrow, StatusName.StraighterShot) }); bloodletter.AddComponents(new List <Component> { new SkillBaseComponent(bloodletter, SkillName.Bloodletter, SkillType.Ability), new CooldownComponent(bloodletter, 15m), new PotencyComponent(bloodletter, 130) }); empyrealArrow.AddComponents(new List <Component> { new SkillBaseComponent(empyrealArrow, SkillName.EmpyrealArrow, SkillType.Weaponskill), new CooldownComponent(empyrealArrow, 15m), new PotencyComponent(empyrealArrow, 230), new EnhancedEmpyrealArrowComponent(empyrealArrow) }); pitchPerfect.AddComponents(new List <Component> { new SkillBaseComponent(pitchPerfect, SkillName.PitchPerfect, SkillType.Ability), new CooldownComponent(pitchPerfect, 3m), new ConditionalPotencyComponent(pitchPerfect, ConditionalFunctions.PitchPerfectPotency), new UseConditionComponent(pitchPerfect, ConditionalFunctions.IsPitchPerfectUsable), new UsesRepertoireComponent(pitchPerfect) }); sidewinder.AddComponents(new List <Component> { new SkillBaseComponent(sidewinder, SkillName.Sidewinder, SkillType.Ability), new CooldownComponent(sidewinder, 60m), new ConditionalPotencyComponent(sidewinder, ConditionalFunctions.SidewinderPotency) }); ragingStrikes.AddComponents(new List <Component> { new SkillBaseComponent(ragingStrikes, SkillName.RagingStrikes, SkillType.Ability), new CooldownComponent(ragingStrikes, 80m), new StatusEffectComponent(ragingStrikes, AttributeType.Damage, StatusName.RagingStrikes, ActorType.Self, 20m, 1.1m) }); barrage.AddComponents(new List <Component> { new SkillBaseComponent(barrage, SkillName.Barrage, SkillType.Ability), new CooldownComponent(barrage, 80m), new GenericStatusEffectComponent(barrage, StatusName.Barrage, 10m) }); theWanderersMinuet.AddComponents(new List <Component> { new SkillBaseComponent(theWanderersMinuet, SkillName.TheWanderersMinuet, SkillType.Spell), new CooldownComponent(theWanderersMinuet, 80m), new PotencyComponent(theWanderersMinuet, 100), new SongComponent(theWanderersMinuet, SongName.TheWanderersMinuet) }); magesBallad.AddComponents(new List <Component> { new SkillBaseComponent(magesBallad, SkillName.MagesBallad, SkillType.Spell), new CooldownComponent(magesBallad, 80m), new PotencyComponent(magesBallad, 100), new SongComponent(magesBallad, SongName.MagesBallad) }); armysPaeon.AddComponents(new List <Component> { new SkillBaseComponent(armysPaeon, SkillName.ArmysPaeon, SkillType.Spell), new CooldownComponent(armysPaeon, 80m), new PotencyComponent(armysPaeon, 100), new SongComponent(armysPaeon, SongName.ArmysPaeon) }); // Initializing player components player.AddComponents(new List <Component> { new BardComponent(player, new List <Entity> { heavyShot, straightShot, causticBite, stormBite, ironJaws, refulgentArrow, bloodletter, empyrealArrow, pitchPerfect, sidewinder, ragingStrikes, barrage, theWanderersMinuet, magesBallad, armysPaeon }), new AttributesComponent(player, playerAttributes), new ModifierStateComponent(player), new AnimationLockComponent(player), new AutoAttackComponent(player, 100), new RiverOfBloodComponent(player, riverOfBloodSkillList), new SkillControlComponent(player, Job.Bard), // DEBUG: Setting enemy as player's target new TargetComponent(player, enemy) }); // Initializing enemy components enemy.AddComponents(new List <Component> { new HealthComponent(enemy, 0), new OverTimeStateComponent(enemy) }); // Making entities list _entities.Add(player); _entities.Add(enemy); _entities.Add(heavyShot); _entities.Add(straightShot); _entities.Add(causticBite); _entities.Add(stormBite); _entities.Add(ironJaws); _entities.Add(refulgentArrow); _entities.Add(bloodletter); _entities.Add(empyrealArrow); _entities.Add(pitchPerfect); _entities.Add(sidewinder); _entities.Add(ragingStrikes); _entities.Add(barrage); _entities.Add(theWanderersMinuet); _entities.Add(magesBallad); _entities.Add(armysPaeon); foreach (Entity e in _entities) { foreach (Component c in e.Components) { if (c is AnimationLockComponent) { animationLockComponents.Add((AnimationLockComponent)c); } else if (c is AttributesComponent) { attributesComponents.Add((AttributesComponent)c); } else if (c is AutoAttackComponent) { autoAttackComponents.Add((AutoAttackComponent)c); } else if (c is BardComponent) { bardComponents.Add((BardComponent)c); } else if (c is ConditionalPotencyComponent) { conditionalPotencyComponents.Add((ConditionalPotencyComponent)c); } else if (c is CooldownComponent) { cooldownComponents.Add((CooldownComponent)c); } else if (c is DotEffectComponent) { dotEffectComponents.Add((DotEffectComponent)c); } else if (c is EnhancedEmpyrealArrowComponent) { enhancedEmpyrealArrowComponents.Add((EnhancedEmpyrealArrowComponent)c); } else if (c is GenericStatusEffectComponent) { genericStatusEffectComponents.Add((GenericStatusEffectComponent)c); } else if (c is HealthComponent) { healthComponents.Add((HealthComponent)c); } else if (c is IronJawsEffectComponent) { ironJawsEffectComponents.Add((IronJawsEffectComponent)c); } else if (c is ModifierStateComponent) { modifierStateComponents.Add((ModifierStateComponent)c); } else if (c is OverTimeStateComponent) { overtimeStateComponents.Add((OverTimeStateComponent)c); } else if (c is PotencyComponent) { potencyComponents.Add((PotencyComponent)c); } else if (c is RiverOfBloodComponent) { riverOfBloodComponents.Add((RiverOfBloodComponent)c); } else if (c is SkillBaseComponent) { skillBaseComponents.Add((SkillBaseComponent)c); } else if (c is SkillControlComponent) { skillControlComponents.Add((SkillControlComponent)c); } else if (c is SongComponent) { songComponents.Add((SongComponent)c); } else if (c is StatusEffectComponent) { statusEffectComponents.Add((StatusEffectComponent)c); } else if (c is StraighterShotEffectComponent) { straighterShotEffectComponents.Add((StraighterShotEffectComponent)c); } else if (c is TargetComponent) { targetComponents.Add((TargetComponent)c); } else if (c is UseConditionComponent) { useConditionComponents.Add((UseConditionComponent)c); } else if (c is UsesEnablerComponent) { usesEnablerComponents.Add((UsesEnablerComponent)c); } else if (c is UsesRepertoireComponent) { usesRepertoireComponents.Add((UsesRepertoireComponent)c); } } } // Initializing systems //_systems.Add(new AIDebugSystem(player, bardComponents, cooldownComponents, modifierStateComponents, overtimeStateComponents, skillBaseComponents, targetComponents)); _systems.Add(new NewAISystem(player, bardComponents, cooldownComponents, modifierStateComponents, overtimeStateComponents, skillBaseComponents, skillControlComponents, targetComponents)); _systems.Add(new OverTimeSystem(bardComponents, cooldownComponents, healthComponents, modifierStateComponents, overtimeStateComponents, riverOfBloodComponents)); _systems.Add(new RepertoireSystem(bardComponents, cooldownComponents, modifierStateComponents, riverOfBloodComponents)); _systems.Add(new BuffSystem(bardComponents, modifierStateComponents)); _systems.Add(new AutoAttackSystem(attributesComponents, autoAttackComponents, bardComponents, healthComponents, modifierStateComponents, targetComponents)); _systems.Add(new SkillSystem(animationLockComponents, attributesComponents, bardComponents, conditionalPotencyComponents, cooldownComponents, dotEffectComponents, enhancedEmpyrealArrowComponents, genericStatusEffectComponents, healthComponents, ironJawsEffectComponents, modifierStateComponents, overtimeStateComponents, potencyComponents, skillBaseComponents, skillControlComponents, songComponents, statusEffectComponents, straighterShotEffectComponents, targetComponents, useConditionComponents, usesEnablerComponents, usesRepertoireComponents)); }
public AttributesDictionary GetAriyalaSet(string code) { // Checks if the input is valid if (!ariyalaRegex.IsMatch(code)) { throw new FormatException("\nInvalid link or code. "); } // Navigates the page string ariyalaLink = "http://ffxiv.ariyala.com/" + ariyalaRegex.Match(code).Groups[3].Value; driver.Url = ariyalaLink; driver.Navigate(); wait.Until(new Func <IWebDriver, bool>(IsLoaded)); //TODO: Change for all jobs // Checks if it's a BRD gearset by reading the content of the html element if (driver.FindElement(By.Id("categoryBoxContentName")).Text != "Bard") { throw new NotImplementedException("\nNot a bard gearset. "); } // Reads the attributes from the html elements IReadOnlyCollection <IWebElement> elementList = driver.FindElements(By.XPath(xpath)); AttributesDictionary attributesFromAriyala = new AttributesDictionary(); if (elementList.Count != JobSettings.brdAttributeTypes.Count) { throw new NotFoundException("\nNumber of attributes read and expected mismatch. "); } for (int i = 0; i < elementList.Count; i++) { int.TryParse(attributeRegex.Match(elementList.ElementAt(i).Text).Groups[1].Value, out int attribute); if (attribute == 0) { throw new FormatException("\nInvalid attribute. "); } // Stores the read attribute into the dictionary attributesFromAriyala[JobSettings.brdAttributeTypes[i]] = attribute; } bool validAttackPower = true; bool validWeapDamage = true; bool validWeapDelay = true; do { try { Console.WriteLine("\nPlease manually input the Attack Power:"); int.TryParse(Console.ReadLine(), out int attackPower); if (attackPower <= 0) { throw new InvalidDataException("\nNumber must be greater than zero."); } attributesFromAriyala[JobSettings.brdAttributeTypes[0]] = attackPower; validAttackPower = true; } catch (Exception e) { Console.WriteLine(e.Message); validAttackPower = false; } }while (!validAttackPower); // Asks for weapon damage and weapon delay do { try { Console.WriteLine("\nPlease manually input the Weapon Damage:"); int.TryParse(Console.ReadLine(), out int weaponDamage); if (weaponDamage <= 0) { throw new InvalidDataException("\nNumber must be greater than zero."); } attributesFromAriyala[AttributeType.WeaponDamage] = weaponDamage; validWeapDamage = true; } catch (Exception e) { Console.WriteLine(e.Message); validWeapDamage = false; } }while (!validWeapDamage); do { try { Console.WriteLine("\nPlease manually input the Weapon Delay:"); decimal.TryParse(Console.ReadLine(), out decimal weaponDelay); if (weaponDelay <= 0) { throw new InvalidDataException("\nNumber must be greater than zero."); } attributesFromAriyala[AttributeType.WeaponDelay] = weaponDelay; validWeapDelay = true; } catch (Exception e) { Console.WriteLine(e.Message); validWeapDelay = false; } }while (!validWeapDelay); return(attributesFromAriyala); }
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()); } } }