Example #1
0
        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);
        }
Example #2
0
        public double CalculateCritChance()
        {
            var critChance = FormulaLibrary.CritChance(Crt);

            if (StatusEffects.ContainsKey(Skills.StatusEffects.InternalRelease))
            {
                critChance += 0.10;
            }

            return(critChance);
        }
Example #3
0
        // -- 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);
        }
Example #4
0
        public double CalculateDamageOverTimeMultiplier(DamageType damageType, Actor target)
        {
            var multiplier = FormulaLibrary.SkillSpeedMultiplier(Sks);

            if (StatusEffects.ContainsKey(Skills.StatusEffects.BloodForBlood))
            {
                multiplier *= 1.10;
            }

            if (target.StatusEffects.ContainsKey(Skills.StatusEffects.TrickAttack))
            {
                multiplier *= 1.10;
            }

            if (damageType == DamageType.Slashing)
            {
                if (target.StatusEffects.ContainsKey(Skills.StatusEffects.DancingEdge) ||
                    target.StatusEffects.ContainsKey(Skills.StatusEffects.StormsEye))
                {
                    multiplier *= 1.10;
                }
            }

            if (damageType == DamageType.Physical || damageType == DamageType.Slashing)
            {
                if (StatusEffects.ContainsKey(Skills.StatusEffects.KissOfTheWasp))
                {
                    multiplier *= 1.20;
                }
            }

            if (damageType == DamageType.Magical)
            {
                if (target.StatusEffects.ContainsKey(Skills.StatusEffects.FoeRequiem))
                {
                    multiplier *= 1.10;
                }
            }

            return(multiplier);
        }
Example #5
0
        public void DecrementDamageOverTimeDuration(bool verbose)
        {
            foreach (var dot in DamageOverTimeEffects.ToList())
            {
                var dotEffect = DamageOverTimeEffects[dot.Key];

                if (GameEngine.GetCurrentGameTime() % (long)TimeSpan.FromSeconds(3).TotalMilliseconds == 0)
                {
                    var damage = FormulaLibrary.WeaponSkills(dotEffect.Potency, dotEffect.WeaponDamage, dotEffect.Dex, dotEffect.Det, dotEffect.Multiplier);

                    damage = (damage * dotEffect.CritChance * FormulaLibrary.CritDmg(dotEffect.Crt)) +
                             (damage * (1 - dotEffect.CritChance));

                    if (verbose)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"{dot.Key} ticks for {damage}!");
                    }

                    dotEffect.Target.DamageTaken += damage;
                }

                dotEffect.Duration--;
                if (dotEffect.Duration <= 0)
                {
                    if (verbose)
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine($"{dot.Key} has fallen off!");
                    }

                    DamageOverTimeEffects.Remove(dot.Key);
                }
                else
                {
                    DamageOverTimeEffects[dot.Key] = dotEffect;
                }
            }
        }
Example #6
0
        private static void RegenerateSkillSpeedRanks()
        {
            var minSkillSpeed = Convert.ToInt32(ConfigurationManager.AppSettings["MIN_SKS"]);
            var maxSkillSpeed = Convert.ToInt32(ConfigurationManager.AppSettings["MAX_SKS"]);
            Console.WriteLine($"Regenerating skill speed rankings ... values from { minSkillSpeed } to { maxSkillSpeed }. If this range is not the full range desired, please enter the full range in the program configuration.");

            var skillSpeedDps = new Dictionary<int, double>();

            for (var i = minSkillSpeed; i <= maxSkillSpeed; i++)
            {
                var player = PlayerFactory.CreatePlayer();
                player.Sks = i;
                var dps = RunSimulation(false, player);
                Console.WriteLine($"Skill Speed: { i }, DPS: { dps }");
                skillSpeedDps.Add(i, dps);
            }

            using (var filestream = File.OpenWrite(FormulaLibrary.GetSkillSpeedRanksFilePath()))
            using (var writer = new StreamWriter(filestream))
            {
                writer.Write(JsonConvert.SerializeObject(skillSpeedDps));
            }
        }
