@drmxrcy/tcg-lorcana 0.0.0-202602060544
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 +160 -0
- package/package.json +45 -0
- package/src/__tests__/integration/move-enumeration.test.ts +256 -0
- package/src/__tests__/rules/section-01-concepts.test.ts +426 -0
- package/src/__tests__/rules/section-03-gameplay.test.ts +298 -0
- package/src/__tests__/rules/section-04-turn-structure.test.ts +708 -0
- package/src/__tests__/rules/section-05-cards.test.ts +158 -0
- package/src/__tests__/rules/section-06-card-types.test.ts +342 -0
- package/src/__tests__/rules/section-07-abilities.test.ts +333 -0
- package/src/__tests__/rules/section-08-zones.test.ts +231 -0
- package/src/__tests__/rules/section-09-damage.test.ts +148 -0
- package/src/__tests__/rules/section-10-keywords.test.ts +469 -0
- package/src/__tests__/spec-01-foundation-types.test.ts +534 -0
- package/src/__tests__/spec-02-zones-card-states.test.ts +295 -0
- package/src/card-utils.ts +302 -0
- package/src/cards/README.md +296 -0
- package/src/cards/abilities/index.ts +175 -0
- package/src/cards/index.ts +10 -0
- package/src/deck-validation.ts +175 -0
- package/src/engine/lorcana-engine.ts +625 -0
- package/src/game-definition/__tests__/core-zone-integration.test.ts +553 -0
- package/src/game-definition/__tests__/zone-operations.test.ts +362 -0
- package/src/game-definition/__tests__/zones.test.ts +176 -0
- package/src/game-definition/definition.ts +45 -0
- package/src/game-definition/flow/turn-flow.ts +216 -0
- package/src/game-definition/index.ts +31 -0
- package/src/game-definition/moves/abilities/activate-ability.ts +51 -0
- package/src/game-definition/moves/core/__tests__/move-parameter-enumeration.test.ts +316 -0
- package/src/game-definition/moves/core/challenge.test.ts +545 -0
- package/src/game-definition/moves/core/challenge.ts +81 -0
- package/src/game-definition/moves/core/play-card.ts +83 -0
- package/src/game-definition/moves/core/quest.test.ts +448 -0
- package/src/game-definition/moves/core/quest.ts +49 -0
- package/src/game-definition/moves/debug/manual-exert.ts +36 -0
- package/src/game-definition/moves/effects/resolve-bag.ts +35 -0
- package/src/game-definition/moves/effects/resolve-effect.ts +34 -0
- package/src/game-definition/moves/index.ts +85 -0
- package/src/game-definition/moves/locations/move-character-to-location.ts +42 -0
- package/src/game-definition/moves/resources/put-card-into-inkwell.test.ts +462 -0
- package/src/game-definition/moves/resources/put-card-into-inkwell.ts +51 -0
- package/src/game-definition/moves/setup/alter-hand.test.ts +395 -0
- package/src/game-definition/moves/setup/alter-hand.ts +210 -0
- package/src/game-definition/moves/setup/choose-first-player.test.ts +450 -0
- package/src/game-definition/moves/setup/choose-first-player.ts +105 -0
- package/src/game-definition/moves/setup/draw-cards.ts +37 -0
- package/src/game-definition/moves/songs/sing-together.ts +47 -0
- package/src/game-definition/moves/songs/sing.ts +56 -0
- package/src/game-definition/moves/standard/concede.test.ts +189 -0
- package/src/game-definition/moves/standard/concede.ts +72 -0
- package/src/game-definition/moves/standard/pass-turn.ts +49 -0
- package/src/game-definition/setup/game-setup.ts +19 -0
- package/src/game-definition/trackers/tracker-config.ts +23 -0
- package/src/game-definition/win-conditions/lore-victory.ts +26 -0
- package/src/game-definition/zone-operations.ts +405 -0
- package/src/game-definition/zones/zone-configs.ts +59 -0
- package/src/game-definition/zones.ts +283 -0
- package/src/index.ts +189 -0
- package/src/operations/index.ts +7 -0
- package/src/operations/lorcana-operations.ts +288 -0
- package/src/queries/README.md +56 -0
- package/src/resolvers/__tests__/condition-resolver.test.ts +301 -0
- package/src/resolvers/condition-registry.ts +70 -0
- package/src/resolvers/condition-resolver.ts +85 -0
- package/src/resolvers/conditions/basic.ts +81 -0
- package/src/resolvers/conditions/card-state.ts +12 -0
- package/src/resolvers/conditions/comparison.ts +102 -0
- package/src/resolvers/conditions/existence.ts +219 -0
- package/src/resolvers/conditions/history.ts +68 -0
- package/src/resolvers/conditions/index.ts +15 -0
- package/src/resolvers/conditions/logical.ts +55 -0
- package/src/resolvers/conditions/resolution.ts +41 -0
- package/src/resolvers/conditions/revealed.ts +42 -0
- package/src/resolvers/conditions/zone.ts +84 -0
- package/src/setup.test.ts +18 -0
- package/src/targeting/__tests__/filter-resolver.test.ts +294 -0
- package/src/targeting/__tests__/real-cards-targeting.test.ts +303 -0
- package/src/targeting/__tests__/targeting-dsl.test.ts +386 -0
- package/src/targeting/enum-expansion.ts +387 -0
- package/src/targeting/filter-registry.ts +322 -0
- package/src/targeting/filter-resolver.ts +145 -0
- package/src/targeting/index.ts +91 -0
- package/src/targeting/lorcana-target-dsl.ts +495 -0
- package/src/targeting/targeting-ui.ts +407 -0
- package/src/testing/index.ts +14 -0
- package/src/testing/lorcana-test-engine.ts +813 -0
- package/src/types/README.md +303 -0
- package/src/types/__tests__/lorcana-state.test.ts +168 -0
- package/src/types/__tests__/move-enumeration.test.ts +179 -0
- package/src/types/branded-types.ts +106 -0
- package/src/types/game-state.ts +184 -0
- package/src/types/index.ts +87 -0
- package/src/types/keywords.ts +187 -0
- package/src/types/lorcana-state.ts +260 -0
- package/src/types/move-enumeration.ts +126 -0
- package/src/types/move-params.ts +216 -0
- package/src/validators/index.ts +7 -0
- package/src/validators/move-validators.ts +374 -0
- package/src/zones/card-state.ts +234 -0
- package/src/zones/index.ts +42 -0
- package/src/zones/zone-config.ts +150 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 4: Turn Structure
|
|
3
|
+
*
|
|
4
|
+
* Tests for rules 4.1-4.4 from Disney Lorcana Comprehensive Rules (Aug 22, 2025)
|
|
5
|
+
* Covers phases, beginning phase, main phase (quest, challenge, inkwell, etc.), and end of turn.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
|
+
import { createPlayerId } from "@drmxrcy/tcg-core";
|
|
10
|
+
import {
|
|
11
|
+
LorcanaTestEngine,
|
|
12
|
+
PLAYER_ONE,
|
|
13
|
+
PLAYER_TWO,
|
|
14
|
+
} from "../../testing/lorcana-test-engine";
|
|
15
|
+
|
|
16
|
+
describe("Section 4: Turn Structure", () => {
|
|
17
|
+
let testEngine: LorcanaTestEngine;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
testEngine = new LorcanaTestEngine(
|
|
21
|
+
{ hand: 7, deck: 53, inkwell: 3 },
|
|
22
|
+
{ hand: 7, deck: 53, inkwell: 3 },
|
|
23
|
+
{ skipPreGame: true },
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
testEngine.dispose();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("4.1. Phases", () => {
|
|
32
|
+
/**
|
|
33
|
+
* Rule 4.1.1: A turn has three phases, which occur in this order:
|
|
34
|
+
* Beginning Phase, Main Phase, and End of Turn Phase.
|
|
35
|
+
*/
|
|
36
|
+
test.failing("Rule 4.1.1 - Turn has three phases in order", () => {
|
|
37
|
+
// Assert: Turn structure should have Beginning -> Main -> End
|
|
38
|
+
const phases = ["beginning", "main", "end"];
|
|
39
|
+
expect(true).toBe(false); // Will fail until phase tracking implemented
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Rule 4.1.2: The Beginning Phase is where a player resets their cards.
|
|
44
|
+
* Effects that end at the start end, effects that begin at start happen.
|
|
45
|
+
* Has three steps: Ready, Set, and Draw.
|
|
46
|
+
*/
|
|
47
|
+
test.failing("Rule 4.1.2 - Beginning Phase has Ready, Set, Draw steps", () => {
|
|
48
|
+
// Assert: Beginning phase should contain all three steps
|
|
49
|
+
expect(true).toBe(false); // Will fail until step tracking implemented
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Rule 4.1.3: The Main Phase is where a player can act on their turn,
|
|
54
|
+
* choosing to perform any of the Main Phase turn actions.
|
|
55
|
+
*/
|
|
56
|
+
test.failing("Rule 4.1.3 - Main Phase allows turn actions", () => {
|
|
57
|
+
// Assert: During main phase, player can take turn actions
|
|
58
|
+
const phase = testEngine.getGamePhase();
|
|
59
|
+
expect(phase).toBe("main");
|
|
60
|
+
expect(true).toBe(false); // Will fail until fully verified
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Rule 4.1.4: The End of Turn Phase is where all effects that end at the
|
|
65
|
+
* current turn end. Triggered abilities resolve, then next player's turn.
|
|
66
|
+
*/
|
|
67
|
+
test.failing("Rule 4.1.4 - End of Turn ends 'this turn' effects", () => {
|
|
68
|
+
// Arrange: Set up "this turn" effect
|
|
69
|
+
|
|
70
|
+
// Act: End turn
|
|
71
|
+
|
|
72
|
+
// Assert: Effect should end
|
|
73
|
+
expect(true).toBe(false); // Will fail until end of turn effects implemented
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("4.2. Beginning Phase", () => {
|
|
78
|
+
describe("4.2.1. Ready Step", () => {
|
|
79
|
+
/**
|
|
80
|
+
* Rule 4.2.1.1: The active player readies all their cards in play and inkwell.
|
|
81
|
+
*/
|
|
82
|
+
test.failing("Rule 4.2.1.1 - Ready step readies all exerted cards", () => {
|
|
83
|
+
// Arrange: Create exerted character
|
|
84
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
85
|
+
strength: 2,
|
|
86
|
+
willpower: 3,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Exert the character (e.g., by questing)
|
|
90
|
+
testEngine.quest(character);
|
|
91
|
+
expect(testEngine.getCardMeta(character)?.state).toBe("exerted");
|
|
92
|
+
|
|
93
|
+
// Act: Pass turn and come back (triggers ready step)
|
|
94
|
+
testEngine.passTurn();
|
|
95
|
+
testEngine.passTurn();
|
|
96
|
+
|
|
97
|
+
// Assert: Character should be ready
|
|
98
|
+
expect(testEngine.getCardMeta(character)?.state).toBe("ready");
|
|
99
|
+
expect(true).toBe(false); // Verify with actual ready step
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Rule 4.2.1.2: Effects that apply "During your turn" start applying.
|
|
104
|
+
*/
|
|
105
|
+
test.failing("Rule 4.2.1.2 - 'During your turn' effects start", () => {
|
|
106
|
+
// Arrange: Create card with "During your turn" effect
|
|
107
|
+
|
|
108
|
+
// Act: Start turn
|
|
109
|
+
|
|
110
|
+
// Assert: Effect should be active
|
|
111
|
+
expect(true).toBe(false); // Will fail until turn effects implemented
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Rule 4.2.1.3: Effects that end "at the start of your turn" or
|
|
116
|
+
* "at the start of your next turn" end.
|
|
117
|
+
*/
|
|
118
|
+
test.failing("Rule 4.2.1.3 - 'At start of turn' effects end", () => {
|
|
119
|
+
// Arrange: Set up effect that ends at start of turn
|
|
120
|
+
|
|
121
|
+
// Act: Start turn
|
|
122
|
+
|
|
123
|
+
// Assert: Effect should end
|
|
124
|
+
expect(true).toBe(false); // Will fail until turn effect timing implemented
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Rule 4.2.1.4: Effects that trigger "at the start of your turn" trigger
|
|
129
|
+
* but do not yet resolve (see Set step).
|
|
130
|
+
*/
|
|
131
|
+
test.failing("Rule 4.2.1.4 - Start of turn triggers queue but don't resolve", () => {
|
|
132
|
+
// Arrange: Create card with "at the start of your turn" trigger
|
|
133
|
+
|
|
134
|
+
// Act: Enter Ready step
|
|
135
|
+
|
|
136
|
+
// Assert: Trigger should be queued, not resolved
|
|
137
|
+
expect(true).toBe(false); // Will fail until trigger queuing implemented
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("4.2.2. Set Step", () => {
|
|
142
|
+
/**
|
|
143
|
+
* Rule 4.2.2.1: Characters that are in play are no longer "drying" and
|
|
144
|
+
* will be able to quest, challenge, or pay costs for activated abilities.
|
|
145
|
+
*/
|
|
146
|
+
test.failing("Rule 4.2.2.1 - Characters dry at Set step", () => {
|
|
147
|
+
// Arrange: Create fresh character (drying)
|
|
148
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
149
|
+
strength: 2,
|
|
150
|
+
willpower: 3,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Assert: Initially cannot quest (drying)
|
|
154
|
+
// Act: Pass turn to complete set step
|
|
155
|
+
// Assert: Now can quest
|
|
156
|
+
expect(true).toBe(false); // Will fail until drying system verified
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Rule 4.2.2.2: The active player gains lore from locations with a lore value.
|
|
161
|
+
* This isn't a triggered ability and doesn't use the bag.
|
|
162
|
+
*/
|
|
163
|
+
test.failing("Rule 4.2.2.2 - Location lore gained at Set step", () => {
|
|
164
|
+
// Arrange: Create location with lore value
|
|
165
|
+
// Note: Would need location creation method
|
|
166
|
+
|
|
167
|
+
// Act: Start turn (Set step)
|
|
168
|
+
|
|
169
|
+
// Assert: Lore should be gained automatically
|
|
170
|
+
expect(true).toBe(false); // Will fail until location lore implemented
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Rule 4.2.2.3: Effects that would occur "At the start of your turn"
|
|
175
|
+
* and abilities from Ready step are added to bag and resolve.
|
|
176
|
+
*/
|
|
177
|
+
test.failing("Rule 4.2.2.3 - Start of turn triggers resolve at Set step", () => {
|
|
178
|
+
// Arrange: Create card with start of turn trigger
|
|
179
|
+
|
|
180
|
+
// Act: Complete Set step
|
|
181
|
+
|
|
182
|
+
// Assert: Trigger should have resolved
|
|
183
|
+
expect(true).toBe(false); // Will fail until Set step resolution implemented
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("4.2.3. Draw Step", () => {
|
|
188
|
+
/**
|
|
189
|
+
* Rule 4.2.3.1: Drawing is when a player takes the top card of their deck
|
|
190
|
+
* and puts it into their hand.
|
|
191
|
+
*/
|
|
192
|
+
test.failing("Rule 4.2.3.1 - Draw takes top card to hand", () => {
|
|
193
|
+
// Arrange: Note initial deck and hand sizes
|
|
194
|
+
|
|
195
|
+
// Act: Draw occurs
|
|
196
|
+
|
|
197
|
+
// Assert: Deck size -1, hand size +1
|
|
198
|
+
expect(true).toBe(false); // Will fail until draw verified
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Rule 4.2.3.2: First, the active player draws a card from their deck.
|
|
203
|
+
* If this is the first turn of the game, skip this step.
|
|
204
|
+
*/
|
|
205
|
+
test.failing("Rule 4.2.3.2 - First player skips draw on turn 1", () => {
|
|
206
|
+
// Arrange: Fresh game, first player's turn
|
|
207
|
+
|
|
208
|
+
// Assert: First player should not draw on turn 1
|
|
209
|
+
expect(true).toBe(false); // Will fail until first turn skip implemented
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Rule 4.2.3.3: Once all effects resolved, game moves into Main Phase.
|
|
214
|
+
*/
|
|
215
|
+
test.failing("Rule 4.2.3.3 - Transition to Main Phase after Draw", () => {
|
|
216
|
+
// Act: Complete Draw step
|
|
217
|
+
|
|
218
|
+
// Assert: Should be in Main Phase
|
|
219
|
+
expect(true).toBe(false); // Will fail until phase transition verified
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("4.3. Main Phase", () => {
|
|
225
|
+
describe("4.3.1-4.3.2. Turn Actions", () => {
|
|
226
|
+
/**
|
|
227
|
+
* Rule 4.3.1: Turn actions are the actions that the game allows a player
|
|
228
|
+
* to take during their turn. No effect or other card is needed.
|
|
229
|
+
*/
|
|
230
|
+
test.failing("Rule 4.3.1 - Turn actions available without cards", () => {
|
|
231
|
+
// Assert: Basic turn actions should be available
|
|
232
|
+
const moves = testEngine.getAvailableMoves(PLAYER_ONE);
|
|
233
|
+
expect(moves.length).toBeGreaterThan(0);
|
|
234
|
+
expect(true).toBe(false); // Will fail until move enumeration verified
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Rule 4.3.2: The active player may take turn actions in any order during
|
|
239
|
+
* Main Phase. Each action can be taken any number of times with resources.
|
|
240
|
+
*/
|
|
241
|
+
test.failing("Rule 4.3.2 - Turn actions can be taken in any order", () => {
|
|
242
|
+
// Arrange: Set up multiple possible actions
|
|
243
|
+
|
|
244
|
+
// Act: Take actions in various orders
|
|
245
|
+
|
|
246
|
+
// Assert: Order should be flexible
|
|
247
|
+
expect(true).toBe(false); // Will fail until action order verified
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe("4.3.3. Put Card Into Inkwell", () => {
|
|
252
|
+
/**
|
|
253
|
+
* Rule 4.3.3: Put a card into the inkwell. Limited to once per turn.
|
|
254
|
+
*/
|
|
255
|
+
test.failing("Rule 4.3.3 - Inkwell limited to once per turn", () => {
|
|
256
|
+
// Arrange: Get inkable card from hand
|
|
257
|
+
const hand = testEngine.getZone("hand", PLAYER_ONE);
|
|
258
|
+
const inkableCard = hand[0];
|
|
259
|
+
|
|
260
|
+
// Act: Put card into inkwell
|
|
261
|
+
testEngine.putCardInInkwell(inkableCard);
|
|
262
|
+
|
|
263
|
+
// Try to ink again - should fail
|
|
264
|
+
const hand2 = testEngine.getZone("hand", PLAYER_ONE);
|
|
265
|
+
const result = testEngine.engine.executeMove("putACardIntoTheInkwell", {
|
|
266
|
+
playerId: createPlayerId(PLAYER_ONE),
|
|
267
|
+
params: { cardId: hand2[0] },
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Assert: Second ink should fail
|
|
271
|
+
expect(result.success).toBe(false);
|
|
272
|
+
expect(true).toBe(false); // Will fail until ink limit verified
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Rule 4.3.3.1: Player declares they're putting a card into inkwell,
|
|
277
|
+
* chooses and reveals a card with the inkwell symbol.
|
|
278
|
+
*/
|
|
279
|
+
test.failing("Rule 4.3.3.1 - Only inkable cards can go to inkwell", () => {
|
|
280
|
+
// Arrange: Need a non-inkable card
|
|
281
|
+
|
|
282
|
+
// Act: Try to put non-inkable card in inkwell
|
|
283
|
+
|
|
284
|
+
// Assert: Should fail
|
|
285
|
+
expect(true).toBe(false); // Will fail until inkable check implemented
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Rule 4.3.3.2: The player places the revealed card in their inkwell
|
|
290
|
+
* facedown and ready.
|
|
291
|
+
*/
|
|
292
|
+
test.failing("Rule 4.3.3.2 - Ink cards placed facedown and ready", () => {
|
|
293
|
+
// Arrange: Get inkable card
|
|
294
|
+
const hand = testEngine.getZone("hand", PLAYER_ONE);
|
|
295
|
+
const card = hand[0];
|
|
296
|
+
|
|
297
|
+
// Act: Ink the card
|
|
298
|
+
testEngine.putCardInInkwell(card);
|
|
299
|
+
|
|
300
|
+
// Assert: Card should be in inkwell, ready (not exerted)
|
|
301
|
+
const inkwell = testEngine.getZone("inkwell", PLAYER_ONE);
|
|
302
|
+
expect(inkwell).toContain(card);
|
|
303
|
+
expect(true).toBe(false); // Will fail until inkwell state verified
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
describe("4.3.4. Play a Card", () => {
|
|
308
|
+
/**
|
|
309
|
+
* Rule 4.3.4.1: The active player can play a card from their hand by
|
|
310
|
+
* announcing the card and paying its cost.
|
|
311
|
+
*/
|
|
312
|
+
test.failing("Rule 4.3.4.1 - Playing a card requires paying cost", () => {
|
|
313
|
+
// Arrange: Card with cost 3, 3 ink available
|
|
314
|
+
|
|
315
|
+
// Act: Play the card
|
|
316
|
+
|
|
317
|
+
// Assert: Ink should be spent, card in play
|
|
318
|
+
expect(true).toBe(false); // Will fail until play card implemented
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Rule 4.3.4.2: Cards can normally be played only from a player's hand.
|
|
323
|
+
* Only the active player can play cards.
|
|
324
|
+
*/
|
|
325
|
+
test.failing("Rule 4.3.4.2 - Only active player can play from hand", () => {
|
|
326
|
+
// Act: Non-active player tries to play
|
|
327
|
+
|
|
328
|
+
// Assert: Should fail
|
|
329
|
+
expect(true).toBe(false); // Will fail until active player check implemented
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Rule 4.3.4.5: The total cost is ink cost or alternate cost plus modifiers.
|
|
334
|
+
* Apply additional costs first, then increases, then reductions.
|
|
335
|
+
*/
|
|
336
|
+
test.failing("Rule 4.3.4.5 - Cost calculation order: additional, increase, reduction", () => {
|
|
337
|
+
// Arrange: Card with multiple cost modifiers
|
|
338
|
+
|
|
339
|
+
// Act: Calculate total cost
|
|
340
|
+
|
|
341
|
+
// Assert: Order should be additional -> increase -> reduction
|
|
342
|
+
expect(true).toBe(false); // Will fail until cost calculation implemented
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Rule 4.3.4.6: The player pays the total cost by exerting ready ink cards.
|
|
347
|
+
*/
|
|
348
|
+
test.failing("Rule 4.3.4.6 - Paying cost exerts ink cards", () => {
|
|
349
|
+
// Arrange: Note ink state before
|
|
350
|
+
|
|
351
|
+
// Act: Play card with cost
|
|
352
|
+
|
|
353
|
+
// Assert: Appropriate number of ink cards exerted
|
|
354
|
+
expect(true).toBe(false); // Will fail until ink payment implemented
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Rule 4.3.4.7: Once cost is paid, card is "played". Characters enter Play zone.
|
|
359
|
+
* Actions resolve immediately and go to discard.
|
|
360
|
+
*/
|
|
361
|
+
test.failing("Rule 4.3.4.7 - Character enters play, action goes to discard", () => {
|
|
362
|
+
// For characters: should be in play zone
|
|
363
|
+
// For actions: should resolve and go to discard
|
|
364
|
+
expect(true).toBe(false); // Will fail until zone placement verified
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Rule 4.3.4.10: If a card can be played "for free," ignore all ink costs.
|
|
369
|
+
* Other steps and non-ink costs still apply.
|
|
370
|
+
*/
|
|
371
|
+
test.failing("Rule 4.3.4.10 - Free play ignores ink, not other costs", () => {
|
|
372
|
+
// Arrange: Card with free play available but additional cost
|
|
373
|
+
|
|
374
|
+
// Act: Play for free
|
|
375
|
+
|
|
376
|
+
// Assert: Ink not spent, additional cost still required
|
|
377
|
+
expect(true).toBe(false); // Will fail until free play implemented
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe("4.3.5. Quest", () => {
|
|
382
|
+
/**
|
|
383
|
+
* Rule 4.3.5.1: Sending a character on a quest is a turn action.
|
|
384
|
+
* Only characters can quest.
|
|
385
|
+
*/
|
|
386
|
+
test.failing("Rule 4.3.5.1 - Only characters can quest", () => {
|
|
387
|
+
// Arrange: Create character
|
|
388
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
389
|
+
strength: 2,
|
|
390
|
+
willpower: 3,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Act: Quest
|
|
394
|
+
testEngine.quest(character);
|
|
395
|
+
|
|
396
|
+
// Assert: Lore should be gained
|
|
397
|
+
expect(testEngine.getLore(PLAYER_ONE)).toBeGreaterThan(0);
|
|
398
|
+
expect(true).toBe(false); // Will fail until quest fully verified
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Rule 4.3.5.5: Check for restrictions that prevent questing
|
|
403
|
+
* (drying, Reckless, etc.).
|
|
404
|
+
*/
|
|
405
|
+
test.failing("Rule 4.3.5.5 - Check restrictions before questing", () => {
|
|
406
|
+
// Arrange: Create character with Reckless while opponent has exerted character
|
|
407
|
+
|
|
408
|
+
// Act: Try to quest
|
|
409
|
+
|
|
410
|
+
// Assert: Should be blocked by Reckless
|
|
411
|
+
expect(true).toBe(false); // Will fail until quest restrictions implemented
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Rule 4.3.5.7: Third, the player exerts the questing character.
|
|
416
|
+
*/
|
|
417
|
+
test.failing("Rule 4.3.5.7 - Questing exerts the character", () => {
|
|
418
|
+
// Arrange: Ready character
|
|
419
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
420
|
+
strength: 2,
|
|
421
|
+
willpower: 3,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Act: Quest
|
|
425
|
+
testEngine.quest(character);
|
|
426
|
+
|
|
427
|
+
// Assert: Character should be exerted
|
|
428
|
+
expect(testEngine.getCardMeta(character)?.state).toBe("exerted");
|
|
429
|
+
expect(true).toBe(false); // Verify with actual implementation
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Rule 4.3.5.8: The quest completes and questing player gains lore equal
|
|
434
|
+
* to the character's lore value.
|
|
435
|
+
*/
|
|
436
|
+
test.failing("Rule 4.3.5.8 - Gain lore equal to character's lore value", () => {
|
|
437
|
+
// Arrange: Character with lore value 2
|
|
438
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
439
|
+
strength: 2,
|
|
440
|
+
willpower: 3,
|
|
441
|
+
lore: 2,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const initialLore = testEngine.getLore(PLAYER_ONE);
|
|
445
|
+
|
|
446
|
+
// Act: Quest
|
|
447
|
+
testEngine.quest(character);
|
|
448
|
+
|
|
449
|
+
// Assert: Lore should increase by character's lore value
|
|
450
|
+
expect(testEngine.getLore(PLAYER_ONE)).toBe(initialLore + 2);
|
|
451
|
+
expect(true).toBe(false); // Will fail until lore value properly used
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
describe("4.3.6. Challenge", () => {
|
|
456
|
+
/**
|
|
457
|
+
* Rule 4.3.6.1: Sending a character into a challenge is a turn action.
|
|
458
|
+
* Only characters can challenge.
|
|
459
|
+
*/
|
|
460
|
+
test.failing("Rule 4.3.6.1 - Only characters can challenge", () => {
|
|
461
|
+
// Arrange
|
|
462
|
+
const attacker = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
463
|
+
strength: 3,
|
|
464
|
+
willpower: 4,
|
|
465
|
+
});
|
|
466
|
+
const defender = testEngine.createCharacterInPlay(PLAYER_TWO, {
|
|
467
|
+
strength: 2,
|
|
468
|
+
willpower: 3,
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Exert defender so it can be challenged
|
|
472
|
+
testEngine.changeActivePlayer(PLAYER_TWO);
|
|
473
|
+
testEngine.passTurn(); // Let defender dry
|
|
474
|
+
testEngine.passTurn();
|
|
475
|
+
testEngine.changeActivePlayer(PLAYER_ONE);
|
|
476
|
+
testEngine.passTurn();
|
|
477
|
+
testEngine.passTurn();
|
|
478
|
+
testEngine.changeActivePlayer(PLAYER_TWO);
|
|
479
|
+
// Need defender exerted - would quest but need to set up properly
|
|
480
|
+
|
|
481
|
+
expect(true).toBe(false); // Will fail until challenge fully set up
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Rule 4.3.6.7: The player chooses an exerted opposing character to challenge.
|
|
486
|
+
*/
|
|
487
|
+
test.failing("Rule 4.3.6.7 - Can only challenge exerted characters", () => {
|
|
488
|
+
// Arrange: Attacker and ready defender
|
|
489
|
+
const attacker = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
490
|
+
strength: 3,
|
|
491
|
+
willpower: 4,
|
|
492
|
+
});
|
|
493
|
+
const readyDefender = testEngine.createCharacterInPlay(PLAYER_TWO, {
|
|
494
|
+
strength: 2,
|
|
495
|
+
willpower: 3,
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// Act: Try to challenge ready defender
|
|
499
|
+
const result = testEngine.engine.executeMove("challenge", {
|
|
500
|
+
playerId: createPlayerId(PLAYER_ONE),
|
|
501
|
+
params: {
|
|
502
|
+
attackerId: attacker,
|
|
503
|
+
defenderId: readyDefender,
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// Assert: Should fail - can't challenge ready character
|
|
508
|
+
expect(result.success).toBe(false);
|
|
509
|
+
expect(true).toBe(false); // Verify with actual implementation
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Rule 4.3.6.9: Fourth, the challenging player exerts the challenging character.
|
|
514
|
+
*/
|
|
515
|
+
test.failing("Rule 4.3.6.9 - Challenging exerts the attacker", () => {
|
|
516
|
+
// After successful challenge setup, attacker should be exerted
|
|
517
|
+
expect(true).toBe(false); // Will fail until challenge exert verified
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Rule 4.3.6.13: Both characters deal damage equal to their Strength
|
|
522
|
+
* to the other character (Challenge Damage step).
|
|
523
|
+
*/
|
|
524
|
+
test.failing("Rule 4.3.6.13 - Both characters deal damage in challenge", () => {
|
|
525
|
+
// After challenge, both should have taken damage equal to other's strength
|
|
526
|
+
expect(true).toBe(false); // Will fail until damage dealing verified
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Rule 4.3.6.14: If a character's Strength is negative, it counts as 0
|
|
531
|
+
* for determining damage.
|
|
532
|
+
*/
|
|
533
|
+
test.failing("Rule 4.3.6.14 - Negative strength counts as 0 damage", () => {
|
|
534
|
+
// Arrange: Character with 0 or negative strength
|
|
535
|
+
|
|
536
|
+
// Act: Challenge
|
|
537
|
+
|
|
538
|
+
// Assert: Should deal 0 damage
|
|
539
|
+
expect(true).toBe(false); // Will fail until negative strength handled
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Rule 4.3.6.19-22: Players can challenge locations.
|
|
544
|
+
* Locations are never ready/exerted, can be challenged anytime.
|
|
545
|
+
* Locations don't have strength and don't deal damage.
|
|
546
|
+
*/
|
|
547
|
+
test.failing("Rule 4.3.6.19 - Can challenge locations", () => {
|
|
548
|
+
// Arrange: Create location to challenge
|
|
549
|
+
|
|
550
|
+
// Act: Challenge the location
|
|
551
|
+
|
|
552
|
+
// Assert: Location takes damage, attacker takes none from location
|
|
553
|
+
expect(true).toBe(false); // Will fail until location challenge implemented
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Rule 4.3.6.23: If a character is removed from challenge, that challenge ends.
|
|
558
|
+
*/
|
|
559
|
+
test.failing("Rule 4.3.6.23 - Challenge ends if character removed", () => {
|
|
560
|
+
// Arrange: Set up ability that removes character from challenge
|
|
561
|
+
|
|
562
|
+
// Act: Trigger removal during challenge
|
|
563
|
+
|
|
564
|
+
// Assert: Challenge should end without damage step completing
|
|
565
|
+
expect(true).toBe(false); // Will fail until challenge removal implemented
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
describe("4.3.7. Move a Character to a Location", () => {
|
|
570
|
+
/**
|
|
571
|
+
* Rule 4.3.7.1: A player can move only their characters to their locations.
|
|
572
|
+
* Can't move opposing characters or to opposing locations.
|
|
573
|
+
*/
|
|
574
|
+
test.failing("Rule 4.3.7.1 - Can only move own characters to own locations", () => {
|
|
575
|
+
// Assert: Moving opponent's character should fail
|
|
576
|
+
// Assert: Moving to opponent's location should fail
|
|
577
|
+
expect(true).toBe(false); // Will fail until move restrictions implemented
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Rule 4.3.7.4: The player pays the location's move cost.
|
|
582
|
+
*/
|
|
583
|
+
test.failing("Rule 4.3.7.4 - Moving requires paying move cost", () => {
|
|
584
|
+
// Arrange: Location with move cost 2
|
|
585
|
+
|
|
586
|
+
// Act: Move character to location
|
|
587
|
+
|
|
588
|
+
// Assert: Move cost should be paid
|
|
589
|
+
expect(true).toBe(false); // Will fail until move cost implemented
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
describe("4.3.8. Use Activated Abilities", () => {
|
|
594
|
+
/**
|
|
595
|
+
* Rule 4.3.8.1: The use of activated abilities is a turn action.
|
|
596
|
+
*/
|
|
597
|
+
test.failing("Rule 4.3.8.1 - Activated abilities are turn actions", () => {
|
|
598
|
+
// Arrange: Card with activated ability
|
|
599
|
+
|
|
600
|
+
// Act: Use the ability
|
|
601
|
+
|
|
602
|
+
// Assert: Ability should execute
|
|
603
|
+
expect(true).toBe(false); // Will fail until activated abilities implemented
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Rule 4.3.8.2: Exert abilities of characters can only be used if dry.
|
|
608
|
+
*/
|
|
609
|
+
test.failing("Rule 4.3.8.2 - Exert abilities require character to be dry", () => {
|
|
610
|
+
// Arrange: Fresh character with exert ability
|
|
611
|
+
|
|
612
|
+
// Act: Try to use exert ability (should fail - not dry)
|
|
613
|
+
|
|
614
|
+
// Assert: Should not be usable until dry
|
|
615
|
+
expect(true).toBe(false); // Will fail until drying check implemented
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Rule 4.3.8.3: Activated abilities of items can be used the turn played.
|
|
620
|
+
*/
|
|
621
|
+
test.failing("Rule 4.3.8.3 - Item abilities usable immediately", () => {
|
|
622
|
+
// Arrange: Item with activated ability
|
|
623
|
+
|
|
624
|
+
// Act: Play item and use ability same turn
|
|
625
|
+
|
|
626
|
+
// Assert: Should work
|
|
627
|
+
expect(true).toBe(false); // Will fail until item abilities implemented
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Rule 4.3.8.4: If activated ability can be used "for free," ignore ink costs.
|
|
632
|
+
*/
|
|
633
|
+
test.failing("Rule 4.3.8.4 - Free activated ability ignores ink cost", () => {
|
|
634
|
+
// Arrange: Ability with ink cost that can be used for free
|
|
635
|
+
|
|
636
|
+
// Act: Use for free
|
|
637
|
+
|
|
638
|
+
// Assert: Ink not spent
|
|
639
|
+
expect(true).toBe(false); // Will fail until free ability implemented
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
describe("4.4. End of Turn Phase", () => {
|
|
645
|
+
/**
|
|
646
|
+
* Rule 4.4.1: To end a turn, there must be no abilities waiting to resolve.
|
|
647
|
+
*/
|
|
648
|
+
test.failing("Rule 4.4.1 - Cannot end turn with unresolved abilities", () => {
|
|
649
|
+
// Arrange: Trigger an ability that adds to bag
|
|
650
|
+
|
|
651
|
+
// Act: Try to end turn
|
|
652
|
+
|
|
653
|
+
// Assert: Should not end until bag is empty
|
|
654
|
+
expect(true).toBe(false); // Will fail until bag check implemented
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Rule 4.4.1.1: Effects that would occur "At the end of the turn"
|
|
659
|
+
* and "At the end of your turn" are added to the bag.
|
|
660
|
+
*/
|
|
661
|
+
test.failing("Rule 4.4.1.1 - End of turn triggers added to bag", () => {
|
|
662
|
+
// Arrange: Card with end of turn trigger
|
|
663
|
+
|
|
664
|
+
// Act: Declare end of turn
|
|
665
|
+
|
|
666
|
+
// Assert: Trigger should be in bag
|
|
667
|
+
expect(true).toBe(false); // Will fail until end triggers implemented
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Rule 4.4.1.2: Resolve all triggers in the bag.
|
|
672
|
+
*/
|
|
673
|
+
test.failing("Rule 4.4.1.2 - End of turn triggers resolve", () => {
|
|
674
|
+
// After end of turn declared, all triggers should resolve
|
|
675
|
+
expect(true).toBe(false); // Will fail until trigger resolution verified
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Rule 4.4.1.3: Effects with "this turn" duration end.
|
|
680
|
+
* If this causes new triggers, return to resolving bag.
|
|
681
|
+
*/
|
|
682
|
+
test.failing("Rule 4.4.1.3 - 'This turn' effects end at end of turn", () => {
|
|
683
|
+
// Arrange: Apply "this turn" effect
|
|
684
|
+
|
|
685
|
+
// Act: End turn
|
|
686
|
+
|
|
687
|
+
// Assert: Effect should no longer apply
|
|
688
|
+
expect(true).toBe(false); // Will fail until turn duration effects implemented
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Rule 4.4.1.4: The turn ends for the active player, and the next player
|
|
693
|
+
* begins their turn.
|
|
694
|
+
*/
|
|
695
|
+
test.failing("Rule 4.4.1.4 - Turn passes to next player", () => {
|
|
696
|
+
// Arrange: Note current player
|
|
697
|
+
const currentPlayer = testEngine.getTurnPlayer();
|
|
698
|
+
|
|
699
|
+
// Act: End turn
|
|
700
|
+
testEngine.passTurn();
|
|
701
|
+
|
|
702
|
+
// Assert: Different player's turn
|
|
703
|
+
const newPlayer = testEngine.getTurnPlayer();
|
|
704
|
+
expect(newPlayer).not.toBe(currentPlayer);
|
|
705
|
+
expect(true).toBe(false); // Will fail until turn passing verified
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
});
|