|
|
|
@ -24,7 +24,7 @@ import { |
|
|
|
|
CharacterStatuses, |
|
|
|
|
isZpReady |
|
|
|
|
} from "../model/Character"; |
|
|
|
|
import {GameState, TimerDirection} from "../model/GameState"; |
|
|
|
|
import {GameState, lookupIdentifier, TimerDirection} from "../model/GameState"; |
|
|
|
|
import { |
|
|
|
|
formatMeteredResource, |
|
|
|
|
formatResourceDelta, formatResourceMax, formatResourceValue, |
|
|
|
@ -266,6 +266,16 @@ interpreter.addAttribute<number>("numberValue", { |
|
|
|
|
StatusOrItemCounterWrapped(lParen: TerminalNode, counter: NonterminalNode, _rParen: TerminalNode): number { |
|
|
|
|
return (counter as InterpreterNode).numberValue |
|
|
|
|
}, |
|
|
|
|
StatusOrItemCounter(counter: NonterminalNode): number { |
|
|
|
|
return (counter as InterpreterNode).numberValue |
|
|
|
|
}, |
|
|
|
|
StatusOrItemDelta(delta: NonterminalNode): number { |
|
|
|
|
return (delta as InterpreterNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
StatusOrItemDeltaWrapped(_lParen: TerminalNode, delta: NonterminalNode, _rParen: TerminalNode): number { |
|
|
|
|
return (delta as InterpreterNode).numberValue; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
StatusOrItemAddOperation(operands: NonterminalNode, colon: NonterminalNode, deltaOperator: NonterminalNode, identifier: NonterminalNode, counter: IterationNode): number { |
|
|
|
|
if (counter.numChildren === 0) { |
|
|
|
|
return 0 |
|
|
|
@ -311,6 +321,9 @@ interpreter.addAttribute<string>("identifier", { |
|
|
|
|
StatusOrItemAddOperation(operands: NonterminalNode, colon: NonterminalNode, deltaOperator: NonterminalNode, identifier: NonterminalNode, _counter: NonterminalNode): string { |
|
|
|
|
return (identifier as InterpreterNode).identifier |
|
|
|
|
}, |
|
|
|
|
StatusOrItemRemoveOperation(_arg0: NonterminalNode, _arg1: NonterminalNode, _arg2: NonterminalNode, identifier: NonterminalNode): string { |
|
|
|
|
return (identifier as InterpreterNode).identifier; |
|
|
|
|
}, |
|
|
|
|
StatusOrItemCounterDeltaOperation(operands: NonterminalNode, colon: NonterminalNode, identifier: NonterminalNode, _delta: NonterminalNode): string { |
|
|
|
|
return (identifier as InterpreterNode).identifier |
|
|
|
|
}, |
|
|
|
@ -598,6 +611,9 @@ interpreter.addAttribute<Operands>("operands", { |
|
|
|
|
StatusOrItemAddOperation(operands: NonterminalNode, _colon: NonterminalNode, _delta: NonterminalNode, _statusOrItem: NonterminalNode, _counter: IterationNode): Operands { |
|
|
|
|
return (operands as InterpreterNode).operands |
|
|
|
|
}, |
|
|
|
|
StatusOrItemRemoveOperation(operands: NonterminalNode, _arg1: NonterminalNode, _arg2: NonterminalNode, _arg3: NonterminalNode): Operands { |
|
|
|
|
return (operands as InterpreterNode).operands |
|
|
|
|
}, |
|
|
|
|
Operands(arg0: NonterminalNode): Operands { |
|
|
|
|
return (arg0.asIteration() as InterpreterNode).operands |
|
|
|
|
}, |
|
|
|
@ -624,7 +640,7 @@ interpreter.addAttribute<Operands>("operands", { |
|
|
|
|
}, |
|
|
|
|
_terminal(): never { |
|
|
|
|
throw Error(`No idea what to say ${this.ctorName} terminal node's operands value is`) |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
interpreter.addAttribute<Operands>("targets", { |
|
|
|
@ -1064,6 +1080,20 @@ interpreter.addOperation<EvaluationContext>("evaluate(ctx)", { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
StatusOrItemRemoveOperation(_arg0: NonterminalNode, _arg1: NonterminalNode, _arg2: NonterminalNode, _arg3: NonterminalNode): EvaluationContext { |
|
|
|
|
const ctx = (this as EvaluationNode).args.ctx |
|
|
|
|
const operands = evaluateOperands((this as InterpreterNode).operands, ctx) |
|
|
|
|
const statusOrItemId = (this as InterpreterNode).identifier |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
...ctx, |
|
|
|
|
game: { |
|
|
|
|
...ctx.game, |
|
|
|
|
characters: ctx.game.characters.map((c) => |
|
|
|
|
operands.has(c.id) ? CharacterStatuses.removeStatus(c, statusOrItemId) : c), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
ClearOperation(_arg0: NonterminalNode, _arg1: NonterminalNode, _arg2: NonterminalNode, _arg3: NonterminalNode, _arg4: NonterminalNode): EvaluationContext { |
|
|
|
|
return EvaluateClear(this as EvaluationNode); |
|
|
|
|
}, |
|
|
|
@ -1110,7 +1140,7 @@ function RenderDelta(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const affinity = node.affinity |
|
|
|
|
const element = node.element |
|
|
|
|
const operandsBefore = lookupOperands(node.operands, ctx) |
|
|
|
|
const ctxAfter = EvaluateDelta(node) |
|
|
|
|
const ctxAfter = node.evaluate(ctx) |
|
|
|
|
const operandsAfter = lookupOperands(node.operands, ctxAfter) |
|
|
|
|
|
|
|
|
|
for (const [id, after] of operandsAfter) { |
|
|
|
@ -1184,7 +1214,7 @@ function RenderMeteredSet(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const newValue = node.currentValue |
|
|
|
|
const newMax = node.maxValue |
|
|
|
|
const operandsBefore = lookupOperands(node.operands, ctx) |
|
|
|
|
const ctxAfter = EvaluateDelta(node) |
|
|
|
|
const ctxAfter = node.evaluate(ctx) |
|
|
|
|
const operandsAfter = lookupOperands(node.operands, ctxAfter) |
|
|
|
|
|
|
|
|
|
for (const [id, after] of operandsAfter) { |
|
|
|
@ -1261,7 +1291,7 @@ function RenderValueSet(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const resource = node.resource |
|
|
|
|
const newValue = node.currentValue |
|
|
|
|
const operandsBefore = lookupOperands(node.operands, ctx) |
|
|
|
|
const ctxAfter = EvaluateDelta(node) |
|
|
|
|
const ctxAfter = node.evaluate(ctx) |
|
|
|
|
const operandsAfter = lookupOperands(node.operands, ctxAfter) |
|
|
|
|
|
|
|
|
|
for (const [id, after] of operandsAfter) { |
|
|
|
@ -1317,7 +1347,7 @@ function RenderValueSet(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
result.push(`${clockText}: [${formatResourceValue(resource ?? MeteredResource.Segments, newValue)}`) |
|
|
|
|
break |
|
|
|
|
default: |
|
|
|
|
throw Error(`Don't know how to render metered set on ${before.type} ${id}`) |
|
|
|
|
throw Error(`Don't know how to render value set on ${before.type} ${id}`) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
@ -1332,7 +1362,7 @@ function RenderMaxSet(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const resource = node.resource |
|
|
|
|
const newMax = node.maxValue |
|
|
|
|
const operandsBefore = lookupOperands(node.operands, ctx) |
|
|
|
|
const ctxAfter = EvaluateDelta(node) |
|
|
|
|
const ctxAfter = node.evaluate(ctx) |
|
|
|
|
const operandsAfter = lookupOperands(node.operands, ctxAfter) |
|
|
|
|
|
|
|
|
|
for (const [id, after] of operandsAfter) { |
|
|
|
@ -1346,7 +1376,7 @@ function RenderMaxSet(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
throw Error(`character ${id} somehow changed type between calls?`) |
|
|
|
|
} |
|
|
|
|
if (resource && !isMeteredResource(resource)) { |
|
|
|
|
throw Error(`somehow got non-metered resource in metered set`) |
|
|
|
|
throw Error(`somehow got non-metered resource in max set`) |
|
|
|
|
} |
|
|
|
|
const beforeChar = before.character |
|
|
|
|
const afterChar = after.character |
|
|
|
@ -1389,12 +1419,12 @@ function RenderMaxSet(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const afterClock = after.clock |
|
|
|
|
const clockText = afterClock.text |
|
|
|
|
if (resource && !isMeteredResource(resource)) { |
|
|
|
|
throw Error(`somehow got non-metered resource in metered set`) |
|
|
|
|
throw Error(`somehow got non-metered resource in max set`) |
|
|
|
|
} |
|
|
|
|
result.push(`${clockText}: [${formatResourceMax(resource ?? MeteredResource.Segments, newMax)}`) |
|
|
|
|
break |
|
|
|
|
default: |
|
|
|
|
throw Error(`Don't know how to render metered set on ${before.type} ${id}`) |
|
|
|
|
throw Error(`Don't know how to render max set on ${before.type} ${id}`) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
@ -1409,7 +1439,7 @@ function RenderClear(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const resource = node.resource |
|
|
|
|
const newMax = node.maxValue |
|
|
|
|
const operandsBefore = lookupOperands(node.operands, ctx) |
|
|
|
|
const ctxAfter = EvaluateDelta(node) |
|
|
|
|
const ctxAfter = node.evaluate(ctx) |
|
|
|
|
const operandsAfter = lookupOperands(node.operands, ctxAfter) |
|
|
|
|
|
|
|
|
|
for (const [id, after] of operandsAfter) { |
|
|
|
@ -1437,6 +1467,44 @@ function RenderClear(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
} |
|
|
|
|
result.push(`${clockText}: [${formatResourceMax(resource ?? MeteredResource.Segments, newMax)}`) |
|
|
|
|
break |
|
|
|
|
default: |
|
|
|
|
throw Error(`Don't know how to render resource clear on ${before.type} ${id}`) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
|
...ctxAfter, |
|
|
|
|
output: result.length > 0 ? result.join("\n") : null |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function RenderStatusAdd(node: MarkdownNode): MarkdownOutput { |
|
|
|
|
const ctx = node.args.ctx |
|
|
|
|
const result: string[] = [] |
|
|
|
|
const identifier = node.identifier |
|
|
|
|
const counter = node.numberValue |
|
|
|
|
const operandsBefore = lookupOperands(node.operands, ctx) |
|
|
|
|
const ctxAfter = node.evaluate(ctx) |
|
|
|
|
const operandsAfter = lookupOperands(node.operands, ctxAfter) |
|
|
|
|
const status = lookupIdentifier(ctxAfter.game, identifier) |
|
|
|
|
const statusName = status.type === "status" ? status.status.name : identifier |
|
|
|
|
|
|
|
|
|
for (const [id, after] of operandsAfter) { |
|
|
|
|
const before = operandsBefore.get(id) |
|
|
|
|
if (!before) { |
|
|
|
|
throw Error("Somehow an object appeared?") |
|
|
|
|
} |
|
|
|
|
switch (before.type) { |
|
|
|
|
case "character": |
|
|
|
|
if (after.type !== "character") { |
|
|
|
|
throw Error(`character ${id} somehow changed type between calls?`) |
|
|
|
|
} |
|
|
|
|
const beforeChar = before.character |
|
|
|
|
const afterChar = after.character |
|
|
|
|
const charName = (afterChar.privacy ? applyCharacterPrivacy(afterChar) : afterChar)?.name |
|
|
|
|
if (CharacterStatuses.hasStatus(beforeChar, identifier) !== CharacterStatuses.hasStatus(afterChar, identifier)) { |
|
|
|
|
result.push(`${charName}: [+${statusName}${counter === 0 ? "" : `(${counter})`}]`) |
|
|
|
|
} |
|
|
|
|
break |
|
|
|
|
default: |
|
|
|
|
throw Error(`Don't know how to render metered set on ${before.type} ${id}`) |
|
|
|
|
} |
|
|
|
@ -1501,6 +1569,9 @@ interpreter.addOperation<MarkdownOutput>("renderMarkdown(ctx)", { |
|
|
|
|
ClearOperationAlternate2(_arg0: NonterminalNode, _arg1: NonterminalNode, _arg2: NonterminalNode, _arg3: NonterminalNode): MarkdownOutput { |
|
|
|
|
return RenderClear(this as MarkdownNode); |
|
|
|
|
}, |
|
|
|
|
StatusOrItemAddOperation(_arg0: NonterminalNode, _arg1: NonterminalNode, _arg2: NonterminalNode, _arg3: NonterminalNode, _arg4: IterationNode): MarkdownOutput { |
|
|
|
|
return RenderStatusAdd(this as MarkdownNode); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
_iter(...children: readonly Node[]): MarkdownOutput { |
|
|
|
|
let ctx = (this as MarkdownNode).args.ctx |
|
|
|
|