Exemple #1
0
        public ActionDistribution Clone()
        {
            ActionDistribution clone = (ActionDistribution)this.MemberwiseClone();

            clone.fraction   = (double[])clone.fraction.Clone();
            clone.eps        = (double[])clone.eps.Clone();
            clone.mps        = (double[])clone.mps.Clone();
            clone.cps        = (double[])clone.cps.Clone();
            clone.tps        = (double[])clone.tps.Clone();
            clone.passiveEPS = (double[])clone.passiveEPS.Clone();
            clone.passiveMPS = (double[])clone.passiveMPS.Clone();
            clone.passiveTPS = (double[])clone.passiveTPS.Clone();
            return(clone);
        }
Exemple #2
0
        public static ActionDistribution Combine(ActionDistribution[] dists, double[] coeffs)
        {
            ActionDistribution dist = new ActionDistribution(dists[0].actions, dists[0].passives);
            int e = dist.fraction.Length;
            int p = dist.passives;
            int n = dists.Length;

            dist.maxFraction = 0;
            dist.maxMPS      = 0;

            for (int i = 0; i < n; ++i)
            {
                dist.totalMPS      += dists[i].totalMPS * coeffs[i];
                dist.totalFraction += dists[i].totalFraction * coeffs[i];
                dist.maxMPS        += dists[i].maxMPS * coeffs[i];
                dist.maxFraction   += dists[i].maxFraction * coeffs[i];
                for (int j = 0; j < e; ++j)
                {
                    dist.fraction[j] += dists[i].fraction[j] * coeffs[i];
                    dist.eps[j]      += dists[i].eps[j] * coeffs[i];
                    dist.mps[j]      += dists[i].mps[j] * coeffs[i];
                    dist.tps[j]      += dists[i].tps[j] * coeffs[i];
                    dist.cps[j]      += dists[i].cps[j] * coeffs[i];
                }
                for (int j = 0; j < p; ++j)
                {
                    dist.passiveEPS[j] += dists[i].passiveEPS[j] * coeffs[i];
                }
                for (int j = 0; j < p; ++j)
                {
                    dist.passiveMPS[j] += dists[i].passiveMPS[j] * coeffs[i];
                }
                for (int j = 0; j < p; ++j)
                {
                    dist.passiveTPS[j] += dists[i].passiveTPS[j] * coeffs[i];
                }
            }
            return(dist);
        }
