@bct-app/game-engine 0.1.19 → 0.1.21

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.d.mts CHANGED
@@ -133,9 +133,6 @@ type TDslPlayer = TPlayer & {
133
133
  characterKind: string | undefined;
134
134
  reminderMarks: string[];
135
135
  effectiveAlive: boolean;
136
- diedThisTurn: boolean;
137
- wasExecuted: boolean;
138
- wasExecutedToday: boolean;
139
136
  };
140
137
  type TDslNomination = {
141
138
  nominator: number;
@@ -161,6 +158,7 @@ type TDslContext = {
161
158
  };
162
159
  currentTimeline: {
163
160
  turn: number;
161
+ previousTurn: number;
164
162
  phase: string;
165
163
  time: TTimeline['time'] | undefined;
166
164
  isFirstOfPhase: boolean;
package/dist/index.d.ts CHANGED
@@ -133,9 +133,6 @@ type TDslPlayer = TPlayer & {
133
133
  characterKind: string | undefined;
134
134
  reminderMarks: string[];
135
135
  effectiveAlive: boolean;
136
- diedThisTurn: boolean;
137
- wasExecuted: boolean;
138
- wasExecutedToday: boolean;
139
136
  };
140
137
  type TDslNomination = {
141
138
  nominator: number;
@@ -161,6 +158,7 @@ type TDslContext = {
161
158
  };
162
159
  currentTimeline: {
163
160
  turn: number;
161
+ previousTurn: number;
164
162
  phase: string;
165
163
  time: TTimeline['time'] | undefined;
166
164
  isFirstOfPhase: boolean;
package/dist/index.js CHANGED
@@ -519,19 +519,20 @@ var applyStatusChange = createEffectHandler("STATUS_CHANGE", ({
519
519
  effect,
520
520
  payloads,
521
521
  makePlayersEffect,
522
- operationInTimelineIdx,
522
+ operationTurn,
523
523
  abilityMap,
524
- operation
524
+ operation,
525
+ operationTime
525
526
  }) => {
526
527
  const maybeStatus = getSourceValue(effect.source, payloads);
527
528
  if (maybeStatus === "DEAD") {
528
529
  const ability = abilityMap.get(operation.abilityId);
529
- const turn = operationInTimelineIdx >= 0 ? operationInTimelineIdx : 0;
530
530
  const cause = effect.deathCause ?? (ability?.category === "STORYTELLER" ? "STORYTELLER" : "ABILITY");
531
531
  makePlayersEffect.forEach((player) => {
532
532
  player.isDead = true;
533
533
  player.deathCause = cause;
534
- player.deathTurn = turn;
534
+ player.deathTurn = operationTurn;
535
+ player.deathTime = operationTime;
535
536
  });
536
537
  return;
537
538
  }
@@ -540,6 +541,7 @@ var applyStatusChange = createEffectHandler("STATUS_CHANGE", ({
540
541
  player.isDead = false;
541
542
  delete player.deathCause;
542
543
  delete player.deathTurn;
544
+ delete player.deathTime;
543
545
  });
544
546
  return;
545
547
  }
@@ -562,18 +564,14 @@ var effectHandlers = {
562
564
  };
563
565
 
564
566
  // src/dsl/context.ts
565
- var decoratePlayer = (player, characterMap, currentTurn) => {
567
+ var decoratePlayer = (player, characterMap) => {
566
568
  const isDead = Boolean(player.isDead);
567
569
  const retainsBypass = isDead && (player.retainsAbility === "ALIVENESS" || player.retainsAbility === "ALL");
568
- const wasExecuted = isDead && player.deathCause === "EXECUTION";
569
570
  return {
570
571
  ...player,
571
572
  characterKind: characterMap.get(player.characterId)?.kind,
572
573
  reminderMarks: (player.reminders ?? []).map((r) => r.mark),
573
- effectiveAlive: !isDead || retainsBypass,
574
- diedThisTurn: isDead && typeof player.deathTurn === "number" && player.deathTurn === currentTurn,
575
- wasExecuted,
576
- wasExecutedToday: wasExecuted && player.deathTurn === currentTurn
574
+ effectiveAlive: !isDead || retainsBypass
577
575
  };
578
576
  };
579
577
  var isExecutionTimeline = (tl) => {
@@ -581,7 +579,7 @@ var isExecutionTimeline = (tl) => {
581
579
  return (tl.operations ?? []).some((op) => op.kind === "execution");
582
580
  };
583
581
  var buildDslContextFromDerived = (derived, payload = []) => {
584
- const players = derived.players.map((p) => decoratePlayer(p, derived.characterMap, derived.currentTurn));
582
+ const players = derived.players.map((p) => decoratePlayer(p, derived.characterMap));
585
583
  const effector = players.find((p) => p.seat === derived.effectorSeat);
586
584
  const aliveCount = players.filter((p) => !p.isDead).length;
587
585
  const deadCount = players.length - aliveCount;
@@ -609,6 +607,7 @@ var buildDslContextFromDerived = (derived, payload = []) => {
609
607
  },
610
608
  currentTimeline: {
611
609
  turn: derived.currentTurn,
610
+ previousTurn: derived.currentTurn - 1,
612
611
  phase: derived.currentPhase,
613
612
  time: derived.currentPhase === "NIGHT" ? "night" : derived.currentPhase === "DAY" ? "day" : void 0,
614
613
  isFirstOfPhase: derived.isFirstOfPhase,
@@ -638,8 +637,8 @@ var buildDslContextFromLifetime = ({
638
637
  const currentTime = nowTl?.time;
639
638
  const currentPhase = currentTime === "night" ? "NIGHT" : currentTime === "day" ? "DAY" : "NIGHT";
640
639
  const playersRaw = snapshotSeatMap ? [...snapshotSeatMap.values()] : [];
641
- const players = playersRaw.map((p) => decoratePlayer(p, characterMap, currentTurn));
642
- const effectorDecorated = effector ? players.find((p) => p.seat === effector.seat) ?? decoratePlayer(effector, characterMap, currentTurn) : void 0;
640
+ const players = playersRaw.map((p) => decoratePlayer(p, characterMap));
641
+ const effectorDecorated = effector ? players.find((p) => p.seat === effector.seat) ?? decoratePlayer(effector, characterMap) : void 0;
643
642
  const todayOps = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "day").flatMap((tl) => tl.operations ?? []);
644
643
  const tonightOps = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "night").flatMap((tl) => tl.operations ?? []);
645
644
  const yesterdayDayOps = timelines.filter((tl) => tl.turn === currentTurn - 1 && tl.time === "day").flatMap((tl) => tl.operations ?? []);
@@ -681,6 +680,7 @@ var buildDslContextFromLifetime = ({
681
680
  },
682
681
  currentTimeline: {
683
682
  turn: currentTurn,
683
+ previousTurn: currentTurn - 1,
684
684
  phase: currentPhase,
685
685
  time: currentTime,
686
686
  isFirstOfPhase: false,
@@ -869,13 +869,11 @@ var PLAYER_FIELDS = [
869
869
  { name: "alignment", type: "string", label: "\u9635\u8425", description: "GOOD / EVIL" },
870
870
  { name: "isDead", type: "boolean", label: "\u662F\u5426\u6B7B\u4EA1" },
871
871
  { name: "effectiveAlive", type: "boolean", label: "\u6709\u6548\u5B58\u6D3B", description: "\u8003\u8651 retainsAbility\uFF08ALIVENESS/ALL\uFF09\u540E\u662F\u5426\u6309\u5B58\u6D3B\u5904\u7406" },
872
- { name: "diedThisTurn", type: "boolean", label: "\u672C\u56DE\u5408\u6B7B\u4EA1" },
873
- { name: "wasExecuted", type: "boolean", label: "\u66FE\u88AB\u5904\u51B3" },
874
- { name: "wasExecutedToday", type: "boolean", label: "\u4ECA\u65E5\u88AB\u5904\u51B3" },
875
872
  { name: "characterId", type: "string", label: "\u89D2\u8272 ID" },
876
873
  { name: "characterKind", type: "string", label: "\u89D2\u8272\u7C7B\u578B", description: "Townsfolk / Outsiders / Minions / Demons" },
877
874
  { name: "deathCause", type: "string", label: "\u6B7B\u4EA1\u539F\u56E0", description: "EXECUTION / DEMON / ABILITY / STORYTELLER / OTHER" },
878
875
  { name: "deathTurn", type: "number", label: "\u6B7B\u4EA1\u56DE\u5408" },
876
+ { name: "deathTime", type: "string", label: "\u6B7B\u4EA1\u65F6\u6BB5", description: "day / night" },
879
877
  { name: "abilities", type: "string[]", label: "\u80FD\u529B ID \u5217\u8868" },
880
878
  { name: "reminderMarks", type: "string[]", label: "\u63D0\u793A\u7269 mark \u5217\u8868" },
881
879
  { name: "hasUsedDeadVote", type: "boolean", label: "\u662F\u5426\u4F7F\u7528\u8FC7\u6B7B\u4EA1\u6295\u7968" },
@@ -894,6 +892,7 @@ var NOMINATION_FIELDS = [
894
892
  ];
895
893
  var CURRENT_TIMELINE_FIELDS = [
896
894
  { name: "turn", type: "number", label: "\u5F53\u524D\u56DE\u5408" },
895
+ { name: "previousTurn", type: "number", label: "\u4E0A\u4E00\u56DE\u5408", description: "= turn - 1\uFF0C\u9996\u56DE\u5408\u4E3A -1" },
897
896
  { name: "phase", type: "string", label: "\u5F53\u524D\u9636\u6BB5", description: "NIGHT / DAY / DUSK / DAWN" },
898
897
  { name: "time", type: "string", label: "\u5F53\u524D\u65F6\u6BB5", description: "night / day" },
899
898
  { name: "isFirstOfPhase", type: "boolean", label: "\u662F\u5426\u672C\u9636\u6BB5\u9996\u6B21" },
@@ -1708,6 +1707,8 @@ var applyOperationToPlayers = ({
1708
1707
  abilityMap,
1709
1708
  nowTimelineIndex,
1710
1709
  operationInTimelineIdx: record.operationInTimelineIdx,
1710
+ operationTurn: timelines[record.operationInTimelineIdx]?.turn ?? 0,
1711
+ operationTime: timelines[record.operationInTimelineIdx]?.time ?? "night",
1711
1712
  makePlayersEffect
1712
1713
  };
1713
1714
  handler(context);
package/dist/index.mjs CHANGED
@@ -463,19 +463,20 @@ var applyStatusChange = createEffectHandler("STATUS_CHANGE", ({
463
463
  effect,
464
464
  payloads,
465
465
  makePlayersEffect,
466
- operationInTimelineIdx,
466
+ operationTurn,
467
467
  abilityMap,
468
- operation
468
+ operation,
469
+ operationTime
469
470
  }) => {
470
471
  const maybeStatus = getSourceValue(effect.source, payloads);
471
472
  if (maybeStatus === "DEAD") {
472
473
  const ability = abilityMap.get(operation.abilityId);
473
- const turn = operationInTimelineIdx >= 0 ? operationInTimelineIdx : 0;
474
474
  const cause = effect.deathCause ?? (ability?.category === "STORYTELLER" ? "STORYTELLER" : "ABILITY");
475
475
  makePlayersEffect.forEach((player) => {
476
476
  player.isDead = true;
477
477
  player.deathCause = cause;
478
- player.deathTurn = turn;
478
+ player.deathTurn = operationTurn;
479
+ player.deathTime = operationTime;
479
480
  });
480
481
  return;
481
482
  }
@@ -484,6 +485,7 @@ var applyStatusChange = createEffectHandler("STATUS_CHANGE", ({
484
485
  player.isDead = false;
485
486
  delete player.deathCause;
486
487
  delete player.deathTurn;
488
+ delete player.deathTime;
487
489
  });
488
490
  return;
489
491
  }
@@ -506,18 +508,14 @@ var effectHandlers = {
506
508
  };
507
509
 
508
510
  // src/dsl/context.ts
509
- var decoratePlayer = (player, characterMap, currentTurn) => {
511
+ var decoratePlayer = (player, characterMap) => {
510
512
  const isDead = Boolean(player.isDead);
511
513
  const retainsBypass = isDead && (player.retainsAbility === "ALIVENESS" || player.retainsAbility === "ALL");
512
- const wasExecuted = isDead && player.deathCause === "EXECUTION";
513
514
  return {
514
515
  ...player,
515
516
  characterKind: characterMap.get(player.characterId)?.kind,
516
517
  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
518
+ effectiveAlive: !isDead || retainsBypass
521
519
  };
522
520
  };
523
521
  var isExecutionTimeline = (tl) => {
@@ -525,7 +523,7 @@ var isExecutionTimeline = (tl) => {
525
523
  return (tl.operations ?? []).some((op) => op.kind === "execution");
526
524
  };
527
525
  var buildDslContextFromDerived = (derived, payload = []) => {
528
- const players = derived.players.map((p) => decoratePlayer(p, derived.characterMap, derived.currentTurn));
526
+ const players = derived.players.map((p) => decoratePlayer(p, derived.characterMap));
529
527
  const effector = players.find((p) => p.seat === derived.effectorSeat);
530
528
  const aliveCount = players.filter((p) => !p.isDead).length;
531
529
  const deadCount = players.length - aliveCount;
@@ -553,6 +551,7 @@ var buildDslContextFromDerived = (derived, payload = []) => {
553
551
  },
554
552
  currentTimeline: {
555
553
  turn: derived.currentTurn,
554
+ previousTurn: derived.currentTurn - 1,
556
555
  phase: derived.currentPhase,
557
556
  time: derived.currentPhase === "NIGHT" ? "night" : derived.currentPhase === "DAY" ? "day" : void 0,
558
557
  isFirstOfPhase: derived.isFirstOfPhase,
@@ -582,8 +581,8 @@ var buildDslContextFromLifetime = ({
582
581
  const currentTime = nowTl?.time;
583
582
  const currentPhase = currentTime === "night" ? "NIGHT" : currentTime === "day" ? "DAY" : "NIGHT";
584
583
  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;
584
+ const players = playersRaw.map((p) => decoratePlayer(p, characterMap));
585
+ const effectorDecorated = effector ? players.find((p) => p.seat === effector.seat) ?? decoratePlayer(effector, characterMap) : void 0;
587
586
  const todayOps = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "day").flatMap((tl) => tl.operations ?? []);
588
587
  const tonightOps = timelines.filter((tl) => tl.turn === currentTurn && tl.time === "night").flatMap((tl) => tl.operations ?? []);
589
588
  const yesterdayDayOps = timelines.filter((tl) => tl.turn === currentTurn - 1 && tl.time === "day").flatMap((tl) => tl.operations ?? []);
@@ -625,6 +624,7 @@ var buildDslContextFromLifetime = ({
625
624
  },
626
625
  currentTimeline: {
627
626
  turn: currentTurn,
627
+ previousTurn: currentTurn - 1,
628
628
  phase: currentPhase,
629
629
  time: currentTime,
630
630
  isFirstOfPhase: false,
@@ -813,13 +813,11 @@ var PLAYER_FIELDS = [
813
813
  { name: "alignment", type: "string", label: "\u9635\u8425", description: "GOOD / EVIL" },
814
814
  { name: "isDead", type: "boolean", label: "\u662F\u5426\u6B7B\u4EA1" },
815
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
816
  { name: "characterId", type: "string", label: "\u89D2\u8272 ID" },
820
817
  { name: "characterKind", type: "string", label: "\u89D2\u8272\u7C7B\u578B", description: "Townsfolk / Outsiders / Minions / Demons" },
821
818
  { name: "deathCause", type: "string", label: "\u6B7B\u4EA1\u539F\u56E0", description: "EXECUTION / DEMON / ABILITY / STORYTELLER / OTHER" },
822
819
  { name: "deathTurn", type: "number", label: "\u6B7B\u4EA1\u56DE\u5408" },
820
+ { name: "deathTime", type: "string", label: "\u6B7B\u4EA1\u65F6\u6BB5", description: "day / night" },
823
821
  { name: "abilities", type: "string[]", label: "\u80FD\u529B ID \u5217\u8868" },
824
822
  { name: "reminderMarks", type: "string[]", label: "\u63D0\u793A\u7269 mark \u5217\u8868" },
825
823
  { name: "hasUsedDeadVote", type: "boolean", label: "\u662F\u5426\u4F7F\u7528\u8FC7\u6B7B\u4EA1\u6295\u7968" },
@@ -838,6 +836,7 @@ var NOMINATION_FIELDS = [
838
836
  ];
839
837
  var CURRENT_TIMELINE_FIELDS = [
840
838
  { name: "turn", type: "number", label: "\u5F53\u524D\u56DE\u5408" },
839
+ { name: "previousTurn", type: "number", label: "\u4E0A\u4E00\u56DE\u5408", description: "= turn - 1\uFF0C\u9996\u56DE\u5408\u4E3A -1" },
841
840
  { name: "phase", type: "string", label: "\u5F53\u524D\u9636\u6BB5", description: "NIGHT / DAY / DUSK / DAWN" },
842
841
  { name: "time", type: "string", label: "\u5F53\u524D\u65F6\u6BB5", description: "night / day" },
843
842
  { name: "isFirstOfPhase", type: "boolean", label: "\u662F\u5426\u672C\u9636\u6BB5\u9996\u6B21" },
@@ -1652,6 +1651,8 @@ var applyOperationToPlayers = ({
1652
1651
  abilityMap,
1653
1652
  nowTimelineIndex,
1654
1653
  operationInTimelineIdx: record.operationInTimelineIdx,
1654
+ operationTurn: timelines[record.operationInTimelineIdx]?.turn ?? 0,
1655
+ operationTime: timelines[record.operationInTimelineIdx]?.time ?? "night",
1655
1656
  makePlayersEffect
1656
1657
  };
1657
1658
  handler(context);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bct-app/game-engine",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "Game engine utilities for BCT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,7 +30,7 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@bct-app/game-model": "0.1.12"
33
+ "@bct-app/game-model": "0.1.14"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@vitest/ui": "^4.1.3",