Support target-scoped trauma mechanics
This commit is contained in:
@@ -25,6 +25,11 @@ export type MechanicEventDefinition = {
|
||||
key: MechanicEventKind;
|
||||
label: string;
|
||||
description: string;
|
||||
fields?: readonly {
|
||||
path: string;
|
||||
label: string;
|
||||
type: 'boolean' | 'number' | 'string';
|
||||
}[];
|
||||
};
|
||||
|
||||
export const MECHANIC_EVENT_REGISTRY: Readonly<Record<MechanicEventKind, MechanicEventDefinition>> = {
|
||||
@@ -36,7 +41,11 @@ export const MECHANIC_EVENT_REGISTRY: Readonly<Record<MechanicEventKind, Mechani
|
||||
weapon_hit: {
|
||||
key: 'weapon_hit',
|
||||
label: 'Weapon hit',
|
||||
description: 'A weapon attack connects with a target. Critical and distance details belong in event values.'
|
||||
description: 'A weapon attack connects with a target. The headshot boolean distinguishes headshots from body shots.',
|
||||
fields: [
|
||||
{ path: 'targetId', label: 'Target ID', type: 'string' },
|
||||
{ path: 'values.headshot', label: 'Headshot', type: 'boolean' }
|
||||
]
|
||||
},
|
||||
skill_deployed: {
|
||||
key: 'skill_deployed',
|
||||
@@ -326,6 +335,7 @@ export type MechanicOutcomeEmission = {
|
||||
clauseId: string;
|
||||
outcomeId: string;
|
||||
at: number;
|
||||
targetId: string | null;
|
||||
phase: OutcomePhase;
|
||||
kind: MechanicOutcome['kind'];
|
||||
scope: MechanicOutcome['scope'];
|
||||
@@ -401,6 +411,7 @@ type EvaluationContext = {
|
||||
type ContinuousDelivery = {
|
||||
clauseId: string;
|
||||
outcomeId: string;
|
||||
targetId: string | null;
|
||||
phase: OutcomePhase;
|
||||
scope: MechanicOutcomeScope;
|
||||
resource: MechanicResource;
|
||||
@@ -895,14 +906,22 @@ function emitOutcomes(
|
||||
continuousDeliveries?: ContinuousDelivery[]
|
||||
): MechanicOutcomeEmission[] {
|
||||
const emissions: MechanicOutcomeEmission[] = [];
|
||||
const stateValues = (outcome: MechanicOutcome) => {
|
||||
const current = outcomeState(outcome, context);
|
||||
const previous = outcome.statePool ? before.get(outcome.statePool) ?? current : current;
|
||||
return {
|
||||
current,
|
||||
previous,
|
||||
effective: outcome.phase === 'on_exit' ? previous : current
|
||||
};
|
||||
};
|
||||
const eligible = (clause.outcomes ?? []).filter((outcome) => {
|
||||
if (phase === 'before' && outcome.phase !== 'on_event') return false;
|
||||
if (phase === 'after' && outcome.phase === 'on_event') return false;
|
||||
const current = outcomeState(outcome, context);
|
||||
const previous = outcome.statePool ? before.get(outcome.statePool) ?? current : current;
|
||||
const { current, previous, effective } = stateValues(outcome);
|
||||
if (!phaseMatches(outcome.phase, previous, current)) return false;
|
||||
if (outcome.minStacks !== undefined && current < outcome.minStacks) return false;
|
||||
if (outcome.maxStacks !== undefined && current > outcome.maxStacks) return false;
|
||||
if (outcome.minStacks !== undefined && effective < outcome.minStacks) return false;
|
||||
if (outcome.maxStacks !== undefined && effective > outcome.maxStacks) return false;
|
||||
return true;
|
||||
}).sort((left, right) => {
|
||||
const priority = (outcome: MechanicOutcome) =>
|
||||
@@ -910,7 +929,7 @@ function emitOutcomes(
|
||||
return priority(left) - priority(right);
|
||||
});
|
||||
for (const outcome of eligible) {
|
||||
const current = outcomeState(outcome, context);
|
||||
const { effective: current } = stateValues(outcome);
|
||||
const baseValue = numericValue(outcome.value, context);
|
||||
const value = outcome.perStack ? baseValue * current : baseValue;
|
||||
const resolvedValue = resolveOutcomeValue(outcome, value, context);
|
||||
@@ -925,6 +944,7 @@ function emitOutcomes(
|
||||
continuousDeliveries?.push({
|
||||
clauseId: clause.id,
|
||||
outcomeId: outcome.id,
|
||||
targetId: context.event.targetId ?? null,
|
||||
phase: outcome.phase,
|
||||
scope: outcome.scope,
|
||||
resource: outcomeResource(outcome),
|
||||
@@ -957,6 +977,7 @@ function emitOutcomes(
|
||||
clauseId: clause.id,
|
||||
outcomeId: outcome.id,
|
||||
at,
|
||||
targetId: context.event.targetId ?? null,
|
||||
phase: outcome.phase,
|
||||
kind: outcome.kind,
|
||||
scope: outcome.scope,
|
||||
@@ -1007,6 +1028,7 @@ function advanceContinuousDeliveries(
|
||||
clauseId: delivery.clauseId,
|
||||
outcomeId: delivery.outcomeId,
|
||||
at: through,
|
||||
targetId: delivery.targetId,
|
||||
phase: delivery.phase,
|
||||
kind: 'restoration',
|
||||
scope: delivery.scope,
|
||||
|
||||
Reference in New Issue
Block a user