@bct-app/game-engine 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -505,6 +505,521 @@ var effectHandlers = {
505
505
  STATUS_CHANGE: applyStatusChange
506
506
  };
507
507
 
508
+ // src/dsl/context.ts
509
+ var decoratePlayer = (player, characterMap, currentTurn) => {
510
+ const isDead = Boolean(player.isDead);
511
+ const retainsBypass = isDead && (player.retainsAbility === "ALIVENESS" || player.retainsAbility === "ALL");
512
+ const wasExecuted = isDead && player.deathCause === "EXECUTION";
513
+ return {
514
+ ...player,
515
+ characterKind: characterMap.get(player.characterId)?.kind,
516
+ reminderMarks: (player.reminders ?? []).map((r) => r.mark),
517
+ effectiveAlive: !isDead || retainsBypass,
518
+ diedThisTurn: isDead && typeof player.deathTurn === "number" && player.deathTurn === currentTurn,
519
+ wasExecuted,
520
+ wasExecutedToday: wasExecuted && player.deathTurn === currentTurn
521
+ };
522
+ };
523
+ var isExecutionTimeline = (tl) => {
524
+ if (!tl) return false;
525
+ return (tl.operations ?? []).some((op) => op.kind === "execution");
526
+ };
527
+ var buildDslContextFromDerived = (derived, payload = []) => {
528
+ const players = derived.players.map((p) => decoratePlayer(p, derived.characterMap, derived.currentTurn));
529
+ const effector = players.find((p) => p.seat === derived.effectorSeat);
530
+ const aliveCount = players.filter((p) => !p.isDead).length;
531
+ const deadCount = players.length - aliveCount;
532
+ const executedTodayCount = players.filter(
533
+ (p) => p.isDead && p.deathCause === "EXECUTION" && p.deathTurn === derived.currentTurn
534
+ ).length;
535
+ const nominatedTodayCount = derived.todayNominations.length;
536
+ const playerDiedToday = players.some(
537
+ (p) => p.isDead && typeof p.deathTurn === "number" && p.deathTurn === derived.currentTurn
538
+ );
539
+ return {
540
+ effector,
541
+ players,
542
+ operations: {
543
+ all: derived.allOperations,
544
+ today: derived.todayOperations,
545
+ tonight: derived.tonightOperations,
546
+ yesterdayDay: derived.yesterdayDayOperations,
547
+ yesterdayNight: derived.yesterdayNightOperations
548
+ },
549
+ nominations: {
550
+ all: derived.allNominations,
551
+ today: derived.todayNominations,
552
+ yesterday: derived.yesterdayNominations
553
+ },
554
+ currentTimeline: {
555
+ turn: derived.currentTurn,
556
+ phase: derived.currentPhase,
557
+ time: derived.currentPhase === "NIGHT" ? "night" : derived.currentPhase === "DAY" ? "day" : void 0,
558
+ isFirstOfPhase: derived.isFirstOfPhase,
559
+ isExecution: (derived.currentPhase === "DAY" ? derived.todayOperations : derived.tonightOperations).some((op) => op.kind === "execution")
560
+ },
561
+ global: {
562
+ aliveCount,
563
+ deadCount,
564
+ executedTodayCount,
565
+ nominatedTodayCount,
566
+ executionHappenedToday: derived.todayOperations.some((op) => op.kind === "execution"),
567
+ playerDiedToday
568
+ },
569
+ payload
570
+ };
571
+ };
572
+ var buildDslContextFromLifetime = ({
573
+ snapshotSeatMap,
574
+ timelines,
575
+ nowTimelineIndex,
576
+ characterMap,
577
+ effector,
578
+ payloads
579
+ }) => {
580
+ const nowTl = timelines[nowTimelineIndex];
581
+ const currentTurn = nowTl?.turn ?? -1;
582
+ const currentTime = nowTl?.time;
583
+ const currentPhase = currentTime === "night" ? "NIGHT" : currentTime === "day" ? "DAY" : "NIGHT";
584
+ const playersRaw = snapshotSeatMap ? [...snapshotSeatMap.values()] : [];
585
+ const players = playersRaw.map((p) => decoratePlayer(p, characterMap, currentTurn));
586
+ const effectorDecorated = effector ? players.find((p) => p.seat === effector.seat) ?? decoratePlayer(effector, characterMap, currentTurn) : void 0;
587
+ const todayOps = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "day").flatMap((tl) => tl.operations ?? []);
588
+ const tonightOps = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "night").flatMap((tl) => tl.operations ?? []);
589
+ const yesterdayDayOps = timelines.filter((tl) => tl.turn === currentTurn - 1 && tl.time === "day").flatMap((tl) => tl.operations ?? []);
590
+ const yesterdayNightOps = timelines.filter((tl) => tl.turn === currentTurn - 1 && tl.time === "night").flatMap((tl) => tl.operations ?? []);
591
+ const allOps = timelines.flatMap((tl) => tl.operations ?? []);
592
+ const todayNoms = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "day").flatMap((tl) => (tl.nominations ?? []).map((n) => ({ nominator: n.nominator, nominee: n.nominee })));
593
+ const yesterdayNoms = timelines.filter((tl) => tl.turn === currentTurn - 1 && tl.time === "day").flatMap((tl) => (tl.nominations ?? []).map((n) => ({ nominator: n.nominator, nominee: n.nominee })));
594
+ const allNoms = timelines.filter((tl) => tl.time === "day").flatMap((tl) => (tl.nominations ?? []).map((n) => ({
595
+ nominator: n.nominator,
596
+ nominee: n.nominee,
597
+ turn: tl.turn
598
+ })));
599
+ const aliveCount = players.filter((p) => !p.isDead).length;
600
+ const deadCount = players.length - aliveCount;
601
+ const executedTodayCount = players.filter(
602
+ (p) => p.isDead && p.deathCause === "EXECUTION" && p.deathTurn === currentTurn
603
+ ).length;
604
+ const playerDiedToday = timelines.some((tl) => {
605
+ if (tl.turn !== currentTurn || tl.time !== "day") return false;
606
+ return (tl.operations ?? []).some((op) => {
607
+ const kind = op.kind;
608
+ return kind === "execution" || kind === "death";
609
+ });
610
+ });
611
+ return {
612
+ effector: effectorDecorated,
613
+ players,
614
+ operations: {
615
+ all: allOps,
616
+ today: todayOps,
617
+ tonight: tonightOps,
618
+ yesterdayDay: yesterdayDayOps,
619
+ yesterdayNight: yesterdayNightOps
620
+ },
621
+ nominations: {
622
+ all: allNoms,
623
+ today: todayNoms,
624
+ yesterday: yesterdayNoms
625
+ },
626
+ currentTimeline: {
627
+ turn: currentTurn,
628
+ phase: currentPhase,
629
+ time: currentTime,
630
+ isFirstOfPhase: false,
631
+ isExecution: isExecutionTimeline(nowTl)
632
+ },
633
+ global: {
634
+ aliveCount,
635
+ deadCount,
636
+ executedTodayCount,
637
+ nominatedTodayCount: todayNoms.length,
638
+ executionHappenedToday: timelines.some(
639
+ (tl) => tl.turn === currentTurn && tl.time === "day" && isExecutionTimeline(tl)
640
+ ),
641
+ playerDiedToday
642
+ },
643
+ payload: payloads
644
+ };
645
+ };
646
+
647
+ // src/dsl/bindings.ts
648
+ var rootBindings = (ctx) => ({
649
+ effector: ctx.effector,
650
+ players: ctx.players,
651
+ operations: ctx.operations,
652
+ nominations: ctx.nominations,
653
+ currentTimeline: ctx.currentTimeline,
654
+ global: ctx.global,
655
+ payload: ctx.payload
656
+ });
657
+ var extendBindings = (parent, name, value) => ({
658
+ ...parent,
659
+ [name]: value
660
+ });
661
+
662
+ // src/dsl/operators.ts
663
+ var deepEqual = (a, b) => {
664
+ if (a === b) return true;
665
+ if (Array.isArray(a) && Array.isArray(b)) {
666
+ if (a.length !== b.length) return false;
667
+ for (let i = 0; i < a.length; i++) {
668
+ if (!deepEqual(a[i], b[i])) return false;
669
+ }
670
+ return true;
671
+ }
672
+ return false;
673
+ };
674
+ var asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
675
+ var compareOrder = (lhs, rhs, cmp) => {
676
+ const l = asNumber(lhs);
677
+ const r = asNumber(rhs);
678
+ if (l === void 0 || r === void 0) return false;
679
+ return cmp(l, r);
680
+ };
681
+ var applyOperator = (op, lhs, rhs) => {
682
+ switch (op) {
683
+ case "EQ":
684
+ return deepEqual(lhs, rhs);
685
+ case "NE":
686
+ return !deepEqual(lhs, rhs);
687
+ case "LT":
688
+ return compareOrder(lhs, rhs, (l, r) => l < r);
689
+ case "LTE":
690
+ return compareOrder(lhs, rhs, (l, r) => l <= r);
691
+ case "GT":
692
+ return compareOrder(lhs, rhs, (l, r) => l > r);
693
+ case "GTE":
694
+ return compareOrder(lhs, rhs, (l, r) => l >= r);
695
+ case "IN":
696
+ return Array.isArray(rhs) && rhs.some((v) => deepEqual(v, lhs));
697
+ case "NOT_IN":
698
+ return Array.isArray(rhs) && !rhs.some((v) => deepEqual(v, lhs));
699
+ case "CONTAINS":
700
+ if (Array.isArray(lhs)) return lhs.some((v) => deepEqual(v, rhs));
701
+ if (typeof lhs === "string") return typeof rhs === "string" && lhs.includes(rhs);
702
+ return false;
703
+ case "MATCHES":
704
+ if (typeof lhs !== "string" || typeof rhs !== "string") return false;
705
+ try {
706
+ return new RegExp(rhs).test(lhs);
707
+ } catch {
708
+ return false;
709
+ }
710
+ case "EXISTS":
711
+ return lhs !== void 0 && lhs !== null;
712
+ case "TRUTHY":
713
+ return Boolean(lhs);
714
+ }
715
+ };
716
+ var applyCountOperator = (op, actual, expected) => {
717
+ switch (op) {
718
+ case "EQ":
719
+ return actual === expected;
720
+ case "NE":
721
+ return actual !== expected;
722
+ case "LT":
723
+ return actual < expected;
724
+ case "LTE":
725
+ return actual <= expected;
726
+ case "GT":
727
+ return actual > expected;
728
+ case "GTE":
729
+ return actual >= expected;
730
+ }
731
+ };
732
+
733
+ // src/dsl/path.ts
734
+ var MAX_STEPS = 32;
735
+ var stepInto = (current, step) => {
736
+ if (current === void 0 || current === null) return void 0;
737
+ if (step.kind === "field") {
738
+ if (typeof current !== "object") return void 0;
739
+ const record = current;
740
+ return record[step.name];
741
+ }
742
+ if (step.kind === "index") {
743
+ if (!Array.isArray(current)) return void 0;
744
+ return current[step.value];
745
+ }
746
+ return void 0;
747
+ };
748
+ var evaluatePath = (path, bindings) => {
749
+ if (path.steps.length > MAX_STEPS) return void 0;
750
+ let current = Object.prototype.hasOwnProperty.call(bindings, path.root) ? bindings[path.root] : void 0;
751
+ for (const step of path.steps) {
752
+ current = stepInto(current, step);
753
+ if (current === void 0) return void 0;
754
+ }
755
+ return current;
756
+ };
757
+
758
+ // src/dsl/eval.ts
759
+ var MAX_EXPR_DEPTH = 16;
760
+ var MAX_QUANTIFIER_SIZE = 256;
761
+ var resolveValue = (value, bindings) => {
762
+ if (!value) return void 0;
763
+ if (value.kind === "LITERAL") return value.value;
764
+ return evaluatePath(value.path, bindings);
765
+ };
766
+ var evalAtom = (atom, bindings, depth) => {
767
+ if (atom.type === "PATH") {
768
+ const lhs = evaluatePath(atom.path, bindings);
769
+ const rhs = resolveValue(atom.value, bindings);
770
+ return applyOperator(atom.op, lhs, rhs);
771
+ }
772
+ const source = evaluatePath(atom.source, bindings);
773
+ if (!Array.isArray(source)) {
774
+ return atom.type === "FORALL";
775
+ }
776
+ if (source.length > MAX_QUANTIFIER_SIZE) return false;
777
+ if (atom.type === "EXISTS") {
778
+ return source.some(
779
+ (item) => evalExpr(atom.where, extendBindings(bindings, atom.as, item), depth + 1)
780
+ );
781
+ }
782
+ if (atom.type === "FORALL") {
783
+ return source.every(
784
+ (item) => evalExpr(atom.where, extendBindings(bindings, atom.as, item), depth + 1)
785
+ );
786
+ }
787
+ let count = 0;
788
+ for (const item of source) {
789
+ if (!atom.where || evalExpr(atom.where, extendBindings(bindings, atom.as, item), depth + 1)) {
790
+ count += 1;
791
+ }
792
+ }
793
+ return applyCountOperator(atom.op, count, atom.value);
794
+ };
795
+ var evalExpr = (expr, bindings, depth = 0) => {
796
+ if (depth > MAX_EXPR_DEPTH) return false;
797
+ switch (expr.op) {
798
+ case "AND":
799
+ return expr.children.every((child) => evalExpr(child, bindings, depth + 1));
800
+ case "OR":
801
+ return expr.children.some((child) => evalExpr(child, bindings, depth + 1));
802
+ case "NOT":
803
+ return !evalExpr(expr.child, bindings, depth + 1);
804
+ case "ATOM":
805
+ return evalAtom(expr.atom, bindings, depth + 1);
806
+ }
807
+ };
808
+ var evalDslExpr = (expr, ctx) => evalExpr(expr, rootBindings(ctx), 0);
809
+
810
+ // src/dsl/catalog.ts
811
+ var PLAYER_FIELDS = [
812
+ { name: "seat", type: "number", label: "\u5EA7\u4F4D\u53F7" },
813
+ { name: "alignment", type: "string", label: "\u9635\u8425", description: "GOOD / EVIL" },
814
+ { name: "isDead", type: "boolean", label: "\u662F\u5426\u6B7B\u4EA1" },
815
+ { name: "effectiveAlive", type: "boolean", label: "\u6709\u6548\u5B58\u6D3B", description: "\u8003\u8651 retainsAbility\uFF08ALIVENESS/ALL\uFF09\u540E\u662F\u5426\u6309\u5B58\u6D3B\u5904\u7406" },
816
+ { name: "diedThisTurn", type: "boolean", label: "\u672C\u56DE\u5408\u6B7B\u4EA1" },
817
+ { name: "wasExecuted", type: "boolean", label: "\u66FE\u88AB\u5904\u51B3" },
818
+ { name: "wasExecutedToday", type: "boolean", label: "\u4ECA\u65E5\u88AB\u5904\u51B3" },
819
+ { name: "characterId", type: "string", label: "\u89D2\u8272 ID" },
820
+ { name: "characterKind", type: "string", label: "\u89D2\u8272\u7C7B\u578B", description: "Townsfolk / Outsiders / Minions / Demons" },
821
+ { name: "deathCause", type: "string", label: "\u6B7B\u4EA1\u539F\u56E0", description: "EXECUTION / DEMON / ABILITY / STORYTELLER / OTHER" },
822
+ { name: "deathTurn", type: "number", label: "\u6B7B\u4EA1\u56DE\u5408" },
823
+ { name: "abilities", type: "string[]", label: "\u80FD\u529B ID \u5217\u8868" },
824
+ { name: "reminderMarks", type: "string[]", label: "\u63D0\u793A\u7269 mark \u5217\u8868" },
825
+ { name: "hasUsedDeadVote", type: "boolean", label: "\u662F\u5426\u4F7F\u7528\u8FC7\u6B7B\u4EA1\u6295\u7968" },
826
+ { name: "retainsAbility", type: "string", label: "\u80FD\u529B\u4FDD\u7559\u8303\u56F4" }
827
+ ];
828
+ var OPERATION_FIELDS = [
829
+ { name: "effector", type: "number", label: "\u65BD\u52A8\u8005\u5EA7\u4F4D" },
830
+ { name: "abilityId", type: "string", label: "\u80FD\u529B ID" },
831
+ { name: "kind", type: "string", label: "\u64CD\u4F5C\u79CD\u7C7B" },
832
+ { name: "payloads", type: "unknown[]", label: "Payload \u5217\u8868" }
833
+ ];
834
+ var NOMINATION_FIELDS = [
835
+ { name: "nominator", type: "number", label: "\u63D0\u540D\u8005\u5EA7\u4F4D" },
836
+ { name: "nominee", type: "number", label: "\u88AB\u63D0\u540D\u8005\u5EA7\u4F4D" },
837
+ { name: "turn", type: "number", label: "\u56DE\u5408", description: "\u4EC5 all \u96C6\u5408\u53EF\u7528" }
838
+ ];
839
+ var CURRENT_TIMELINE_FIELDS = [
840
+ { name: "turn", type: "number", label: "\u5F53\u524D\u56DE\u5408" },
841
+ { name: "phase", type: "string", label: "\u5F53\u524D\u9636\u6BB5", description: "NIGHT / DAY / DUSK / DAWN" },
842
+ { name: "time", type: "string", label: "\u5F53\u524D\u65F6\u6BB5", description: "night / day" },
843
+ { name: "isFirstOfPhase", type: "boolean", label: "\u662F\u5426\u672C\u9636\u6BB5\u9996\u6B21" },
844
+ { name: "isExecution", type: "boolean", label: "\u5F53\u524D\u65F6\u95F4\u7EBF\u542B\u5904\u51B3" }
845
+ ];
846
+ var GLOBAL_FIELDS = [
847
+ { name: "aliveCount", type: "number", label: "\u5B58\u6D3B\u73A9\u5BB6\u6570" },
848
+ { name: "deadCount", type: "number", label: "\u6B7B\u4EA1\u73A9\u5BB6\u6570" },
849
+ { name: "executedTodayCount", type: "number", label: "\u4ECA\u65E5\u88AB\u5904\u51B3\u4EBA\u6570" },
850
+ { name: "nominatedTodayCount", type: "number", label: "\u4ECA\u65E5\u63D0\u540D\u603B\u6570" },
851
+ { name: "executionHappenedToday", type: "boolean", label: "\u4ECA\u65E5\u662F\u5426\u5DF2\u53D1\u751F\u5904\u51B3" },
852
+ { name: "playerDiedToday", type: "boolean", label: "\u4ECA\u65E5\u662F\u5426\u6709\u73A9\u5BB6\u6B7B\u4EA1" }
853
+ ];
854
+ var OPERATIONS_FIELDS = [
855
+ { name: "all", type: "operation[]", label: "\u6240\u6709\u64CD\u4F5C" },
856
+ { name: "today", type: "operation[]", label: "\u4ECA\u65E5\u64CD\u4F5C" },
857
+ { name: "tonight", type: "operation[]", label: "\u4ECA\u591C\u64CD\u4F5C" },
858
+ { name: "yesterdayDay", type: "operation[]", label: "\u6628\u65E5\u767D\u5929\u64CD\u4F5C" },
859
+ { name: "yesterdayNight", type: "operation[]", label: "\u6628\u591C\u64CD\u4F5C" }
860
+ ];
861
+ var NOMINATIONS_FIELDS = [
862
+ { name: "all", type: "nomination[]", label: "\u6240\u6709\u63D0\u540D" },
863
+ { name: "today", type: "nomination[]", label: "\u4ECA\u65E5\u63D0\u540D" },
864
+ { name: "yesterday", type: "nomination[]", label: "\u6628\u65E5\u63D0\u540D" }
865
+ ];
866
+ var DSL_CATALOG = [
867
+ {
868
+ name: "effector",
869
+ type: "player",
870
+ label: "\u80FD\u529B\u53D1\u52A8\u8005",
871
+ description: "\u5F53\u524D\u8BC4\u4F30\u65F6\u7684\u80FD\u529B\u65BD\u653E\u8005\u5FEB\u7167",
872
+ fields: PLAYER_FIELDS
873
+ },
874
+ {
875
+ name: "players",
876
+ type: "player[]",
877
+ label: "\u5168\u90E8\u73A9\u5BB6",
878
+ description: "\u5F53\u524D\u5FEB\u7167\u4E0B\u6240\u6709\u73A9\u5BB6\uFF08\u5E94\u914D\u5408 EXISTS / FORALL / COUNT \u4F7F\u7528\uFF09"
879
+ },
880
+ {
881
+ name: "operations",
882
+ type: "object",
883
+ label: "\u5386\u53F2\u64CD\u4F5C\u96C6\u5408",
884
+ fields: OPERATIONS_FIELDS
885
+ },
886
+ {
887
+ name: "nominations",
888
+ type: "object",
889
+ label: "\u5386\u53F2\u63D0\u540D\u96C6\u5408",
890
+ fields: NOMINATIONS_FIELDS
891
+ },
892
+ {
893
+ name: "currentTimeline",
894
+ type: "object",
895
+ label: "\u5F53\u524D\u65F6\u95F4\u7EBF",
896
+ fields: CURRENT_TIMELINE_FIELDS
897
+ },
898
+ {
899
+ name: "global",
900
+ type: "object",
901
+ label: "\u5168\u5C40\u805A\u5408",
902
+ fields: GLOBAL_FIELDS
903
+ },
904
+ {
905
+ name: "payload",
906
+ type: "unknown[]",
907
+ label: "\u80FD\u529B Payload \u6570\u7EC4",
908
+ description: "\u5F53\u524D\u8C03\u7528 / \u64CD\u4F5C\u7684 payload \u539F\u59CB\u6570\u7EC4"
909
+ }
910
+ ];
911
+ var DSL_ITEM_FIELDS = {
912
+ player: PLAYER_FIELDS,
913
+ operation: OPERATION_FIELDS,
914
+ nomination: NOMINATION_FIELDS
915
+ };
916
+ var DSL_OPERATORS = [
917
+ { value: "EQ", label: "\u7B49\u4E8E", arity: "binary" },
918
+ { value: "NE", label: "\u4E0D\u7B49\u4E8E", arity: "binary" },
919
+ { value: "LT", label: "<", arity: "binary" },
920
+ { value: "LTE", label: "<=", arity: "binary" },
921
+ { value: "GT", label: ">", arity: "binary" },
922
+ { value: "GTE", label: ">=", arity: "binary" },
923
+ { value: "IN", label: "\u5C5E\u4E8E", arity: "binary" },
924
+ { value: "NOT_IN", label: "\u4E0D\u5C5E\u4E8E", arity: "binary" },
925
+ { value: "CONTAINS", label: "\u5305\u542B", arity: "binary" },
926
+ { value: "MATCHES", label: "\u6B63\u5219\u5339\u914D", arity: "binary" },
927
+ { value: "EXISTS", label: "\u5B58\u5728", arity: "unary" },
928
+ { value: "TRUTHY", label: "\u4E3A\u771F", arity: "unary" }
929
+ ];
930
+
931
+ // src/dsl/trace.ts
932
+ var MAX_QUANTIFIER_SIZE2 = 256;
933
+ var renderPath = (p) => p.steps.reduce((acc, s) => acc + (s.kind === "field" ? `.${s.name}` : `[${s.value}]`), p.root);
934
+ var resolveValue2 = (value, bindings) => {
935
+ if (!value) return void 0;
936
+ if (value.kind === "LITERAL") return value.value;
937
+ return evaluatePath(value.path, bindings);
938
+ };
939
+ var renderValue = (value, bindings) => {
940
+ if (!value) return void 0;
941
+ if (value.kind === "LITERAL") return value.value;
942
+ return { ref: renderPath(value.path), resolved: evaluatePath(value.path, bindings) };
943
+ };
944
+ var traceAtom = (atom, bindings) => {
945
+ if (atom.type === "PATH") {
946
+ const lhs = evaluatePath(atom.path, bindings);
947
+ const rhs = resolveValue2(atom.value, bindings);
948
+ const ok2 = applyOperator(atom.op, lhs, rhs);
949
+ return {
950
+ op: "ATOM",
951
+ atomType: "PATH",
952
+ ok: ok2,
953
+ path: renderPath(atom.path),
954
+ operator: atom.op,
955
+ lhs,
956
+ rhs: renderValue(atom.value, bindings)
957
+ };
958
+ }
959
+ const source = evaluatePath(atom.source, bindings);
960
+ const sourceArr = Array.isArray(source) ? source : [];
961
+ const sizeCapped = sourceArr.length > MAX_QUANTIFIER_SIZE2;
962
+ let matched = 0;
963
+ if (!sizeCapped) {
964
+ for (const item of sourceArr) {
965
+ const childBindings = extendBindings(bindings, atom.as, item);
966
+ if (!atom.where || traceExprOk(atom.where, childBindings)) matched += 1;
967
+ }
968
+ }
969
+ if (atom.type === "COUNT") {
970
+ const ok2 = !sizeCapped && applyCountOperator(atom.op, matched, atom.value);
971
+ return {
972
+ op: "ATOM",
973
+ atomType: "COUNT",
974
+ ok: ok2,
975
+ source: renderPath(atom.source),
976
+ size: sourceArr.length,
977
+ matched,
978
+ operator: atom.op,
979
+ expected: atom.value,
980
+ bindings: atom.as
981
+ };
982
+ }
983
+ const ok = atom.type === "EXISTS" ? matched > 0 : !sizeCapped && (sourceArr.length === 0 || matched === sourceArr.length);
984
+ return {
985
+ op: "ATOM",
986
+ atomType: atom.type,
987
+ ok,
988
+ source: renderPath(atom.source),
989
+ size: sourceArr.length,
990
+ matched,
991
+ bindings: atom.as
992
+ };
993
+ };
994
+ var traceExprOk = (expr, bindings) => {
995
+ switch (expr.op) {
996
+ case "AND":
997
+ return expr.children.every((c) => traceExprOk(c, bindings));
998
+ case "OR":
999
+ return expr.children.some((c) => traceExprOk(c, bindings));
1000
+ case "NOT":
1001
+ return !traceExprOk(expr.child, bindings);
1002
+ case "ATOM":
1003
+ return traceAtom(expr.atom, bindings).ok;
1004
+ }
1005
+ };
1006
+ var traceExpr = (expr, bindings) => {
1007
+ if (expr.op === "AND") {
1008
+ const children = expr.children.map((c) => traceExpr(c, bindings));
1009
+ return { op: "AND", ok: children.every((c) => c.ok), children };
1010
+ }
1011
+ if (expr.op === "OR") {
1012
+ const children = expr.children.map((c) => traceExpr(c, bindings));
1013
+ return { op: "OR", ok: children.some((c) => c.ok), children };
1014
+ }
1015
+ if (expr.op === "NOT") {
1016
+ const child = traceExpr(expr.child, bindings);
1017
+ return { op: "NOT", ok: !child.ok, child };
1018
+ }
1019
+ return traceAtom(expr.atom, bindings);
1020
+ };
1021
+ var traceDslExpr = (expr, ctx) => traceExpr(expr, rootBindings(ctx));
1022
+
508
1023
  // src/effects/resolve-targets.ts
