Add rolemaster auto retry skill toggle
This commit is contained in:
@@ -76,7 +76,7 @@ public sealed class CampaignApiTests(WebApplicationFactory<Program> factory) : A
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RolemasterSkillDefinitions_RoundTripFumbleRangeThroughApi()
|
||||
public async Task RolemasterSkillDefinitions_RoundTripRetryAndFumbleOptionsThroughApi()
|
||||
{
|
||||
using var factory = CreateFactory(88, 42, 17);
|
||||
using var gmClient = factory.CreateClient(new() { AllowAutoRedirect = false });
|
||||
@@ -93,15 +93,22 @@ public sealed class CampaignApiTests(WebApplicationFactory<Program> factory) : A
|
||||
var group = await PostAsync<CreateSkillGroupRequest, SkillGroupSummary>(gmClient, $"/api/characters/{character.Id}/skill-groups", new("Perception", "d100!+15", 0, false, 5));
|
||||
Assert.Equal(5, group.FumbleRange);
|
||||
|
||||
var skill = await PostAsync<CreateSkillRequest, SkillSummary>(gmClient, $"/api/characters/{character.Id}/skills", new("Awareness", "d100!+35", 0, false, group.Id, 3));
|
||||
Assert.Equal(3, skill.FumbleRange);
|
||||
var invalidRetry = await gmClient.PostAsJsonAsync($"/api/characters/{character.Id}/skills", new CreateSkillRequest("Bad Retry", "d100+35", 0, false, group.Id, null, true));
|
||||
Assert.Equal(HttpStatusCode.BadRequest, invalidRetry.StatusCode);
|
||||
|
||||
var updatedSkill = await PutAsync<UpdateSkillRequest, SkillSummary>(gmClient, $"/api/skills/{skill.Id}", new("Awareness", "d100!+45", 0, false, group.Id, 4));
|
||||
var skill = await PostAsync<CreateSkillRequest, SkillSummary>(gmClient, $"/api/characters/{character.Id}/skills", new("Awareness", "d100!+35", 0, false, group.Id, 3, true));
|
||||
Assert.Equal(3, skill.FumbleRange);
|
||||
Assert.True(skill.RolemasterAutoRetry);
|
||||
|
||||
var updatedSkill = await PutAsync<UpdateSkillRequest, SkillSummary>(gmClient, $"/api/skills/{skill.Id}", new("Awareness", "d100!+45", 0, false, group.Id, 4, true));
|
||||
Assert.Equal(4, updatedSkill.FumbleRange);
|
||||
Assert.True(updatedSkill.RolemasterAutoRetry);
|
||||
|
||||
var sheet = await GetAsync<CharacterSheet>(gmClient, $"/api/characters/{character.Id}/sheet");
|
||||
Assert.Equal(5, Assert.Single(sheet.SkillGroups).FumbleRange);
|
||||
Assert.Equal(4, Assert.Single(sheet.Skills).FumbleRange);
|
||||
var sheetSkill = Assert.Single(sheet.Skills);
|
||||
Assert.Equal(4, sheetSkill.FumbleRange);
|
||||
Assert.True(sheetSkill.RolemasterAutoRetry);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -131,6 +131,7 @@ public sealed class HostingCoverageTests
|
||||
Assert.Contains("WildDice", columns);
|
||||
Assert.Contains("AllowFumble", columns);
|
||||
Assert.Contains("FumbleRange", columns);
|
||||
Assert.Contains("RolemasterAutoRetry", columns);
|
||||
|
||||
using var skillGroupsTableInfoCommand = verifyConnection.CreateCommand();
|
||||
skillGroupsTableInfoCommand.CommandText = "PRAGMA table_info('SkillGroups');";
|
||||
@@ -208,6 +209,11 @@ public sealed class HostingCoverageTests
|
||||
rolemasterHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260402222501_AddRolemasterFumbleRange';";
|
||||
var rolemasterHistoryCount = Convert.ToInt32(rolemasterHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, rolemasterHistoryCount);
|
||||
|
||||
using var retryHistoryCommand = verifyConnection.CreateCommand();
|
||||
retryHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260414204309_AddRolemasterAutoRetry';";
|
||||
var retryHistoryCount = Convert.ToInt32(retryHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, retryHistoryCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -348,6 +354,11 @@ public sealed class HostingCoverageTests
|
||||
rolemasterHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260402222501_AddRolemasterFumbleRange';";
|
||||
var rolemasterHistoryCount = Convert.ToInt32(rolemasterHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, rolemasterHistoryCount);
|
||||
|
||||
using var retryHistoryCommand = verifyConnection.CreateCommand();
|
||||
retryHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260414204309_AddRolemasterAutoRetry';";
|
||||
var retryHistoryCount = Convert.ToInt32(retryHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, retryHistoryCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -459,6 +470,7 @@ public sealed class HostingCoverageTests
|
||||
skillColumns.Add(skillsTableInfoReader.GetString(1));
|
||||
|
||||
Assert.Contains("FumbleRange", skillColumns);
|
||||
Assert.Contains("RolemasterAutoRetry", skillColumns);
|
||||
|
||||
using var skillGroupsTableInfoCommand = verifyConnection.CreateCommand();
|
||||
skillGroupsTableInfoCommand.CommandText = "PRAGMA table_info('SkillGroups');";
|
||||
@@ -473,5 +485,10 @@ public sealed class HostingCoverageTests
|
||||
authorizationRolesHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260226170000_AddAuthorizationRoles';";
|
||||
var authorizationRolesHistoryCount = Convert.ToInt32(authorizationRolesHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, authorizationRolesHistoryCount);
|
||||
|
||||
using var retryHistoryCommand = verifyConnection.CreateCommand();
|
||||
retryHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260414204309_AddRolemasterAutoRetry';";
|
||||
var retryHistoryCount = Convert.ToInt32(retryHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, retryHistoryCount);
|
||||
}
|
||||
}
|
||||
@@ -48,20 +48,24 @@ public sealed class ServiceHelperExtractionTests
|
||||
public void SkillDefinitionValidator_ValidatesRulesetSpecificOptions()
|
||||
{
|
||||
var d6 = SkillDefinitionValidator.Validate(RulesetKind.D6, "2D+1", 1, true, null);
|
||||
var rolemaster = SkillDefinitionValidator.Validate(RulesetKind.Rolemaster, "d100!+15", 0, false, 5);
|
||||
var rolemaster = SkillDefinitionValidator.Validate(RulesetKind.Rolemaster, "d100!+15", 0, false, 5, true);
|
||||
var invalidD6 = SkillDefinitionValidator.Validate(RulesetKind.D6, "2D+1", 0, true, null);
|
||||
var invalidRolemaster = SkillDefinitionValidator.Validate(RulesetKind.Rolemaster, "d100!+15", 0, false, null);
|
||||
var invalidRetry = SkillDefinitionValidator.Validate(RulesetKind.Rolemaster, "d100+15", 0, false, null, true);
|
||||
|
||||
Assert.True(d6.Succeeded);
|
||||
Assert.Equal(("2D+1", 1, true, (int?)null), d6.Value);
|
||||
Assert.Equal(("2D+1", 1, true, (int?)null, false), d6.Value);
|
||||
|
||||
Assert.True(rolemaster.Succeeded);
|
||||
Assert.Equal(("d100!+15", 0, false, (int?)5), rolemaster.Value);
|
||||
Assert.Equal(("d100!+15", 0, false, (int?)5, true), rolemaster.Value);
|
||||
|
||||
Assert.False(invalidD6.Succeeded);
|
||||
Assert.Equal("invalid_wild_dice", invalidD6.Error!.Code);
|
||||
|
||||
Assert.False(invalidRolemaster.Succeeded);
|
||||
Assert.Equal("invalid_fumble_range", invalidRolemaster.Error!.Code);
|
||||
|
||||
Assert.False(invalidRetry.Succeeded);
|
||||
Assert.Equal("invalid_rolemaster_retry", invalidRetry.Error!.Code);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ public sealed class ServicePersistenceTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RolemasterFumbleRange_PersistsAcrossDatabaseReload()
|
||||
public void RolemasterSkillOptions_PersistAcrossDatabaseReload()
|
||||
{
|
||||
using var harness = ServiceTestSupport.CreateHarness();
|
||||
var service = harness.Service;
|
||||
@@ -108,7 +108,7 @@ public sealed class ServicePersistenceTests
|
||||
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Rolemaster Persistence", "rolemaster"));
|
||||
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Loremaster", campaign.Id));
|
||||
var group = ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Perception", "d100!+25", 0, false, 5));
|
||||
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Read Runes", "d100!+35", 0, false, group.Id, 3));
|
||||
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Read Runes", "d100!+35", 0, false, group.Id, 3, true));
|
||||
|
||||
using var reloadedHarness = ServiceTestSupport.CreateHarnessFromPath(harness.DbPath);
|
||||
var reloadedSheet = ServiceTestSupport.GetValue(reloadedHarness.Service.GetCharacterSheet(ownerSession, character.Id));
|
||||
@@ -118,5 +118,6 @@ public sealed class ServicePersistenceTests
|
||||
|
||||
var reloadedSkill = Assert.Single(reloadedSheet.Skills, current => current.Id == skill.Id);
|
||||
Assert.Equal(3, reloadedSkill.FumbleRange);
|
||||
Assert.True(reloadedSkill.RolemasterAutoRetry);
|
||||
}
|
||||
}
|
||||
@@ -324,7 +324,8 @@ public sealed class ServiceSharedHelperTests
|
||||
DiceRollDefinition = "d100!+25",
|
||||
WildDice = 0,
|
||||
AllowFumble = false,
|
||||
FumbleRange = 3
|
||||
FumbleRange = 3,
|
||||
RolemasterAutoRetry = true
|
||||
};
|
||||
store.RebuildCampaignStateLocked();
|
||||
store.TouchRosterLocked(campaignId);
|
||||
@@ -371,6 +372,7 @@ public sealed class ServiceSharedHelperTests
|
||||
Assert.Single(sheet.Skills);
|
||||
Assert.Equal(5, groupSummary.FumbleRange);
|
||||
Assert.Equal(3, skillSummary.FumbleRange);
|
||||
Assert.True(skillSummary.RolemasterAutoRetry);
|
||||
Assert.Equal("private", rollResult.Visibility);
|
||||
Assert.Equal("Owner", logDto.RollerDisplayName);
|
||||
Assert.Equal("private-self", logListDto.VisibilityStyle);
|
||||
|
||||
@@ -224,5 +224,12 @@ public sealed class ServiceSkillGroupAndOwnershipTests
|
||||
Assert.Equal(0, openEndedSkill.WildDice);
|
||||
Assert.False(openEndedSkill.AllowFumble);
|
||||
Assert.Equal(5, openEndedSkill.FumbleRange);
|
||||
|
||||
var invalidRetrySkill = service.UpdateSkill(ownerSession, percentileSkill.Id, "Perception", "d100+15", 0, false, rolemasterGroup.Id, null, true);
|
||||
Assert.False(invalidRetrySkill.Succeeded);
|
||||
Assert.Equal("invalid_rolemaster_retry", invalidRetrySkill.Error!.Code);
|
||||
|
||||
var retrySkill = ServiceTestSupport.GetValue(service.UpdateSkill(ownerSession, percentileSkill.Id, "Perception", "d100!+85", 0, false, rolemasterGroup.Id, 5, true));
|
||||
Assert.True(retrySkill.RolemasterAutoRetry);
|
||||
}
|
||||
}
|
||||
@@ -122,12 +122,12 @@ public sealed class WorkspaceQueryServiceTests
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<SkillSummary> CreateSkill(string sessionToken, Guid characterId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null)
|
||||
public ServiceResult<SkillSummary> CreateSkill(string sessionToken, Guid characterId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null, bool rolemasterAutoRetry = false)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<SkillSummary> UpdateSkill(string sessionToken, Guid skillId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null)
|
||||
public ServiceResult<SkillSummary> UpdateSkill(string sessionToken, Guid skillId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null, bool rolemasterAutoRetry = false)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ public sealed class WorkspaceStateTests
|
||||
[Fact]
|
||||
public void SkillDefinitionLabel_FormatsD6RolemasterAndDefaultRulesets()
|
||||
{
|
||||
var skill = new CharacterSheetSkill(Guid.NewGuid(), null, "Awareness", "d100!+15", 1, true, 5);
|
||||
var skill = new CharacterSheetSkill(Guid.NewGuid(), null, "Awareness", "d100!+15", 1, true, 5, true);
|
||||
var state = new WorkspaceState { SelectedCampaign = new(Guid.NewGuid(), "Alpha", "d6", new(Guid.NewGuid(), "GM"), []) };
|
||||
|
||||
Assert.Equal("d100!+15, wild 1, fumble on", state.SkillDefinitionLabel(skill));
|
||||
|
||||
state.SelectedCampaign = new(Guid.NewGuid(), "Alpha", "rolemaster", new(Guid.NewGuid(), "GM"), []);
|
||||
Assert.Equal("Open-ended percentile: d100!+15, fumble <= 5", state.SkillDefinitionLabel(skill));
|
||||
Assert.Equal("Open-ended percentile: d100!+15, fumble <= 5, auto retry", state.SkillDefinitionLabel(skill));
|
||||
|
||||
state.SelectedCampaign = new(Guid.NewGuid(), "Alpha", "dnd5e", new(Guid.NewGuid(), "GM"), []);
|
||||
Assert.Equal("d100!+15", state.SkillDefinitionLabel(skill));
|
||||
@@ -52,7 +52,7 @@ public sealed class WorkspaceStateTests
|
||||
SelectedCampaign = new(Guid.NewGuid(), "Alpha", "d6", new(Guid.NewGuid(), "GM"), [ownedCharacter, secondOwnedCharacter, otherCharacter]),
|
||||
SelectedCharacterId = secondOwnedCharacter.Id,
|
||||
ActiveCharacterId = ownedCharacter.Id,
|
||||
SelectedCharacterSkills = [new(Guid.NewGuid(), null, "Stealth", "2D+1", 1, true, null)],
|
||||
SelectedCharacterSkills = [new(Guid.NewGuid(), null, "Stealth", "2D+1", 1, true, null, false)],
|
||||
SelectedCharacterSkillGroups = [new(Guid.NewGuid(), "Combat", "2D+1", 1, true, null)]
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user