Files
RpgRoller/RpgRoller/Services/SkillDefinitionValidator.cs

75 lines
5.5 KiB
C#

using RpgRoller.Domain;
namespace RpgRoller.Services;
public static class SkillDefinitionValidator
{
public static ServiceResult<(string CanonicalExpression, int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)> Validate(RulesetKind ruleset, string diceRollDefinition, int wildDice, bool allowFumble, int? fumbleRange, bool rolemasterAutoRetry = false)
{
var expressionValidation = DiceRules.ParseExpression(ruleset, diceRollDefinition);
if (!expressionValidation.Succeeded)
return ServiceResult<(string CanonicalExpression, int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure(expressionValidation.Error!.Code, expressionValidation.Error.Message);
var optionsValidation = ValidateOptions(ruleset, expressionValidation.Value!, wildDice, allowFumble, fumbleRange, rolemasterAutoRetry);
if (!optionsValidation.Succeeded)
return ServiceResult<(string CanonicalExpression, int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure(optionsValidation.Error!.Code, optionsValidation.Error.Message);
return ServiceResult<(string CanonicalExpression, int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Success((expressionValidation.Value!.Canonical, optionsValidation.Value.WildDice, optionsValidation.Value.AllowFumble, optionsValidation.Value.FumbleRange, optionsValidation.Value.RolemasterAutoRetry));
}
private static ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)> ValidateOptions(RulesetKind ruleset, DiceExpression expression, int wildDice, bool allowFumble, int? fumbleRange, bool rolemasterAutoRetry)
{
if (wildDice < 0 || wildDice > 50)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_wild_dice", "Wild dice must be between 0 and 50.");
if (ruleset == RulesetKind.D6)
{
if (wildDice < 1)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_wild_dice", "D6 skills require at least one wild die.");
if (fumbleRange.HasValue)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_fumble_range", "Fumble range is only supported for Rolemaster open-ended percentile skills.");
if (rolemasterAutoRetry)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_rolemaster_retry", "Automatic retry is only supported for Rolemaster open-ended percentile skills.");
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Success((wildDice, allowFumble, null, false));
}
if (ruleset == RulesetKind.Rolemaster)
{
if (wildDice != 0)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_wild_dice", "Rolemaster skills do not support wild dice.");
if (allowFumble)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_allow_fumble", "Rolemaster skills do not use the D6 allow-fumble option.");
if (expression.Kind == DiceExpressionKind.RolemasterOpenEndedPercentile)
{
if (!fumbleRange.HasValue)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_fumble_range", "Rolemaster open-ended percentile skills require a fumble range.");
if (fumbleRange < 0 || fumbleRange >= 96)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_fumble_range", "Fumble range must be between 0 and 95.");
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Success((0, false, fumbleRange, rolemasterAutoRetry));
}
if (fumbleRange.HasValue)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_fumble_range", "Fumble range is only valid for Rolemaster open-ended percentile skills.");
if (rolemasterAutoRetry)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_rolemaster_retry", "Automatic retry is only supported for Rolemaster open-ended percentile skills.");
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Success((0, false, null, false));
}
if (fumbleRange.HasValue)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_fumble_range", "Fumble range is only supported for Rolemaster open-ended percentile skills.");
if (rolemasterAutoRetry)
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Failure("invalid_rolemaster_retry", "Automatic retry is only supported for Rolemaster open-ended percentile skills.");
return ServiceResult<(int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry)>.Success((0, false, null, false));
}
}