Exemple #3
0
        ActionDistribution[] computeRaidHealing(bool burst, out int[] candidates)
        {
            ActionDistribution[] dists = new ActionDistribution[calc.Division.Count];

            for (int div = 0; div < calc.Division.Count; ++div)
            {
                TreeStats stats = calc.Stats[div];
                ComputedSpell[] spells = calc.Spells[div];
                TreeComputedData data = DivisionData[div];

                bool refreshLBWithDHs = Talents.EmpoweredTouch == 2 && opts.RefreshLifebloomWithDirectHeals;
                ContinuousAction[] actions = calc.Actions[div];
                ActionDistribution dist = new ActionDistribution(actions, (int)TreePassive.Count);
                if (!burst)
                    dist.MaxMPS = calc.ManaRegen;

                addPassiveHealing(dist, stats);
                addSelfHealing(dist, actions, spells, 1);

                addLifebloomRefresh(dist, actions, spells[(int)TreeSpell.Lifebloom], data, refreshLBWithDHs, opts.RejuvenationTankDuringRaid);

                double minDHRate = 0;
                if (refreshLBWithDHs)
                    minDHRate = Math.Max(minDHRate, 1.0f / data.LifebloomRefreshInterval);
                // note that 1/15 + 1/25 > 1/10, so in practice swiftmends and cchts alone should be enough to keep up Harmony, unless the Swiftmend cast delay has been set high (> 4 seconds)
                if (opts.Restoration)
                    minDHRate = Math.Max(minDHRate, 1.0f / 10.0f - 1.0 / (15 + opts.SwiftmendCastDelay));
                addSpecialDirectHeals(dist, spells, stats, refreshLBWithDHs, !burst, minDHRate, burst);

                // TODO: add option to choose when to use tranquility (maybe even model it as a division?)
                dist.AddActionOnCooldown((int)TreeAction.RaidTranquility);

                if (Restoration)
                    dist.AddActionOnCooldown((int)TreeAction.RaidSwiftmend);

                if (opts.RejuvenationTankDuringRaid)
                    dist.AddActionOnCooldown((int)TreeAction.TankRejuvenation);

                if (Talents.WildGrowth > 0)
                    dist.AddActionOnCooldown((int)TreeAction.RaidWildGrowth);

                dists[div] = dist;
            }

            List<int> candidatesList = new List<int>();
            if(Talents.NaturesSwiftness > 0)
                candidatesList.Add((int)TreeAction.RaidSwiftHT);
            candidatesList.Add((int)TreeAction.RaidRejuvenation);
            candidatesList.Add((int)TreeAction.RaidHealingTouch);
            candidatesList.Add((int)TreeAction.RaidNourish);
            candidatesList.Add((int)TreeAction.RaidRegrowth);
            if(character.DruidTalents.NaturesBounty > 0)
                candidatesList.Add(opts.RejuvenationTankDuringRaid ? (int)TreeAction.RaidRj2NourishNB : (int)TreeAction.RaidRj3NourishNB);
            candidatesList.Add((int)TreeAction.RaidTolLb);
            candidatesList.Add((int)TreeAction.RaidTolLbCcHt);
            candidates = candidatesList.ToArray();

            return dists;
        }
Exemple #4
0
 void addSelfHealing(ActionDistribution dist, ContinuousAction[] actions, ComputedSpell[] spells, double weight)
 {
     dist.AddPassive((int)TreePassive.Perserverance, PerseveranceHPS * weight);
     dist.AddPassive((int)TreePassive.NaturesWard, actions[(int)TreeAction.RaidRejuvenation].EPS * actions[(int)TreeAction.RaidRejuvenation].Time / spells[(int)TreeSpell.Rejuvenation].Duration * NaturesWardUptime * weight);
 }
Exemple #5
0
 void addPassiveHealing(ActionDistribution dist, TreeStats stats)
 {
     dist.AddPassive((int)TreePassive.HealingTrinkets, stats.Healed * stats.DirectHealMultiplier * getCritMultiplier(stats, 0, 0));
     if (InsectSwarm)
         dist.AddActionOnCooldown((int)TreeAction.InsectSwarm);
 }
Exemple #6
0
        void addSpecialDirectHeals(ActionDistribution dist, ComputedSpell[] spells, TreeStats stats, bool onTank, bool useCCs, double minRate, bool htFiller)
        {
            // TODO: possibly make configurable, it's disabled because in practice it's unlikely to have a clearcast exactly when Nature's Grace is to be triggered
            bool procNaturesGraceWithCCs = false;

            bool naturesGraceHandled = false;
            if (InsectSwarm)
                naturesGraceHandled = true;

            double dhrate = 0;

            double ccrate = spells[(int)TreeSpell.Lifebloom].TPS * 0.02f * Talents.MalfurionsGift;
            if (ccrate != 0.0f)
            {
                if (procNaturesGraceWithCCs && Talents.NaturesGrace > 0)
                {
                    naturesGraceHandled = true;
                    dist.AddAction(onTank ? (int)TreeAction.TankClearRegrowth : (int)TreeAction.RaidClearRegrowth, 1.0f / 60.0f * spells[(int)TreeSpell.Regrowth].Action.Time);
                    ccrate -= 1.0f / 60.0f;
                    dhrate += 1.0f / 60.0f;
                }

                if (useCCs)
                {
                    dist.AddAction(onTank ? (int)TreeAction.TankClearHT : (int)TreeAction.RaidClearHT, ccrate * spells[(int)TreeSpell.HealingTouch].Action.Time);
                    dhrate += ccrate;
                }
            }

            if (!naturesGraceHandled && Talents.NaturesGrace > 0)
            {
                dist.AddAction(onTank ? (int)TreeAction.TankRegrowth : (int)TreeAction.RaidRegrowth, 1.0f / 60.0f * spells[(int)TreeSpell.Regrowth].Action.Time);
                dhrate += 1.0f / 60.0f;
            }

            if (dhrate < minRate)
            {
                if (!htFiller)
                    dist.AddAction(onTank ? (int)TreeAction.TankNourish : (int)TreeAction.RaidNourish, (minRate - dhrate) * spells[(int)TreeSpell.Nourish].Action.Time);
                else
                    dist.AddAction(onTank ? (int)TreeAction.TankHealingTouch : (int)TreeAction.RaidHealingTouch, (minRate - dhrate) * spells[(int)TreeSpell.HealingTouch].Action.Time);
            }
        }
