@bct-app/game-engine 0.1.13 → 0.1.15
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 +1 -6
- package/dist/index.d.ts +1 -6
- package/dist/index.js +60 -10
- package/dist/index.mjs +60 -10
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { TPlayer, TOperation, TAbility, TPopulatedCharacter, TTimeline, TTriggerPhase, TEffect, TTargetRef, TPlayerReminder, TReminder } from '@bct-app/game-model';
|
|
2
2
|
|
|
3
|
-
type TLifetimeStatusResolver = (input: {
|
|
4
|
-
player: TPlayer;
|
|
5
|
-
status: 'POISONED' | 'DRUNK' | 'HEALTHY';
|
|
6
|
-
}) => boolean;
|
|
7
3
|
type TLifetimeCustomResolver = (input: {
|
|
8
4
|
key: string;
|
|
9
5
|
payload?: unknown;
|
|
@@ -19,10 +15,9 @@ type TApplyOperationToPlayersArgs = {
|
|
|
19
15
|
characters: TPopulatedCharacter[];
|
|
20
16
|
timelines: TTimeline[];
|
|
21
17
|
timelineIndexAtNow?: number;
|
|
22
|
-
statusResolver?: TLifetimeStatusResolver;
|
|
23
18
|
customResolver?: TLifetimeCustomResolver;
|
|
24
19
|
};
|
|
25
|
-
declare const applyOperationToPlayers: ({ players, operations, allAbilities, characters, timelines, timelineIndexAtNow,
|
|
20
|
+
declare const applyOperationToPlayers: ({ players, operations, allAbilities, characters, timelines, timelineIndexAtNow, customResolver, }: TApplyOperationToPlayersArgs) => TPlayer[];
|
|
26
21
|
|
|
27
22
|
type TCanInvokeAbilityCustomResolver = (atom: {
|
|
28
23
|
resolverId: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { TPlayer, TOperation, TAbility, TPopulatedCharacter, TTimeline, TTriggerPhase, TEffect, TTargetRef, TPlayerReminder, TReminder } from '@bct-app/game-model';
|
|
2
2
|
|
|
3
|
-
type TLifetimeStatusResolver = (input: {
|
|
4
|
-
player: TPlayer;
|
|
5
|
-
status: 'POISONED' | 'DRUNK' | 'HEALTHY';
|
|
6
|
-
}) => boolean;
|
|
7
3
|
type TLifetimeCustomResolver = (input: {
|
|
8
4
|
key: string;
|
|
9
5
|
payload?: unknown;
|
|
@@ -19,10 +15,9 @@ type TApplyOperationToPlayersArgs = {
|
|
|
19
15
|
characters: TPopulatedCharacter[];
|
|
20
16
|
timelines: TTimeline[];
|
|
21
17
|
timelineIndexAtNow?: number;
|
|
22
|
-
statusResolver?: TLifetimeStatusResolver;
|
|
23
18
|
customResolver?: TLifetimeCustomResolver;
|
|
24
19
|
};
|
|
25
|
-
declare const applyOperationToPlayers: ({ players, operations, allAbilities, characters, timelines, timelineIndexAtNow,
|
|
20
|
+
declare const applyOperationToPlayers: ({ players, operations, allAbilities, characters, timelines, timelineIndexAtNow, customResolver, }: TApplyOperationToPlayersArgs) => TPlayer[];
|
|
26
21
|
|
|
27
22
|
type TCanInvokeAbilityCustomResolver = (atom: {
|
|
28
23
|
resolverId: string;
|
package/dist/index.js
CHANGED
|
@@ -843,10 +843,6 @@ var evalPlayerStateOnPlayer = (player, atom, ctx) => {
|
|
|
843
843
|
if (field === "IS_DEAD") {
|
|
844
844
|
return compareBool(Boolean(player.isDead), op, value);
|
|
845
845
|
}
|
|
846
|
-
if (field === "IS_POISONED" || field === "IS_DRUNK" || field === "IS_HEALTHY") {
|
|
847
|
-
const resolved = ctx.statusResolver ? ctx.statusResolver({ player, status: field === "IS_POISONED" ? "POISONED" : field === "IS_DRUNK" ? "DRUNK" : "HEALTHY" }) : false;
|
|
848
|
-
return compareBool(resolved, op, value);
|
|
849
|
-
}
|
|
850
846
|
if (field === "CHARACTER_ID") {
|
|
851
847
|
return compareString(player.characterId, op, value);
|
|
852
848
|
}
|
|
@@ -1025,7 +1021,6 @@ var evaluateLifetime = ({
|
|
|
1025
1021
|
snapshotSeatMap,
|
|
1026
1022
|
characterMap,
|
|
1027
1023
|
payloads,
|
|
1028
|
-
statusResolver,
|
|
1029
1024
|
customResolver
|
|
1030
1025
|
}) => {
|
|
1031
1026
|
const lifetime = getLifetime(effect, payloads);
|
|
@@ -1040,7 +1035,6 @@ var evaluateLifetime = ({
|
|
|
1040
1035
|
snapshotSeatMap,
|
|
1041
1036
|
characterMap,
|
|
1042
1037
|
payloads,
|
|
1043
|
-
statusResolver,
|
|
1044
1038
|
customResolver
|
|
1045
1039
|
};
|
|
1046
1040
|
const expr = lifetime.expr;
|
|
@@ -1050,6 +1044,34 @@ var evaluateLifetime = ({
|
|
|
1050
1044
|
}
|
|
1051
1045
|
return targets.filter((target) => evalExpr(expr, { ...baseCtx, target }));
|
|
1052
1046
|
};
|
|
1047
|
+
var evaluatePrecondition = ({
|
|
1048
|
+
expr,
|
|
1049
|
+
operationTimelineIdx,
|
|
1050
|
+
nowTimelineIndex,
|
|
1051
|
+
timelines,
|
|
1052
|
+
effector,
|
|
1053
|
+
targets,
|
|
1054
|
+
snapshotSeatMap,
|
|
1055
|
+
characterMap,
|
|
1056
|
+
payloads,
|
|
1057
|
+
customResolver
|
|
1058
|
+
}) => {
|
|
1059
|
+
const baseCtx = {
|
|
1060
|
+
operationTimelineIdx,
|
|
1061
|
+
nowTimelineIndex,
|
|
1062
|
+
timelines,
|
|
1063
|
+
effector,
|
|
1064
|
+
snapshotSeatMap,
|
|
1065
|
+
characterMap,
|
|
1066
|
+
payloads,
|
|
1067
|
+
customResolver
|
|
1068
|
+
};
|
|
1069
|
+
const dependsOnTarget = expressionReferencesTarget(expr);
|
|
1070
|
+
if (!dependsOnTarget) {
|
|
1071
|
+
return evalExpr(expr, { ...baseCtx, target: void 0 }) ? targets : [];
|
|
1072
|
+
}
|
|
1073
|
+
return targets.filter((target) => evalExpr(expr, { ...baseCtx, target }));
|
|
1074
|
+
};
|
|
1053
1075
|
|
|
1054
1076
|
// src/apply-operation.ts
|
|
1055
1077
|
var isDeferredOperation = (operation, abilityMap) => {
|
|
@@ -1070,7 +1092,6 @@ var applyOperationToPlayers = ({
|
|
|
1070
1092
|
characters,
|
|
1071
1093
|
timelines,
|
|
1072
1094
|
timelineIndexAtNow,
|
|
1073
|
-
statusResolver,
|
|
1074
1095
|
customResolver
|
|
1075
1096
|
}) => {
|
|
1076
1097
|
if (operations.length === 0) {
|
|
@@ -1089,6 +1110,7 @@ var applyOperationToPlayers = ({
|
|
|
1089
1110
|
}
|
|
1090
1111
|
operationsByTimeline.get(timelineIndex)?.push(operation);
|
|
1091
1112
|
});
|
|
1113
|
+
const preconditionCache = /* @__PURE__ */ new Map();
|
|
1092
1114
|
const runReplay = (lifetimeSnapshotSeatMap) => {
|
|
1093
1115
|
const playersWithStatus = copyPlayers(players);
|
|
1094
1116
|
const applyOpsSequence = (ops) => {
|
|
@@ -1110,7 +1132,7 @@ var applyOperationToPlayers = ({
|
|
|
1110
1132
|
}
|
|
1111
1133
|
return snapshotSeatMap;
|
|
1112
1134
|
};
|
|
1113
|
-
ability.effects.forEach((effect) => {
|
|
1135
|
+
ability.effects.forEach((effect, effectIdx) => {
|
|
1114
1136
|
const resolvedTargets = resolveEffectTargets({
|
|
1115
1137
|
effect,
|
|
1116
1138
|
operation,
|
|
@@ -1122,17 +1144,45 @@ var applyOperationToPlayers = ({
|
|
|
1122
1144
|
if (!resolvedTargets) {
|
|
1123
1145
|
return;
|
|
1124
1146
|
}
|
|
1147
|
+
const precondition = "precondition" in effect ? effect.precondition : void 0;
|
|
1148
|
+
let gatedTargets;
|
|
1149
|
+
if (precondition) {
|
|
1150
|
+
const cachedSeats = preconditionCache.get(operation)?.get(effectIdx);
|
|
1151
|
+
if (cachedSeats) {
|
|
1152
|
+
gatedTargets = resolvedTargets.filter((t) => cachedSeats.has(t.seat));
|
|
1153
|
+
} else {
|
|
1154
|
+
gatedTargets = evaluatePrecondition({
|
|
1155
|
+
expr: precondition,
|
|
1156
|
+
operationTimelineIdx: operationInTimelineIdx,
|
|
1157
|
+
nowTimelineIndex,
|
|
1158
|
+
timelines,
|
|
1159
|
+
effector,
|
|
1160
|
+
targets: resolvedTargets,
|
|
1161
|
+
snapshotSeatMap: playerSeatMap,
|
|
1162
|
+
characterMap,
|
|
1163
|
+
payloads,
|
|
1164
|
+
customResolver
|
|
1165
|
+
});
|
|
1166
|
+
const opCache = preconditionCache.get(operation) ?? /* @__PURE__ */ new Map();
|
|
1167
|
+
opCache.set(effectIdx, new Set(gatedTargets.map((t) => t.seat)));
|
|
1168
|
+
preconditionCache.set(operation, opCache);
|
|
1169
|
+
}
|
|
1170
|
+
} else {
|
|
1171
|
+
gatedTargets = resolvedTargets;
|
|
1172
|
+
}
|
|
1173
|
+
if (gatedTargets.length === 0 && resolvedTargets.length > 0) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1125
1176
|
const makePlayersEffect = evaluateLifetime({
|
|
1126
1177
|
effect,
|
|
1127
1178
|
operationTimelineIdx: operationInTimelineIdx,
|
|
1128
1179
|
nowTimelineIndex,
|
|
1129
1180
|
timelines,
|
|
1130
1181
|
effector,
|
|
1131
|
-
targets:
|
|
1182
|
+
targets: gatedTargets,
|
|
1132
1183
|
snapshotSeatMap: lifetimeSnapshotSeatMap,
|
|
1133
1184
|
characterMap,
|
|
1134
1185
|
payloads,
|
|
1135
|
-
statusResolver,
|
|
1136
1186
|
customResolver
|
|
1137
1187
|
});
|
|
1138
1188
|
const handler = effectHandlers[effect.type];
|
package/dist/index.mjs
CHANGED
|
@@ -803,10 +803,6 @@ var evalPlayerStateOnPlayer = (player, atom, ctx) => {
|
|
|
803
803
|
if (field === "IS_DEAD") {
|
|
804
804
|
return compareBool(Boolean(player.isDead), op, value);
|
|
805
805
|
}
|
|
806
|
-
if (field === "IS_POISONED" || field === "IS_DRUNK" || field === "IS_HEALTHY") {
|
|
807
|
-
const resolved = ctx.statusResolver ? ctx.statusResolver({ player, status: field === "IS_POISONED" ? "POISONED" : field === "IS_DRUNK" ? "DRUNK" : "HEALTHY" }) : false;
|
|
808
|
-
return compareBool(resolved, op, value);
|
|
809
|
-
}
|
|
810
806
|
if (field === "CHARACTER_ID") {
|
|
811
807
|
return compareString(player.characterId, op, value);
|
|
812
808
|
}
|
|
@@ -985,7 +981,6 @@ var evaluateLifetime = ({
|
|
|
985
981
|
snapshotSeatMap,
|
|
986
982
|
characterMap,
|
|
987
983
|
payloads,
|
|
988
|
-
statusResolver,
|
|
989
984
|
customResolver
|
|
990
985
|
}) => {
|
|
991
986
|
const lifetime = getLifetime(effect, payloads);
|
|
@@ -1000,7 +995,6 @@ var evaluateLifetime = ({
|
|
|
1000
995
|
snapshotSeatMap,
|
|
1001
996
|
characterMap,
|
|
1002
997
|
payloads,
|
|
1003
|
-
statusResolver,
|
|
1004
998
|
customResolver
|
|
1005
999
|
};
|
|
1006
1000
|
const expr = lifetime.expr;
|
|
@@ -1010,6 +1004,34 @@ var evaluateLifetime = ({
|
|
|
1010
1004
|
}
|
|
1011
1005
|
return targets.filter((target) => evalExpr(expr, { ...baseCtx, target }));
|
|
1012
1006
|
};
|
|
1007
|
+
var evaluatePrecondition = ({
|
|
1008
|
+
expr,
|
|
1009
|
+
operationTimelineIdx,
|
|
1010
|
+
nowTimelineIndex,
|
|
1011
|
+
timelines,
|
|
1012
|
+
effector,
|
|
1013
|
+
targets,
|
|
1014
|
+
snapshotSeatMap,
|
|
1015
|
+
characterMap,
|
|
1016
|
+
payloads,
|
|
1017
|
+
customResolver
|
|
1018
|
+
}) => {
|
|
1019
|
+
const baseCtx = {
|
|
1020
|
+
operationTimelineIdx,
|
|
1021
|
+
nowTimelineIndex,
|
|
1022
|
+
timelines,
|
|
1023
|
+
effector,
|
|
1024
|
+
snapshotSeatMap,
|
|
1025
|
+
characterMap,
|
|
1026
|
+
payloads,
|
|
1027
|
+
customResolver
|
|
1028
|
+
};
|
|
1029
|
+
const dependsOnTarget = expressionReferencesTarget(expr);
|
|
1030
|
+
if (!dependsOnTarget) {
|
|
1031
|
+
return evalExpr(expr, { ...baseCtx, target: void 0 }) ? targets : [];
|
|
1032
|
+
}
|
|
1033
|
+
return targets.filter((target) => evalExpr(expr, { ...baseCtx, target }));
|
|
1034
|
+
};
|
|
1013
1035
|
|
|
1014
1036
|
// src/apply-operation.ts
|
|
1015
1037
|
var isDeferredOperation = (operation, abilityMap) => {
|
|
@@ -1030,7 +1052,6 @@ var applyOperationToPlayers = ({
|
|
|
1030
1052
|
characters,
|
|
1031
1053
|
timelines,
|
|
1032
1054
|
timelineIndexAtNow,
|
|
1033
|
-
statusResolver,
|
|
1034
1055
|
customResolver
|
|
1035
1056
|
}) => {
|
|
1036
1057
|
if (operations.length === 0) {
|
|
@@ -1049,6 +1070,7 @@ var applyOperationToPlayers = ({
|
|
|
1049
1070
|
}
|
|
1050
1071
|
operationsByTimeline.get(timelineIndex)?.push(operation);
|
|
1051
1072
|
});
|
|
1073
|
+
const preconditionCache = /* @__PURE__ */ new Map();
|
|
1052
1074
|
const runReplay = (lifetimeSnapshotSeatMap) => {
|
|
1053
1075
|
const playersWithStatus = copyPlayers(players);
|
|
1054
1076
|
const applyOpsSequence = (ops) => {
|
|
@@ -1070,7 +1092,7 @@ var applyOperationToPlayers = ({
|
|
|
1070
1092
|
}
|
|
1071
1093
|
return snapshotSeatMap;
|
|
1072
1094
|
};
|
|
1073
|
-
ability.effects.forEach((effect) => {
|
|
1095
|
+
ability.effects.forEach((effect, effectIdx) => {
|
|
1074
1096
|
const resolvedTargets = resolveEffectTargets({
|
|
1075
1097
|
effect,
|
|
1076
1098
|
operation,
|
|
@@ -1082,17 +1104,45 @@ var applyOperationToPlayers = ({
|
|
|
1082
1104
|
if (!resolvedTargets) {
|
|
1083
1105
|
return;
|
|
1084
1106
|
}
|
|
1107
|
+
const precondition = "precondition" in effect ? effect.precondition : void 0;
|
|
1108
|
+
let gatedTargets;
|
|
1109
|
+
if (precondition) {
|
|
1110
|
+
const cachedSeats = preconditionCache.get(operation)?.get(effectIdx);
|
|
1111
|
+
if (cachedSeats) {
|
|
1112
|
+
gatedTargets = resolvedTargets.filter((t) => cachedSeats.has(t.seat));
|
|
1113
|
+
} else {
|
|
1114
|
+
gatedTargets = evaluatePrecondition({
|
|
1115
|
+
expr: precondition,
|
|
1116
|
+
operationTimelineIdx: operationInTimelineIdx,
|
|
1117
|
+
nowTimelineIndex,
|
|
1118
|
+
timelines,
|
|
1119
|
+
effector,
|
|
1120
|
+
targets: resolvedTargets,
|
|
1121
|
+
snapshotSeatMap: playerSeatMap,
|
|
1122
|
+
characterMap,
|
|
1123
|
+
payloads,
|
|
1124
|
+
customResolver
|
|
1125
|
+
});
|
|
1126
|
+
const opCache = preconditionCache.get(operation) ?? /* @__PURE__ */ new Map();
|
|
1127
|
+
opCache.set(effectIdx, new Set(gatedTargets.map((t) => t.seat)));
|
|
1128
|
+
preconditionCache.set(operation, opCache);
|
|
1129
|
+
}
|
|
1130
|
+
} else {
|
|
1131
|
+
gatedTargets = resolvedTargets;
|
|
1132
|
+
}
|
|
1133
|
+
if (gatedTargets.length === 0 && resolvedTargets.length > 0) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1085
1136
|
const makePlayersEffect = evaluateLifetime({
|
|
1086
1137
|
effect,
|
|
1087
1138
|
operationTimelineIdx: operationInTimelineIdx,
|
|
1088
1139
|
nowTimelineIndex,
|
|
1089
1140
|
timelines,
|
|
1090
1141
|
effector,
|
|
1091
|
-
targets:
|
|
1142
|
+
targets: gatedTargets,
|
|
1092
1143
|
snapshotSeatMap: lifetimeSnapshotSeatMap,
|
|
1093
1144
|
characterMap,
|
|
1094
1145
|
payloads,
|
|
1095
|
-
statusResolver,
|
|
1096
1146
|
customResolver
|
|
1097
1147
|
});
|
|
1098
1148
|
const handler = effectHandlers[effect.type];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bct-app/game-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
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.
|
|
33
|
+
"@bct-app/game-model": "0.1.9"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@vitest/ui": "^4.1.3",
|