Example #7
0
        private static void RunBestInSlotSolver()
        {
            var numIterations = 0;
            var accFilter = 0;
            var sksFilter = 0;
            var strictFilter = 0;
            var primaryStatFilter = 0;
            var secondaryStatFilter = 0;

            var recordedRuns = new List<RecordedDPS>();

            // Read and filter inventory.
            var weaponItems = FilterWeapons(Inventory.Config.MainHand.Cast<InventorySection.MainHandElementCollection.ItemElement>().ToList());
            var headItems = FilterItems<InventorySection.HeadElementCollection.ItemElement>(Inventory.Config.Head.Cast<InventorySection.HeadElementCollection.ItemElement>().ToList());
            var bodyItems = FilterItems<InventorySection.BodyElementCollection.ItemElement>(Inventory.Config.Body.Cast<InventorySection.BodyElementCollection.ItemElement>().ToList());
            var handItems = FilterItems<InventorySection.HandsElementCollection.ItemElement>(Inventory.Config.Hands.Cast<InventorySection.HandsElementCollection.ItemElement>().ToList());
            var waistItems = FilterItems<InventorySection.WaistElementCollection.ItemElement>(Inventory.Config.Waist.Cast<InventorySection.WaistElementCollection.ItemElement>().ToList());
            var legItems = FilterItems<InventorySection.LegsElementCollection.ItemElement>(Inventory.Config.Legs.Cast<InventorySection.LegsElementCollection.ItemElement>().ToList());
            var feetItems = FilterItems<InventorySection.FeetElementCollection.ItemElement>(Inventory.Config.Feet.Cast<InventorySection.FeetElementCollection.ItemElement>().ToList());
            var neckItems = FilterItems<InventorySection.NeckElementCollection.ItemElement>(Inventory.Config.Neck.Cast<InventorySection.NeckElementCollection.ItemElement>().ToList());
            var earItems = FilterItems<InventorySection.EarsElementCollection.ItemElement>(Inventory.Config.Ears.Cast<InventorySection.EarsElementCollection.ItemElement>().ToList());
            var wristItems = FilterItems<InventorySection.WristsElementCollection.ItemElement>(Inventory.Config.Wrists.Cast<InventorySection.WristsElementCollection.ItemElement>().ToList());

            // We don't filter rings or food because they're a little different than just stat sticks. Rings are unique and food boost stats by percentages.

            var leftRingItems = Inventory.Config.LeftRing.Cast<InventorySection.LeftRingElementCollection.ItemElement>().ToList();
            var rightRingItems = Inventory.Config.RightRing.Cast<InventorySection.RightRingElementCollection.ItemElement>().ToList();
            var foodItems = Inventory.Config.Food.Cast<InventorySection.FoodElementCollection.ItemElement>().ToList();

            // for all combinations
            foreach (var weapon in weaponItems)
            {
                foreach (var head in headItems)
                {
                    foreach (var body in bodyItems)
                    {
                        foreach (var hands in handItems)
                        {
                            foreach (var waist in waistItems)
                            {
                                foreach (var legs in legItems)
                                {
                                    foreach (var feet in feetItems)
                                    {
                                        foreach (var neck in neckItems)
                                        {
                                            foreach (var ears in earItems)
                                            {
                                                foreach (var wrists in wristItems)
                                                {
                                                    foreach (var leftRing in leftRingItems)
                                                    {
                                                        foreach (var rightRing in rightRingItems)
                                                        {
                                                            // rings are unique
                                                            if (rightRing.Name.Equals(leftRing.Name,
                                                                StringComparison.OrdinalIgnoreCase))
                                                            {
                                                                continue;
                                                            }
                                                            foreach (var food in foodItems)
                                                            {
                                                                var player = PlayerFactory.CreatePlayer(true);
                                                                // add weapon
                                                                player.Weapon = new Weapon
                                                                {
                                                                    AutoAttack = weapon.Aa,
                                                                    WeaponDamage = weapon.Wd,
                                                                    Delay = weapon.Delay
                                                                };

                                                                // add stats
                                                                player.Dex += weapon.Dex + head.Dex + body.Dex +
                                                                              hands.Dex + waist.Dex + legs.Dex +
                                                                              feet.Dex + neck.Dex + ears.Dex +
                                                                              wrists.Dex + leftRing.Dex + rightRing.Dex;
                                                                player.Acc += weapon.Acc + head.Acc + body.Acc +
                                                                              hands.Acc + waist.Acc + legs.Acc +
                                                                              feet.Acc + neck.Acc + ears.Acc +
                                                                              wrists.Acc + leftRing.Acc + rightRing.Acc;
                                                                player.Crt += weapon.Crt + head.Crt + body.Crt +
                                                                              hands.Crt + waist.Crt + legs.Crt +
                                                                              feet.Crt + neck.Crt + ears.Crt +
                                                                              wrists.Crt + leftRing.Crt + rightRing.Crt;
                                                                player.Det += weapon.Det + head.Det + body.Det +
                                                                              hands.Det + waist.Det + legs.Det +
                                                                              feet.Det + neck.Det + ears.Det +
                                                                              wrists.Det + leftRing.Det + rightRing.Det;
                                                                player.Sks += weapon.Sks + head.Sks + body.Sks +
                                                                              hands.Sks + waist.Sks + legs.Sks +
                                                                              feet.Sks + neck.Sks + ears.Sks +
                                                                              wrists.Sks + leftRing.Sks + rightRing.Sks;

                                                                // add food bonus
                                                                var accBonus = (int)(player.Acc * food.AccModifier) - (int)player.Acc;
                                                                player.Acc += accBonus >= food.MaxAccBonus ? food.MaxAccBonus : accBonus;

                                                                var crtBonus = (int)(player.Crt * food.CrtModifier) - (int)player.Crt;
                                                                player.Crt += crtBonus >= food.MaxCrtBonus ? food.MaxCrtBonus : crtBonus;

                                                                var detBonus = (int)(player.Det * food.DetModifier) - (int)player.Det;
                                                                player.Det += detBonus >= food.MaxDetBonus ? food.MaxDetBonus : detBonus;

                                                                var sksBonus = (int)(player.Sks * food.SksModifier) - (int)player.Sks;
                                                                player.Sks += sksBonus >= food.MaxSksBonus ? food.MaxSksBonus : sksBonus;

                                                                // add party bonus
                                                                player.Dex = (int)(player.Dex * 1.03);

                                                                // run heuristics to pre-filter worse combinations
                                                                if (player.Acc < Convert.ToInt32(ConfigurationManager.AppSettings["MIN_ACC"]))
                                                                {
                                                                    accFilter++;
                                                                    continue;
                                                                }
                                                                if (player.Sks < Convert.ToInt32(ConfigurationManager.AppSettings["MIN_SKS"]) ||
                                                                    player.Sks > Convert.ToInt32(ConfigurationManager.AppSettings["MAX_SKS"]))
                                                                {
                                                                    sksFilter++;
                                                                    continue;
                                                                }

                                                                try
                                                                {
                                                                    if (recordedRuns.Count > 0)
                                                                    {
                                                                        var skip = false;
                                                                        foreach (var recordedRun in recordedRuns)
                                                                        {
                                                                            var recordedPlayer = recordedRun.Player;

                                                                            if (player.Weapon.WeaponDamage <= recordedPlayer.Weapon.WeaponDamage &&
                                                                                player.Dex <= recordedPlayer.Dex &&
                                                                                player.Crt <= recordedPlayer.Crt &&
                                                                                player.Det <= recordedPlayer.Det &&
                                                                                FormulaLibrary.GetSkillSpeedRank(player.Sks) <=
                                                                                FormulaLibrary.GetSkillSpeedRank(recordedPlayer.Sks))
                                                                            {
                                                                                strictFilter++;
                                                                                skip = true;
                                                                                break;
                                                                            }

                                                                            if (player.Weapon.WeaponDamage <= recordedPlayer.Weapon.WeaponDamage &&
                                                                                player.Dex <= recordedPlayer.Dex &&
                                                                                player.Crt >= recordedPlayer.Crt &&
                                                                                player.Det >= recordedPlayer.Det &&
                                                                                FormulaLibrary.GetSkillSpeedRank(player.Sks) <=
                                                                                FormulaLibrary.GetSkillSpeedRank(recordedPlayer.Sks))
                                                                            {
                                                                                var crtGain = player.Crt - recordedPlayer.Crt;
                                                                                var detGain = player.Det - recordedPlayer.Det;
                                                                                var secondaryStatGain = crtGain * 1.5 + detGain;

                                                                                var strLoss = recordedPlayer.Dex - player.Dex;
                                                                                var wdLoss = recordedPlayer.Weapon.WeaponDamage - player.Weapon.WeaponDamage;
                                                                                var primaryStatLoss = strLoss + 5 * wdLoss;

                                                                                if (secondaryStatGain < primaryStatLoss)
                                                                                {
                                                                                    primaryStatFilter++;
                                                                                    skip = true;
                                                                                    break;
                                                                                }
                                                                            }

                                                                            if (player.Weapon.WeaponDamage <= recordedPlayer.Weapon.WeaponDamage &&
                                                                                player.Dex <= recordedPlayer.Dex &&
                                                                                FormulaLibrary.GetSkillSpeedRank(player.Sks) <=
                                                                                FormulaLibrary.GetSkillSpeedRank(recordedPlayer.Sks))
                                                                            {
                                                                                if (player.Crt > recordedPlayer.Crt && player.Det < recordedPlayer.Det)
                                                                                {
                                                                                    var critGain = player.Crt - recordedPlayer.Crt;
                                                                                    var detLoss = recordedPlayer.Det - player.Det;
                                                                                    if (critGain * 1.75 <= detLoss)
                                                                                    {
                                                                                        secondaryStatFilter++;
                                                                                        skip = true;
                                                                                        break;
                                                                                    }
                                                                                }
                                                                                if (player.Crt < recordedPlayer.Crt && player.Det > recordedPlayer.Det)
                                                                                {
                                                                                    var detGain = player.Det - recordedPlayer.Det;
                                                                                    var critLoss = recordedPlayer.Crt - player.Crt;
                                                                                    if (detGain * 1.25 <= critLoss)
                                                                                    {
                                                                                        secondaryStatFilter++;
                                                                                        skip = true;
                                                                                        break;
                                                                                    }
                                                                                }
                                                                            }
                                                                        }

                                                                        if (skip)
                                                                        {
                                                                            continue;
                                                                        }
                                                                    }
                                                                }
                                                                catch (Exception)
                                                                {
                                                                    continue;
                                                                }


                                                                // run the sim
                                                                try
                                                                {
                                                                    numIterations++;
                                                                    var dps = RunSimulation(false, player);
                                                                    recordedRuns.Add(new RecordedDPS
                                                                    {
                                                                        Player = player,
                                                                        DPS = dps,
                                                                        EquipmentNames = new List<string>
                                                                        {
                                                                            weapon.Name, head.Name, body.Name, hands.Name, waist.Name,
                                                                            legs.Name, feet.Name, neck.Name, ears.Name, wrists.Name,
                                                                            leftRing.Name, rightRing.Name, food.Name
                                                                        }
                                                                    });

                                                                    Console.WriteLine($"Iteration {numIterations} - DPS is: {dps}");
                                                                }
                                                                catch (Exception)
                                                                {
                                                                    // suppress errors due to SKS
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            var counter = 1;
            foreach (var run in recordedRuns.OrderByDescending(r => r.DPS))
            {
                Console.WriteLine($"--Number {counter++}");
                Console.WriteLine("DPS: " + run.DPS);
                Console.WriteLine("Player Equipment:");
                run.EquipmentNames.ForEach(Console.WriteLine);
                Console.WriteLine("Player stats:");
                Console.WriteLine($"Dex: {run.Player.Dex}");
                Console.WriteLine($"Acc: {run.Player.Acc}");
                Console.WriteLine($"Crt: {run.Player.Crt}");
                Console.WriteLine($"Det: {run.Player.Det}");
                Console.WriteLine($"Sks: {run.Player.Sks}");

                if (counter > 250)
                {
                    break;
                }
            }

            Console.WriteLine("Diagnostics: ");
            Console.WriteLine($"AccFilter: {accFilter}");
            Console.WriteLine($"SksFilter: {sksFilter}");
            Console.WriteLine($"StrictFilter: {strictFilter}");
            Console.WriteLine($"PrimaryStatFilter: {primaryStatFilter}");
            Console.WriteLine($"SecondaryStatFilter: {secondaryStatFilter}");
        }
Example #8
0
        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);
        }