private static NodeValue?SelectSingleValue(List <NodeValue?> values) { NodeValue?result = null; var hasDistinctValues = false; foreach (var nullableValue in values) { if (nullableValue is NodeValue value) { if (value.IsZero) { return(new NodeValue(0)); } if (result is null) { result = value; } else if (!value.AlmostEquals(result.Value)) { hasDistinctValues = true; } } } if (hasDistinctValues) { throw new NotSupportedException("Multiple modifiers with none having value 0 are not supported"); } return(result); }
public void GetValuesReturnsCorrectResult() { var expected = new NodeValue?[] { new NodeValue(0), new NodeValue(1), new NodeValue(2), new NodeValue(3), }; var nodes = expected.Select(MockNode).ToList(); var nodeCollections = new[] { MockNodeCollection(nodes[0], nodes[1]), MockNodeCollection(nodes[1], nodes[2]), MockNodeCollection(nodes[2], nodes[3]), }; var stats = new IStat[] { new StatStub(), new StatStub(), new StatStub(), }; var nodeRepositoryMock = new Mock <INodeRepository>(); for (var i = 0; i < stats.Length; i++) { var iClosure = i; nodeRepositoryMock.Setup(r => r.GetFormNodeCollection(stats[iClosure], Form.More, Path)) .Returns(nodeCollections[i]); } var sut = CreateSut(nodeRepositoryMock.Object); var actual = sut.GetValues(Form.More, stats, Path); Assert.AreEqual(expected, actual); }
public static double Single(this NodeValue? @this) { if (!(@this is NodeValue value)) { throw new InvalidOperationException("NodeValue? has no value"); } return(value.Single); }
private void CalculateValue() { using (_cycleGuard.Guard()) { _value = _decoratedNode.Value; } _calculatedValue = true; }
public void CalculateBaseSetCorrectlyAggregatesValuesThatArePartlyZero() { var values = new NodeValue?[] { new NodeValue(-42, 0), new NodeValue(0, 5), new NodeValue(0) }; var actual = NodeValueAggregators.CalculateBaseSet(values); Assert.AreEqual(new NodeValue(-42, 5), actual); }
private static ResultNodeViewModel CreateSut <T>(NodeValue?value) { var stat = new Stat("", dataType: typeof(T)); return(new ResultNodeViewModel(stat) { Value = value }); }
private static NodeValue Combine(NodeValue left, NodeValue?right, Func <double, double, double> operation) { if (!right.HasValue) { return(left); } return(NodeValue.Combine(left, right.Value, operation)); }
public static NodeValue?SumWhereNotNull(this NodeValue?left, NodeValue?right) { if (left is null) { return(right); } if (right is null) { return(left); } return(left + right); }
public void InitializeSetsNodeValuesCorrectly() { var stats = new[] { new Stat("a"), new Stat("b"), }; var expected = new NodeValue?[] { new NodeValue(42), null }; var build = new PoEBuild(); build.ConfigurationStats.SetValue(stats[0], expected[0]); var nodes = stats.Select(s => new ConfigurationNodeViewModel(s)).ToArray(); SetupSut(build, nodes); Assert.AreEqual(expected, nodes.Select(n => n.Value)); }
public NodeValue?Round(NodeValue?value) { if (_rounding != null) { return(_rounding(value)); } else if (!NumericTypes.Contains(DataType) || DataType == typeof(double)) { return(value); } else { return(RoundingBehaviors.Floor(value)); } }
private IReadOnlyList <Modifier> CreateModifiers(NodeValue?value) { if (value is null) { return(new Modifier[0]); } return(new[] { new Modifier(new[] { Stat }, Form.TotalOverride, new FunctionalValue(c => Calculate(c, value.Value), $"{Stat.Minimum} <= {value} <= {Stat.Maximum}"), new ModifierSource.Global(new ModifierSource.Local.UserSpecified())) }); }
public NodeValue?GetValue(IStat stat, NodeType nodeType, PathDefinition path) { if (nodeType != NodeType.PathTotal || !_value._regens(_value._pool).Equals(stat)) { return(_originalContext.GetValue(stat, nodeType, path)); } NodeValue?result = null; foreach (var pool in _applyingPools) { var value = _originalContext.GetValue(_value._regens(pool), nodeType, path); result = result.SumWhereNotNull(value); } return(result); }
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(Calculate, $"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?Calculate(IValueCalculationContext context) { NodeValue?result = null; foreach (var functionalValue in values) { if (!(functionalValue.Calculate(context) is NodeValue value)) { continue; } if (result is NodeValue r && !r.AlmostEquals(value)) { throw new ParseException( $"ApplyModifiersToDamage values must be equal for all concretized stats. {result} and {value} given"); } result = value; } return(result); } }
private IValue BuildInPastXSecondsValue(BuildParameters parameters, IValueBuilder seconds) { var builtEntity = BuildEntity(parameters, Entity); var recentOccurrencesStat = BuildRecentOccurrencesStat(parameters, builtEntity); var lastOccurenceStat = BuildLastOccurrenceStat(parameters, builtEntity); var secondsValue = seconds.Build(parameters); return(new ConditionalValue(Calculate, $"({RecentlySeconds} <= {secondsValue} && {recentOccurrencesStat} > 0) " + $"|| {lastOccurenceStat} <= {secondsValue}")); bool Calculate(IValueCalculationContext context) { NodeValue?threshold = secondsValue.Calculate(context); if (RecentlySeconds <= threshold && context.GetValue(recentOccurrencesStat) > 0) { return(true); } return(context.GetValue(lastOccurenceStat) <= threshold); } }
/// <summary> /// Returns the value created by applying <paramref name="operation"/> to <paramref name="value"/> if /// <paramref name="value"/> is not <c>null</c>. Returns <c>null</c> otherwise. /// </summary> public static NodeValue?Select(this NodeValue?value, Func <double, double> operation) => value.Select(v => v.Select(operation));
public void CalculateBaseSetThrowsExceptionIfMultipleValuesWithNonUZeroMaximumArePassed() { var values = new NodeValue?[] { new NodeValue(0, 5), new NodeValue(0, 44) }; Assert.Throws <NotSupportedException>(() => NodeValueAggregators.CalculateBaseSet(values)); }
private static NodeValue?CalculateFromMinAndMax(NodeValue?min, NodeValue?max) => min.HasValue && max.HasValue ? new NodeValue(min.Value.Minimum, max.Value.Maximum) : (NodeValue?)null;
public NodeValue?Round(NodeValue?value) => value;
/// <summary> /// Returns true if this <c>NodeValue?</c> representing a boolean value represents <c>true</c>. /// </summary> public static bool IsTrue(this NodeValue? @this) => @this.HasValue;
public static ExplicitRegistrationType.UserSpecifiedValue UserSpecifiedValue(NodeValue?defaultValue) => new ExplicitRegistrationType.UserSpecifiedValue(defaultValue);
private static Tags ToTags(NodeValue?value) => value is NodeValue v ? ((Tags)(int)v.Maximum) : Tags.Default;
public static Modifier CreateModifier(string stat, Form form, NodeValue?value, ModifierSource source = null) => CreateModifier(stat, form, new Constant(value), source);
public ConfigurationNodeViewModel(IStat stat, NodeValue?defaultValue = null) : base(stat) { _defaultValue = defaultValue; }
public Constant(NodeValue?value) : base(value) =>
/// <summary> /// Returns true if this <c>NodeValue?</c> representing a boolean value represents <c>true</c>. /// </summary> public static bool IsTrue(this NodeValue? @this) => @this.HasValue && @this.Value != new NodeValue(0);
private static Tags ToTags(NodeValue?value) => value is NodeValue v?TagsExtensions.DecodeFromDouble(v.Single) : Tags.Default;
public static double?SingleOrNull(this NodeValue? @this) => @this.Select(v => v.Single);
private static NodeValue Max(NodeValue left, NodeValue?right) => Combine(left, right, Math.Max);
public static ICalculationNode MockNode(NodeValue?value = null) => Mock.Of <ICalculationNode>(n => n.Value == value);
public UserSpecifiedValue(NodeValue?defaultValue) => DefaultValue = defaultValue;