Support target-scoped trauma mechanics

This commit is contained in:
JB
2026-07-27 22:20:52 -04:00
parent 7e78d75f85
commit 0b3be3587b
20 changed files with 1032 additions and 93 deletions
+97 -3
View File
@@ -182,14 +182,27 @@ describe('conditional mechanic persistence adapter', () => {
version: 1,
simulationReadiness: 'ready',
scenarioInputs: [],
pools: [],
pools: [{
key: 'marked-target',
label: 'Marked Target',
stateKind: 'target_mark',
scope: 'target',
initial: 0,
min: 0,
max: 1
}],
clauses: [{
key: 'weapon-kill',
label: 'Weapon kill',
event: 'enemy_killed',
if: { kind: 'true' },
reducer: { kind: 'none' },
mutations: [],
mutations: [{
kind: 'set',
pool: 'marked-target',
entity: { kind: 'event_target' },
value: 1
}],
outcomes: [{
key: 'restore-health',
label: 'Restore Health',
@@ -204,6 +217,51 @@ describe('conditional mechanic persistence adapter', () => {
I: { value: 240 },
II: { value: 336 }
}
}, {
key: 'target-detonation',
label: 'Target Detonation',
phase: 'on_exit',
kind: 'direct_damage',
scope: 'target',
basis: 'flat',
statePool: 'marked-target',
perStack: true,
variants: {
I: {
value: 240,
expression: {
op: 'multiply',
left: 240,
right: {
op: 'divide',
left: {
ref: {
source: 'attribute',
attributeId: '82a95611-283b-4fd8-a6ed-3567a316f36e'
}
},
right: 100
}
}
},
II: {
value: 336,
expression: {
op: 'multiply',
left: 336,
right: {
op: 'divide',
left: {
ref: {
source: 'attribute',
attributeId: '82a95611-283b-4fd8-a6ed-3567a316f36e'
}
},
right: 100
}
}
}
}
}]
}]
});
@@ -213,7 +271,9 @@ describe('conditional mechanic persistence adapter', () => {
)).all();
expect(saved).toEqual([
{ delivery_mode: 'continuous', delivery_duration_seconds: 3 },
{ delivery_mode: 'continuous', delivery_duration_seconds: 3 }
{ delivery_mode: 'instant', delivery_duration_seconds: null },
{ delivery_mode: 'continuous', delivery_duration_seconds: 3 },
{ delivery_mode: 'instant', delivery_duration_seconds: null }
]);
const loaded = await loadConditionalRuleDraft(
database,
@@ -229,5 +289,39 @@ describe('conditional mechanic persistence adapter', () => {
II: { value: 336 }
}
});
expect(loaded?.pools[0]).toMatchObject({
key: 'marked-target',
stateKind: 'target_mark',
scope: 'target'
});
expect(loaded?.clauses[0].mutations).toEqual([{
kind: 'set',
pool: 'marked-target',
entity: { kind: 'event_target' },
value: 1
}]);
expect(loaded?.clauses[0].outcomes[1]).toMatchObject({
phase: 'on_exit',
kind: 'direct_damage',
scope: 'target',
statePool: 'marked-target',
perStack: true,
variants: {
I: {
value: 240,
expression: expect.objectContaining({
right: expect.objectContaining({
left: {
ref: {
source: 'attribute',
attributeId: '82a95611-283b-4fd8-a6ed-3567a316f36e'
}
}
})
})
},
II: { value: 336 }
}
});
});
});