Support live attribute restoration mechanics
This commit is contained in:
@@ -156,6 +156,8 @@ function isReference(value: unknown): value is ValueReference {
|
||||
&& (value.timing === undefined || value.timing === 'pre_event' || value.timing === 'current');
|
||||
case 'equipment':
|
||||
return typeof value.path === 'string' && Boolean(value.path.trim());
|
||||
case 'attribute':
|
||||
return typeof value.attributeId === 'string' && Boolean(value.attributeId.trim());
|
||||
case 'reducer':
|
||||
return true;
|
||||
case 'pool':
|
||||
@@ -167,6 +169,33 @@ function isReference(value: unknown): value is ValueReference {
|
||||
}
|
||||
}
|
||||
|
||||
function validateAttributeReferences(
|
||||
value: unknown,
|
||||
allowedAttributeIds: ReadonlySet<string> | undefined,
|
||||
errors: string[],
|
||||
path = 'Conditional mechanic'
|
||||
) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item, index) =>
|
||||
validateAttributeReferences(item, allowedAttributeIds, errors, `${path} item ${index + 1}`));
|
||||
return;
|
||||
}
|
||||
if (!object(value)) return;
|
||||
if (
|
||||
value.source === 'attribute'
|
||||
&& typeof value.attributeId === 'string'
|
||||
&& value.attributeId.trim()
|
||||
&& allowedAttributeIds
|
||||
&& !allowedAttributeIds.has(value.attributeId)
|
||||
) {
|
||||
errors.push(`${path} references unknown Attribute "${value.attributeId}".`);
|
||||
return;
|
||||
}
|
||||
for (const [key, nested] of Object.entries(value)) {
|
||||
validateAttributeReferences(nested, allowedAttributeIds, errors, `${path} ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
function isExpression(value: unknown): value is NumericExpression {
|
||||
if (finite(value)) return true;
|
||||
if (!object(value)) return false;
|
||||
@@ -357,6 +386,19 @@ function parseOutcome(
|
||||
} else if (value.resource !== undefined) {
|
||||
errors.push(`${path} may only use a resource for restoration or resource cost.`);
|
||||
}
|
||||
const delivery = value.delivery ?? 'instant';
|
||||
if (delivery !== 'instant' && delivery !== 'continuous') {
|
||||
errors.push(`${path} has an invalid delivery mode.`);
|
||||
} else if (delivery === 'continuous') {
|
||||
if (kind !== 'restoration') {
|
||||
errors.push(`${path} may only use continuous delivery for restoration.`);
|
||||
}
|
||||
if (!finite(value.durationSeconds) || value.durationSeconds <= 0) {
|
||||
errors.push(`${path} continuous delivery requires a positive duration.`);
|
||||
}
|
||||
} else if (value.durationSeconds !== undefined) {
|
||||
errors.push(`${path} may only set a duration for continuous delivery.`);
|
||||
}
|
||||
if (
|
||||
value.combatTiming !== undefined
|
||||
&& value.combatTiming !== 'pre_event'
|
||||
@@ -547,6 +589,7 @@ export function parseConditionalMechanicDraft(
|
||||
pools,
|
||||
clauses
|
||||
};
|
||||
validateAttributeReferences(draft, options.allowedAttributeIds, errors);
|
||||
const inputRequiresAssumption = scenarioInputs.some(
|
||||
(input) => input.readiness === 'requires_assumption'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user