Exemple #7
0
 void addLifebloomRefresh(ActionDistribution dist, ContinuousAction[] actions, ComputedSpell spell, TreeComputedData data, bool automatic, bool rejuvenationUp)
 {
     if (!automatic)
         dist.AddActionOnCooldown((int)TreeAction.ReLifebloom);
     
     dist.AddPassive((int)TreePassive.RollingLifebloom, (rejuvenationUp ? spell.TankAction.Periodic : spell.RaidAction.Periodic) * 3 * opts.TankLifebloomEH / spell.Duration, -data.LifebloomMPSGain);
     dist.AddPassiveTPS((int)TreePassive.RollingLifebloom, spell.TPS);
 }
Exemple #8
0
        ActionDistribution[] computeTankHealing(bool burst, out int[] candidates)
        {
            ActionDistribution[] dists = new ActionDistribution[calc.Division.Count];
            for (int div = 0; div < calc.Division.Count; ++div)
            {
                TreeStats stats = calc.Stats[div];
                ComputedSpell[] spells = calc.Spells[div];
                TreeComputedData data = DivisionData[div];
                ContinuousAction[] actions = calc.Actions[div];
                ActionDistribution dist = new ActionDistribution(actions, (int)TreePassive.Count);

                if (!burst)
                    dist.MaxMPS = calc.ManaRegen;

                addPassiveHealing(dist, stats);
                addSelfHealing(dist, actions, spells, opts.TankRaidHealingWeight);

                addLifebloomRefresh(dist, actions, spells[(int)TreeSpell.Lifebloom], data, Talents.EmpoweredTouch != 0, true);

                // assume we will automatically heal the tank enough to refresh lifebloom if we have Empowered Touch
                addSpecialDirectHeals(dist, spells, stats, true, !burst, 0, false);

                if (Restoration && opts.TankSwiftmend)
                    dist.AddActionOnCooldown((int)TreeAction.TankSwiftmend);

                if (!burst && opts.TankWildGrowth && Talents.WildGrowth > 0)
                    dist.AddActionOnCooldown((int)TreeAction.TankWildGrowth);

                dists[div] = dist;
            }

            List<int> candidatesList = new List<int>();
            if (Talents.NaturesSwiftness > 0)
                candidatesList.Add((int)TreeAction.TankSwiftHT);
            candidatesList.Add((int)TreeAction.TankRejuvenation);
            candidatesList.Add((int)TreeAction.TankHealingTouch);
            candidatesList.Add((int)TreeAction.TankNourish);
            candidatesList.Add((int)TreeAction.TankRegrowth);
            if(character.DruidTalents.NaturesBounty > 0)
                candidatesList.Add((int)TreeAction.TankRj2NourishNB);
            candidatesList.Add((int)TreeAction.TankTolLbCcHt);
            candidates = candidatesList.ToArray();

            return dists;
        }
Exemple #9
0
 public ActionDistributionsByDivision(FightDivision division, ActionDistribution[] dists)
 {
     Division      = division;
     Distributions = dists;
     Distribution  = ActionDistribution.Combine(dists, Division.Fractions);
 }
