@drmxrcy/tcg-lorcana-types 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.
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Control Flow Effect Types
3
+ *
4
+ * Effects that control the flow of ability resolution:
5
+ * - Sequence (do A then B)
6
+ * - Choice (choose one of A or B)
7
+ * - Conditional (if X then A else B)
8
+ * - Optional (you may do A)
9
+ * - For-each (for each X, do A)
10
+ * - Repeat (do A X times)
11
+ */
12
+
13
+ import type { Condition } from "../condition-types";
14
+ import type { CharacterTarget, PlayerTarget } from "../target-types";
15
+ import type { Amount, EffectDuration } from "./amount-types";
16
+
17
+ // Forward reference - will be imported from combined-types at runtime
18
+ // This avoids circular dependency during type checking
19
+ import type { Effect } from "./combined-types";
20
+
21
+ // ============================================================================
22
+ // Control Flow Effects
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Sequence of effects (executed in order)
27
+ *
28
+ * @example "Draw 2 cards, then choose and discard a card"
29
+ */
30
+ export interface SequenceEffect {
31
+ type: "sequence";
32
+ /** Array of effects to execute in order (preferred name) */
33
+ steps?: Effect[];
34
+ /** Alias for steps - both are supported for parser compatibility */
35
+ effects?: Effect[];
36
+ }
37
+
38
+ /**
39
+ * Choose one of multiple effects
40
+ *
41
+ * @example "Choose one: Draw a card. Deal 2 damage to chosen character."
42
+ */
43
+ export interface ChoiceEffect {
44
+ type: "choice";
45
+ /** Array of effect options (preferred name) */
46
+ options?: Effect[];
47
+ /** Alias for options - both are supported for parser compatibility */
48
+ choices?: Effect[];
49
+ /** Who makes the choice */
50
+ chooser?: PlayerTarget;
51
+ /** Who chooses (alternative field) */
52
+ chosenBy?: "you" | "opponent" | "TARGET";
53
+ /** Label/name for each option (for display) */
54
+ optionLabels?: string[];
55
+ }
56
+
57
+ /**
58
+ * Conditional effect (if/then/else)
59
+ *
60
+ * @example "If you have a character named Elsa, draw a card"
61
+ */
62
+ export interface ConditionalEffect {
63
+ type: "conditional";
64
+ condition?: Condition;
65
+ /** Effect to execute if condition is true (preferred) */
66
+ then?: Effect;
67
+ /** Alternative field for then effect */
68
+ effect?: Effect;
69
+ /** Effect to execute if condition is false */
70
+ else?: Effect;
71
+ /** Alternative fields for if-true/if-false */
72
+ ifTrue?: Effect;
73
+ ifFalse?: Effect;
74
+ }
75
+
76
+ /**
77
+ * Optional effect ("you may")
78
+ *
79
+ * @example "You may draw a card"
80
+ */
81
+ export interface OptionalEffect {
82
+ type: "optional";
83
+ effect?: Effect;
84
+ /** Who decides */
85
+ chooser?: PlayerTarget;
86
+ }
87
+
88
+ /**
89
+ * For-each effect (repeat for each X)
90
+ *
91
+ * @example "Gain 1 lore for each character you have in play"
92
+ */
93
+ export interface ForEachEffect {
94
+ type: "for-each";
95
+ counter?: ForEachCounter;
96
+ effect?: Effect;
97
+ /** Maximum times to repeat (optional) */
98
+ maximum?: number;
99
+ /** Stat to modify (for static for-each effects) */
100
+ stat?: "strength" | "willpower" | "lore";
101
+ /** Modifier per count (for static for-each effects) */
102
+ modifier?: number;
103
+ /** Target for the effect */
104
+ target?: CharacterTarget;
105
+ }
106
+
107
+ /**
108
+ * What to count for for-each effects
109
+ */
110
+ export type ForEachCounter =
111
+ | { type: "characters"; controller: "you" | "opponent" | "any" }
112
+ | { type: "damaged-characters"; controller: "you" | "opponent" | "any" }
113
+ | { type: "items"; controller: "you" | "opponent" }
114
+ | { type: "items-in-play"; controller: "you" | "opponent" }
115
+ | { type: "locations"; controller: "you" | "opponent" }
116
+ | { type: "cards-in-hand"; controller: "you" | "opponent" }
117
+ | { type: "cards-in-discard"; controller: "you" | "opponent" }
118
+ | { type: "damage-on-self" }
119
+ | { type: "damage-on-target" }
120
+ | { type: "cards-under-self" }
121
+ | { type: "characters-that-sang"; thisTurn: boolean };
122
+
123
+ /**
124
+ * Repeat effect X times
125
+ */
126
+ export interface RepeatEffect {
127
+ type: "repeat";
128
+ times: Amount;
129
+ effect: Effect;
130
+ }
131
+
132
+ // ============================================================================
133
+ // Additional Effect Types for Parser Support
134
+ // ============================================================================
135
+
136
+ /**
137
+ * Cost-effect pattern - pay a cost to get an effect
138
+ *
139
+ * @example "Return chosen character to your hand to play another character"
140
+ * @example "Banish one of your items to draw 2 cards"
141
+ */
142
+ export interface CostEffectEffect {
143
+ type: "cost-effect";
144
+ cost: Effect | { ink?: number; type?: string; target?: string };
145
+ effect: Effect;
146
+ }
147
+
148
+ /**
149
+ * Reveal and conditional effect - reveal cards and act based on what's revealed
150
+ *
151
+ * @example "Reveal the top card. If it's a character, play it for free."
152
+ */
153
+ export interface RevealAndConditionalEffect {
154
+ type: "reveal-and-conditional";
155
+ reveal: {
156
+ source: "deck" | "hand" | "discard";
157
+ count: number;
158
+ position?: "top" | "bottom";
159
+ };
160
+ condition: {
161
+ type: "card-type" | "classification" | "name" | "cost";
162
+ cardType?: string;
163
+ classification?: string;
164
+ name?: string;
165
+ maxCost?: number;
166
+ };
167
+ ifTrue: Effect;
168
+ ifFalse?: Effect;
169
+ }
170
+
171
+ /**
172
+ * Grant keyword effect (for triggered/action effects, not static)
173
+ *
174
+ * @example "Your characters gain Evasive this turn"
175
+ */
176
+ export interface GrantKeywordEffect {
177
+ type: "grant-keyword";
178
+ keyword: string;
179
+ value?: number;
180
+ target: CharacterTarget;
181
+ duration?: EffectDuration;
182
+ }
183
+
184
+ /**
185
+ * Grant multiple keywords at once
186
+ *
187
+ * @example "Chosen character gains Challenger +2 and Resist +2 this turn"
188
+ */
189
+ export interface GrantKeywordsEffect {
190
+ type: "grant-keywords";
191
+ keywords: Array<{ keyword: string; value?: number }>;
192
+ target: CharacterTarget;
193
+ duration?: EffectDuration;
194
+ }
195
+
196
+ /**
197
+ * Delayed effect - effect that happens at a later time
198
+ *
199
+ * @example "At the end of the turn, banish them"
200
+ */
201
+ export interface DelayedEffect {
202
+ type: "delayed";
203
+ timing: "end-of-turn" | "start-of-next-turn" | "end-of-next-turn";
204
+ effect: Effect;
205
+ }
206
+
207
+ /**
208
+ * Play for free effect
209
+ *
210
+ * @example "Play a character with cost 4 or less for free"
211
+ */
212
+ export interface PlayForFreeEffect {
213
+ type: "play-for-free";
214
+ filter?: {
215
+ cardType?: string;
216
+ maxCost?: number | string;
217
+ classification?: string;
218
+ };
219
+ enterExerted?: boolean;
220
+ }
221
+
222
+ /**
223
+ * Put on deck effect
224
+ *
225
+ * @example "Put the rest on the bottom of your deck in any order"
226
+ */
227
+ export interface PutOnDeckEffect {
228
+ type: "put-on-deck";
229
+ position?: "top" | "bottom" | "choice";
230
+ order?: "any" | "random";
231
+ options?: Array<{ position: "top" | "bottom" } | string>;
232
+ target?: string;
233
+ }
234
+
235
+ /**
236
+ * Look effect (for looking at cards)
237
+ *
238
+ * @example "Look at the top 3 cards of your deck"
239
+ */
240
+ export interface LookEffect {
241
+ type: "look";
242
+ source?: "deck" | "hand" | "discard";
243
+ position?: "top" | "bottom";
244
+ count?: number;
245
+ }
246
+
247
+ /**
248
+ * Put into hand effect
249
+ *
250
+ * @example "You may put one into your hand"
251
+ */
252
+ export interface PutIntoHandEffect {
253
+ type: "put-into-hand";
254
+ count: number;
255
+ source?: "revealed" | "deck" | "discard";
256
+ }
257
+
258
+ /**
259
+ * Compound effect (legacy - use sequence instead)
260
+ * @deprecated Use SequenceEffect instead
261
+ */
262
+ export interface CompoundEffect {
263
+ type: "compound";
264
+ effects?: Effect[];
265
+ }
266
+
267
+ /**
268
+ * For each opponent effect
269
+ */
270
+ export interface ForEachOpponentEffect {
271
+ type: "for-each-opponent";
272
+ effect: Effect;
273
+ condition?: Condition;
274
+ }
275
+
276
+ /**
277
+ * For each player effect
278
+ */
279
+ export interface ForEachPlayerEffect {
280
+ type: "for-each-player";
281
+ effect: Effect;
282
+ }
283
+
284
+ /**
285
+ * Prevent damage effect
286
+ */
287
+ export interface PreventDamageEffect {
288
+ type: "prevent-damage";
289
+ amount?: Amount | "all";
290
+ target?: CharacterTarget;
291
+ source?: "challenges" | "abilities" | "all" | "CHALLENGE";
292
+ }
293
+
294
+ /**
295
+ * Gain ability effect (for triggered effects)
296
+ */
297
+ export interface GainAbilityEffect {
298
+ type: "gain-ability";
299
+ ability?: {
300
+ type: string;
301
+ [key: string]: unknown;
302
+ };
303
+ target?: CharacterTarget;
304
+ duration?: EffectDuration;
305
+ }
306
+
307
+ /**
308
+ * Redirect damage effect
309
+ */
310
+ export interface RedirectDamageEffect {
311
+ type: "redirect-damage";
312
+ from?: CharacterTarget;
313
+ to?: CharacterTarget;
314
+ target?: CharacterTarget;
315
+ /** Amount of damage to redirect */
316
+ amount?: Amount | "all";
317
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Effect Types Index
3
+ *
4
+ * Re-exports all effect types and type guards from sub-modules.
5
+ * Import from this file for all effect-related types.
6
+ */
7
+
8
+ // Shared types
9
+ export type {
10
+ Amount,
11
+ AmountString,
12
+ EffectDuration,
13
+ ForEachCounterType,
14
+ VariableAmount,
15
+ } from "./amount-types";
16
+ export { isVariableAmount } from "./amount-types";
17
+
18
+ // Basic effects
19
+ export type {
20
+ BanishEffect,
21
+ DealDamageEffect,
22
+ DiscardEffect,
23
+ DrawEffect,
24
+ ExertEffect,
25
+ GainLoreEffect,
26
+ LoseLoreEffect,
27
+ MoveDamageEffect,
28
+ PutDamageEffect,
29
+ ReadyEffect,
30
+ RemoveDamageEffect,
31
+ } from "./basic-effects";
32
+ // Combined types and guards
33
+ export type {
34
+ ChallengeReadyEffect,
35
+ Effect,
36
+ EntersPlayWithEffect,
37
+ GainKeywordsEffect,
38
+ ReplacementEffect,
39
+ StaticEffect,
40
+ } from "./combined-types";
41
+ export {
42
+ isControlFlowEffect,
43
+ isScryEffect,
44
+ targetsCharacters,
45
+ } from "./combined-types";
46
+ // Control flow effects
47
+ export type {
48
+ ChoiceEffect,
49
+ CompoundEffect,
50
+ ConditionalEffect,
51
+ CostEffectEffect,
52
+ DelayedEffect,
53
+ ForEachCounter,
54
+ ForEachEffect,
55
+ ForEachOpponentEffect,
56
+ ForEachPlayerEffect,
57
+ GainAbilityEffect,
58
+ GrantKeywordEffect,
59
+ GrantKeywordsEffect,
60
+ LookEffect,
61
+ OptionalEffect,
62
+ PlayForFreeEffect,
63
+ PreventDamageEffect,
64
+ PutIntoHandEffect,
65
+ PutOnDeckEffect,
66
+ RedirectDamageEffect,
67
+ RepeatEffect,
68
+ RevealAndConditionalEffect,
69
+ SequenceEffect,
70
+ } from "./control-flow";
71
+
72
+ // Modifier effects
73
+ export type {
74
+ CostReductionEffect,
75
+ DrawUntilHandSizeEffect,
76
+ EntersPlayEffect,
77
+ GainKeywordEffect,
78
+ GrantAbilityEffect,
79
+ LoseKeywordEffect,
80
+ ModifyStatEffect,
81
+ NameACardEffect,
82
+ PropertyModificationEffect,
83
+ PutOnTopEffect,
84
+ RestrictionEffect,
85
+ RevealHandEffect,
86
+ RevealTopCardEffect,
87
+ SearchDeckEffect,
88
+ SetStatEffect,
89
+ WinConditionEffect,
90
+ } from "./modifier-effects";
91
+ // Movement effects
92
+ export type {
93
+ EnablePlayFromUnderEffect,
94
+ GrantAbilitiesWhileHereEffect,
95
+ MoveCostReductionEffect,
96
+ MoveToLocationEffect,
97
+ PlayCardEffect,
98
+ PutIntoInkwellEffect,
99
+ PutOnBottomEffect,
100
+ PutUnderEffect,
101
+ ReturnFromDiscardEffect,
102
+ ReturnToHandEffect,
103
+ ShuffleIntoDeckEffect,
104
+ } from "./movement-effects";
105
+ // Scry effects
106
+ export type {
107
+ ScryAndFilter,
108
+ ScryCardFilter,
109
+ ScryCardOrdering,
110
+ ScryCardTypeFilter,
111
+ ScryClassificationFilter,
112
+ ScryCostComparisonFilter,
113
+ ScryDeckBottomDestination,
114
+ ScryDeckTopDestination,
115
+ ScryDestination,
116
+ ScryDiscardDestination,
117
+ ScryEffect,
118
+ ScryFloodbornFilter,
119
+ ScryHandDestination,
120
+ ScryInkwellDestination,
121
+ ScryKeywordFilter,
122
+ ScryNameFilter,
123
+ ScryNotFilter,
124
+ ScryOrFilter,
125
+ ScryPlayDestination,
126
+ ScrySongFilter,
127
+ } from "./scry-effects";
128
+ export {
129
+ isScryDeckBottomDestination,
130
+ isScryDeckTopDestination,
131
+ isScryDiscardDestination,
132
+ isScryHandDestination,
133
+ isScryInkwellDestination,
134
+ isScryPlayDestination,
135
+ isScryRemainderDestination,
136
+ } from "./scry-effects";
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Modifier Effect Types
3
+ *
4
+ * Effects that modify game state or card properties:
5
+ * - Stat modifications (strength, willpower, lore)
6
+ * - Keyword granting/removal
7
+ * - Restrictions
8
+ * - Special state modifications
9
+ * - Reveal/Search effects
10
+ */
11
+
12
+ import type { CardType } from "../../cards/card-types";
13
+ import type { Condition } from "../condition-types";
14
+ import type {
15
+ CardTarget,
16
+ CharacterTarget,
17
+ LocationTarget,
18
+ PlayerTarget,
19
+ } from "../target-types";
20
+ import type { Amount, EffectDuration } from "./amount-types";
21
+
22
+ // ============================================================================
23
+ // Stat Modification Effects
24
+ // ============================================================================
25
+
26
+ /**
27
+ * Modify stat effect (for "this turn" effects)
28
+ *
29
+ * @example "Chosen character gets +2 strength this turn"
30
+ * @example "Your characters get +1 lore this turn"
31
+ */
32
+ export interface ModifyStatEffect {
33
+ type: "modify-stat";
34
+ stat?: "strength" | "willpower" | "lore";
35
+ modifier?: Amount;
36
+ target?: CharacterTarget | LocationTarget;
37
+ duration?: EffectDuration;
38
+ /** Alternative field for modifier value */
39
+ value?: Amount;
40
+ }
41
+
42
+ /**
43
+ * Set stat effect (absolute value)
44
+ */
45
+ export interface SetStatEffect {
46
+ type: "set-stat";
47
+ stat: "strength" | "willpower" | "lore";
48
+ value: Amount;
49
+ target: CharacterTarget;
50
+ duration?: EffectDuration;
51
+ }
52
+
53
+ // ============================================================================
54
+ // Keyword Effects
55
+ // ============================================================================
56
+
57
+ /**
58
+ * Grant keyword effect
59
+ *
60
+ * @example "Chosen character gains Rush this turn"
61
+ * @example "Your characters gain Resist +2 this turn"
62
+ */
63
+ export interface GainKeywordEffect {
64
+ type: "gain-keyword";
65
+ keyword?:
66
+ | "Rush"
67
+ | "Ward"
68
+ | "Evasive"
69
+ | "Bodyguard"
70
+ | "Support"
71
+ | "Reckless"
72
+ | "Alert"
73
+ | "Challenger"
74
+ | "Resist"
75
+ | "Singer"
76
+ | "Sing Together"
77
+ | string; // Allow any keyword string for flexibility
78
+ /** For Challenger +X and Resist +X */
79
+ value?: number;
80
+ target?: CharacterTarget;
81
+ duration?: EffectDuration;
82
+ }
83
+
84
+ /**
85
+ * Lose keyword effect
86
+ */
87
+ export interface LoseKeywordEffect {
88
+ type: "lose-keyword";
89
+ keyword: string;
90
+ target: CharacterTarget;
91
+ duration?: EffectDuration;
92
+ }
93
+
94
+ // ============================================================================
95
+ // Restriction Effects
96
+ // ============================================================================
97
+
98
+ /**
99
+ * Apply restriction effect
100
+ *
101
+ * @example "Chosen character can't quest during their next turn"
102
+ * @example "Characters can't be challenged while here"
103
+ */
104
+ export interface RestrictionEffect {
105
+ type: "restriction";
106
+ restriction?:
107
+ | "cant-quest"
108
+ | "cant-challenge"
109
+ | "cant-be-challenged"
110
+ | "cant-ready"
111
+ | "cant-quest-or-challenge"
112
+ | "cant-be-dealt-damage"
113
+ | "cant-sing"
114
+ | "cant-move"
115
+ | "enters-play-exerted"
116
+ | "skip-draw-step"
117
+ | "must-quest" // Forces character to quest if able
118
+ | "cant-play-actions" // Opponents can't play actions
119
+ | "cant-play-characters" // Opponents can't play characters
120
+ | "cant-play" // Generic can't play restriction
121
+ // Extended restrictions for card text coverage
122
+ | "doesnt-ready"; // Character doesn't ready (alias for cant-ready)
123
+ target?: CharacterTarget | PlayerTarget;
124
+ duration?: EffectDuration;
125
+ /** Condition for when the restriction applies */
126
+ condition?: Condition;
127
+ }
128
+
129
+ /**
130
+ * Grant ability effect (can challenge ready characters, etc.)
131
+ */
132
+ export interface GrantAbilityEffect {
133
+ type: "grant-ability";
134
+ ability?:
135
+ | "can-challenge-ready"
136
+ | "takes-no-damage-from-challenges"
137
+ | "return-to-hand-when-banished"
138
+ | { type: string; [key: string]: unknown }; // Allow object-based abilities
139
+ target?: CharacterTarget;
140
+ duration?: EffectDuration;
141
+ }
142
+
143
+ /**
144
+ * Reduce cost effect
145
+ *
146
+ * @example "You pay 1 less to play this item"
147
+ */
148
+ export interface CostReductionEffect {
149
+ type: "cost-reduction";
150
+ amount?: Amount | string;
151
+ /** Alternative field for reduction amount */
152
+ reduction?: { ink: number | string };
153
+ cardType?: CardType | "song";
154
+ target?: PlayerTarget; // Who gets the reduction (usually YOU)
155
+ duration?: EffectDuration;
156
+ }
157
+
158
+ // ============================================================================
159
+ // Misc Effects
160
+ // ============================================================================
161
+
162
+ export interface NameACardEffect {
163
+ type: "name-a-card";
164
+ }
165
+
166
+ export interface RevealTopCardEffect {
167
+ type: "reveal-top-card";
168
+ target?: PlayerTarget; // Whose deck
169
+ }
170
+
171
+ export interface PutOnTopEffect {
172
+ type: "put-on-top";
173
+ source?: "revealed" | CardTarget;
174
+ }
175
+
176
+ export interface DrawUntilHandSizeEffect {
177
+ type: "draw-until-hand-size";
178
+ size: number;
179
+ target?: PlayerTarget;
180
+ }
181
+
182
+ // ============================================================================
183
+ // Special State Modifications
184
+ // ============================================================================
185
+
186
+ /**
187
+ * Enters play modification effect
188
+ *
189
+ * @example "Enters play exerted"
190
+ * @example "Enters play with 2 damage"
191
+ */
192
+ export interface EntersPlayEffect {
193
+ type: "enters-play-modification";
194
+ modification: "exerted" | "damaged";
195
+ amount?: number; // for damaged
196
+ target: CharacterTarget;
197
+ }
198
+
199
+ /**
200
+ * Win condition modification effect
201
+ *
202
+ * @example "Opponents need 25 lore to win"
203
+ */
204
+ export interface WinConditionEffect {
205
+ type: "win-condition-modification";
206
+ loreRequired: number;
207
+ target: PlayerTarget;
208
+ }
209
+
210
+ /**
211
+ * Property modification effect
212
+ *
213
+ * @example "This character counts as being named 'Dalmatian Puppy'"
214
+ */
215
+ export interface PropertyModificationEffect {
216
+ type: "property-modification";
217
+ property?: "name";
218
+ value?: string;
219
+ operation?: "add-alias";
220
+ target?: CharacterTarget;
221
+ }
222
+
223
+ // ============================================================================
224
+ // Reveal/Search Effects
225
+ // ============================================================================
226
+
227
+ /**
228
+ * Reveal hand effect
229
+ */
230
+ export interface RevealHandEffect {
231
+ type: "reveal-hand";
232
+ target: PlayerTarget;
233
+ }
234
+
235
+ /**
236
+ * Search deck effect
237
+ */
238
+ export interface SearchDeckEffect {
239
+ type: "search-deck";
240
+ cardType?: CardType | "song" | "floodborn";
241
+ cardName?: string;
242
+ classification?: string;
243
+ putInto?: "hand" | "top-of-deck" | "play";
244
+ /** Alias for putInto: "top-of-deck" */
245
+ putOnTop?: boolean;
246
+ reveal?: boolean;
247
+ shuffle?: boolean;
248
+ }