Support live attribute restoration mechanics
This commit is contained in:
@@ -72,19 +72,24 @@ const outcomeMetadataColumns = [
|
||||
'application_phase',
|
||||
'combat_timing',
|
||||
'resource_kind',
|
||||
'delivery_mode',
|
||||
'delivery_duration_seconds',
|
||||
'state_pool_id',
|
||||
'min_state_value',
|
||||
'max_state_value',
|
||||
'description_slot'
|
||||
] as const;
|
||||
|
||||
const comparableMetadataValue = (value: unknown) => value === undefined ? null : value;
|
||||
const comparableMetadataValue = (column: typeof outcomeMetadataColumns[number], value: unknown) => {
|
||||
if (column === 'delivery_mode') return value === undefined || value === null ? 'instant' : value;
|
||||
return value === undefined ? null : value;
|
||||
};
|
||||
|
||||
function assertVariantMetadataConsistent(effectKey: string, variants: OutcomeRow[]) {
|
||||
const first = variants[0];
|
||||
for (const variant of variants.slice(1)) {
|
||||
const mismatch = outcomeMetadataColumns.find((column) =>
|
||||
comparableMetadataValue(variant[column]) !== comparableMetadataValue(first[column])
|
||||
comparableMetadataValue(column, variant[column]) !== comparableMetadataValue(column, first[column])
|
||||
);
|
||||
if (mismatch) {
|
||||
throw new Error(
|
||||
@@ -156,6 +161,22 @@ export function conditionalRuleDraftFromRows(
|
||||
assertVariantMetadataConsistent(key, variants);
|
||||
const first = variants[0];
|
||||
const resource = outcomeResource(first);
|
||||
const delivery = first.delivery_mode === undefined || first.delivery_mode === null
|
||||
? 'instant'
|
||||
: String(first.delivery_mode);
|
||||
const durationSeconds = first.delivery_duration_seconds === undefined
|
||||
|| first.delivery_duration_seconds === null
|
||||
? null
|
||||
: Number(first.delivery_duration_seconds);
|
||||
if (delivery !== 'instant' && delivery !== 'continuous') {
|
||||
throw new Error(`Conditional outcome "${key}" has an unsupported delivery mode.`);
|
||||
}
|
||||
if (delivery === 'continuous' && (!Number.isFinite(durationSeconds) || Number(durationSeconds) <= 0)) {
|
||||
throw new Error(`Conditional outcome "${key}" continuous delivery requires a positive duration.`);
|
||||
}
|
||||
if (delivery === 'instant' && durationSeconds !== null) {
|
||||
throw new Error(`Conditional outcome "${key}" instant delivery cannot set a duration.`);
|
||||
}
|
||||
return {
|
||||
key,
|
||||
label: String(first.outcome_key || key),
|
||||
@@ -165,6 +186,9 @@ export function conditionalRuleDraftFromRows(
|
||||
basis: String(first.value_basis) as ConditionalMechanicOutcomeDraft['basis'],
|
||||
...(resource ? { resource } : {}),
|
||||
...(first.combat_timing ? { combatTiming: String(first.combat_timing) as 'pre_event' | 'current' } : {}),
|
||||
...(delivery === 'continuous'
|
||||
? { delivery, durationSeconds: durationSeconds as number }
|
||||
: {}),
|
||||
...(first.stat_attribute_id ? { attributeId: String(first.stat_attribute_id) } : {}),
|
||||
...(first.state_pool_id && poolKeyById.has(String(first.state_pool_id))
|
||||
? { statePool: poolKeyById.get(String(first.state_pool_id)) }
|
||||
@@ -331,9 +355,10 @@ export async function saveConditionalRuleInTransaction(
|
||||
(id,rule_id,clause_id,state_pool_id,effect_key,variant_key,outcome_key,
|
||||
application_kind,effect_scope,stat_attribute_id,value,value_expression_json,
|
||||
value_basis,value_scaling,unit,damage_basis,application_phase,combat_timing,
|
||||
resource_kind,min_state_value,max_state_value,description_slot,sort_order,
|
||||
resource_kind,delivery_mode,delivery_duration_seconds,
|
||||
min_state_value,max_state_value,description_slot,sort_order,
|
||||
created_at,updated_at)
|
||||
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)).run(
|
||||
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)).run(
|
||||
randomUUID(),
|
||||
ruleId,
|
||||
clauseId,
|
||||
@@ -355,6 +380,8 @@ export async function saveConditionalRuleInTransaction(
|
||||
outcome.phase,
|
||||
outcome.combatTiming ?? 'current',
|
||||
outcome.resource ?? null,
|
||||
outcome.delivery ?? 'instant',
|
||||
outcome.durationSeconds ?? null,
|
||||
outcome.minStacks ?? null,
|
||||
outcome.maxStacks ?? null,
|
||||
outcome.descriptionSlot ?? null,
|
||||
|
||||
Reference in New Issue
Block a user