Generalize Rolemaster standard dice parsing

This commit is contained in:
2026-04-03 01:33:32 +02:00
parent e5f00fa693
commit f0dd79e589
17 changed files with 121 additions and 275 deletions

View File

@@ -7,7 +7,7 @@ public sealed class RolemasterApiTests : ApiTestBase
}
[Fact]
public async Task RolemasterRollEndpoints_ExecuteInitiativeAndPercentile()
public async Task RolemasterRollEndpoints_ExecuteGenericRolemasterExpressions()
{
using var factory = CreateFactory(8, 6, 74);
using var client = factory.CreateClient(new() { AllowAutoRedirect = false });
@@ -17,7 +17,7 @@ public sealed class RolemasterApiTests : ApiTestBase
var campaign = await PostAsync<CreateCampaignRequest, CampaignSummary>(client, "/api/campaigns", new("Rolemaster", "rolemaster"));
var character = await PostAsync<CreateCharacterRequest, CharacterSummary>(client, "/api/characters", new("Hero", campaign.Id));
var initiative = await PostAsync<CreateSkillRequest, SkillSummary>(client, $"/api/characters/{character.Id}/skills", new("Initiative", "2d10+48", 0, false));
var initiative = await PostAsync<CreateSkillRequest, SkillSummary>(client, $"/api/characters/{character.Id}/skills", new("Healing", "2d10+48", 0, false));
var perception = await PostAsync<CreateSkillRequest, SkillSummary>(client, $"/api/characters/{character.Id}/skills", new("Perception", "d100-15", 0, false));
var initiativeRoll = await PostAsync<RollSkillRequest, RollResult>(client, $"/api/skills/{initiative.Id}/roll", new("public"));
@@ -26,15 +26,15 @@ public sealed class RolemasterApiTests : ApiTestBase
Assert.Equal(62, initiativeRoll.Result);
Assert.Equal("8+6+48=62", initiativeRoll.Breakdown);
Assert.All(initiativeRoll.Dice, die => Assert.Equal(RollDieKinds.RolemasterInitiative, die.Kind));
Assert.All(initiativeRoll.Dice, die => Assert.Equal(RollDieKinds.RolemasterStandard, die.Kind));
Assert.Equal(59, percentileRoll.Result);
Assert.Equal("74-15=59", percentileRoll.Breakdown);
Assert.Equal(RollDieKinds.RolemasterPercentile, Assert.Single(percentileRoll.Dice).Kind);
Assert.Equal(RollDieKinds.RolemasterStandard, Assert.Single(percentileRoll.Dice).Kind);
Assert.Equal(2, logPage.Entries.Length);
Assert.Equal("8 + 6 | initiative", logPage.Entries[0].SummaryText);
Assert.Equal("74 | percentile", logPage.Entries[1].SummaryText);
Assert.Equal("8 + 6 | rolemaster", logPage.Entries[0].SummaryText);
Assert.Equal("74 | rolemaster", logPage.Entries[1].SummaryText);
}
[Fact]

View File

@@ -12,7 +12,8 @@ public sealed class DiceRulesTests
var d6 = DiceRules.ParseExpression(RulesetKind.D6, "5D+4");
var dnd = DiceRules.ParseExpression(RulesetKind.Dnd5e, "2d12+2");
var rolemasterInitiative = DiceRules.ParseExpression(RulesetKind.Rolemaster, "2d10-15");
var rolemasterImplicitSingle = DiceRules.ParseExpression(RulesetKind.Rolemaster, "d10");
var rolemasterManyDice = DiceRules.ParseExpression(RulesetKind.Rolemaster, "15d10-15");
var rolemasterPercentile = DiceRules.ParseExpression(RulesetKind.Rolemaster, "d100+4");
var rolemasterOpenEnded = DiceRules.ParseExpression(RulesetKind.Rolemaster, "1d100!+85");
var emptyExpression = DiceRules.ParseExpression(RulesetKind.Dnd5e, "");
@@ -21,13 +22,14 @@ public sealed class DiceRulesTests
var tooManySides = DiceRules.ParseExpression(RulesetKind.Dnd5e, "1d1001");
var tooLargeModifier = DiceRules.ParseExpression(RulesetKind.Dnd5e, "1d20+1001");
var negativeDndModifier = DiceRules.ParseExpression(RulesetKind.Dnd5e, "1d20-1");
var invalidRolemasterFormat = DiceRules.ParseExpression(RulesetKind.Rolemaster, "2d12+1");
var invalidRolemasterOpenEndedFormat = DiceRules.ParseExpression(RulesetKind.Rolemaster, "2d10!+1");
var tooNegativeRolemasterModifier = DiceRules.ParseExpression(RulesetKind.Rolemaster, "d100-1001");
var unknownRulesetExpression = DiceRules.ParseExpression((RulesetKind)99, "1d20+1");
Assert.True(d6.Succeeded);
Assert.True(dnd.Succeeded);
Assert.True(rolemasterInitiative.Succeeded);
Assert.True(rolemasterImplicitSingle.Succeeded);
Assert.True(rolemasterManyDice.Succeeded);
Assert.True(rolemasterPercentile.Succeeded);
Assert.True(rolemasterOpenEnded.Succeeded);
Assert.False(emptyExpression.Succeeded);
@@ -36,14 +38,16 @@ public sealed class DiceRulesTests
Assert.False(tooManySides.Succeeded);
Assert.False(tooLargeModifier.Succeeded);
Assert.False(negativeDndModifier.Succeeded);
Assert.False(invalidRolemasterFormat.Succeeded);
Assert.False(invalidRolemasterOpenEndedFormat.Succeeded);
Assert.False(tooNegativeRolemasterModifier.Succeeded);
Assert.False(unknownRulesetExpression.Succeeded);
Assert.Equal("2d10-15", rolemasterInitiative.Value!.Canonical);
Assert.Equal(DiceExpressionKind.RolemasterInitiative, rolemasterInitiative.Value.Kind);
Assert.Equal("d10", rolemasterImplicitSingle.Value!.Canonical);
Assert.Equal(DiceExpressionKind.RolemasterStandard, rolemasterImplicitSingle.Value.Kind);
Assert.Equal("15d10-15", rolemasterManyDice.Value!.Canonical);
Assert.Equal(DiceExpressionKind.RolemasterStandard, rolemasterManyDice.Value.Kind);
Assert.Equal("d100+4", rolemasterPercentile.Value!.Canonical);
Assert.Equal(DiceExpressionKind.RolemasterPercentile, rolemasterPercentile.Value.Kind);
Assert.Equal(DiceExpressionKind.RolemasterStandard, rolemasterPercentile.Value.Kind);
Assert.Equal("d100!+85", rolemasterOpenEnded.Value!.Canonical);
Assert.Equal(DiceExpressionKind.RolemasterOpenEndedPercentile, rolemasterOpenEnded.Value.Kind);

