@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,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 7: Abilities
|
|
3
|
+
*
|
|
4
|
+
* Tests for rules 7.1-7.8 from Disney Lorcana Comprehensive Rules (Aug 22, 2025)
|
|
5
|
+
* Covers General ability rules, Action Cards, Keywords, Triggered Abilities,
|
|
6
|
+
* Activated Abilities, Static Abilities, Replacement Effects, and Ability Modifiers.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
10
|
+
import {
|
|
11
|
+
LorcanaTestEngine,
|
|
12
|
+
PLAYER_ONE,
|
|
13
|
+
PLAYER_TWO,
|
|
14
|
+
} from "../../testing/lorcana-test-engine";
|
|
15
|
+
|
|
16
|
+
describe("Section 7: Abilities", () => {
|
|
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("7.1. General", () => {
|
|
32
|
+
/**
|
|
33
|
+
* Rule 7.1.1: Abilities can have multiple clauses separated by periods or commas.
|
|
34
|
+
*/
|
|
35
|
+
test.failing("Rule 7.1.1 - Multiple clauses in abilities", () => {
|
|
36
|
+
// Arrange: Ability with multiple clauses
|
|
37
|
+
// e.g., "Draw 2 cards. Deal 2 damage to chosen character."
|
|
38
|
+
|
|
39
|
+
// Assert: Each clause should resolve in order
|
|
40
|
+
expect(true).toBe(false); // Will fail until multi-clause parsing implemented
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Rule 7.1.2: "May" means the player can choose not to do it.
|
|
45
|
+
*/
|
|
46
|
+
test.failing("Rule 7.1.2 - 'May' is optional", () => {
|
|
47
|
+
// Arrange: Ability with "may"
|
|
48
|
+
// e.g., "You may draw a card"
|
|
49
|
+
|
|
50
|
+
// Act: Choose not to do it
|
|
51
|
+
|
|
52
|
+
// Assert: Should be valid to skip
|
|
53
|
+
expect(true).toBe(false); // Will fail until optional handling implemented
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Rule 7.1.3: "Put into hand" is different from "draw" (not affected by draw prevention).
|
|
58
|
+
*/
|
|
59
|
+
test.failing("Rule 7.1.3 - Put into hand is not drawing", () => {
|
|
60
|
+
// Arrange: Effect that prevents drawing, effect that puts into hand
|
|
61
|
+
|
|
62
|
+
// Act: Use put into hand effect
|
|
63
|
+
|
|
64
|
+
// Assert: Should still work despite draw prevention
|
|
65
|
+
expect(true).toBe(false); // Will fail until put vs draw distinction implemented
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Rule 7.1.4: "Other" or "Another" means a different card than the source.
|
|
70
|
+
*/
|
|
71
|
+
test.failing("Rule 7.1.4 - 'Other' excludes the source card", () => {
|
|
72
|
+
// Arrange: Ability that affects "other characters"
|
|
73
|
+
|
|
74
|
+
// Assert: Should not affect the card with the ability
|
|
75
|
+
expect(true).toBe(false); // Will fail until other/another targeting implemented
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Rule 7.1.5: Playing cards while resolving abilities requires explicit permission.
|
|
80
|
+
*/
|
|
81
|
+
test.failing("Rule 7.1.5 - Cannot play cards during ability resolution", () => {
|
|
82
|
+
// Arrange: Resolving an ability
|
|
83
|
+
|
|
84
|
+
// Act: Try to play a card
|
|
85
|
+
|
|
86
|
+
// Assert: Should fail unless ability grants permission
|
|
87
|
+
expect(true).toBe(false); // Will fail until resolution timing implemented
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Rule 7.1.6: Loops - If a loop would occur with no way to end, it ends immediately.
|
|
92
|
+
*/
|
|
93
|
+
test.failing("Rule 7.1.6 - Infinite loops end immediately", () => {
|
|
94
|
+
// Arrange: Set up potential infinite loop
|
|
95
|
+
|
|
96
|
+
// Assert: Loop should be broken
|
|
97
|
+
expect(true).toBe(false); // Will fail until loop detection implemented
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Rule 7.1.7: "Up to" allows choosing any number from 0 to the stated maximum.
|
|
102
|
+
*/
|
|
103
|
+
test.failing("Rule 7.1.7 - 'Up to' includes 0", () => {
|
|
104
|
+
// Arrange: Effect with "up to 3"
|
|
105
|
+
|
|
106
|
+
// Act: Choose 0
|
|
107
|
+
|
|
108
|
+
// Assert: Should be valid
|
|
109
|
+
expect(true).toBe(false); // Will fail until up-to handling implemented
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Rule 7.1.8: "That" refers back to a previously mentioned card/target.
|
|
114
|
+
*/
|
|
115
|
+
test.failing("Rule 7.1.8 - 'That' references previous target", () => {
|
|
116
|
+
// Arrange: Effect that chooses target, then refers to "that character"
|
|
117
|
+
|
|
118
|
+
// Assert: "That" should reference the chosen target
|
|
119
|
+
expect(true).toBe(false); // Will fail until reference tracking implemented
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Rule 7.1.9: Revealing cards shows them to all players.
|
|
124
|
+
*/
|
|
125
|
+
test.failing("Rule 7.1.9 - Revealed cards visible to all", () => {
|
|
126
|
+
// Arrange: Effect that reveals cards
|
|
127
|
+
|
|
128
|
+
// Assert: Both players should see revealed cards
|
|
129
|
+
expect(true).toBe(false); // Will fail until reveal visibility implemented
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("7.2. Action Cards", () => {
|
|
134
|
+
/**
|
|
135
|
+
* Action cards have effects, not abilities.
|
|
136
|
+
* Effects resolve immediately and don't use the bag.
|
|
137
|
+
*/
|
|
138
|
+
test.failing("Rule 7.2 - Action effects resolve immediately", () => {
|
|
139
|
+
// Arrange: Play action card
|
|
140
|
+
|
|
141
|
+
// Assert: Effect should resolve without entering bag
|
|
142
|
+
expect(true).toBe(false); // Will fail until action resolution implemented
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("7.3. Keywords", () => {
|
|
147
|
+
/**
|
|
148
|
+
* Rule 7.3.1: Keywords are words/phrases representing larger abilities.
|
|
149
|
+
*/
|
|
150
|
+
test.failing("Rule 7.3.1 - Keywords expand to full abilities", () => {
|
|
151
|
+
// Arrange: Character with "Bodyguard"
|
|
152
|
+
|
|
153
|
+
// Assert: Should have the full Bodyguard ability effect
|
|
154
|
+
expect(true).toBe(false); // Will fail until keyword expansion implemented
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Rule 7.3.2: Reminder text (in italics) isn't rules text - just memory aid.
|
|
159
|
+
*/
|
|
160
|
+
test.failing("Rule 7.3.2 - Reminder text not used for rules", () => {
|
|
161
|
+
// Assert: Reminder text should be ignored in effect resolution
|
|
162
|
+
expect(true).toBe(false); // Will fail until reminder text stripping implemented
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe("7.4. Triggered Abilities", () => {
|
|
167
|
+
/**
|
|
168
|
+
* Rule 7.4.1: Triggered abilities look for specific conditions and fire when met.
|
|
169
|
+
*/
|
|
170
|
+
test.failing("Rule 7.4.1 - Triggered abilities fire on condition", () => {
|
|
171
|
+
// Arrange: Character with "When this character quests, draw a card"
|
|
172
|
+
|
|
173
|
+
// Act: Quest with the character
|
|
174
|
+
|
|
175
|
+
// Assert: Trigger should fire, effect added to bag
|
|
176
|
+
expect(true).toBe(false); // Will fail until triggers implemented
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Rule 7.4.2: Abilities with two trigger conditions need both to be met.
|
|
181
|
+
*/
|
|
182
|
+
test.failing("Rule 7.4.2 - Multiple trigger conditions must all be met", () => {
|
|
183
|
+
// Arrange: Ability with "When X and Y"
|
|
184
|
+
|
|
185
|
+
// Act: Only satisfy one condition
|
|
186
|
+
|
|
187
|
+
// Assert: Should not trigger
|
|
188
|
+
expect(true).toBe(false); // Will fail until compound triggers implemented
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Rule 7.4.3: Floating triggered abilities exist temporarily after source leaves.
|
|
193
|
+
*/
|
|
194
|
+
test.failing("Rule 7.4.3 - Floating triggers persist after source leaves", () => {
|
|
195
|
+
// Arrange: Character with "When this character is banished" trigger
|
|
196
|
+
|
|
197
|
+
// Act: Banish the character
|
|
198
|
+
|
|
199
|
+
// Assert: Trigger should still resolve
|
|
200
|
+
expect(true).toBe(false); // Will fail until floating triggers implemented
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Rule 7.4.4: Delayed triggered abilities are set up by effects.
|
|
205
|
+
*/
|
|
206
|
+
test.failing("Rule 7.4.4 - Delayed triggers created by effects", () => {
|
|
207
|
+
// Arrange: Effect that creates "At end of turn, do X"
|
|
208
|
+
|
|
209
|
+
// Act: Reach end of turn
|
|
210
|
+
|
|
211
|
+
// Assert: Delayed trigger should fire
|
|
212
|
+
expect(true).toBe(false); // Will fail until delayed triggers implemented
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe("7.5. Activated Abilities", () => {
|
|
217
|
+
/**
|
|
218
|
+
* Rule 7.5.1: Activated abilities have a cost and effect.
|
|
219
|
+
*/
|
|
220
|
+
test.failing("Rule 7.5.1 - Activated abilities require paying cost", () => {
|
|
221
|
+
// Arrange: Character with activated ability "{exert}: Draw a card"
|
|
222
|
+
|
|
223
|
+
// Act: Use the ability
|
|
224
|
+
|
|
225
|
+
// Assert: Cost (exert) should be paid, effect should occur
|
|
226
|
+
expect(true).toBe(false); // Will fail until activated abilities implemented
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Rule 7.5.2: Costs must be paid before effect resolves.
|
|
231
|
+
*/
|
|
232
|
+
test.failing("Rule 7.5.2 - Pay costs before effect", () => {
|
|
233
|
+
// Assert: If cost can't be paid, ability can't be used
|
|
234
|
+
expect(true).toBe(false); // Will fail until cost requirement verified
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Rule 7.5.3: Steps to use activated ability:
|
|
239
|
+
* 1. Announce ability
|
|
240
|
+
* 2. Pay costs
|
|
241
|
+
* 3. Effect resolves
|
|
242
|
+
*/
|
|
243
|
+
test.failing("Rule 7.5.3 - Activated ability resolution steps", () => {
|
|
244
|
+
// Assert: Steps should occur in order
|
|
245
|
+
expect(true).toBe(false); // Will fail until activation steps implemented
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
describe("7.6. Static Abilities", () => {
|
|
250
|
+
/**
|
|
251
|
+
* Rule 7.6.1: Static abilities are continuously active.
|
|
252
|
+
*/
|
|
253
|
+
test.failing("Rule 7.6.1 - Static abilities always active", () => {
|
|
254
|
+
// Arrange: Character with "Your other characters get +1 strength"
|
|
255
|
+
|
|
256
|
+
// Assert: Effect should apply continuously while card in play
|
|
257
|
+
expect(true).toBe(false); // Will fail until static abilities implemented
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Rule 7.6.2: Static abilities have duration (while in play or fixed time).
|
|
262
|
+
*/
|
|
263
|
+
test.failing("Rule 7.6.2 - Static ability duration", () => {
|
|
264
|
+
// Arrange: Static ability
|
|
265
|
+
|
|
266
|
+
// Act: Remove card from play
|
|
267
|
+
|
|
268
|
+
// Assert: Effect should end
|
|
269
|
+
expect(true).toBe(false); // Will fail until static duration implemented
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Rule 7.6.3: Timing - static abilities apply immediately when card enters.
|
|
274
|
+
*/
|
|
275
|
+
test.failing("Rule 7.6.3 - Static abilities apply immediately", () => {
|
|
276
|
+
// Arrange: Play card with static ability
|
|
277
|
+
|
|
278
|
+
// Assert: Effect should apply right away
|
|
279
|
+
expect(true).toBe(false); // Will fail until static timing implemented
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Rule 7.6.4: Some static abilities work outside of play (e.g., Shift).
|
|
284
|
+
*/
|
|
285
|
+
test.failing("Rule 7.6.4 - Static abilities can work outside play", () => {
|
|
286
|
+
// Arrange: Card with Shift (works from hand)
|
|
287
|
+
|
|
288
|
+
// Assert: Shift should be usable from hand
|
|
289
|
+
expect(true).toBe(false); // Will fail until out-of-play statics implemented
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe("7.7. Replacement Effects", () => {
|
|
294
|
+
/**
|
|
295
|
+
* Rule 7.7.1: Replacement effects substitute one effect for another.
|
|
296
|
+
*/
|
|
297
|
+
test.failing("Rule 7.7.1 - Replacement effects substitute", () => {
|
|
298
|
+
// Arrange: "If this character would be banished, return it to hand instead"
|
|
299
|
+
|
|
300
|
+
// Act: Try to banish the character
|
|
301
|
+
|
|
302
|
+
// Assert: Character should return to hand instead
|
|
303
|
+
expect(true).toBe(false); // Will fail until replacement effects implemented
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Rule 7.7.2: "Skip" is a replacement effect that replaces with nothing.
|
|
308
|
+
*/
|
|
309
|
+
test.failing("Rule 7.7.2 - Skip replaces with nothing", () => {
|
|
310
|
+
// Arrange: "Skip your draw step"
|
|
311
|
+
|
|
312
|
+
// Act: Reach draw step
|
|
313
|
+
|
|
314
|
+
// Assert: Draw should be skipped entirely
|
|
315
|
+
expect(true).toBe(false); // Will fail until skip effects implemented
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe("7.8. Ability Modifiers", () => {
|
|
320
|
+
/**
|
|
321
|
+
* Ability modifiers change how abilities work.
|
|
322
|
+
*/
|
|
323
|
+
test.failing("Rule 7.8 - Ability modifiers", () => {
|
|
324
|
+
// Arrange: Effect that modifies abilities
|
|
325
|
+
// e.g., "Abilities can't be used"
|
|
326
|
+
|
|
327
|
+
// Act: Try to use ability
|
|
328
|
+
|
|
329
|
+
// Assert: Should be blocked by modifier
|
|
330
|
+
expect(true).toBe(false); // Will fail until ability modifiers implemented
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
});
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 8: Zones
|
|
3
|
+
*
|
|
4
|
+
* Tests for rules 8.1-8.7 from Disney Lorcana Comprehensive Rules (Aug 22, 2025)
|
|
5
|
+
* Covers General zone rules, Deck, Hand, Play, Inkwell, Discard, and Bag.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
|
+
import {
|
|
10
|
+
LorcanaTestEngine,
|
|
11
|
+
PLAYER_ONE,
|
|
12
|
+
PLAYER_TWO,
|
|
13
|
+
} from "../../testing/lorcana-test-engine";
|
|
14
|
+
|
|
15
|
+
describe("Section 8: Zones", () => {
|
|
16
|
+
let testEngine: LorcanaTestEngine;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
testEngine = new LorcanaTestEngine(
|
|
20
|
+
{ hand: 7, deck: 53, inkwell: 0 },
|
|
21
|
+
{ hand: 7, deck: 53, inkwell: 0 },
|
|
22
|
+
{ skipPreGame: true },
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
testEngine.dispose();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("8.1. General", () => {
|
|
31
|
+
/**
|
|
32
|
+
* Rule 8.1.1: Zones are places where cards exist during the game.
|
|
33
|
+
*/
|
|
34
|
+
test.failing("Rule 8.1.1 - Cards exist in zones", () => {
|
|
35
|
+
// Assert: Every card should be in exactly one zone
|
|
36
|
+
expect(true).toBe(false); // Will fail until zone tracking verified
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Rule 8.1.2: Public zones - all players can see cards.
|
|
41
|
+
* Private zones - only owner can see cards.
|
|
42
|
+
*/
|
|
43
|
+
test.failing("Rule 8.1.2 - Public vs private zone visibility", () => {
|
|
44
|
+
// Assert: Play/Discard are public, Hand/Deck are private
|
|
45
|
+
expect(true).toBe(false); // Will fail until visibility system implemented
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Rule 8.1.3: Fail to find - If an effect searches for a card that doesn't exist,
|
|
50
|
+
* the search fails but the effect continues.
|
|
51
|
+
*/
|
|
52
|
+
test.failing("Rule 8.1.3 - Fail to find doesn't stop effect", () => {
|
|
53
|
+
// Arrange: Effect that searches for non-existent card
|
|
54
|
+
|
|
55
|
+
// Act: Execute effect
|
|
56
|
+
|
|
57
|
+
// Assert: Search fails gracefully, rest of effect continues
|
|
58
|
+
expect(true).toBe(false); // Will fail until fail-to-find implemented
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("8.2. Deck", () => {
|
|
63
|
+
/**
|
|
64
|
+
* Rule 8.2.1: Deck is a private zone. Players can't look at cards in deck.
|
|
65
|
+
*/
|
|
66
|
+
test.failing("Rule 8.2.1 - Deck is private", () => {
|
|
67
|
+
// Assert: Players shouldn't be able to view opponent's deck
|
|
68
|
+
expect(true).toBe(false); // Will fail until deck privacy implemented
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Rule 8.2.2: When adding cards to top or bottom of deck, they go in order
|
|
73
|
+
* (first card mentioned goes to extreme position).
|
|
74
|
+
*/
|
|
75
|
+
test.failing("Rule 8.2.2 - Deck ordering for top/bottom", () => {
|
|
76
|
+
// Arrange: Put cards A, B, C on top (in that order)
|
|
77
|
+
|
|
78
|
+
// Assert: Next draw should be C (last put on top = top)
|
|
79
|
+
expect(true).toBe(false); // Will fail until deck ordering implemented
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("8.3. Hand", () => {
|
|
84
|
+
/**
|
|
85
|
+
* Rule 8.3.1: Hand is a private zone. Only the owner can see their hand.
|
|
86
|
+
*/
|
|
87
|
+
test.failing("Rule 8.3.1 - Hand is private", () => {
|
|
88
|
+
// Assert: Opponent shouldn't see your hand
|
|
89
|
+
expect(true).toBe(false); // Will fail until hand privacy implemented
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Hand has no size limit.
|
|
94
|
+
*/
|
|
95
|
+
test.failing("Rule 8.3 - No hand size limit", () => {
|
|
96
|
+
// Assert: Player can have any number of cards in hand
|
|
97
|
+
expect(true).toBe(false); // Will fail until hand size verified
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("8.4. Play", () => {
|
|
102
|
+
/**
|
|
103
|
+
* Rule 8.4.1: Play is a public zone where characters, items, and locations exist.
|
|
104
|
+
*/
|
|
105
|
+
test.failing("Rule 8.4.1 - Play zone is public", () => {
|
|
106
|
+
// Assert: Both players can see cards in play
|
|
107
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
108
|
+
strength: 2,
|
|
109
|
+
willpower: 3,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Both players should be able to see this character
|
|
113
|
+
expect(testEngine.getZone("play", PLAYER_ONE)).toContain(character);
|
|
114
|
+
expect(true).toBe(false); // Will fail until visibility verified
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Rule 8.4.2: "In play" means the card is in the Play zone.
|
|
119
|
+
*/
|
|
120
|
+
test.failing("Rule 8.4.2 - 'In play' means in Play zone", () => {
|
|
121
|
+
// Assert: Only cards in Play zone are "in play"
|
|
122
|
+
expect(true).toBe(false); // Will fail until in-play check implemented
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Rule 8.4.3: Leaving play - when a card leaves play, all attached cards,
|
|
127
|
+
* damage, and effects on it are removed.
|
|
128
|
+
*/
|
|
129
|
+
test.failing("Rule 8.4.3 - Leaving play clears damage and effects", () => {
|
|
130
|
+
// Arrange: Character with damage
|
|
131
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
132
|
+
strength: 2,
|
|
133
|
+
willpower: 5,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Add damage somehow
|
|
137
|
+
// Then banish/return to hand
|
|
138
|
+
|
|
139
|
+
// Assert: Damage should be cleared when leaving play
|
|
140
|
+
expect(true).toBe(false); // Will fail until leaving play cleanup implemented
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("8.5. Inkwell", () => {
|
|
145
|
+
/**
|
|
146
|
+
* Rule 8.5.1: Inkwell contains ink cards used to pay costs.
|
|
147
|
+
*/
|
|
148
|
+
test.failing("Rule 8.5.1 - Inkwell holds ink for paying costs", () => {
|
|
149
|
+
// Arrange: Put cards in inkwell
|
|
150
|
+
|
|
151
|
+
// Act: Pay a cost
|
|
152
|
+
|
|
153
|
+
// Assert: Ink cards should exert to pay
|
|
154
|
+
expect(true).toBe(false); // Will fail until inkwell payment verified
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Ink cards are placed facedown.
|
|
159
|
+
*/
|
|
160
|
+
test.failing("Rule 8.5 - Ink cards are facedown", () => {
|
|
161
|
+
// Assert: Ink cards should be facedown (not visible)
|
|
162
|
+
expect(true).toBe(false); // Will fail until ink visibility implemented
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Ink cards ready at start of turn.
|
|
167
|
+
*/
|
|
168
|
+
test.failing("Rule 8.5 - Ink readies at turn start", () => {
|
|
169
|
+
// Arrange: Exert ink by paying cost
|
|
170
|
+
|
|
171
|
+
// Act: Pass turn, start new turn
|
|
172
|
+
|
|
173
|
+
// Assert: Ink should be ready again
|
|
174
|
+
expect(true).toBe(false); // Will fail until ink ready implemented
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("8.6. Discard", () => {
|
|
179
|
+
/**
|
|
180
|
+
* Rule 8.6.1: Discard pile is a public zone.
|
|
181
|
+
*/
|
|
182
|
+
test.failing("Rule 8.6.1 - Discard is public", () => {
|
|
183
|
+
// Assert: Both players can see discard pile
|
|
184
|
+
expect(true).toBe(false); // Will fail until discard visibility verified
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Banished characters and used actions go to discard.
|
|
189
|
+
*/
|
|
190
|
+
test.failing("Rule 8.6 - Banished cards go to discard", () => {
|
|
191
|
+
// Arrange: Banish a character
|
|
192
|
+
|
|
193
|
+
// Assert: Character should be in discard pile
|
|
194
|
+
expect(true).toBe(false); // Will fail until banish destination verified
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("8.7. Bag", () => {
|
|
199
|
+
/**
|
|
200
|
+
* Rule 8.7.1: The bag holds triggered abilities waiting to resolve.
|
|
201
|
+
*/
|
|
202
|
+
test.failing("Rule 8.7.1 - Bag holds triggered abilities", () => {
|
|
203
|
+
// Arrange: Trigger an ability
|
|
204
|
+
|
|
205
|
+
// Assert: Ability should be in bag waiting to resolve
|
|
206
|
+
expect(true).toBe(false); // Will fail until bag system implemented
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Rule 8.7.2: Active player chooses which triggered ability to resolve first.
|
|
211
|
+
*/
|
|
212
|
+
test.failing("Rule 8.7.2 - Active player chooses resolution order", () => {
|
|
213
|
+
// Arrange: Multiple triggers in bag
|
|
214
|
+
|
|
215
|
+
// Act: Active player selects order
|
|
216
|
+
|
|
217
|
+
// Assert: Triggers resolve in chosen order
|
|
218
|
+
expect(true).toBe(false); // Will fail until bag ordering implemented
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Rule 8.7.3: Abilities from active player resolve before opponent's.
|
|
223
|
+
*/
|
|
224
|
+
test.failing("Rule 8.7.3 - Active player's triggers first", () => {
|
|
225
|
+
// Arrange: Both players have triggered abilities
|
|
226
|
+
|
|
227
|
+
// Assert: Active player's resolve first
|
|
228
|
+
expect(true).toBe(false); // Will fail until bag priority implemented
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
});
|