Add quick parse notation for critical editor
This commit is contained in:
@@ -14,6 +14,7 @@ public sealed record CriticalCellEditorResponse(
|
||||
string ColumnLabel,
|
||||
string ColumnRole,
|
||||
string RawCellText,
|
||||
string QuickParseInput,
|
||||
string DescriptionText,
|
||||
string? RawAffixText,
|
||||
string ParseStatus,
|
||||
|
||||
@@ -9,7 +9,8 @@ public sealed record CriticalCellEditorSnapshot(
|
||||
bool AreEffectsOverridden,
|
||||
bool AreBranchesOverridden,
|
||||
IReadOnlyList<CriticalEffectEditorItem> Effects,
|
||||
IReadOnlyList<CriticalBranchEditorItem> Branches)
|
||||
IReadOnlyList<CriticalBranchEditorItem> Branches,
|
||||
string? QuickParseInput)
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
||||
|
||||
@@ -21,7 +22,8 @@ public sealed record CriticalCellEditorSnapshot(
|
||||
request.AreEffectsOverridden,
|
||||
request.AreBranchesOverridden,
|
||||
request.Effects,
|
||||
request.Branches);
|
||||
request.Branches,
|
||||
request.QuickParseInput);
|
||||
|
||||
public string ToJson() =>
|
||||
JsonSerializer.Serialize(this, JsonOptions);
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace RolemasterDb.App.Features;
|
||||
|
||||
public sealed record CriticalCellUpdateRequest(
|
||||
string RawCellText,
|
||||
string QuickParseInput,
|
||||
string DescriptionText,
|
||||
string? RawAffixText,
|
||||
string ParseStatus,
|
||||
|
||||
100
src/RolemasterDb.App/Features/CriticalQuickNotationFormatter.cs
Normal file
100
src/RolemasterDb.App/Features/CriticalQuickNotationFormatter.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RolemasterDb.App.Features;
|
||||
|
||||
public static class CriticalQuickNotationFormatter
|
||||
{
|
||||
public static string Format(
|
||||
string descriptionText,
|
||||
IReadOnlyList<CriticalEffectEditorItem> effects,
|
||||
IReadOnlyList<CriticalBranchEditorItem> branches)
|
||||
{
|
||||
var lines = new List<string>
|
||||
{
|
||||
CollapseWhitespace(descriptionText)
|
||||
};
|
||||
|
||||
var baseAffixLine = FormatEffects(effects);
|
||||
if (!string.IsNullOrWhiteSpace(baseAffixLine))
|
||||
{
|
||||
lines.Add(baseAffixLine);
|
||||
}
|
||||
|
||||
foreach (var branch in branches.OrderBy(item => item.SortOrder))
|
||||
{
|
||||
var payloadParts = new List<string>();
|
||||
var branchDescription = CollapseWhitespace(branch.DescriptionText);
|
||||
if (!string.IsNullOrWhiteSpace(branchDescription))
|
||||
{
|
||||
payloadParts.Add(branchDescription);
|
||||
}
|
||||
|
||||
var branchAffixLine = FormatEffects(branch.Effects);
|
||||
if (!string.IsNullOrWhiteSpace(branchAffixLine))
|
||||
{
|
||||
payloadParts.Add(branchAffixLine);
|
||||
}
|
||||
|
||||
if (payloadParts.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.Add($"{CollapseWhitespace(branch.ConditionText)}: {string.Join(", ", payloadParts)}");
|
||||
}
|
||||
|
||||
return string.Join(Environment.NewLine, lines.Where(line => !string.IsNullOrWhiteSpace(line)));
|
||||
}
|
||||
|
||||
private static string? FormatEffects(IReadOnlyList<CriticalEffectEditorItem> effects)
|
||||
{
|
||||
var tokens = effects
|
||||
.Select(FormatEffect)
|
||||
.Where(token => !string.IsNullOrWhiteSpace(token))
|
||||
.ToList();
|
||||
|
||||
return tokens.Count == 0 ? null : string.Join(", ", tokens);
|
||||
}
|
||||
|
||||
private static string? FormatEffect(CriticalEffectEditorItem effect) =>
|
||||
effect.EffectCode switch
|
||||
{
|
||||
Domain.CriticalEffectCodes.DirectHits => effect.ValueInteger is int hits ? $"+{hits}" : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.StunnedRounds => effect.DurationRounds is int rounds ? $"{rounds}s" : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.MustParryRounds => effect.DurationRounds is int rounds ? $"{rounds}mp" : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.NoParryRounds => effect.DurationRounds is int rounds ? $"{rounds}np" : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.BleedPerRound => effect.PerRound is int bleed ? $"{bleed}hpr" : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.FoePenalty => effect.Modifier is int penalty ? penalty.ToString(System.Globalization.CultureInfo.InvariantCulture) : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.AttackerBonusNextRound => effect.Modifier is int bonus ? $"+{bonus}b" : effect.SourceText,
|
||||
Domain.CriticalEffectCodes.PowerPointModifier => FormatPowerPointModifier(effect.ValueExpression, effect.SourceText),
|
||||
_ => effect.SourceText ?? effect.EffectCode
|
||||
};
|
||||
|
||||
private static string? FormatPowerPointModifier(string? valueExpression, string? sourceText)
|
||||
{
|
||||
var expression = CollapseWhitespace(valueExpression);
|
||||
if (string.IsNullOrWhiteSpace(expression))
|
||||
{
|
||||
return sourceText;
|
||||
}
|
||||
|
||||
expression = expression.Trim();
|
||||
if (expression.StartsWith('+'))
|
||||
{
|
||||
expression = expression[1..];
|
||||
}
|
||||
|
||||
if (expression.StartsWith('(') && expression.EndsWith(')') && expression.Length > 2)
|
||||
{
|
||||
expression = expression[1..^1].Trim();
|
||||
}
|
||||
|
||||
expression = Regex.Replace(expression, @"\s+", string.Empty);
|
||||
return $"+{expression}pp";
|
||||
}
|
||||
|
||||
private static string CollapseWhitespace(string? value) =>
|
||||
string.IsNullOrWhiteSpace(value)
|
||||
? string.Empty
|
||||
: Regex.Replace(value.Trim(), @"\s+", " ");
|
||||
}
|
||||
@@ -296,7 +296,7 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
}
|
||||
|
||||
var currentState = CreateCurrentEditorState(result);
|
||||
var generatedContent = await ParseCriticalCellContentAsync(dbContext, result.CriticalTableId, currentState.RawCellText, cancellationToken);
|
||||
var generatedContent = await ParseCriticalCellContentAsync(dbContext, result.CriticalTableId, currentState.QuickParseInput, cancellationToken);
|
||||
return CreateCellEditorResponse(result, currentState, generatedContent.ValidationErrors, CreateComparisonState(generatedContent));
|
||||
}
|
||||
|
||||
@@ -325,8 +325,7 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
return null;
|
||||
}
|
||||
|
||||
var affixLegend = await BuildSharedAffixLegendAsync(dbContext, result.CriticalTableId, cancellationToken);
|
||||
var content = SharedParsing.CriticalCellTextParser.Parse(currentState.RawCellText, affixLegend);
|
||||
var content = await ParseCriticalCellContentAsync(dbContext, result.CriticalTableId, currentState.QuickParseInput, cancellationToken);
|
||||
var generatedState = CreateGeneratedEditorState(content);
|
||||
var mergedState = MergeGeneratedState(currentState, generatedState);
|
||||
return CreateCellEditorResponse(result, mergedState, content.ValidationErrors, CreateComparisonState(content));
|
||||
@@ -370,7 +369,7 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var generatedContent = await ParseCriticalCellContentAsync(dbContext, result.CriticalTableId, request.RawCellText, cancellationToken);
|
||||
var generatedContent = await ParseCriticalCellContentAsync(dbContext, result.CriticalTableId, request.QuickParseInput, cancellationToken);
|
||||
return CreateCellEditorResponse(result, request, generatedContent.ValidationErrors, CreateComparisonState(generatedContent));
|
||||
}
|
||||
|
||||
@@ -452,6 +451,7 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
result.CriticalColumn.Label,
|
||||
result.CriticalColumn.Role,
|
||||
state.RawCellText,
|
||||
state.QuickParseInput,
|
||||
state.DescriptionText,
|
||||
state.RawAffixText,
|
||||
state.ParseStatus,
|
||||
@@ -575,8 +575,13 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
{
|
||||
if (CriticalCellEditorSnapshot.TryParse(result.ParsedJson, out var snapshot) && snapshot is not null)
|
||||
{
|
||||
var snapshotQuickParseInput = string.IsNullOrWhiteSpace(snapshot.QuickParseInput)
|
||||
? CriticalQuickNotationFormatter.Format(result.DescriptionText, snapshot.Effects, snapshot.Branches)
|
||||
: snapshot.QuickParseInput;
|
||||
|
||||
return new CriticalCellUpdateRequest(
|
||||
result.RawCellText,
|
||||
snapshotQuickParseInput,
|
||||
result.DescriptionText,
|
||||
result.RawAffixText,
|
||||
result.ParseStatus,
|
||||
@@ -600,6 +605,7 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
|
||||
return new CriticalCellUpdateRequest(
|
||||
result.RawCellText,
|
||||
CriticalQuickNotationFormatter.Format(result.DescriptionText, effects, branches),
|
||||
result.DescriptionText,
|
||||
result.RawAffixText,
|
||||
result.ParseStatus,
|
||||
@@ -623,17 +629,18 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
.ToList();
|
||||
|
||||
return new CriticalCellUpdateRequest(
|
||||
content.RawCellText,
|
||||
content.DescriptionText,
|
||||
content.RawAffixText,
|
||||
ResolveParseStatus(content.Effects, content.Branches),
|
||||
SerializeParsedEffects(content.Effects),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
effects,
|
||||
branches);
|
||||
RawCellText: string.Empty,
|
||||
QuickParseInput: content.RawCellText,
|
||||
DescriptionText: content.DescriptionText,
|
||||
RawAffixText: content.RawAffixText,
|
||||
ParseStatus: ResolveParseStatus(content.Effects, content.Branches),
|
||||
ParsedJson: SerializeParsedEffects(content.Effects),
|
||||
IsDescriptionOverridden: false,
|
||||
IsRawAffixTextOverridden: false,
|
||||
AreEffectsOverridden: false,
|
||||
AreBranchesOverridden: false,
|
||||
Effects: effects,
|
||||
Branches: branches);
|
||||
}
|
||||
|
||||
private static CriticalCellUpdateRequest MergeGeneratedState(
|
||||
@@ -641,6 +648,7 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
CriticalCellUpdateRequest generatedState) =>
|
||||
new(
|
||||
currentState.RawCellText,
|
||||
currentState.QuickParseInput,
|
||||
currentState.IsDescriptionOverridden ? currentState.DescriptionText : generatedState.DescriptionText,
|
||||
currentState.IsRawAffixTextOverridden ? currentState.RawAffixText : generatedState.RawAffixText,
|
||||
generatedState.ParseStatus,
|
||||
@@ -922,11 +930,11 @@ public sealed class LookupService(IDbContextFactory<RolemasterDbContext> dbConte
|
||||
private static async Task<SharedParsing.CriticalCellParseContent> ParseCriticalCellContentAsync(
|
||||
RolemasterDbContext dbContext,
|
||||
int tableId,
|
||||
string rawCellText,
|
||||
string quickParseInput,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var affixLegend = await BuildSharedAffixLegendAsync(dbContext, tableId, cancellationToken);
|
||||
return SharedParsing.CriticalCellTextParser.Parse(rawCellText, affixLegend);
|
||||
return SharedParsing.CriticalQuickNotationParser.Parse(quickParseInput, affixLegend);
|
||||
}
|
||||
|
||||
private static bool IsLegendSymbolEffectCode(string effectCode) =>
|
||||
|
||||
Reference in New Issue
Block a user