View File

@@ -3,7 +3,7 @@ namespace RpgRoller.Tests;
public sealed class ServiceRolemasterRollTests
{
[Fact]
public void RollSkill_RolemasterInitiative_ComputesTotalAndTagsDice()
public void RollSkill_RolemasterStandardMultiDie_ComputesTotalAndTagsDice()
{
using var harness = ServiceTestSupport.CreateHarness(7, 10);
var service = harness.Service;
@@ -12,34 +12,34 @@ public sealed class ServiceRolemasterRollTests
var session = ServiceTestSupport.GetValue(service.Login("gm-init", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(session, "Rolemaster", "rolemaster"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(session, "Hero", campaign.Id));
var skill = ServiceTestSupport.GetValue(service.CreateSkill(session, character.Id, "Initiative", "2d10+48", 0, false));
var skill = ServiceTestSupport.GetValue(service.CreateSkill(session, character.Id, "Healing", "2d10+48", 0, false));
var roll = ServiceTestSupport.GetValue(service.RollSkill(session, skill.Id, "public"));
var logPage = ServiceTestSupport.GetValue(service.GetCampaignLogPage(session, campaign.Id, limit: 5));
Assert.Equal(65, roll.Result);
Assert.Equal("7+10+48=65", roll.Breakdown);
Assert.Equal("7 + 10 | initiative", Assert.Single(logPage.Entries).SummaryText);
Assert.Equal("7 + 10 | rolemaster", Assert.Single(logPage.Entries).SummaryText);
Assert.Collection(
roll.Dice,
die =>
{
Assert.Equal(7, die.Roll);
Assert.Equal(1, die.Sequence);
Assert.Equal(RollDieKinds.RolemasterInitiative, die.Kind);
Assert.Equal(RollDieKinds.RolemasterStandard, die.Kind);
Assert.Equal(7, die.SignedContribution);
},
die =>
{
Assert.Equal(10, die.Roll);
Assert.Equal(2, die.Sequence);
Assert.Equal(RollDieKinds.RolemasterInitiative, die.Kind);
Assert.Equal(RollDieKinds.RolemasterStandard, die.Kind);
Assert.Equal(10, die.SignedContribution);
});
}
[Fact]
public void RollSkill_RolemasterPercentile_ComputesTotalAndTagsDice()
public void RollSkill_RolemasterStandardSingleDie_ComputesTotalAndTagsDice()
{
using var harness = ServiceTestSupport.CreateHarness(73);
var service = harness.Service;
@@ -55,12 +55,12 @@ public sealed class ServiceRolemasterRollTests
Assert.Equal(58, roll.Result);
Assert.Equal("73-15=58", roll.Breakdown);
Assert.Equal("73 | percentile", Assert.Single(logPage.Entries).SummaryText);
Assert.Equal("73 | rolemaster", Assert.Single(logPage.Entries).SummaryText);
var die = Assert.Single(roll.Dice);
Assert.Equal(73, die.Roll);
Assert.Equal(1, die.Sequence);
Assert.Equal(RollDieKinds.RolemasterPercentile, die.Kind);
Assert.Equal(RollDieKinds.RolemasterStandard, die.Kind);
Assert.Equal(73, die.SignedContribution);
}