509
1024
  var isPayloadRef = (value) => {
510
1025
  if (!value || typeof value !== "object") {
@@ -550,7 +1065,23 @@ var resolveSelectorScope = (dynamicTarget, payloads) => {
550
1065
  (value) => value === "BOTH_SIDES" || value === "LEFT_SIDE" || value === "RIGHT_SIDE"
551
1066
  ) ?? "BOTH_SIDES";
552
1067
  };
553
- var matchesCondition = (player, condition, payloads, characterMap) => {
1068
+ var matchesExprCondition = (player, condition, playerSeatMap, characterMap, effector, payloads) => {
1069
+ const dslCtx = buildDslContextFromLifetime({
1070
+ snapshotSeatMap: playerSeatMap,
1071
+ timelines: [],
1072
+ nowTimelineIndex: -1,
1073
+ characterMap,
1074
+ effector,
1075
+ payloads
1076
+ });
1077
+ const decoratedPlayer = dslCtx.players.find((p) => p.seat === player.seat);
1078
+ const bindings = extendBindings(rootBindings(dslCtx), "it", decoratedPlayer ?? player);
1079
+ return evalExpr(condition.expr, bindings);
1080
+ };
1081
+ var matchesCondition = (player, condition, payloads, characterMap, playerSeatMap, effector) => {
1082
+ if (condition.kind === "EXPR") {
1083
+ return matchesExprCondition(player, condition, playerSeatMap, characterMap, effector, payloads);
1084
+ }
554
1085
  if (condition.field === "IS_DEAD") {
555
1086
  const expected = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "boolean");
556
1087
  if (typeof expected !== "boolean") {
@@ -566,6 +1097,18 @@ var matchesCondition = (player, condition, payloads, characterMap) => {
566
1097
  const expectedSeat = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "number");
567
1098
  return typeof expectedSeat === "number" && player.seat === expectedSeat;
568
1099
  }
1100
+ if (condition.field === "ALIGNMENT") {
1101
+ const alignment = player.alignment;
1102
+ if (!alignment) {
1103
+ return false;
1104
+ }
1105
+ if (condition.operator === "IN") {
1106
+ const expectedAlignments = resolveDynamicValue(condition.value, payloads, (value) => Array.isArray(value) && value.every((item) => typeof item === "string"));
1107
+ return Array.isArray(expectedAlignments) && expectedAlignments.includes(alignment);
1108
+ }
1109
+ const expectedAlignment = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "string");
1110
+ return typeof expectedAlignment === "string" && alignment === expectedAlignment;
1111
+ }
569
1112
  const character = characterMap.get(player.characterId);
570
1113
  const kind = character?.kind;
571
1114
  if (!kind) {
@@ -578,15 +1121,17 @@ var matchesCondition = (player, condition, payloads, characterMap) => {
578
1121
  const expectedKind = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "string");
579
1122
  return typeof expectedKind === "string" && kind === expectedKind;
580
1123
  };
581
- var passesWhere = (player, dynamicTarget, payloads, characterMap) => {
1124
+ var passesWhere = (player, dynamicTarget, payloads, characterMap, playerSeatMap, effector) => {
582
1125
  const where = dynamicTarget.where;
583
1126
  const conditions = where?.conditions ?? [];
584
1127
  if (conditions.length === 0) return true;
585
1128
  const isAllMode = where?.mode !== "ANY";
586
- const results = conditions.map((condition) => matchesCondition(player, condition, payloads, characterMap));
1129
+ const results = conditions.map(
1130
+ (condition) => matchesCondition(player, condition, payloads, characterMap, playerSeatMap, effector)
1131
+ );
587
1132
  return isAllMode ? results.every(Boolean) : results.some(Boolean);
588
1133
  };
589
- var walkSidesWithFilter = (dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap) => {
1134
+ var walkSidesWithFilter = (dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap, playerSeatMap, effector) => {
590
1135
  const scope = resolveSelectorScope(dynamicTarget, payloads);
591
1136
  if (!anchorSeat) return { left: [], right: [] };
592
1137
  const anchorIdx = sortedPlayers.findIndex((player) => player.seat === anchorSeat);
@@ -597,13 +1142,13 @@ var walkSidesWithFilter = (dynamicTarget, sortedPlayers, anchorSeat, payloads, c
597
1142
  if (scope === "LEFT_SIDE" || scope === "BOTH_SIDES") {
598
1143
  for (let step = 1; step < total; step += 1) {
599
1144
  const player = sortedPlayers[(anchorIdx + step) % total];
600
- if (passesWhere(player, dynamicTarget, payloads, characterMap)) left.push(player);
1145
+ if (passesWhere(player, dynamicTarget, payloads, characterMap, playerSeatMap, effector)) left.push(player);
601
1146
  }
602
1147
  }
603
1148
  if (scope === "RIGHT_SIDE" || scope === "BOTH_SIDES") {
604
1149
  for (let step = 1; step < total; step += 1) {
605
1150
  const player = sortedPlayers[(anchorIdx - step + total) % total];
606
- if (passesWhere(player, dynamicTarget, payloads, characterMap)) right.push(player);
1151
+ if (passesWhere(player, dynamicTarget, payloads, characterMap, playerSeatMap, effector)) right.push(player);
607
1152
  }
608
1153
  }
609
1154
  return { left, right };
@@ -677,10 +1222,12 @@ var resolveEffectTargets = ({
677
1222
  const sortedPlayers = getSortedPlayers(playerSeatMap);
678
1223
  const anchorSeat = getAnchorSeat(dynamicTarget, payloads, effector);
679
1224
  if (!dynamicTarget.selector) {
680
- const matches = sortedPlayers.filter((player) => passesWhere(player, dynamicTarget, payloads, characterMap));
1225
+ const matches = sortedPlayers.filter(
1226
+ (player) => passesWhere(player, dynamicTarget, payloads, characterMap, playerSeatMap, effector)
1227
+ );
681
1228
  return pickBalanced({ left: matches, right: [] }, dynamicTarget, payloads);
682
1229
  }
683
- const sides = walkSidesWithFilter(dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap);
1230
+ const sides = walkSidesWithFilter(dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap, playerSeatMap, effector);
684
1231
  return pickBalanced(sides, dynamicTarget, payloads);
685
1232
  }
686
1233
  return [];
@@ -826,7 +1373,7 @@ var evalPlayerState = (atom, ctx) => {
826
1373
  const single = players[0];
827
1374
  return evalPlayerStateOnPlayer(single, atom, ctx);
828
1375
  };
829
- var isExecutionTimeline = (tl) => {
1376
+ var isExecutionTimeline2 = (tl) => {
830
1377
  if (!tl) return false;
831
1378
  return (tl.operations ?? []).some((op) => op.kind === "execution");
832
1379
  };
@@ -854,7 +1401,7 @@ var evalTime = (atom, ctx) => {
854
1401
  if (spec.event === "NEXT_NIGHT" && tl.time === "night") return false;
855
1402
  if (spec.event === "NEXT_DUSK" && prevTime === "day" && tl.time === "night") return false;
856
1403
  if (spec.event === "NEXT_DAWN" && prevTime === "night" && tl.time === "day") return false;
857
- if (spec.event === "NEXT_EXECUTION" && isExecutionTimeline(tl)) return false;
1404
+ if (spec.event === "NEXT_EXECUTION" && isExecutionTimeline2(tl)) return false;
858
1405
  prevTime = tl.time;
859
1406
  }
860
1407
  return true;
@@ -895,7 +1442,7 @@ var evalGameState = (atom, ctx) => {
895
1442
  if (spec.kind === "EXECUTION_HAPPENED_TODAY") {
896
1443
  const turn = ctx.timelines[ctx.nowTimelineIndex]?.turn;
897
1444
  if (typeof turn !== "number") return false;
898
- return ctx.timelines.some((tl) => tl.turn === turn && tl.time === "day" && isExecutionTimeline(tl));
1445
+ return ctx.timelines.some((tl) => tl.turn === turn && tl.time === "day" && isExecutionTimeline2(tl));
899
1446
  }
900
1447
  if (spec.kind === "PLAYER_DIED_TODAY") {
901
1448
  const turn = ctx.timelines[ctx.nowTimelineIndex]?.turn;
@@ -910,7 +1457,7 @@ var evalGameState = (atom, ctx) => {
910
1457
  }
911
1458
  return true;
912
1459
  };
913
- var evalAtom = (atom, ctx) => {
1460
+ var evalAtom2 = (atom, ctx) => {
914
1461
  switch (atom.type) {
915
1462
  case "TIME":
916
1463
  return evalTime(atom, ctx);
@@ -929,18 +1476,30 @@ var evalAtom = (atom, ctx) => {
929
1476
  target: ctx.target,
930
1477
  snapshotSeatMap: ctx.snapshotSeatMap
931
1478
  }) : false;
1479
+ case "DSL": {
1480
+ if (!ctx.snapshotSeatMap) return true;
1481
+ const dslCtx = buildDslContextFromLifetime({
1482
+ snapshotSeatMap: ctx.snapshotSeatMap,
1483
+ timelines: ctx.timelines,
1484
+ nowTimelineIndex: ctx.nowTimelineIndex,
1485
+ characterMap: ctx.characterMap,
1486
+ effector: ctx.effector,
1487
+ payloads: ctx.payloads
1488
+ });
1489
+ return evalDslExpr(atom.expr, dslCtx);
1490
+ }
932
1491
  }
933
1492
  };
934
- var evalExpr = (expr, ctx) => {
1493
+ var evalExpr2 = (expr, ctx) => {
935
1494
  switch (expr.op) {
936
1495
  case "AND":
937
- return expr.children.every((child) => evalExpr(child, ctx));
1496
+ return expr.children.every((child) => evalExpr2(child, ctx));
938
1497
  case "OR":
939
- return expr.children.some((child) => evalExpr(child, ctx));
1498
+ return expr.children.some((child) => evalExpr2(child, ctx));
940
1499
  case "NOT":
941
- return !evalExpr(expr.child, ctx);
1500
+ return !evalExpr2(expr.child, ctx);
942
1501
  case "ATOM":
943
- return evalAtom(expr.atom, ctx);
1502
+ return evalAtom2(expr.atom, ctx);
944
1503
  }
945
1504
  };
946
1505
  var expressionReferencesTarget = (expr) => {
@@ -978,9 +1537,9 @@ var evaluateLifetime = ({
978
1537
  const expr = lifetime.expr;
979
1538
  const dependsOnTarget = expressionReferencesTarget(expr);
980
1539
  if (!dependsOnTarget) {
981
- return evalExpr(expr, { ...baseCtx, target: void 0 }) ? targets : [];
1540
+ return evalExpr2(expr, { ...baseCtx, target: void 0 }) ? targets : [];
982
1541
  }
983
- return targets.filter((target) => evalExpr(expr, { ...baseCtx, target }));
1542
+ return targets.filter((target) => evalExpr2(expr, { ...baseCtx, target }));
984
1543
  };
985
1544
  var evaluatePrecondition = ({
986
1545
  expr,
@@ -1006,9 +1565,9 @@ var evaluatePrecondition = ({
1006
1565
  };
1007
1566
  const dependsOnTarget = expressionReferencesTarget(expr);
1008
1567
  if (!dependsOnTarget) {
1009
- return evalExpr(expr, { ...baseCtx, target: void 0 }) ? targets : [];
1568
+ return evalExpr2(expr, { ...baseCtx, target: void 0 }) ? targets : [];
1010
1569
  }
1011
- return targets.filter((target) => evalExpr(expr, { ...baseCtx, target }));
1570
+ return targets.filter((target) => evalExpr2(expr, { ...baseCtx, target }));
1012
1571
  };
1013
1572
 
1014
1573
  // src/apply-operation.ts
@@ -1330,6 +1889,12 @@ var deriveContext = ({
1330
1889
  const yesterdayDayOperations = timelines.filter((tl) => tl.turn === last.turn - 1 && tl.time === "day").flatMap((tl) => tl.operations ?? []);
1331
1890
  const yesterdayNightOperations = timelines.filter((tl) => tl.turn === last.turn - 1 && tl.time === "night").flatMap((tl) => tl.operations ?? []);
1332
1891
  const todayNominations = timelines.filter((tl) => tl.turn === last.turn && tl.time === "day").flatMap((tl) => tl.nominations ?? []).map((n) => ({ nominator: n.nominator, nominee: n.nominee }));
1892
+ const yesterdayNominations = timelines.filter((tl) => tl.turn === last.turn - 1 && tl.time === "day").flatMap((tl) => tl.nominations ?? []).map((n) => ({ nominator: n.nominator, nominee: n.nominee }));
1893
+ const allNominations = timelines.filter((tl) => tl.time === "day").flatMap((tl) => (tl.nominations ?? []).map((n) => ({
1894
+ nominator: n.nominator,
1895
+ nominee: n.nominee,
1896
+ turn: tl.turn
1897
+ })));
1333
1898
  return {
1334
1899
  currentTurn: last.turn,
1335
1900
  currentPhase: TIME_TO_PHASE[last.time],
@@ -1341,6 +1906,8 @@ var deriveContext = ({
1341
1906
  yesterdayDayOperations,
1342
1907
  yesterdayNightOperations,
1343
1908
  todayNominations,
1909
+ yesterdayNominations,
1910
+ allNominations,
1344
1911
  effectorSeat: candidate.effector,
1345
1912
  effector,
1346
1913
  abilityId: candidate.abilityId,
@@ -1349,6 +1916,14 @@ var deriveContext = ({
1349
1916
  operationTimeMap
1350
1917
  };
1351
1918
  };
1919
+ var nominationsForActionScope = (scope, ctx) => {
1920
+ if (scope === "TONIGHT" || scope === "TODAY") return ctx.todayNominations;
1921
+ if (scope === "YESTERDAY") return ctx.yesterdayNominations;
1922
+ return ctx.allNominations.map((n) => ({ nominator: n.nominator, nominee: n.nominee }));
1923
+ };
1924
+ var extractPayloadSeats = (op) => (op.payloads ?? []).flatMap(
1925
+ (v) => typeof v === "number" ? [v] : Array.isArray(v) ? v.filter((x) => typeof x === "number") : []
1926
+ );
1352
1927
  var operationsForActionScope = (scope, ctx) => {
1353
1928
  if (scope === "TONIGHT") return ctx.tonightOperations;
1354
1929
  if (scope === "TODAY") return ctx.todayOperations;
@@ -1404,23 +1979,37 @@ var evalAtomAction = (atom, ctx) => {
1404
1979
  if (subjectSeats.size === 0) return `no players match subject ${atom.subject.ref}`;
1405
1980
  const actorSeats = atom.actor ? seatsMatchingTargetRef(atom.actor, ctx) : null;
1406
1981
  if (atom.action === "NOMINATED") {
1407
- const noms = ctx.todayNominations;
1982
+ const noms = nominationsForActionScope(atom.scope, ctx);
1408
1983
  const found = noms.some(
1409
1984
  (n) => subjectSeats.has(n.nominee) && (actorSeats === null || actorSeats.has(n.nominator))
1410
1985
  );
1411
- return found ? null : "no matching NOMINATED event in today";
1986
+ return found ? null : "no matching NOMINATED event in scope";
1987
+ }
1988
+ if (atom.action === "NOMINATES") {
1989
+ const noms = nominationsForActionScope(atom.scope, ctx);
1990
+ const found = noms.some(
1991
+ (n) => subjectSeats.has(n.nominator) && (actorSeats === null || actorSeats.has(n.nominee))
1992
+ );
1993
+ return found ? null : "no matching NOMINATES event in scope";
1412
1994
  }
1413
1995
  const scoped = operationsForActionScope(atom.scope, ctx);
1414
1996
  if (atom.action === "CHOSEN_AS_TARGET") {
1415
1997
  const found = scoped.some((op) => {
1416
1998
  if (actorSeats !== null && !actorSeats.has(op.effector)) return false;
1417
- const payloadSeats = (op.payloads ?? []).flatMap(
1418
- (v) => typeof v === "number" ? [v] : Array.isArray(v) ? v.filter((x) => typeof x === "number") : []
1419
- );
1999
+ const payloadSeats = extractPayloadSeats(op);
1420
2000
  return payloadSeats.some((s) => subjectSeats.has(s));
1421
2001
  });
1422
2002
  return found ? null : "no matching CHOSEN_AS_TARGET in scope";
1423
2003
  }
2004
+ if (atom.action === "CHOOSES_TARGET") {
2005
+ const found = scoped.some((op) => {
2006
+ if (!subjectSeats.has(op.effector)) return false;
2007
+ if (actorSeats === null) return true;
2008
+ const payloadSeats = extractPayloadSeats(op);
2009
+ return payloadSeats.some((s) => actorSeats.has(s));
2010
+ });
2011
+ return found ? null : "no matching CHOOSES_TARGET in scope";
2012
+ }
1424
2013
  const turnsInScope = (() => {
1425
2014
  if (atom.scope === "TONIGHT" || atom.scope === "TODAY") return [ctx.currentTurn];
1426
2015
  if (atom.scope === "YESTERDAY") return [ctx.currentTurn - 1];
@@ -1450,6 +2039,18 @@ var evalAtomAction = (atom, ctx) => {
1450
2039
  }
1451
2040
  return "no matching EXECUTED in scope";
1452
2041
  }
2042
+ if (atom.action === "EXECUTES") {
2043
+ const scopedNoms = atom.scope === "EVER" ? ctx.allNominations : atom.scope === "YESTERDAY" ? ctx.yesterdayNominations.map((n) => ({ ...n, turn: ctx.currentTurn - 1 })) : ctx.todayNominations.map((n) => ({ ...n, turn: ctx.currentTurn }));
2044
+ const found = scopedNoms.some((n) => {
2045
+ if (!subjectSeats.has(n.nominator)) return false;
2046
+ if (actorSeats !== null && !actorSeats.has(n.nominee)) return false;
2047
+ const executed = ctx.players.find(
2048
+ (p) => p.seat === n.nominee && p.isDead && p.deathCause === "EXECUTION" && p.deathTurn === n.turn
2049
+ );
2050
+ return Boolean(executed);
2051
+ });
2052
+ return found ? null : "no matching EXECUTES in scope";
2053
+ }
1453
2054
  void scoped;
1454
2055
  return `unknown action ${atom.action}`;
1455
2056
  };
@@ -1486,7 +2087,7 @@ var evalAtomGlobalCount = (atom, ctx) => {
1486
2087
  }
1487
2088
  return compareCount2(actual, atom.operator, atom.value) ? null : `global count ${atom.subject}=${actual} fails ${atom.operator} ${atom.value}`;
1488
2089
  };
1489
- var evalAtom2 = (atom, ctx, customResolver) => {
2090
+ var evalAtom3 = (atom, ctx, customResolver) => {
1490
2091
  if (atom.type === "TIME") return evalAtomTime(atom, ctx);
1491
2092
  if (atom.type === "STATE") return evalAtomState(atom, ctx);
1492
2093
  if (atom.type === "ACTION") return evalAtomAction(atom, ctx);
@@ -1496,12 +2097,16 @@ var evalAtom2 = (atom, ctx, customResolver) => {
1496
2097
  if (!customResolver) return `no custom resolver registered for ${atom.resolverId}`;
1497
2098
  return customResolver({ resolverId: atom.resolverId, args: atom.args }, ctx) ? null : `custom resolver ${atom.resolverId} returned false`;
1498
2099
  }
2100
+ if (atom.type === "DSL") {
2101
+ const dslCtx = buildDslContextFromDerived(ctx);
2102
+ return evalDslExpr(atom.expr, dslCtx) ? null : "DSL expression returned false";
2103
+ }
1499
2104
  return "unknown atom";
1500
2105
  };
1501
- var evalExpr2 = (expr, ctx, customResolver) => {
2106
+ var evalExpr3 = (expr, ctx, customResolver) => {
1502
2107
  if (expr.op === "AND") {
1503
2108
  for (const child of expr.children) {
1504
- const reason = evalExpr2(child, ctx, customResolver);
2109
+ const reason = evalExpr3(child, ctx, customResolver);
1505
2110
  if (reason) return reason;
1506
2111
  }
1507
2112
  return null;
@@ -1509,17 +2114,17 @@ var evalExpr2 = (expr, ctx, customResolver) => {
1509
2114
  if (expr.op === "OR") {
1510
2115
  const reasons = [];
1511
2116
  for (const child of expr.children) {
1512
- const reason = evalExpr2(child, ctx, customResolver);
2117
+ const reason = evalExpr3(child, ctx, customResolver);
1513
2118
  if (!reason) return null;
1514
2119
  reasons.push(reason);
1515
2120
  }
1516
2121
  return `OR: all branches failed (${reasons.join("; ")})`;
1517
2122
  }
1518
2123
  if (expr.op === "NOT") {
1519
- const reason = evalExpr2(expr.child, ctx, customResolver);
2124
+ const reason = evalExpr3(expr.child, ctx, customResolver);
1520
2125
  return reason ? null : "NOT: inner expression was true";
1521
2126
  }
1522
- return evalAtom2(expr.atom, ctx, customResolver);
2127
+ return evalAtom3(expr.atom, ctx, customResolver);
1523
2128
  };
1524
2129
  var canInvokeAbility = ({
1525
2130
  ability,
@@ -1539,23 +2144,47 @@ var canInvokeAbility = ({
1539
2144
  if (derived.effector?.retainsAbility === "ALL") {
1540
2145
  return { allowed: true };
1541
2146
  }
1542
- const reason = evalExpr2(window, derived, customResolver);
2147
+ const reason = evalExpr3(window, derived, customResolver);
1543
2148
  return reason ? { allowed: false, reason } : { allowed: true };
1544
2149
  };
2150
+
2151
+ // src/trigger-action.ts
2152
+ var ACTIVE_TRIGGER_ACTIONS = /* @__PURE__ */ new Set([
2153
+ "NOMINATES",
2154
+ "CHOOSES_TARGET",
2155
+ "EXECUTES"
2156
+ ]);
2157
+ var isActiveTriggerAction = (action) => ACTIVE_TRIGGER_ACTIONS.has(action);
1545
2158
  export {
2159
+ ACTIVE_TRIGGER_ACTIONS,
2160
+ DSL_CATALOG,
2161
+ DSL_ITEM_FIELDS,
2162
+ DSL_OPERATORS,
1546
2163
  adjustValueAsNumber,
1547
2164
  adjustValueAsNumberArray,
2165
+ applyCountOperator,
1548
2166
  applyOperationToPlayers,
2167
+ applyOperator,
2168
+ buildDslContextFromDerived,
2169
+ buildDslContextFromLifetime,
1549
2170
  buildPlayerSeatMap,
1550
2171
  canInvokeAbility,
1551
2172
  copyPlayers,
1552
2173
  deriveContext,
2174
+ evalDslExpr,
2175
+ evalExpr as evalDslExprWithBindings,
2176
+ evaluatePath,
2177
+ extendBindings,
1553
2178
  getSourceValue,
1554
2179
  getValueFromPayloads,
2180
+ isActiveTriggerAction,
1555
2181
  isNumberOrNumberArray,
1556
2182
  isPlayerReminderArray,
1557
2183
  isReminder,
1558
2184
  resolveSourceValue,
1559
2185
  resolveTargetRef,
2186
+ rootBindings,
2187
+ traceDslExpr,
2188
+ traceExpr,
1560
2189
  transformEmptyArray
1561
2190
  };