private static ValueConverter ApplyToDamageValueConverter(IEnumerable <IStat> applyStats)
        {
            var values = applyStats
                         .Select(s => new FunctionalValue(c => c.GetValue(s) / 100, $"{s}.Value / 100"))
                         .ToList();
            var multiplier = new FunctionalValue(
                c => values.Select(v => v.Calculate(c)).AggregateOnValues(Combine),
                $"RequireEqualWhereNotNull({string.Join(",", values)})");

            return(v => v.Multiply(new ValueBuilderImpl(multiplier)));

            // There isn't any obvious way to combine different values but it currently can't happen:
            // - More than one source damage source for ApplyModifiersToSkillDamage can't happen because
            //   With(DamageSource) only takes one argument.
            // - Different ApplyModifiersToAilmentDamage values for different source damage sources don't make sense.
            //   If e.g. crit multi for spells and attacks would be applied to ailments at different values, it would
            //   be ambiguous how to apply generic crit multi, which is split into the damage sources, to ailments.
            // - The current solution would not work if different stats of the original StatBuilderResult (built from
            //   the core builder) have different ApplyModifiersTo values. That is possible with IDamageStatBuilder and
            //   its damage types, but damage-type specific ApplyModifiersTo modifiers do not exist.
            NodeValue Combine(NodeValue left, NodeValue right)
            {
                if (left == right)
                {
                    return(left);
                }
                throw new ParseException(
                          $"ApplyModifiersToDamage values must be equal for all concretized stats. {left} and {right} given");
            }
        }
예제 #2
0
 public void CalculateReturnsCorrectResultWithMainPath(Form form)
 {
     NodeValue?expected         = new NodeValue((int)form);
     var       fireDamage       = AilmentDamage(DamageType.Fire);
     var       coldDamage       = AilmentDamage(DamageType.Cold);
     var       transformedValue = new FunctionalValue(c => c.GetValues(form, coldDamage).Sum(), "");
     var       paths            = new[]
        public void CalculateChecksForSameSta()
        {
            var transformedValue = new FunctionalValue(c => c.GetValues(Form.BaseSet, Paths).First(), "");
            var sut     = CreateSut(new Stat("a"), Form.BaseSet, transformedValue);
            var context = MockContext(2, 4);

            var actual = sut.Calculate(context);

            Assert.AreEqual(2, actual.Single());
        }
        public void CalculateOnlyManipulatesContextForRegenStat()
        {
            var expected         = new NodeValue(42);
            var unrelatedStat    = new Stat("a");
            var paths            = new[] { new PathDefinition(new ModifierSource.Local.Skill()), };
            var transformedValue = new FunctionalValue(c => c.GetValues(unrelatedStat, NodeType.PathTotal).Sum(), "");
            var context          = Mock.Of <IValueCalculationContext>(c =>
                                                                      c.GetPaths(unrelatedStat) == paths &&
                                                                      c.GetValue(unrelatedStat, NodeType.PathTotal, paths[0]) == expected);
            var sut = CreateSut(transformedValue);

            var actual = sut.Calculate(context);

            Assert.AreEqual(expected, actual);
        }
        public void CalculateOnlyManipulatesContextForPathTotal()
        {
            var expected         = new NodeValue(42);
            var transformedValue =
                new FunctionalValue(c => c.GetValues(Regen(Pool.Life), NodeType.Base).Sum(), "");
            var context = Mock.Of <IValueCalculationContext>(c =>
                                                             c.GetPaths(Regen(Pool.Life)) == new[] { Path } &&
                                                             c.GetValue(Regen(Pool.Life), NodeType.Base, Path) == expected &&
                                                             c.GetValue(TargetPool(Pool.Life), NodeType.Total, Path) == TargetValueFor(Pool.Life) &&
                                                             c.GetValue(TargetPool(Pool.Mana), NodeType.Total, Path) == TargetValueFor(Pool.Mana) &&
                                                             c.GetValue(TargetPool(Pool.EnergyShield), NodeType.Total, Path) == TargetValueFor(Pool.EnergyShield));
            var sut = CreateSut(transformedValue);

            var actual = sut.Calculate(context);

            Assert.AreEqual(expected, actual);
        }
예제 #6
0
        public void CalculateReturnsOriginalResultIfValueUsesDifferentStats()
        {
            var expected      = (NodeValue?)43;
            var ailmentDamage = new Stat("Damage.Spell.Ignite");
            var skillDamage   = ConcretizeDamage(new SkillDamageSpecification(DamageSource.Spell));
            var unrelated     = new Stat("unrelated");
            var paths         = new[] { PathDefinition.MainPath, new PathDefinition(new ModifierSource.Local.Given()) };
            var context       = Mock.Of <IValueCalculationContext>(c =>
                                                                   c.GetPaths(unrelated) == paths.Take(1).ToList() &&
                                                                   c.GetPaths(skillDamage) == paths.Skip(1).ToList() &&
                                                                   c.GetValue(unrelated, NodeType.PathTotal, paths[0]) == expected &&
                                                                   c.GetValue(unrelated, NodeType.PathTotal, paths[1]) == new NodeValue(10));
            var transformedValue = new FunctionalValue(c => c.GetValues(unrelated, NodeType.PathTotal).Sum(), "");
            var sut = new AilmentDamageUncappedSubtotalValue(ailmentDamage, skillDamage, transformedValue);

            var actual = sut.Calculate(context);

            Assert.AreEqual(expected, actual);
        }
예제 #7
0
        public void CalculateReturnsCorrectResult(params double?[] values)
        {
            var expected        = (NodeValue?)values.Max();
            var transformedStat = new Stat("transformed");
            var paths           = values
                                  .Select((_, i) => new PathDefinition(new ModifierSource.Local.Gem(new Gem("", 1, 1, ItemSlot.Helm, i, 0, true))))
                                  .ToList();
            var contextMock = new Mock <IValueCalculationContext>();

            contextMock.Setup(c => c.GetPaths(transformedStat)).Returns(paths);
            for (var i = 0; i < paths.Count; i++)
            {
                var path = paths[i];
                contextMock.Setup(c => c.GetValue(transformedStat, NodeType.PathTotal, path))
                .Returns((NodeValue?)values[i]);
            }
            var transformedValue = new FunctionalValue(c => c.GetValues(transformedStat, NodeType.PathTotal).Sum(), "");
            var sut = new RequirementUncappedSubtotalValue(transformedStat, transformedValue);

            var actual = sut.Calculate(contextMock.Object);

            Assert.AreEqual(expected, actual);
        }
        private static AilmentDamageBaseValue CreateSut(IStat ailmentDamage, IStat skillDamage)
        {
            var transformedValue = new FunctionalValue(c => c.GetValue(ailmentDamage, NodeType.BaseSet), "");

            return(new AilmentDamageBaseValue(skillDamage, transformedValue));
        }
예제 #9
0
        private static AilmentDamageUncappedSubtotalValue CreateSut(IStat ailmentDamage, IStat skillDamage)
        {
            var transformedValue = new FunctionalValue(c => c.GetValues(ailmentDamage, NodeType.PathTotal).Sum(), "");

            return(new AilmentDamageUncappedSubtotalValue(ailmentDamage, skillDamage, transformedValue));
        }