/// <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 static IEnumerable <Modifier> Build( IIntermediateModifier modifier, IntermediateModifierEntry entry, ModifierSource originalSource, Entity modifierSourceEntity) { if (entry.Form == null || entry.Stat == null || entry.Value == null) { yield break; } 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); yield return(new Modifier(stats, form, value, source)); } }
public IntermediateModifierBuilder( IIntermediateModifier modifier, ModifierSource originalSource, Entity modifierSourceEntity) { _modifier = modifier; _originalSource = originalSource; _modifierSourceEntity = modifierSourceEntity; }
public IStatBuilder ResolveToReferencedBuilder(IIntermediateModifier unresolved, ResolveContext context) { if (unresolved.Entries.Count != 1) { throw new ParseException( $"Referenced matchers must have exactly one IntermediateModifierEntry, {unresolved.Entries.Count} given ({unresolved})"); } var entry = unresolved.Entries.Single(); if (entry.Value != null) { throw new ParseException($"Referenced matchers may not have values ({entry})"); } if (entry.Form != null) { throw new ParseException($"Referenced matchers may not have forms ({entry})"); } if (entry.Stat == null) { throw new ParseException($"Referenced matchers must have stats ({entry})"); } var stat = unresolved.StatConverter(entry.Stat); if (entry.Condition != null) { stat = stat.WithCondition(entry.Condition); } return(stat.Resolve(context)); }
/// <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))); }
/// <summary> /// Builds <paramref name="modifier"/> by creating a <see cref="Modifier"/> from each of its entries. /// The <see cref="IIntermediateModifier.StatConverter"/> is applied to each stat and /// <see cref="IIntermediateModifier.ValueConverter"/> to each value. Entries with null form, stat or value /// are ignored. /// </summary> public static IReadOnlyList <Modifier> Build(this IIntermediateModifier modifier, ModifierSource originalSource, Entity modifierSourceEntity) { return(( from entry in modifier.Entries from m in Build(modifier, entry, originalSource, modifierSourceEntity) select m ).ToList()); }
/// <summary> /// Builds <paramref name="modifier"/> by creating a <see cref="Modifier"/> from each of its entries. /// The <see cref="IIntermediateModifier.StatConverter"/> is applied to each stat and /// <see cref="IIntermediateModifier.ValueConverter"/> to each value. Entries with null form, stat or value /// are ignored. /// </summary> public static IReadOnlyList <Modifier> Build(this IIntermediateModifier modifier, ModifierSource originalSource) { return(( from entry in modifier.Entries let m = Build(modifier, entry, originalSource) where m != null select m ).ToList()); }
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()); }
/// <summary> /// Builds <paramref name="modifier"/> by creating a <see cref="Modifier"/> from each of its entries. /// The <see cref="IIntermediateModifier.StatConverter"/> is applied to each non-null stat and /// <see cref="IIntermediateModifier.ValueConverter"/> to each non-null value. /// <paramref name="defaultCondition"/> is set as the condition for each entry that has a null condition. /// </summary> public static IReadOnlyList <Modifier> Build(this IIntermediateModifier modifier, object defaultCondition) { IStatBuilder ConvertStat(IIntermediateModifier r, IStatBuilder s) => s == null ? null : r.StatConverter(s); IValueBuilder ConvertValue(IIntermediateModifier r, IValueBuilder v) => v == null ? null : r.ValueConverter(v); return((from entry in modifier.Entries let stat = ConvertStat(modifier, entry.Stat) let value = ConvertValue(modifier, entry.Value) select new Modifier(stat, entry.Form, value, entry.Condition ?? defaultCondition)) .ToList()); }
/// <summary> /// Builds <paramref name="modifier"/> by creating a <see cref="Modifier"/> from each of its entries. /// The <see cref="IIntermediateModifier.StatConverter"/> is applied to each stat and /// <see cref="IIntermediateModifier.ValueConverter"/> to each value. Entries with null form, stat or value /// are ignored. /// </summary> public static IReadOnlyList <Modifier> Build( this IIntermediateModifier modifier, ModifierSource originalSource, Entity modifierSourceEntity) => new IntermediateModifierBuilder(modifier, originalSource, modifierSourceEntity).Build();
public MatcherData(string regex, IIntermediateModifier modifier, string matchSubstitution = "") { Regex = regex; Modifier = modifier; MatchSubstitution = matchSubstitution; }
public MatcherDataParseResult(IIntermediateModifier modifier, IReadOnlyDictionary <string, string> regexGroups) { Modifier = modifier; RegexGroups = regexGroups; }