/// <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)); } }
/// <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)); }
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))); }
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()); }
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()); }