public double Attack(StrikingDummy target, WeaponSkills weaponSkill) { var animationLocked = QueuedEffects.ContainsKey(Skills.StatusEffects.AnimationLocked); if (GcdDuration > 0 || animationLocked) { return(0); } var potency = WeaponLibrary.WeaponPotencies(weaponSkill, LastSkills); var damage = FormulaLibrary.WeaponSkills(potency, Weapon.WeaponDamage, GetDexterity(), Det, CalculateMultiplier(target, DamageType.Slashing)); if (StatusEffects.ContainsKey(Skills.StatusEffects.Duality)) { damage *= 2; StatusEffects.Remove(Skills.StatusEffects.Duality); } else { damage = (damage * CalculateCritChance() * FormulaLibrary.CritDmg(Crt)) + (damage * (1 - CalculateCritChance())); } WeaponLibrary.QueueEffect(this, target, weaponSkill); var gcdMultiplier = StatusEffects.ContainsKey(Skills.StatusEffects.Huton) ? 0.85 : 1.00; GcdDuration = (int)TimeSpan.FromSeconds(FormulaLibrary.Gcd(Sks, gcdMultiplier)).TotalMilliseconds; LastSkills.Push(weaponSkill); return(damage); }
public static void QueueEffect(Player player, StrikingDummy strikingDummy, WeaponSkills weaponSkill) { WeaponSkills lastSkill; player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); switch (weaponSkill) { case WeaponSkills.ShadowFang: if (player.LastSkills.Peek() == WeaponSkills.SpinningEdge) { strikingDummy.QueuedEffects.Add(StatusEffects.ShadowFang, new EffectSnapshot { Duration = 585, CritChance = player.CalculateCritChance(), Crt = player.Crt, Det = player.Det, Multiplier = player.CalculateDamageOverTimeMultiplier(DamageType.Physical, strikingDummy), Dex = player.GetDexterity(), Potency = 40, Target = strikingDummy, WeaponDamage = player.Weapon.WeaponDamage }); } break; case WeaponSkills.Mutilate: strikingDummy.QueuedEffects.Add(StatusEffects.Mutilate, new EffectSnapshot { Duration = 400, CritChance = player.CalculateCritChance(), Crt = player.Crt, Det = player.Det, Multiplier = player.CalculateDamageOverTimeMultiplier(DamageType.Physical, strikingDummy), Dex = player.GetDexterity(), Potency = 30, Target = strikingDummy, WeaponDamage = player.Weapon.WeaponDamage }); break; case WeaponSkills.DancingEdge: lastSkill = player.LastSkills.Pop(); if (lastSkill == WeaponSkills.GustSlash && player.LastSkills.Peek() == WeaponSkills.SpinningEdge) { strikingDummy.QueuedEffects.Add(StatusEffects.DancingEdge, new EffectSnapshot { Duration = 395, Target = strikingDummy }); } player.LastSkills.Push(lastSkill); break; case WeaponSkills.ArmorCrush: lastSkill = player.LastSkills.Pop(); if (lastSkill == WeaponSkills.GustSlash && player.LastSkills.Peek() == WeaponSkills.SpinningEdge) { player.QueuedEffects.Add(StatusEffects.ArmorCrush, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); } player.LastSkills.Push(lastSkill); break; } }
public Battle(IActor[] actors, int length = 180, int num_enemies = 1) { Actors = actors; Friendlies = actors; FightLength = length * 1000; _logger.Debug("Fight length: {0}", FightLength); Time = 0; TickOffset = new Random().Next(0, 3000); _logger.Debug("Tick offset: {0}", TickOffset); foreach (IActor actor in actors) { _logger.Debug("Actor added: [{0}] {1}", actor.JobID.ToString(), actor.Name); } // Initialize enemies. Enemies = new ITarget[num_enemies]; for (int i = 0; i < num_enemies; i++) { Enemies[i] = new StrikingDummy(); _logger.Debug("Enemy added: {0}", Enemies[i].Name); } Targets = Friendlies.ToList().Concat(Enemies.ToList()).ToArray(); EventQueue = new IntervalHeap <BattleEvent>(); EventLog = new ArrayList <CombatLogEvent>(); // Add the inital Actor decisions to the queue. These should drive the rest of the // simulation. foreach (IActor actor in Actors) { EventQueue.Add(new BattleEvent(BattleEventType.ACTOR_READY, Time, actor)); } // Event to signal the end of the fight. EventQueue.Add(new BattleEvent(BattleEventType.FIGHT_COMPLETE, FightLength)); // Event to signal the next Aura tick. EventQueue.Add(new BattleEvent(BattleEventType.AURA_TICK, Time + TickOffset)); if (TickOffset > 1500) { EventQueue.Add(new BattleEvent(BattleEventType.REGEN_TICK, 1500 - TickOffset)); } else { EventQueue.Add(new BattleEvent(BattleEventType.REGEN_TICK, TickOffset + 1500)); } }
public static void QueueEffect(Player player, StrikingDummy strikingDummy, WeaponSkills weaponSkill) { player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = Game.GetGlobalAnimationLockDurationMs(), Target = player }); switch (weaponSkill) { case WeaponSkills.HeavyThrust: player.QueuedEffects.Add(StatusEffects.HeavyThrust, new EffectSnapshot { Duration = 1289, Target = player }); break; case WeaponSkills.Disembowel: if (player.LastSkills.Peek() == WeaponSkills.ImpulseDrive) { strikingDummy.QueuedEffects.Add(StatusEffects.Disembowel, new EffectSnapshot { Duration = 1651, Target = strikingDummy }); } break; case WeaponSkills.ChaosThrust: var lastSkill = player.LastSkills.Pop(); if (lastSkill == WeaponSkills.Disembowel && player.LastSkills.Peek() == WeaponSkills.ImpulseDrive) { strikingDummy.QueuedEffects.Add(StatusEffects.ChaosThrust, new EffectSnapshot { Duration = 1651, CritChance = player.CalculateCritChance(), Crt = player.Crt, Det = player.Det, Multiplier = player.CalculateDamageOverTimeMultiplier(), Str = player.GetStrength(), Potency = 35, Target = strikingDummy, WeaponDamage = player.Weapon.WeaponDamage }); } player.LastSkills.Push(lastSkill); break; case WeaponSkills.Phlebotomize: strikingDummy.QueuedEffects.Add(StatusEffects.Phlebotomize, new EffectSnapshot { Duration = 1111, CritChance = player.CalculateCritChance(), Crt = player.Crt, Det = player.Det, Multiplier = player.CalculateDamageOverTimeMultiplier(), Str = player.GetStrength(), Potency = 30, Target = strikingDummy, WeaponDamage = player.Weapon.WeaponDamage }); break; } }
public bool UseBuffSpell(StrikingDummy target, Spells spell, bool verbose = false) { if (GcdDuration <= 0) { throw new Exception($"Warning! Using off-gcd ability { spell } when GCD is available! Remaining cooldown on { spell }: { Cooldowns[spell]}"); } if (Cooldowns.ContainsKey(spell) || QueuedEffects.ContainsKey(Skills.StatusEffects.AnimationLocked)) { return(false); } SpellLibrary.QueueEffect(this, spell, target, verbose); Cooldowns.Add(spell, SpellLibrary.SpellCooldowns(spell)); return(true); }
public MainPage() { IGearsetDAO dao = new GearsetDAOJsonImpl(); var set = dao.GetEquipmentSetByName("WHMGear"); PlayerCharacter actor = new PlayerCharacter("Kirima Yaeger", CharacterClan.HYUR_MIDLANDER, JobID.WHM, set); StrikingDummy dummy = new StrikingDummy(); ITarget[] targets = new ITarget[] { dummy }; ITarget[] friendlies = new ITarget[] { actor }; var decision = actor.DecideAction(1234, friendlies, targets); Application.Current.Exit(); }
// -- Methods public double AutoAttack(StrikingDummy target) { if (AutoAttackDuration > 0) { return(0); } var damage = FormulaLibrary.AutoAttack(Weapon.AutoAttack, GetDexterity(), Det, Weapon.Delay, CalculateMultiplier(target, DamageType.Slashing)); damage = (damage * CalculateCritChance() * FormulaLibrary.CritDmg(Crt)) + (damage * (1 - CalculateCritChance())); AutoAttackDuration = StatusEffects.ContainsKey(Skills.StatusEffects.Huton) ? (int)(TimeSpan.FromSeconds(Weapon.Delay).TotalMilliseconds * 0.85) : (int)TimeSpan.FromSeconds(Weapon.Delay).TotalMilliseconds; return(damage); }
public static void QueueEffect(Player player, Spells spell, StrikingDummy target, bool verbose) { switch (spell) { case Spells.DreamWithinADream: player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.Mug: player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.InternalRelease: player.QueuedEffects.Add(StatusEffects.InternalRelease, new EffectSnapshot { Duration = 650, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.BloodForBlood: player.QueuedEffects.Add(StatusEffects.BloodForBlood, new EffectSnapshot { Duration = 650, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.Duality: player.QueuedEffects.Add(StatusEffects.Duality, new EffectSnapshot { Duration = 650, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.DexterityPotion: player.QueuedEffects.Add(StatusEffects.DexterityPotion, new EffectSnapshot { Duration = 949, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = 1334, Target = player }); break; case Spells.Jugulate: player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.TrickAttack: target.QueuedEffects.Add(StatusEffects.TrickAttack, new EffectSnapshot { Duration = 955, Target = target }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.FumaShuriken: player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = 500 + GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.Raiton: player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = 1000 + GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.PrePullSuiton: player.QueuedEffects.Add(StatusEffects.Suiton, new EffectSnapshot { Duration = 1000, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.Suiton: player.QueuedEffects.Add(StatusEffects.Suiton, new EffectSnapshot { Duration = 2500, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = 1500 + GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.Kassatsu: player.QueuedEffects.Add(StatusEffects.Kassatsu, new EffectSnapshot { Duration = 1000, Target = player }); player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; case Spells.Delay: player.QueuedEffects.Add(StatusEffects.AnimationLocked, new EffectSnapshot { Duration = GameEngine.GetGlobalAnimationLockDurationMs(), Target = player }); break; default: throw new Exception($"Unknown spell { spell }!"); } if (verbose) { var animationLockDuration = player.QueuedEffects[StatusEffects.AnimationLocked].Duration; var remainingGCD = player.GcdDuration; if (animationLockDuration > remainingGCD) { Console.WriteLine($"Warning! GCD clipped by { spell } at { GameEngine.GetFormattedGameTime() } by { animationLockDuration - remainingGCD } milliseconds!"); } } }
public double UseDamageSpell(StrikingDummy target, Spells spell, bool verbose = false) { if (GcdDuration <= 0 && spell != Spells.PrePullSuiton) { var remainingCd = Cooldowns.ContainsKey(spell) ? Cooldowns[spell] : 0; throw new Exception($"Warning! Using off-gcd ability { spell } when GCD is available! Remaining cooldown on { spell }: { remainingCd }"); } if (Cooldowns.ContainsKey(spell) || QueuedEffects.ContainsKey(Skills.StatusEffects.AnimationLocked)) { return(0); } if (spell == Spells.FumaShuriken || spell == Spells.Raiton || spell == Spells.Suiton) { if (Cooldowns.ContainsKey(Spells.FumaShuriken) || Cooldowns.ContainsKey(Spells.Raiton) || Cooldowns.ContainsKey(Spells.Suiton)) { return(0); } } if (spell == Spells.TrickAttack) { if (!StatusEffects.ContainsKey(Skills.StatusEffects.Suiton)) { throw new Exception($"Warning! Cannot use TA without Suiton active!"); } if (verbose) { Console.WriteLine("Suiton removed after TA cast!"); } StatusEffects.Remove(Skills.StatusEffects.Suiton); } var potency = SpellLibrary.SpellPotencies(spell); var multiplier = CalculateMultiplier(target, SpellLibrary.SpellDamageType(spell)); var damage = FormulaLibrary.WeaponSkills(potency, Weapon.WeaponDamage, GetDexterity(), Det, multiplier); var guaranteeCrit = false; if (spell == Spells.FumaShuriken || spell == Spells.Raiton || spell == Spells.Suiton) { if (StatusEffects.ContainsKey(Skills.StatusEffects.Kassatsu)) { guaranteeCrit = true; StatusEffects.Remove(Skills.StatusEffects.Kassatsu); } } if (guaranteeCrit) { damage *= FormulaLibrary.CritDmg(Crt); } else { damage = (damage * CalculateCritChance() * FormulaLibrary.CritDmg(Crt)) + (damage * (1 - CalculateCritChance())); } SpellLibrary.QueueEffect(this, spell, target, verbose); if (spell == Spells.FumaShuriken) { Cooldowns.Add(spell, 500 + SpellLibrary.SpellCooldowns(spell)); } else if (spell == Spells.Raiton) { Cooldowns.Add(spell, 1000 + SpellLibrary.SpellCooldowns(spell)); } else if (spell == Spells.Suiton) { Cooldowns.Add(spell, 1500 + SpellLibrary.SpellCooldowns(spell)); } else if (spell == Spells.PrePullSuiton) { Cooldowns.Add(Spells.Suiton, SpellLibrary.SpellCooldowns(Spells.Suiton)); } else { Cooldowns.Add(spell, SpellLibrary.SpellCooldowns(spell)); } return(damage); }