Add quick parse notation for critical editor
This commit is contained in:
@@ -9,6 +9,14 @@ public static class AffixEffectParser
|
||||
private static readonly Regex DirectHitsRegex = new(@"[+-]\s*\d+\s*H\b", RegexOptions.Compiled);
|
||||
private static readonly Regex PowerPointModifierRegex = new(@"\+\s*\((?<expression>[^)]+)\)\s*P\b", RegexOptions.Compiled);
|
||||
private static readonly Regex ModifierRegex = new(@"\((?<noise>[^0-9+\-)]*)(?<sign>[+-])\s*(?<value>\d+)\)", RegexOptions.Compiled);
|
||||
private static readonly Regex QuickDirectHitsRegex = new(@"^\+(?<value>\d+)(?:H)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickStunnedRegex = new(@"^(?<value>\d+)s$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickMustParryRegex = new(@"^(?<value>\d+)mp$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickNoParryRegex = new(@"^(?<value>\d+)np$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickBleedRegex = new(@"^(?<value>\d+)hpr$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickFoePenaltyRegex = new(@"^-(?<value>\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickAttackerBonusRegex = new(@"^\+(?<value>\d+)b$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QuickPowerPointRegex = new(@"^\+(?<expression>.+)pp$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static IReadOnlyList<ParsedCriticalEffect> Parse(string? rawAffixText, AffixLegend affixLegend)
|
||||
{
|
||||
@@ -27,6 +35,31 @@ public static class AffixEffectParser
|
||||
return effects;
|
||||
}
|
||||
|
||||
public static bool TryParseAffixToken(
|
||||
string token,
|
||||
AffixLegend affixLegend,
|
||||
out IReadOnlyList<ParsedCriticalEffect> effects,
|
||||
out string normalizedToken)
|
||||
{
|
||||
normalizedToken = CriticalCellParserSupport.CollapseWhitespace(token);
|
||||
if (TryParseQuickToken(normalizedToken, out var quickEffects, out var canonicalToken))
|
||||
{
|
||||
normalizedToken = canonicalToken;
|
||||
effects = quickEffects;
|
||||
return true;
|
||||
}
|
||||
|
||||
var legacyEffects = Parse(normalizedToken, affixLegend);
|
||||
if (legacyEffects.Count > 0)
|
||||
{
|
||||
effects = legacyEffects;
|
||||
return true;
|
||||
}
|
||||
|
||||
effects = [];
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ParseLine(string line, AffixLegend affixLegend, List<ParsedCriticalEffect> effects)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line) || line is "-" or "–" or "—")
|
||||
@@ -163,6 +196,174 @@ public static class AffixEffectParser
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryParseQuickToken(
|
||||
string token,
|
||||
out IReadOnlyList<ParsedCriticalEffect> effects,
|
||||
out string canonicalToken)
|
||||
{
|
||||
canonicalToken = token;
|
||||
|
||||
if (TryMatchSingle(QuickDirectHitsRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.DirectHits,
|
||||
FoeTarget,
|
||||
int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"+{match.Groups["value"].Value}"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickStunnedRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.StunnedRounds,
|
||||
FoeTarget,
|
||||
null,
|
||||
null,
|
||||
int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"{match.Groups["value"].Value}s"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickMustParryRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.MustParryRounds,
|
||||
FoeTarget,
|
||||
null,
|
||||
null,
|
||||
int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"{match.Groups["value"].Value}mp"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickNoParryRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.NoParryRounds,
|
||||
FoeTarget,
|
||||
null,
|
||||
null,
|
||||
int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"{match.Groups["value"].Value}np"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickBleedRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.BleedPerRound,
|
||||
FoeTarget,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"{match.Groups["value"].Value}hpr"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickFoePenaltyRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.FoePenalty,
|
||||
FoeTarget,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
-int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"-{match.Groups["value"].Value}"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickAttackerBonusRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.AttackerBonusNextRound,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
int.Parse(match.Groups["value"].Value),
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"+{match.Groups["value"].Value}b"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryMatchSingle(QuickPowerPointRegex, token, match =>
|
||||
new ParsedCriticalEffect(
|
||||
CriticalEffectCodes.PowerPointModifier,
|
||||
FoeTarget,
|
||||
null,
|
||||
NormalizePowerPointExpression(match.Groups["expression"].Value),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"quick",
|
||||
$"+{NormalizePowerPointExpression(match.Groups["expression"].Value)}pp"), out effects, out canonicalToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
effects = [];
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryMatchSingle(
|
||||
Regex regex,
|
||||
string token,
|
||||
Func<Match, ParsedCriticalEffect> createEffect,
|
||||
out IReadOnlyList<ParsedCriticalEffect> effects,
|
||||
out string canonicalToken)
|
||||
{
|
||||
var match = regex.Match(token);
|
||||
if (!match.Success)
|
||||
{
|
||||
effects = [];
|
||||
canonicalToken = token;
|
||||
return false;
|
||||
}
|
||||
|
||||
var effect = createEffect(match);
|
||||
effects = [effect];
|
||||
canonicalToken = effect.SourceText ?? token;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ParsedCriticalEffect CreateSymbolEffect(string effectCode, int magnitude, string sourceText) =>
|
||||
effectCode switch
|
||||
{
|
||||
@@ -276,4 +477,22 @@ public static class AffixEffectParser
|
||||
.Replace(" +", "+", StringComparison.Ordinal)
|
||||
.Replace("( ", "(", StringComparison.Ordinal)
|
||||
.Replace(" )", ")", StringComparison.Ordinal);
|
||||
|
||||
private static string NormalizePowerPointExpression(string value)
|
||||
{
|
||||
var normalized = CriticalCellParserSupport.CollapseWhitespace(value)
|
||||
.Replace(" ", string.Empty, StringComparison.Ordinal);
|
||||
|
||||
if (normalized.StartsWith('+'))
|
||||
{
|
||||
normalized = normalized[1..];
|
||||
}
|
||||
|
||||
if (normalized.StartsWith('(') && normalized.EndsWith(')') && normalized.Length > 2)
|
||||
{
|
||||
normalized = normalized[1..^1];
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user