Exemple #10
0
        public static void AddBestActions(ActionDistribution[] dists, double[] factors, int[] candidates, double unevenPart)
        {
            if (unevenPart < 1)
            {
                for (int i = 0; i < dists.Length; ++i)
                {
                    double maxMPS = dists[i].MaxMPS;
                    dists[i].MaxMPS = dists[i].TotalMPS * unevenPart + maxMPS * (1 - unevenPart);
                    dists[i].AddBestActions(candidates);
                }
            }

            if(unevenPart > 0)
                AddBestActions(dists, factors, candidates);
        }
Exemple #11
0
        public static void AddBestActions(ActionDistribution[] dists, double[] factors, int[] candidates)
        {
            KeyValuePair<int, double>[][] selectedActions;
            
            FindBestActions(dists, factors, candidates, out selectedActions);

            for (int i = 0; i < dists.Length; ++i)
            {
                double maxMPS = dists[i].MaxMPS;
                dists[i].MaxMPS = double.PositiveInfinity;
                foreach(KeyValuePair<int, double> sel in selectedActions[i])
                {
                    dists[i].AddAction(sel.Key, sel.Value);
                }
                
                dists[i].MaxMPS = maxMPS;
            }
        }
Exemple #12
0
        public static void FindBestActions(ActionDistribution[] dists, double[] factors, int[] candidates, out KeyValuePair<int, double>[][] selectedActions)
        {
            int n = dists.Length;
            ContinuousAction[][] actionSets = new ContinuousAction[n][];
            double mpsLeft = 0.0;
            double[] timeLeft = new double[n];
            for (int i = 0; i < n; ++i)
            {
                actionSets[i] = dists[i].Actions;
                timeLeft[i] = dists[i].MaxFraction - dists[i].TotalFraction;
                mpsLeft += (dists[i].MaxMPS - dists[i].TotalMPS) * factors[i];
            }

            FindBestActions(actionSets, factors, candidates, timeLeft, mpsLeft, out selectedActions);
        }
Exemple #13
0
 public ActionDistributionsByDivision(FightDivision division, ActionDistribution[] dists)
 {
     Division = division;
     Distributions = dists;
     Distribution = ActionDistribution.Combine(dists, Division.Fractions);
 }
Exemple #14
0
        public static ActionDistribution Combine(ActionDistribution[] dists, double[] coeffs)
        {
            ActionDistribution dist = new ActionDistribution(dists[0].actions, dists[0].passives);
            int e = dist.fraction.Length;
            int p = dist.passives;
            int n = dists.Length;
            dist.maxFraction = 0;
            dist.maxMPS = 0;

            for(int i = 0; i < n; ++i)
            {
                dist.totalMPS += dists[i].totalMPS * coeffs[i];
                dist.totalFraction += dists[i].totalFraction * coeffs[i];
                dist.maxMPS += dists[i].maxMPS * coeffs[i];
                dist.maxFraction += dists[i].maxFraction * coeffs[i];
                for (int j = 0; j < e; ++j)
                {
                    dist.fraction[j] += dists[i].fraction[j] * coeffs[i];
                    dist.eps[j] += dists[i].eps[j] * coeffs[i];
                    dist.mps[j] += dists[i].mps[j] * coeffs[i];
                    dist.tps[j] += dists[i].tps[j] * coeffs[i];
                    dist.cps[j] += dists[i].cps[j] * coeffs[i];
                }
                for (int j = 0; j < p; ++j)
                    dist.passiveEPS[j] += dists[i].passiveEPS[j] * coeffs[i];
                for (int j = 0; j < p; ++j)
                    dist.passiveMPS[j] += dists[i].passiveMPS[j] * coeffs[i];
                for (int j = 0; j < p; ++j)
                    dist.passiveTPS[j] += dists[i].passiveTPS[j] * coeffs[i];
            }
            return dist;
        }