@drmxrcy/tcg-core 0.0.0-202602060542
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/README.md +882 -0
- package/package.json +58 -0
- package/src/__tests__/alpha-clash-engine-definition.test.ts +319 -0
- package/src/__tests__/createMockAlphaClashGame.ts +462 -0
- package/src/__tests__/createMockGrandArchiveGame.ts +373 -0
- package/src/__tests__/createMockGundamGame.ts +379 -0
- package/src/__tests__/createMockLorcanaGame.ts +328 -0
- package/src/__tests__/createMockOnePieceGame.ts +429 -0
- package/src/__tests__/createMockRiftboundGame.ts +462 -0
- package/src/__tests__/grand-archive-engine-definition.test.ts +118 -0
- package/src/__tests__/gundam-engine-definition.test.ts +110 -0
- package/src/__tests__/integration-complete-game.test.ts +508 -0
- package/src/__tests__/integration-network-sync.test.ts +469 -0
- package/src/__tests__/lorcana-engine-definition.test.ts +100 -0
- package/src/__tests__/move-enumeration.test.ts +725 -0
- package/src/__tests__/multiplayer-engine.test.ts +555 -0
- package/src/__tests__/one-piece-engine-definition.test.ts +114 -0
- package/src/__tests__/riftbound-engine-definition.test.ts +124 -0
- package/src/actions/action-definition.test.ts +201 -0
- package/src/actions/action-definition.ts +122 -0
- package/src/actions/action-timing.test.ts +490 -0
- package/src/actions/action-timing.ts +257 -0
- package/src/cards/card-definition.test.ts +268 -0
- package/src/cards/card-definition.ts +27 -0
- package/src/cards/card-instance.test.ts +422 -0
- package/src/cards/card-instance.ts +49 -0
- package/src/cards/computed-properties.test.ts +530 -0
- package/src/cards/computed-properties.ts +84 -0
- package/src/cards/conditional-modifiers.test.ts +390 -0
- package/src/cards/modifiers.test.ts +286 -0
- package/src/cards/modifiers.ts +51 -0
- package/src/engine/MULTIPLAYER.md +425 -0
- package/src/engine/__tests__/rule-engine-flow.test.ts +348 -0
- package/src/engine/__tests__/rule-engine-history.test.ts +535 -0
- package/src/engine/__tests__/rule-engine-moves.test.ts +488 -0
- package/src/engine/__tests__/rule-engine.test.ts +366 -0
- package/src/engine/index.ts +14 -0
- package/src/engine/multiplayer-engine.example.ts +571 -0
- package/src/engine/multiplayer-engine.ts +409 -0
- package/src/engine/rule-engine.test.ts +286 -0
- package/src/engine/rule-engine.ts +1539 -0
- package/src/engine/tracker-system.ts +172 -0
- package/src/examples/__tests__/coin-flip-game.test.ts +641 -0
- package/src/filtering/card-filter.test.ts +230 -0
- package/src/filtering/card-filter.ts +91 -0
- package/src/filtering/card-query.test.ts +901 -0
- package/src/filtering/card-query.ts +273 -0
- package/src/filtering/filter-matching.test.ts +944 -0
- package/src/filtering/filter-matching.ts +315 -0
- package/src/flow/SERIALIZATION.md +428 -0
- package/src/flow/__tests__/flow-definition.test.ts +427 -0
- package/src/flow/__tests__/flow-manager.test.ts +756 -0
- package/src/flow/__tests__/flow-serialization.test.ts +565 -0
- package/src/flow/flow-definition.ts +453 -0
- package/src/flow/flow-manager.ts +1044 -0
- package/src/flow/index.ts +35 -0
- package/src/game-definition/__tests__/game-definition-validation.test.ts +359 -0
- package/src/game-definition/__tests__/game-definition.test.ts +291 -0
- package/src/game-definition/__tests__/move-definitions.test.ts +328 -0
- package/src/game-definition/game-definition.ts +261 -0
- package/src/game-definition/index.ts +28 -0
- package/src/game-definition/move-definitions.ts +188 -0
- package/src/game-definition/validation.ts +183 -0
- package/src/history/history-manager.test.ts +497 -0
- package/src/history/history-manager.ts +312 -0
- package/src/history/history-operations.ts +122 -0
- package/src/history/index.ts +9 -0
- package/src/history/types.ts +255 -0
- package/src/index.ts +32 -0
- package/src/logging/index.ts +27 -0
- package/src/logging/log-formatter.ts +187 -0
- package/src/logging/logger.ts +276 -0
- package/src/logging/types.ts +148 -0
- package/src/moves/create-move.test.ts +331 -0
- package/src/moves/create-move.ts +64 -0
- package/src/moves/move-enumeration.ts +228 -0
- package/src/moves/move-executor.test.ts +431 -0
- package/src/moves/move-executor.ts +195 -0
- package/src/moves/move-system.test.ts +380 -0
- package/src/moves/move-system.ts +463 -0
- package/src/moves/standard-moves.ts +231 -0
- package/src/operations/card-operations.test.ts +236 -0
- package/src/operations/card-operations.ts +116 -0
- package/src/operations/card-registry-impl.test.ts +251 -0
- package/src/operations/card-registry-impl.ts +70 -0
- package/src/operations/card-registry.test.ts +234 -0
- package/src/operations/card-registry.ts +106 -0
- package/src/operations/counter-operations.ts +152 -0
- package/src/operations/game-operations.test.ts +280 -0
- package/src/operations/game-operations.ts +140 -0
- package/src/operations/index.ts +24 -0
- package/src/operations/operations-impl.test.ts +354 -0
- package/src/operations/operations-impl.ts +468 -0
- package/src/operations/zone-operations.test.ts +295 -0
- package/src/operations/zone-operations.ts +223 -0
- package/src/rng/seeded-rng.test.ts +339 -0
- package/src/rng/seeded-rng.ts +123 -0
- package/src/targeting/index.ts +48 -0
- package/src/targeting/target-definition.test.ts +273 -0
- package/src/targeting/target-definition.ts +37 -0
- package/src/targeting/target-dsl.ts +279 -0
- package/src/targeting/target-resolver.ts +486 -0
- package/src/targeting/target-validation.test.ts +994 -0
- package/src/targeting/target-validation.ts +286 -0
- package/src/telemetry/events.ts +202 -0
- package/src/telemetry/index.ts +21 -0
- package/src/telemetry/telemetry-manager.ts +127 -0
- package/src/telemetry/types.ts +68 -0
- package/src/testing/__tests__/testing-utilities-integration.test.ts +161 -0
- package/src/testing/index.ts +88 -0
- package/src/testing/test-assertions.test.ts +341 -0
- package/src/testing/test-assertions.ts +256 -0
- package/src/testing/test-card-factory.test.ts +228 -0
- package/src/testing/test-card-factory.ts +111 -0
- package/src/testing/test-context-factory.ts +187 -0
- package/src/testing/test-end-assertions.test.ts +262 -0
- package/src/testing/test-end-assertions.ts +95 -0
- package/src/testing/test-engine-builder.test.ts +389 -0
- package/src/testing/test-engine-builder.ts +46 -0
- package/src/testing/test-flow-assertions.test.ts +284 -0
- package/src/testing/test-flow-assertions.ts +115 -0
- package/src/testing/test-player-builder.test.ts +132 -0
- package/src/testing/test-player-builder.ts +46 -0
- package/src/testing/test-replay-assertions.test.ts +356 -0
- package/src/testing/test-replay-assertions.ts +164 -0
- package/src/testing/test-rng-helpers.test.ts +260 -0
- package/src/testing/test-rng-helpers.ts +190 -0
- package/src/testing/test-state-builder.test.ts +373 -0
- package/src/testing/test-state-builder.ts +99 -0
- package/src/testing/test-zone-factory.test.ts +295 -0
- package/src/testing/test-zone-factory.ts +224 -0
- package/src/types/branded-utils.ts +54 -0
- package/src/types/branded.test.ts +175 -0
- package/src/types/branded.ts +33 -0
- package/src/types/index.ts +8 -0
- package/src/types/state.test.ts +198 -0
- package/src/types/state.ts +154 -0
- package/src/validation/card-type-guards.test.ts +242 -0
- package/src/validation/card-type-guards.ts +179 -0
- package/src/validation/index.ts +40 -0
- package/src/validation/schema-builders.test.ts +403 -0
- package/src/validation/schema-builders.ts +345 -0
- package/src/validation/type-guard-builder.test.ts +216 -0
- package/src/validation/type-guard-builder.ts +109 -0
- package/src/validation/validator-builder.test.ts +375 -0
- package/src/validation/validator-builder.ts +273 -0
- package/src/zones/index.ts +28 -0
- package/src/zones/zone-factory.test.ts +183 -0
- package/src/zones/zone-factory.ts +44 -0
- package/src/zones/zone-operations.test.ts +800 -0
- package/src/zones/zone-operations.ts +306 -0
- package/src/zones/zone-state-helpers.test.ts +337 -0
- package/src/zones/zone-state-helpers.ts +128 -0
- package/src/zones/zone-visibility.test.ts +156 -0
- package/src/zones/zone-visibility.ts +36 -0
- package/src/zones/zone.test.ts +186 -0
- package/src/zones/zone.ts +66 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { createPlayerId } from "../types";
|
|
3
|
+
import type { InternalState } from "../types/state";
|
|
4
|
+
import { createGameOperations } from "./operations-impl";
|
|
5
|
+
|
|
6
|
+
// Helper to create PlayerId for tests
|
|
7
|
+
const playerId = createPlayerId;
|
|
8
|
+
|
|
9
|
+
describe("GameOperations", () => {
|
|
10
|
+
const createTestState = (): InternalState => ({
|
|
11
|
+
zones: {},
|
|
12
|
+
cards: {},
|
|
13
|
+
cardMetas: {},
|
|
14
|
+
otp: undefined,
|
|
15
|
+
pendingMulligan: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("OTP Operations", () => {
|
|
19
|
+
it("should set OTP player", () => {
|
|
20
|
+
const state = createTestState();
|
|
21
|
+
const ops = createGameOperations(state);
|
|
22
|
+
|
|
23
|
+
ops.setOTP(playerId("player-1"));
|
|
24
|
+
|
|
25
|
+
expect(state.otp).toBe(playerId("player-1"));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should get OTP player", () => {
|
|
29
|
+
const state = createTestState();
|
|
30
|
+
state.otp = playerId("player-2");
|
|
31
|
+
const ops = createGameOperations(state);
|
|
32
|
+
|
|
33
|
+
const otp = ops.getOTP();
|
|
34
|
+
|
|
35
|
+
expect(otp).toBe(playerId("player-2"));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should return undefined when OTP not set", () => {
|
|
39
|
+
const state = createTestState();
|
|
40
|
+
const ops = createGameOperations(state);
|
|
41
|
+
|
|
42
|
+
const otp = ops.getOTP();
|
|
43
|
+
|
|
44
|
+
expect(otp).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should overwrite existing OTP", () => {
|
|
48
|
+
const state = createTestState();
|
|
49
|
+
state.otp = playerId("player-1");
|
|
50
|
+
const ops = createGameOperations(state);
|
|
51
|
+
|
|
52
|
+
ops.setOTP(playerId("player-2"));
|
|
53
|
+
|
|
54
|
+
expect(state.otp).toBe(playerId("player-2"));
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("Pending Mulligan Operations", () => {
|
|
59
|
+
it("should set pending mulligan list", () => {
|
|
60
|
+
const state = createTestState();
|
|
61
|
+
const ops = createGameOperations(state);
|
|
62
|
+
|
|
63
|
+
ops.setPendingMulligan([playerId("player-1"), playerId("player-2")]);
|
|
64
|
+
|
|
65
|
+
expect(state.pendingMulligan).toEqual([
|
|
66
|
+
playerId("player-1"),
|
|
67
|
+
playerId("player-2"),
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should get pending mulligan list", () => {
|
|
72
|
+
const state = createTestState();
|
|
73
|
+
state.pendingMulligan = [playerId("player-1"), playerId("player-2")];
|
|
74
|
+
const ops = createGameOperations(state);
|
|
75
|
+
|
|
76
|
+
const pending = ops.getPendingMulligan();
|
|
77
|
+
|
|
78
|
+
expect(pending).toEqual([playerId("player-1"), playerId("player-2")]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should return copy of pending mulligan list to prevent mutation", () => {
|
|
82
|
+
const state = createTestState();
|
|
83
|
+
state.pendingMulligan = [playerId("player-1")];
|
|
84
|
+
const ops = createGameOperations(state);
|
|
85
|
+
|
|
86
|
+
const pending = ops.getPendingMulligan();
|
|
87
|
+
pending.push(playerId("player-2"));
|
|
88
|
+
|
|
89
|
+
expect(state.pendingMulligan).toEqual([playerId("player-1")]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should return empty array when pending mulligan not set", () => {
|
|
93
|
+
const state = createTestState();
|
|
94
|
+
const ops = createGameOperations(state);
|
|
95
|
+
|
|
96
|
+
const pending = ops.getPendingMulligan();
|
|
97
|
+
|
|
98
|
+
expect(pending).toEqual([]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should add player to pending mulligan list", () => {
|
|
102
|
+
const state = createTestState();
|
|
103
|
+
state.pendingMulligan = [playerId("player-1")];
|
|
104
|
+
const ops = createGameOperations(state);
|
|
105
|
+
|
|
106
|
+
ops.addPendingMulligan(playerId("player-2"));
|
|
107
|
+
|
|
108
|
+
expect(state.pendingMulligan).toEqual([
|
|
109
|
+
playerId("player-1"),
|
|
110
|
+
playerId("player-2"),
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should not add duplicate player to pending mulligan list", () => {
|
|
115
|
+
const state = createTestState();
|
|
116
|
+
state.pendingMulligan = [playerId("player-1")];
|
|
117
|
+
const ops = createGameOperations(state);
|
|
118
|
+
|
|
119
|
+
ops.addPendingMulligan(playerId("player-1"));
|
|
120
|
+
|
|
121
|
+
expect(state.pendingMulligan).toEqual([playerId("player-1")]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should initialize list when adding to undefined pending mulligan", () => {
|
|
125
|
+
const state = createTestState();
|
|
126
|
+
const ops = createGameOperations(state);
|
|
127
|
+
|
|
128
|
+
ops.addPendingMulligan(playerId("player-1"));
|
|
129
|
+
|
|
130
|
+
expect(state.pendingMulligan).toEqual([playerId("player-1")]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should remove player from pending mulligan list", () => {
|
|
134
|
+
const state = createTestState();
|
|
135
|
+
state.pendingMulligan = [
|
|
136
|
+
playerId("player-1"),
|
|
137
|
+
playerId("player-2"),
|
|
138
|
+
playerId("player-3"),
|
|
139
|
+
];
|
|
140
|
+
const ops = createGameOperations(state);
|
|
141
|
+
|
|
142
|
+
ops.removePendingMulligan(playerId("player-2"));
|
|
143
|
+
|
|
144
|
+
expect(state.pendingMulligan).toEqual([
|
|
145
|
+
playerId("player-1"),
|
|
146
|
+
playerId("player-3"),
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should handle removing player not in list", () => {
|
|
151
|
+
const state = createTestState();
|
|
152
|
+
state.pendingMulligan = [playerId("player-1")];
|
|
153
|
+
const ops = createGameOperations(state);
|
|
154
|
+
|
|
155
|
+
ops.removePendingMulligan(playerId("player-2"));
|
|
156
|
+
|
|
157
|
+
expect(state.pendingMulligan).toEqual([playerId("player-1")]);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should handle removing from empty list", () => {
|
|
161
|
+
const state = createTestState();
|
|
162
|
+
state.pendingMulligan = [];
|
|
163
|
+
const ops = createGameOperations(state);
|
|
164
|
+
|
|
165
|
+
ops.removePendingMulligan(playerId("player-1"));
|
|
166
|
+
|
|
167
|
+
expect(state.pendingMulligan).toEqual([]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should handle removing from undefined list", () => {
|
|
171
|
+
const state = createTestState();
|
|
172
|
+
const ops = createGameOperations(state);
|
|
173
|
+
|
|
174
|
+
ops.removePendingMulligan(playerId("player-1"));
|
|
175
|
+
|
|
176
|
+
expect(state.pendingMulligan).toBeUndefined();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("should replace entire list with setPendingMulligan", () => {
|
|
180
|
+
const state = createTestState();
|
|
181
|
+
state.pendingMulligan = [playerId("player-1"), playerId("player-2")];
|
|
182
|
+
const ops = createGameOperations(state);
|
|
183
|
+
|
|
184
|
+
ops.setPendingMulligan([playerId("player-3"), playerId("player-4")]);
|
|
185
|
+
|
|
186
|
+
expect(state.pendingMulligan).toEqual([
|
|
187
|
+
playerId("player-3"),
|
|
188
|
+
playerId("player-4"),
|
|
189
|
+
]);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("Choosing First Player Operations", () => {
|
|
194
|
+
it("should set choosing first player", () => {
|
|
195
|
+
const state = createTestState();
|
|
196
|
+
const ops = createGameOperations(state);
|
|
197
|
+
|
|
198
|
+
ops.setChoosingFirstPlayer(playerId("player-1"));
|
|
199
|
+
|
|
200
|
+
expect(state.choosingFirstPlayer).toBe(playerId("player-1"));
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should get choosing first player", () => {
|
|
204
|
+
const state = createTestState();
|
|
205
|
+
state.choosingFirstPlayer = playerId("player-2");
|
|
206
|
+
const ops = createGameOperations(state);
|
|
207
|
+
|
|
208
|
+
const chooser = ops.getChoosingFirstPlayer();
|
|
209
|
+
|
|
210
|
+
expect(chooser).toBe(playerId("player-2"));
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("should return undefined when choosing first player not set", () => {
|
|
214
|
+
const state = createTestState();
|
|
215
|
+
const ops = createGameOperations(state);
|
|
216
|
+
|
|
217
|
+
const chooser = ops.getChoosingFirstPlayer();
|
|
218
|
+
|
|
219
|
+
expect(chooser).toBeUndefined();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("should overwrite existing choosing first player", () => {
|
|
223
|
+
const state = createTestState();
|
|
224
|
+
state.choosingFirstPlayer = playerId("player-1");
|
|
225
|
+
const ops = createGameOperations(state);
|
|
226
|
+
|
|
227
|
+
ops.setChoosingFirstPlayer(playerId("player-2"));
|
|
228
|
+
|
|
229
|
+
expect(state.choosingFirstPlayer).toBe(playerId("player-2"));
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe("Integration", () => {
|
|
234
|
+
it("should handle typical game setup flow", () => {
|
|
235
|
+
const state = createTestState();
|
|
236
|
+
const ops = createGameOperations(state);
|
|
237
|
+
|
|
238
|
+
// Choose first player
|
|
239
|
+
ops.setOTP(playerId("player-1"));
|
|
240
|
+
|
|
241
|
+
// Set all players pending mulligan
|
|
242
|
+
ops.setPendingMulligan([playerId("player-1"), playerId("player-2")]);
|
|
243
|
+
|
|
244
|
+
// Verify state
|
|
245
|
+
expect(ops.getOTP()).toBe(playerId("player-1"));
|
|
246
|
+
expect(ops.getPendingMulligan()).toEqual([
|
|
247
|
+
playerId("player-1"),
|
|
248
|
+
playerId("player-2"),
|
|
249
|
+
]);
|
|
250
|
+
|
|
251
|
+
// Player 1 decides to keep
|
|
252
|
+
ops.removePendingMulligan(playerId("player-1"));
|
|
253
|
+
expect(ops.getPendingMulligan()).toEqual([playerId("player-2")]);
|
|
254
|
+
|
|
255
|
+
// Player 2 decides to keep
|
|
256
|
+
ops.removePendingMulligan(playerId("player-2"));
|
|
257
|
+
expect(ops.getPendingMulligan()).toEqual([]);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("should handle complete first player selection flow", () => {
|
|
261
|
+
const state = createTestState();
|
|
262
|
+
const ops = createGameOperations(state);
|
|
263
|
+
|
|
264
|
+
// 1. Randomly pick who gets to choose (simulated)
|
|
265
|
+
ops.setChoosingFirstPlayer(playerId("player-1"));
|
|
266
|
+
expect(ops.getChoosingFirstPlayer()).toBe(playerId("player-1"));
|
|
267
|
+
|
|
268
|
+
// 2. That player chooses who goes first
|
|
269
|
+
ops.setOTP(playerId("player-2"));
|
|
270
|
+
expect(ops.getOTP()).toBe(playerId("player-2"));
|
|
271
|
+
|
|
272
|
+
// 3. All players mulligan
|
|
273
|
+
ops.setPendingMulligan([playerId("player-1"), playerId("player-2")]);
|
|
274
|
+
expect(ops.getPendingMulligan()).toEqual([
|
|
275
|
+
playerId("player-1"),
|
|
276
|
+
playerId("player-2"),
|
|
277
|
+
]);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { PlayerId } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Game Operations
|
|
5
|
+
*
|
|
6
|
+
* Provides controlled access to game-level internal state:
|
|
7
|
+
* - OTP (On The Play): The player who goes first
|
|
8
|
+
* - Pending Mulligan: Players who need to decide on mulligan
|
|
9
|
+
*
|
|
10
|
+
* These are universal TCG concepts that apply across all card games.
|
|
11
|
+
*/
|
|
12
|
+
export type GameOperations = {
|
|
13
|
+
/**
|
|
14
|
+
* Set the player who is "on the play" (goes first)
|
|
15
|
+
*
|
|
16
|
+
* This is a universal TCG concept. The player marked as OTP
|
|
17
|
+
* typically goes first and may have different rules apply
|
|
18
|
+
* (e.g., no card draw on first turn in some games).
|
|
19
|
+
*
|
|
20
|
+
* @param playerId - Player to mark as on the play
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // In a choose first player move:
|
|
25
|
+
* context.game.setOTP('player-1');
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
setOTP(playerId: PlayerId): void;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get the player who is on the play
|
|
32
|
+
*
|
|
33
|
+
* @returns Player ID of OTP, or undefined if not yet set
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const firstPlayer = context.game.getOTP();
|
|
38
|
+
* if (firstPlayer === context.playerId) {
|
|
39
|
+
* // Current player goes first
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
getOTP(): PlayerId | undefined;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Set the player who gets to choose the first player
|
|
47
|
+
*
|
|
48
|
+
* In games like Lorcana, one player is randomly designated to choose
|
|
49
|
+
* who will be the starting player (OTP). This is distinct from OTP itself.
|
|
50
|
+
*
|
|
51
|
+
* @param playerId - Player designated to make the choice
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // In game setup, randomly choose who gets to pick:
|
|
56
|
+
* const chooser = context.rng.choice(['player-1', 'player-2']);
|
|
57
|
+
* context.game.setChoosingFirstPlayer(chooser);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
setChoosingFirstPlayer(playerId: PlayerId): void;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the player designated to choose the first player
|
|
64
|
+
*
|
|
65
|
+
* @returns Player ID of chooser, or undefined if not yet set
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* // In chooseFirstPlayer move condition:
|
|
70
|
+
* const chooser = context.game.getChoosingFirstPlayer();
|
|
71
|
+
* if (context.playerId !== chooser) {
|
|
72
|
+
* return { reason: "Only the designated player can choose", errorCode: "NOT_CHOOSER" };
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
getChoosingFirstPlayer(): PlayerId | undefined;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Set the list of players who need to decide on mulligan
|
|
80
|
+
*
|
|
81
|
+
* Replaces the entire pending mulligan list.
|
|
82
|
+
* Typically called during game setup to initialize the list.
|
|
83
|
+
*
|
|
84
|
+
* @param playerIds - Array of player IDs pending mulligan
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // After choosing first player, all players can mulligan:
|
|
89
|
+
* context.game.setPendingMulligan(['player-1', 'player-2']);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
setPendingMulligan(playerIds: PlayerId[]): void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get the list of players pending mulligan
|
|
96
|
+
*
|
|
97
|
+
* @returns Array of player IDs (copy to prevent mutation)
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const pending = context.game.getPendingMulligan();
|
|
102
|
+
* if (pending.includes(context.playerId)) {
|
|
103
|
+
* // Current player can still mulligan
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
getPendingMulligan(): PlayerId[];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Add a player to the pending mulligan list
|
|
111
|
+
*
|
|
112
|
+
* Use this to mark a player as needing to decide on mulligan.
|
|
113
|
+
* Has no effect if player is already in the list.
|
|
114
|
+
*
|
|
115
|
+
* @param playerId - Player to add to mulligan list
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* // Allow a player to mulligan again (game-specific rule):
|
|
120
|
+
* context.game.addPendingMulligan('player-1');
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
addPendingMulligan(playerId: PlayerId): void;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Remove a player from the pending mulligan list
|
|
127
|
+
*
|
|
128
|
+
* Use this when a player completes their mulligan decision.
|
|
129
|
+
* Has no effect if player is not in the list.
|
|
130
|
+
*
|
|
131
|
+
* @param playerId - Player to remove from mulligan list
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* // After player decides to keep or mulligan:
|
|
136
|
+
* context.game.removePendingMulligan(context.playerId);
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
removePendingMulligan(playerId: PlayerId): void;
|
|
140
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operations API
|
|
3
|
+
*
|
|
4
|
+
* Provides controlled access to internal game state through specialized operations interfaces:
|
|
5
|
+
* - ZoneOperations: Manage card zones and card movement
|
|
6
|
+
* - CardOperations: Manage card metadata and state
|
|
7
|
+
* - GameOperations: Manage game-level state (OTP, mulligan)
|
|
8
|
+
* - CounterOperations: Manage counters and flags on cards
|
|
9
|
+
* - CardRegistry: Access static card definitions
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type { CardOperations } from "./card-operations";
|
|
13
|
+
export type { CardRegistry } from "./card-registry";
|
|
14
|
+
export { createCardRegistry } from "./card-registry-impl";
|
|
15
|
+
export type { CounterOperations } from "./counter-operations";
|
|
16
|
+
export type { GameOperations } from "./game-operations";
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
createCardOperations,
|
|
20
|
+
createCounterOperations,
|
|
21
|
+
createGameOperations,
|
|
22
|
+
createZoneOperations,
|
|
23
|
+
} from "./operations-impl";
|
|
24
|
+
export type { ZoneOperations } from "./zone-operations";
|