/// <summary>
        /// Merges <paramref name="left"/> with <paramref name="right"/> and returns the result.
        /// </summary>
        /// <remarks>
        /// The converters are merged by creating new converters that successively apply both. The entries of
        /// <paramref name="left"/> are merged with the entries of <paramref name="right"/>.
        /// <para> Two entries are merged by anding the conditions and taking the non-null form, stat and value,
        /// i.e. two merged entries may not both have forms, stats or values.
        /// </para>
        /// <para> Which entries are merged depends on the number of entries in <paramref name="left"/> and
        /// <paramref name="right"/>.
        /// <list type="bullet">
        /// <item>Both have more than one entry: An <see cref="ArgumentException"/> is thrown.</item>
        /// <item>One has no entries: The result has no entries.</item>
        /// <item>Otherwise: The single entry of one <see cref="IIntermediateModifier"/>
        /// is merged with every entry of the other <see cref="IIntermediateModifier"/>, i.e. the result has as much
        /// entries as the other <see cref="IIntermediateModifier"/>.</item>
        /// </list>
        /// </para>
        /// </remarks>
        public static IIntermediateModifier MergeWith(this IIntermediateModifier left, IIntermediateModifier right)
        {
            IStatBuilder ConvertStat(IStatBuilder s) =>
            right.StatConverter(left.StatConverter(s));

            IValueBuilder ConvertValue(IValueBuilder v) =>
            right.ValueConverter(left.ValueConverter(v));

            if (left.Entries.Count > 1 && right.Entries.Count > 1)
            {
                // This simple solution will fail once there are stat lines that parse into multiple stats
                // and have a condition requiring splitting by main hand and off hand.
                throw new ArgumentException("There may only be one IIntermediateModifier with multiple entries");
            }

            IEnumerable <IntermediateModifierEntry> entries;

            if (left.Entries.IsEmpty())
            {
                entries = right.Entries;
            }
            else if (right.Entries.IsEmpty())
            {
                entries = left.Entries;
            }
            else
            {
                entries = left.Entries.SelectMany(l => right.Entries.Select(r => Merge(l, r)));
            }

            return(new SimpleIntermediateModifier(entries.ToList(), ConvertStat, ConvertValue));
        }
            private void Build(IntermediateModifierEntry entry)
            {
                if (entry.Form == null || entry.Stat == null || entry.Value == null)
                {
                    return;
                }

                var(form, formValueConverter) = entry.Form.Build();
                var buildParameters = new BuildParameters(_originalSource, _modifierSourceEntity, form);

                var statBuilder = entry.Stat;

                if (entry.Condition != null)
                {
                    statBuilder = statBuilder.WithCondition(entry.Condition);
                }

                statBuilder = _modifier.StatConverter(statBuilder);
                var statBuilderResults = statBuilder.Build(buildParameters);

                foreach (var(stats, source, statValueConverter) in statBuilderResults)
                {
                    var valueBuilder = formValueConverter(statValueConverter(_modifier.ValueConverter(entry.Value)));
                    var value        = valueBuilder.Build(buildParameters);
                    _modifiers.Add(CreateModifier(stats, form, value, source));
                }
            }
Example #3
0
        /// <summary>
        /// Merges <paramref name="left"/> with <paramref name="right"/> and returns the result.
        /// </summary>
        /// <remarks>
        /// The converters are merged by creating new converters that successively apply both. The entries of
        /// <paramref name="left"/> are merged with the entries of <paramref name="right"/>.
        /// <para> Two entries are merged by anding the conditions and taking the non-null form, stat and value,
        /// i.e. two merged entries may not both have forms, stats or values.
        /// </para>
        /// <para> Which entries are merged depends on the number of entries in <paramref name="left"/> and
        /// <paramref name="right"/>.
        /// <list type="bullet">
        /// <item>Both have more than one entry: An <see cref="ArgumentException"/> is thrown.</item>
        /// <item>One has no entries: The result has no entries.</item>
        /// <item>Otherwise: The single entry of one <see cref="IIntermediateModifier"/>
        /// is merged with every entry of the other <see cref="IIntermediateModifier"/>, i.e. the result has as much
        /// entries as the other <see cref="IIntermediateModifier"/>.</item>
        /// </list>
        /// </para>
        /// </remarks>
        public static IIntermediateModifier MergeWith(this IIntermediateModifier left, IIntermediateModifier right)
        {
            IStatBuilder ConvertStat(IStatBuilder s) =>
            right.StatConverter(left.StatConverter(s));

            IValueBuilder ConvertValue(IValueBuilder v) =>
            right.ValueConverter(left.ValueConverter(v));

            if (left.Entries.Count > right.Entries.Count)
            {
                (left, right) = (right, left);
            }

            if (left.Entries.Count > 1)
            {
                throw new ArgumentException("There may only be one IIntermediateModifier with multiple entries");
            }

            if (left.Entries.IsEmpty())
            {
                return(new SimpleIntermediateModifier(right.Entries, ConvertStat, ConvertValue));
            }

            var leftEntry = left.Entries.Single();
            IEnumerable <IntermediateModifierEntry> entries = right.Entries.Select(r => Merge(leftEntry, r));

            return(new SimpleIntermediateModifier(entries.ToList(), ConvertStat, ConvertValue));
        }
Example #4
0
        private static Modifier Build(
            IIntermediateModifier modifier, IntermediateModifierEntry entry, ModifierSource originalSource)
        {
            if (entry.Form == null || entry.Stat == null || entry.Value == null)
            {
                return(null);
            }

            var statBuilder = modifier.StatConverter(entry.Stat);

            if (entry.Condition != null)
            {
                statBuilder = statBuilder.WithCondition(entry.Condition);
            }
            var(stats, sourceConverter, statValueConverter) = statBuilder.Build();

            var(form, formValueConverter) = entry.Form.Build();

            var value =
                formValueConverter(
                    statValueConverter(
                        modifier.ValueConverter(entry.Value))).Build();

            return(new Modifier(stats, form, value, sourceConverter(originalSource)));
        }
Example #5
0
 public IIntermediateModifier Resolve(IIntermediateModifier unresolved, ResolveContext context)
 {
     return(_builder
            .WithValues(unresolved.Entries.Select(e => e.Value?.Resolve(context)))
            .WithForms(unresolved.Entries.Select(e => e.Form?.Resolve(context)))
            .WithStats(unresolved.Entries.Select(e => e.Stat?.Resolve(context)))
            .WithConditions(unresolved.Entries.Select(e => e.Condition?.Resolve(context)))
            .WithValueConverter(v => unresolved.ValueConverter(v)?.Resolve(context))
            .WithStatConverter(s => unresolved.StatConverter(s)?.Resolve(context))
            .Build());
 }
Example #6
0
        public IIntermediateModifier Resolve(IIntermediateModifier unresolved, ResolveContext context)
        {
            var entries = unresolved.Entries;

            return(_builder
                   .WithValues(Resolve(entries, e => e.Value, context))
                   .WithForms(Resolve(entries, e => e.Form, context))
                   .WithStats(Resolve(entries, e => e.Stat, context))
                   .WithConditions(Resolve(entries, e => e.Condition, context))
                   .WithValueConverter(v => unresolved.ValueConverter(v).Resolve(context))
                   .WithStatConverter(s => unresolved.StatConverter(s).Resolve(context))
                   .Build());
        }