feat: add threshold support and tagmap support to variable system

Introduce a `threshold` column to tag modifiers in CSV declarations,
allowing modifiers to activate only when a tag's count meets a minimum
requirement.

Implement support for "tagmap" variables (e.g., `#warrior:1;#druid:2`)
which allow for complex, multi-tag state tracking. These variables
can receive specialized tagmap modifications rather than simple
numeric additions.
This commit is contained in:
2026-07-13 15:09:50 +08:00
parent d74ba69fdf
commit 7cb28e631e
4 changed files with 436 additions and 215 deletions
+21 -6
View File
@@ -10,10 +10,25 @@ import { createSignal } from "solid-js";
import { parseInput } from "./command-parser";
import { resolveRollPayload } from "./types/roll";
import { resolveSparkPayload } from "./types/spark";
import { evaluateExpression, expressionIsTag } from "./variable-expression";
import { evaluateExpression } from "./variable-expression";
import { computeCascade, getCombined, setBase } from "./var-reactivity";
import type { VarDeclaration, TagModifier } from "./declare-parser";
// Tagmap pattern: "#warrior:1;#druid:2". Also accepts bare "#tag" as shorthand.
const BARE_TAG_PATTERN = /^#[a-zA-Z_][a-zA-Z0-9_]*$/;
const TAGMAP_PATTERN = /^#[a-zA-Z_][a-zA-Z0-9_]*:\d+(?:;#[a-zA-Z_][a-zA-Z0-9_]*:\d+)*$/;
function isTagMapExpr(expr: string): boolean {
const t = expr.trim();
return BARE_TAG_PATTERN.test(t) || TAGMAP_PATTERN.test(t);
}
function normalizeTagMap(expr: string): string {
const t = expr.trim();
if (BARE_TAG_PATTERN.test(t)) return t + ":1";
return t;
}
// ---------------------------------------------------------------------------
// Result
// ---------------------------------------------------------------------------
@@ -174,12 +189,12 @@ function dispatchSet(
try {
if (p.tags && p.tags.length > 0) {
// Rolltag: pick random tag
// Rolltag: pick random tag, format as tagmap entry
const idx = Math.floor(Math.random() * p.tags.length);
newValue = p.tags[idx];
} else if (p.expr && expressionIsTag(p.expr)) {
// Bare tag value
newValue = p.expr.trim();
newValue = normalizeTagMap(p.tags[idx]);
} else if (p.expr && isTagMapExpr(p.expr)) {
// Tagmap value (e.g. "#warrior:1;#druid:2" or bare "#warrior")
newValue = normalizeTagMap(p.expr);
} else if (p.expr) {
// Numeric expression — evaluate using combined values
const result = evaluateExpression(p.expr, {