@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,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 9: Damage
|
|
3
|
+
*
|
|
4
|
+
* Tests for rules 9.1-9.4 from Disney Lorcana Comprehensive Rules (Aug 22, 2025)
|
|
5
|
+
* Covers damage representation, "put" vs "deal", moving damage, and leaving play.
|
|
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 9: Damage", () => {
|
|
16
|
+
let testEngine: LorcanaTestEngine;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
testEngine = new LorcanaTestEngine(
|
|
20
|
+
{ hand: 7, deck: 53, inkwell: 3 },
|
|
21
|
+
{ hand: 7, deck: 53, inkwell: 3 },
|
|
22
|
+
{ skipPreGame: true },
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
testEngine.dispose();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("9.1. Representation of Damage", () => {
|
|
31
|
+
/**
|
|
32
|
+
* Rule 9.1.1: Damage is tracked on characters and locations using damage counters.
|
|
33
|
+
* Each counter represents 1 damage.
|
|
34
|
+
*/
|
|
35
|
+
test.failing("Rule 9.1.1 - Damage tracked with counters", () => {
|
|
36
|
+
// Arrange: Create character
|
|
37
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
38
|
+
strength: 2,
|
|
39
|
+
willpower: 5,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Initially should have 0 damage
|
|
43
|
+
expect(testEngine.getDamage(character)).toBe(0);
|
|
44
|
+
|
|
45
|
+
// After taking damage, counter should increase
|
|
46
|
+
// (need to deal damage somehow)
|
|
47
|
+
expect(true).toBe(false); // Will fail until damage dealing implemented
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Damage is persistent - accumulates over the game.
|
|
52
|
+
*/
|
|
53
|
+
test.failing("Rule 9.1 - Damage persists across turns", () => {
|
|
54
|
+
// Arrange: Deal damage to character
|
|
55
|
+
|
|
56
|
+
// Act: Pass multiple turns
|
|
57
|
+
|
|
58
|
+
// Assert: Damage should still be there
|
|
59
|
+
expect(true).toBe(false); // Will fail until damage persistence verified
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("9.2. 'Put' Damage", () => {
|
|
64
|
+
/**
|
|
65
|
+
* Rule 9.2.1: "Put damage" is different from "deal damage".
|
|
66
|
+
* Put bypasses effects that modify dealt damage (like Resist).
|
|
67
|
+
*/
|
|
68
|
+
test.failing("Rule 9.2.1 - Put damage bypasses Resist", () => {
|
|
69
|
+
// Arrange: Character with Resist 2
|
|
70
|
+
|
|
71
|
+
// Act: Put 3 damage on it
|
|
72
|
+
|
|
73
|
+
// Assert: Should take full 3 damage (Resist doesn't apply)
|
|
74
|
+
expect(true).toBe(false); // Will fail until put vs deal distinction implemented
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* "Put" also bypasses damage prevention effects.
|
|
79
|
+
*/
|
|
80
|
+
test.failing("Rule 9.2 - Put damage bypasses prevention", () => {
|
|
81
|
+
// Arrange: Damage prevention effect active
|
|
82
|
+
|
|
83
|
+
// Act: Put damage
|
|
84
|
+
|
|
85
|
+
// Assert: Damage should still be placed
|
|
86
|
+
expect(true).toBe(false); // Will fail until put damage implemented
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("9.3. Moving Damage Counters", () => {
|
|
91
|
+
/**
|
|
92
|
+
* Rule 9.3.1: Some effects can move damage counters between cards.
|
|
93
|
+
*/
|
|
94
|
+
test.failing("Rule 9.3.1 - Damage counters can be moved", () => {
|
|
95
|
+
// Arrange: Two characters, one with damage
|
|
96
|
+
|
|
97
|
+
// Act: Move damage from one to other
|
|
98
|
+
|
|
99
|
+
// Assert: Damage should transfer
|
|
100
|
+
expect(true).toBe(false); // Will fail until damage movement implemented
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Moving damage is not dealing or putting damage (doesn't trigger those effects).
|
|
105
|
+
*/
|
|
106
|
+
test.failing("Rule 9.3 - Moving damage is not dealing", () => {
|
|
107
|
+
// Arrange: "When this character takes damage" trigger
|
|
108
|
+
|
|
109
|
+
// Act: Move damage to this character
|
|
110
|
+
|
|
111
|
+
// Assert: Trigger should NOT fire (moving isn't dealing/taking)
|
|
112
|
+
expect(true).toBe(false); // Will fail until damage movement semantics implemented
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("9.4. Leaving Play", () => {
|
|
117
|
+
/**
|
|
118
|
+
* Rule 9.4.1: When a card leaves play, all damage on it is removed.
|
|
119
|
+
*/
|
|
120
|
+
test.failing("Rule 9.4.1 - Damage cleared when leaving play", () => {
|
|
121
|
+
// Arrange: Character with 2 damage (not lethal)
|
|
122
|
+
const character = testEngine.createCharacterInPlay(PLAYER_ONE, {
|
|
123
|
+
strength: 2,
|
|
124
|
+
willpower: 5,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Deal 2 damage somehow
|
|
128
|
+
// Then return character to hand
|
|
129
|
+
|
|
130
|
+
// Act: Play character again
|
|
131
|
+
|
|
132
|
+
// Assert: Should have 0 damage (cleared when left play)
|
|
133
|
+
expect(true).toBe(false); // Will fail until leaving play cleanup implemented
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* If a character would leave play but is prevented, damage stays.
|
|
138
|
+
*/
|
|
139
|
+
test.failing("Rule 9.4 - Prevention keeps damage", () => {
|
|
140
|
+
// Arrange: Character with damage, replacement effect preventing leaving
|
|
141
|
+
|
|
142
|
+
// Act: Try to banish character (prevented)
|
|
143
|
+
|
|
144
|
+
// Assert: Damage should remain
|
|
145
|
+
expect(true).toBe(false); // Will fail until leave prevention implemented
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 10: Keywords
|
|
3
|
+
*
|
|
4
|
+
* Tests for rules 10.1-10.13 from Disney Lorcana Comprehensive Rules (Aug 22, 2025)
|
|
5
|
+
* Covers all keywords: General, Bodyguard, Challenger, Evasive, Reckless, Resist,
|
|
6
|
+
* Rush, Shift, Singer, Sing Together, Support, Vanish, and Ward.
|
|
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 10: Keywords", () => {
|
|
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("10.1. General", () => {
|
|
32
|
+
/**
|
|
33
|
+
* Rule 10.1.1: Keywords are abilities represented by specific words or phrases.
|
|
34
|
+
*/
|
|
35
|
+
test.failing("Rule 10.1.1 - Keywords represent abilities", () => {
|
|
36
|
+
// Assert: Keyword should expand to full ability rules
|
|
37
|
+
expect(true).toBe(false); // Will fail until keyword system implemented
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Rule 10.1.2: Some keywords stack (add together), some don't.
|
|
42
|
+
*/
|
|
43
|
+
test.failing("Rule 10.1.2 - Keyword stacking rules", () => {
|
|
44
|
+
// Arrange: Character with Challenger +2 from two sources
|
|
45
|
+
|
|
46
|
+
// Assert: Should have Challenger +4 (stacks)
|
|
47
|
+
expect(true).toBe(false); // Will fail until keyword stacking implemented
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Rule 10.1.3: Technical definitions define exact keyword behavior.
|
|
52
|
+
* Reminder text is not rules text.
|
|
53
|
+
*/
|
|
54
|
+
test.failing("Rule 10.1.3 - Reminder text is not rules", () => {
|
|
55
|
+
// Assert: Only technical definition applies, not reminder text
|
|
56
|
+
expect(true).toBe(false); // Will fail until keyword parsing verified
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("10.2. Bodyguard", () => {
|
|
61
|
+
/**
|
|
62
|
+
* Rule 10.2.1: Bodyguard - When this character is exerted, opposing characters
|
|
63
|
+
* must challenge this character if able.
|
|
64
|
+
*/
|
|
65
|
+
test.failing("Rule 10.2.1 - Bodyguard forces challenges to this character", () => {
|
|
66
|
+
// Arrange: Bodyguard character (exerted), other character
|
|
67
|
+
// Opponent has character that could challenge either
|
|
68
|
+
|
|
69
|
+
// Assert: Opponent must challenge Bodyguard
|
|
70
|
+
expect(true).toBe(false); // Will fail until Bodyguard implemented
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Bodyguard only applies when exerted.
|
|
75
|
+
*/
|
|
76
|
+
test.failing("Rule 10.2 - Bodyguard requires exerted state", () => {
|
|
77
|
+
// Arrange: Bodyguard character (ready)
|
|
78
|
+
|
|
79
|
+
// Assert: Opponent can challenge other characters
|
|
80
|
+
expect(true).toBe(false); // Will fail until Bodyguard state check implemented
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Multiple Bodyguards - opponent chooses which to challenge.
|
|
85
|
+
*/
|
|
86
|
+
test.failing("Rule 10.2 - Multiple Bodyguards allow choice", () => {
|
|
87
|
+
// Arrange: Two exerted Bodyguard characters
|
|
88
|
+
|
|
89
|
+
// Assert: Opponent can choose either
|
|
90
|
+
expect(true).toBe(false); // Will fail until multiple Bodyguard implemented
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("10.3. Challenger", () => {
|
|
95
|
+
/**
|
|
96
|
+
* Rule 10.3.1: Challenger +X - This character gets +X Strength while challenging.
|
|
97
|
+
*/
|
|
98
|
+
test.failing("Rule 10.3.1 - Challenger adds Strength when challenging", () => {
|
|
99
|
+
// Arrange: Character with Challenger +2 (base strength 3)
|
|
100
|
+
// Defender with 4 willpower
|
|
101
|
+
|
|
102
|
+
// Act: Challenge
|
|
103
|
+
|
|
104
|
+
// Assert: Should deal 5 damage (3 + 2 from Challenger)
|
|
105
|
+
expect(true).toBe(false); // Will fail until Challenger implemented
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Rule 10.3.2: Challenger stacks - multiple sources add together.
|
|
110
|
+
*/
|
|
111
|
+
test.failing("Rule 10.3.2 - Challenger stacks", () => {
|
|
112
|
+
// Arrange: Character with Challenger +2 and Challenger +1
|
|
113
|
+
|
|
114
|
+
// Assert: Should have Challenger +3 total
|
|
115
|
+
expect(true).toBe(false); // Will fail until Challenger stacking implemented
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Challenger only applies while challenging, not when being challenged.
|
|
120
|
+
*/
|
|
121
|
+
test.failing("Rule 10.3 - Challenger only when attacking", () => {
|
|
122
|
+
// Arrange: Challenger character being challenged
|
|
123
|
+
|
|
124
|
+
// Assert: Challenger bonus should NOT apply
|
|
125
|
+
expect(true).toBe(false); // Will fail until Challenger direction implemented
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("10.4. Evasive", () => {
|
|
130
|
+
/**
|
|
131
|
+
* Rule 10.4.1: Evasive - Only characters with Evasive can challenge this character.
|
|
132
|
+
*/
|
|
133
|
+
test.failing("Rule 10.4.1 - Only Evasive can challenge Evasive", () => {
|
|
134
|
+
// Arrange: Evasive character (exerted), non-Evasive attacker
|
|
135
|
+
|
|
136
|
+
// Act: Try to challenge Evasive character
|
|
137
|
+
|
|
138
|
+
// Assert: Should fail
|
|
139
|
+
expect(true).toBe(false); // Will fail until Evasive implemented
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Evasive character can challenge Evasive character.
|
|
144
|
+
*/
|
|
145
|
+
test.failing("Rule 10.4 - Evasive can challenge Evasive", () => {
|
|
146
|
+
// Arrange: Two Evasive characters
|
|
147
|
+
|
|
148
|
+
// Act: One challenges the other
|
|
149
|
+
|
|
150
|
+
// Assert: Should succeed
|
|
151
|
+
expect(true).toBe(false); // Will fail until Evasive vs Evasive implemented
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe("10.5. Reckless", () => {
|
|
156
|
+
/**
|
|
157
|
+
* Rule 10.5.1: Reckless - This character must challenge if able.
|
|
158
|
+
*/
|
|
159
|
+
test.failing("Rule 10.5.1 - Reckless must challenge when possible", () => {
|
|
160
|
+
// Arrange: Reckless character, exerted opponent character
|
|
161
|
+
|
|
162
|
+
// Assert: Reckless character cannot quest (must challenge)
|
|
163
|
+
expect(true).toBe(false); // Will fail until Reckless implemented
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Reckless only forced when a valid challenge target exists.
|
|
168
|
+
*/
|
|
169
|
+
test.failing("Rule 10.5 - Reckless can quest if no targets", () => {
|
|
170
|
+
// Arrange: Reckless character, no exerted opponent characters
|
|
171
|
+
|
|
172
|
+
// Assert: Reckless character can quest
|
|
173
|
+
expect(true).toBe(false); // Will fail until Reckless target check implemented
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Reckless character can use abilities instead of challenging.
|
|
178
|
+
*/
|
|
179
|
+
test.failing("Rule 10.5 - Reckless can use abilities", () => {
|
|
180
|
+
// Arrange: Reckless character with activated ability, valid challenge target
|
|
181
|
+
|
|
182
|
+
// Assert: Can use ability (Reckless doesn't force challenge over abilities)
|
|
183
|
+
// Note: This may depend on exact ruling interpretation
|
|
184
|
+
expect(true).toBe(false); // Will fail until Reckless ability interaction implemented
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("10.6. Resist", () => {
|
|
189
|
+
/**
|
|
190
|
+
* Rule 10.6.1: Resist +X - When this character takes damage, reduce it by X.
|
|
191
|
+
*/
|
|
192
|
+
test.failing("Rule 10.6.1 - Resist reduces damage taken", () => {
|
|
193
|
+
// Arrange: Character with Resist 2, willpower 5
|
|
194
|
+
|
|
195
|
+
// Act: Deal 4 damage
|
|
196
|
+
|
|
197
|
+
// Assert: Should take 2 damage (4 - 2 Resist)
|
|
198
|
+
expect(true).toBe(false); // Will fail until Resist implemented
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Rule 10.6.2: Resist stacks - multiple sources add together.
|
|
203
|
+
*/
|
|
204
|
+
test.failing("Rule 10.6.2 - Resist stacks", () => {
|
|
205
|
+
// Arrange: Character with Resist 2 and Resist 1
|
|
206
|
+
|
|
207
|
+
// Act: Deal 5 damage
|
|
208
|
+
|
|
209
|
+
// Assert: Should take 2 damage (5 - 3 total Resist)
|
|
210
|
+
expect(true).toBe(false); // Will fail until Resist stacking implemented
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Rule 10.6.3: Resist can reduce damage to 0 but not below.
|
|
215
|
+
*/
|
|
216
|
+
test.failing("Rule 10.6.3 - Resist cannot make damage negative", () => {
|
|
217
|
+
// Arrange: Character with Resist 5
|
|
218
|
+
|
|
219
|
+
// Act: Deal 2 damage
|
|
220
|
+
|
|
221
|
+
// Assert: Should take 0 damage (not -3)
|
|
222
|
+
expect(true).toBe(false); // Will fail until Resist floor implemented
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Resist only applies to dealt damage, not put damage.
|
|
227
|
+
*/
|
|
228
|
+
test.failing("Rule 10.6 - Resist doesn't affect put damage", () => {
|
|
229
|
+
// Arrange: Character with Resist 2
|
|
230
|
+
|
|
231
|
+
// Act: Put 3 damage
|
|
232
|
+
|
|
233
|
+
// Assert: Should take 3 damage (put bypasses Resist)
|
|
234
|
+
expect(true).toBe(false); // Will fail until Resist vs put implemented
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe("10.7. Rush", () => {
|
|
239
|
+
/**
|
|
240
|
+
* Rule 10.7.1: Rush - This character can challenge the turn it's played.
|
|
241
|
+
*/
|
|
242
|
+
test.failing("Rule 10.7.1 - Rush allows immediate challenge", () => {
|
|
243
|
+
// Arrange: Play Rush character
|
|
244
|
+
|
|
245
|
+
// Act: Challenge same turn
|
|
246
|
+
|
|
247
|
+
// Assert: Should succeed (no drying restriction)
|
|
248
|
+
expect(true).toBe(false); // Will fail until Rush implemented
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Rush only bypasses challenge restriction, not quest restriction.
|
|
253
|
+
*/
|
|
254
|
+
test.failing("Rule 10.7 - Rush doesn't allow immediate quest", () => {
|
|
255
|
+
// Arrange: Play Rush character
|
|
256
|
+
|
|
257
|
+
// Act: Try to quest same turn
|
|
258
|
+
|
|
259
|
+
// Assert: Should fail (Rush doesn't bypass quest drying)
|
|
260
|
+
expect(true).toBe(false); // Will fail until Rush limitation implemented
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe("10.8. Shift", () => {
|
|
265
|
+
/**
|
|
266
|
+
* Rule 10.8.1: Shift X (cost) - Pay X ink to play this on top of a character
|
|
267
|
+
* with the specified name.
|
|
268
|
+
*/
|
|
269
|
+
test.failing("Rule 10.8.1 - Shift as alternate play cost", () => {
|
|
270
|
+
// Arrange: "Elsa - Snow Queen" in play
|
|
271
|
+
// Floodborn Elsa with Shift 4 in hand
|
|
272
|
+
|
|
273
|
+
// Act: Pay 4 ink to Shift onto Elsa
|
|
274
|
+
|
|
275
|
+
// Assert: Floodborn Elsa should be on top of stack
|
|
276
|
+
expect(true).toBe(false); // Will fail until Shift implemented
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Rule 10.8.2: Shifted character inherits the "dry" state of the base.
|
|
281
|
+
*/
|
|
282
|
+
test.failing("Rule 10.8.2 - Shift inherits dry state", () => {
|
|
283
|
+
// Arrange: Dry character in play
|
|
284
|
+
|
|
285
|
+
// Act: Shift onto it
|
|
286
|
+
|
|
287
|
+
// Assert: New character should also be dry (can quest/challenge)
|
|
288
|
+
expect(true).toBe(false); // Will fail until Shift state inheritance implemented
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Rule 10.8.3: Shifted character inherits damage from the base.
|
|
293
|
+
*/
|
|
294
|
+
test.failing("Rule 10.8.3 - Shift inherits damage", () => {
|
|
295
|
+
// Arrange: Character with 2 damage
|
|
296
|
+
|
|
297
|
+
// Act: Shift onto it
|
|
298
|
+
|
|
299
|
+
// Assert: New character should have 2 damage
|
|
300
|
+
expect(true).toBe(false); // Will fail until Shift damage inheritance implemented
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Rule 10.8.4: When shifted character leaves play, all cards in stack leave.
|
|
305
|
+
*/
|
|
306
|
+
test.failing("Rule 10.8.4 - Stack leaves play together", () => {
|
|
307
|
+
// Arrange: Create shift stack
|
|
308
|
+
|
|
309
|
+
// Act: Banish the top card
|
|
310
|
+
|
|
311
|
+
// Assert: All cards in stack should go to discard
|
|
312
|
+
expect(true).toBe(false); // Will fail until stack leaving implemented
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe("10.9. Singer", () => {
|
|
317
|
+
/**
|
|
318
|
+
* Rule 10.9.1: Singer X - This character counts as cost X for singing songs.
|
|
319
|
+
*/
|
|
320
|
+
test.failing("Rule 10.9.1 - Singer allows singing songs", () => {
|
|
321
|
+
// Arrange: Character with Singer 5, Song with cost 4
|
|
322
|
+
|
|
323
|
+
// Act: Exert character to sing song
|
|
324
|
+
|
|
325
|
+
// Assert: Song should be played (Singer 5 >= Song cost 4)
|
|
326
|
+
expect(true).toBe(false); // Will fail until Singer implemented
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Character cannot sing songs with cost higher than Singer value.
|
|
331
|
+
*/
|
|
332
|
+
test.failing("Rule 10.9 - Singer limits song cost", () => {
|
|
333
|
+
// Arrange: Character with Singer 3, Song with cost 5
|
|
334
|
+
|
|
335
|
+
// Act: Try to sing song
|
|
336
|
+
|
|
337
|
+
// Assert: Should fail (Singer 3 < Song cost 5)
|
|
338
|
+
expect(true).toBe(false); // Will fail until Singer cost check implemented
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe("10.10. Sing Together", () => {
|
|
343
|
+
/**
|
|
344
|
+
* Rule 10.10.1: Sing Together X - Multiple characters can exert together
|
|
345
|
+
* to sing this song if their total ink costs meet or exceed X.
|
|
346
|
+
*/
|
|
347
|
+
test.failing("Rule 10.10.1 - Sing Together combines character costs", () => {
|
|
348
|
+
// Arrange: Two characters (cost 2 each), Song with Sing Together 4
|
|
349
|
+
|
|
350
|
+
// Act: Exert both to sing
|
|
351
|
+
|
|
352
|
+
// Assert: Should succeed (2 + 2 = 4 >= required 4)
|
|
353
|
+
expect(true).toBe(false); // Will fail until Sing Together implemented
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Sing Together uses character ink cost, not Singer value.
|
|
358
|
+
*/
|
|
359
|
+
test.failing("Rule 10.10 - Sing Together uses ink cost", () => {
|
|
360
|
+
// Arrange: Two characters (cost 3 each), even if they have Singer
|
|
361
|
+
|
|
362
|
+
// Assert: Contribution is 3 + 3 = 6, not Singer values
|
|
363
|
+
expect(true).toBe(false); // Will fail until Sing Together cost source implemented
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
describe("10.11. Support", () => {
|
|
368
|
+
/**
|
|
369
|
+
* Rule 10.11.1: Support - When this character quests, choose another character.
|
|
370
|
+
* That character gets +X Strength this turn.
|
|
371
|
+
*/
|
|
372
|
+
test.failing("Rule 10.11.1 - Support grants Strength when questing", () => {
|
|
373
|
+
// Arrange: Character with Support, another character
|
|
374
|
+
|
|
375
|
+
// Act: Quest with Support character
|
|
376
|
+
|
|
377
|
+
// Assert: Chosen character should have +X Strength
|
|
378
|
+
expect(true).toBe(false); // Will fail until Support implemented
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Support bonus lasts until end of turn.
|
|
383
|
+
*/
|
|
384
|
+
test.failing("Rule 10.11 - Support ends at end of turn", () => {
|
|
385
|
+
// Arrange: Use Support
|
|
386
|
+
|
|
387
|
+
// Act: End turn
|
|
388
|
+
|
|
389
|
+
// Assert: Strength bonus should end
|
|
390
|
+
expect(true).toBe(false); // Will fail until Support duration implemented
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
describe("10.12. Vanish", () => {
|
|
395
|
+
/**
|
|
396
|
+
* Rule 10.12.1: Vanish - After this character quests, return it to your hand.
|
|
397
|
+
*/
|
|
398
|
+
test.failing("Rule 10.12.1 - Vanish returns to hand after quest", () => {
|
|
399
|
+
// Arrange: Vanish character
|
|
400
|
+
|
|
401
|
+
// Act: Quest
|
|
402
|
+
|
|
403
|
+
// Assert: Character should be in hand (gained lore first)
|
|
404
|
+
expect(true).toBe(false); // Will fail until Vanish implemented
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Vanish triggers after quest completes (lore is gained first).
|
|
409
|
+
*/
|
|
410
|
+
test.failing("Rule 10.12 - Vanish triggers after lore gained", () => {
|
|
411
|
+
// Arrange: Vanish character, note initial lore
|
|
412
|
+
|
|
413
|
+
// Act: Quest
|
|
414
|
+
|
|
415
|
+
// Assert: Lore should be gained, then character returns to hand
|
|
416
|
+
expect(true).toBe(false); // Will fail until Vanish timing implemented
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
describe("10.13. Ward", () => {
|
|
421
|
+
/**
|
|
422
|
+
* Rule 10.13.1: Ward - Opponents can't choose this character except to challenge.
|
|
423
|
+
*/
|
|
424
|
+
test.failing("Rule 10.13.1 - Ward prevents opponent targeting", () => {
|
|
425
|
+
// Arrange: Ward character, opponent effect that chooses character
|
|
426
|
+
|
|
427
|
+
// Act: Opponent tries to target Ward character
|
|
428
|
+
|
|
429
|
+
// Assert: Should fail (can't choose)
|
|
430
|
+
expect(true).toBe(false); // Will fail until Ward implemented
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Ward doesn't prevent challenges.
|
|
435
|
+
*/
|
|
436
|
+
test.failing("Rule 10.13 - Ward allows challenges", () => {
|
|
437
|
+
// Arrange: Exerted Ward character, opponent attacker
|
|
438
|
+
|
|
439
|
+
// Act: Opponent challenges Ward character
|
|
440
|
+
|
|
441
|
+
// Assert: Should succeed (Ward doesn't block challenges)
|
|
442
|
+
expect(true).toBe(false); // Will fail until Ward challenge exception implemented
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Ward doesn't prevent effects that don't "choose" (e.g., "all characters").
|
|
447
|
+
*/
|
|
448
|
+
test.failing("Rule 10.13 - Ward doesn't block non-choosing effects", () => {
|
|
449
|
+
// Arrange: Ward character, effect that damages "all characters"
|
|
450
|
+
|
|
451
|
+
// Act: Execute effect
|
|
452
|
+
|
|
453
|
+
// Assert: Ward character should be affected
|
|
454
|
+
expect(true).toBe(false); // Will fail until Ward choose distinction implemented
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Ward only protects from opponents, not owner.
|
|
459
|
+
*/
|
|
460
|
+
test.failing("Rule 10.13 - Ward doesn't block owner targeting", () => {
|
|
461
|
+
// Arrange: Ward character, owner effect that chooses character
|
|
462
|
+
|
|
463
|
+
// Act: Owner targets their Ward character
|
|
464
|
+
|
|
465
|
+
// Assert: Should succeed (Ward only blocks opponents)
|
|
466
|
+
expect(true).toBe(false); // Will fail until Ward owner exception implemented
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
});
|