weiss_core/events.rs
1use crate::db::CardId;
2use crate::state::{
3 AttackType, ChoiceOptionRef, ChoiceReason, DamageModifierKind, DamageType, ModifierDuration,
4 ModifierKind, StackItem, TimingWindow, TriggerEffect,
5};
6use serde::{Deserialize, Serialize};
7
8/// Reason for revealing a card.
9#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
10pub enum RevealReason {
11 /// Reveal was due to a trigger check.
12 TriggerCheck,
13 /// Reveal was due to a damage check.
14 DamageCheck,
15 /// Reveal was due to a refresh penalty.
16 RefreshPenalty,
17 /// Reveal was due to a card being played.
18 Play,
19 /// Reveal was due to an ability or effect.
20 AbilityEffect,
21}
22
23/// Audience allowed to see a revealed card.
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
25pub enum RevealAudience {
26 /// Reveal is visible to all observers.
27 Public,
28 /// Reveal is visible only to the card owner.
29 OwnerOnly,
30 /// Reveal is visible only to the controller of the card/effect.
31 ControllerOnly,
32 /// Reveal is visible to both players.
33 BothPlayers,
34 /// Reveal is visible only in full replay output.
35 ReplayOnly,
36}
37
38/// Reason a trigger was canceled.
39#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
40pub enum TriggerCancelReason {
41 /// Trigger source was invalid or left play before resolution.
42 InvalidSource,
43 /// Trigger was suppressed by a rule/effect.
44 Suppressed,
45}
46
47/// Reason a choice was skipped.
48#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
49pub enum ChoiceSkipReason {
50 /// No valid candidates were available.
51 NoCandidates,
52}
53
54/// Logical zone in the game state.
55#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
56pub enum Zone {
57 /// Deck zone.
58 Deck,
59 /// Hand zone.
60 Hand,
61 /// Waiting room zone.
62 WaitingRoom,
63 /// Clock zone.
64 Clock,
65 /// Level zone.
66 Level,
67 /// Stock zone.
68 Stock,
69 /// Memory zone.
70 Memory,
71 /// Climax zone.
72 Climax,
73 /// Resolution zone.
74 Resolution,
75 /// Stage zone.
76 Stage,
77}
78
79/// Snapshot of a choice option for replay/debugging.
80#[derive(Clone, Debug, Serialize, Deserialize)]
81pub struct ChoiceOptionSnapshot {
82 /// Stable id for the option.
83 pub option_id: u64,
84 /// Reference to the underlying option.
85 pub reference: ChoiceOptionRef,
86}
87
88/// Canonical event stream emitted by the engine.
89#[derive(Clone, Debug, Serialize, Deserialize)]
90pub enum Event {
91 /// Player drew a card.
92 Draw {
93 /// Player index.
94 player: u8,
95 /// Card id drawn.
96 card: CardId,
97 },
98 /// Card was revealed during a damage check (damage resolution).
99 Damage {
100 /// Player receiving damage.
101 player: u8,
102 /// Card id revealed.
103 card: CardId,
104 },
105 /// Damage was canceled.
106 DamageCancel {
107 /// Player receiving damage.
108 player: u8,
109 },
110 /// Damage intent before modifiers/cancel resolution.
111 DamageIntent {
112 /// Stable event id for correlating downstream damage events.
113 event_id: u32,
114 /// Source player (if known).
115 source_player: u8,
116 /// Source stage slot (if known).
117 source_slot: Option<u8>,
118 /// Target player.
119 target: u8,
120 /// Intended damage amount.
121 amount: i32,
122 /// Damage classification (battle vs effect damage).
123 damage_type: DamageType,
124 /// Whether damage can be canceled by revealing a climax.
125 cancelable: bool,
126 },
127 /// A damage modifier was applied.
128 DamageModifierApplied {
129 /// Correlated damage event id.
130 event_id: u32,
131 /// Modifier kind applied.
132 modifier: DamageModifierKind,
133 /// Amount before modifier.
134 before_amount: i32,
135 /// Amount after modifier.
136 after_amount: i32,
137 /// Cancelable flag before modifier.
138 before_cancelable: bool,
139 /// Cancelable flag after modifier.
140 after_cancelable: bool,
141 /// Canceled flag before modifier.
142 before_canceled: bool,
143 /// Canceled flag after modifier.
144 after_canceled: bool,
145 },
146 /// Damage amount/cancel state was modified and finalized.
147 DamageModified {
148 /// Correlated damage event id.
149 event_id: u32,
150 /// Target player.
151 target: u8,
152 /// Original damage amount.
153 original: i32,
154 /// Modified damage amount.
155 modified: i32,
156 /// Whether damage was canceled.
157 canceled: bool,
158 /// Damage classification (battle vs effect damage).
159 damage_type: DamageType,
160 },
161 /// Damage was committed (a damage card moved to clock).
162 DamageCommitted {
163 /// Correlated damage event id.
164 event_id: u32,
165 /// Target player.
166 target: u8,
167 /// Damage card id committed.
168 card: CardId,
169 /// Damage classification (battle vs effect damage).
170 damage_type: DamageType,
171 },
172 /// A battle reversal was committed for a stage slot.
173 ReversalCommitted {
174 /// Player index.
175 player: u8,
176 /// Stage slot index.
177 slot: u8,
178 /// Damage event id which caused the reversal (if applicable).
179 cause_damage_event: Option<u32>,
180 },
181 /// A card was revealed (with reason/audience metadata).
182 Reveal {
183 /// Player index.
184 player: u8,
185 /// Card id revealed.
186 card: CardId,
187 /// Reason for the reveal.
188 reason: RevealReason,
189 /// Audience allowed to see the revealed card.
190 audience: RevealAudience,
191 },
192 /// A trigger was queued for resolution.
193 TriggerQueued {
194 /// Stable trigger id.
195 trigger_id: u32,
196 /// Trigger group id for simultaneous triggers.
197 group_id: u32,
198 /// Player index.
199 player: u8,
200 /// Source card id.
201 source: CardId,
202 /// Trigger effect kind.
203 effect: TriggerEffect,
204 },
205 /// Multiple triggers were grouped for resolution ordering.
206 TriggerGrouped {
207 /// Trigger group id.
208 group_id: u32,
209 /// Trigger ids in the group.
210 trigger_ids: Vec<u32>,
211 },
212 /// Trigger was resolved.
213 TriggerResolved {
214 /// Stable trigger id.
215 trigger_id: u32,
216 /// Player index.
217 player: u8,
218 /// Trigger effect kind.
219 effect: TriggerEffect,
220 },
221 /// Trigger was canceled.
222 TriggerCanceled {
223 /// Stable trigger id.
224 trigger_id: u32,
225 /// Player index.
226 player: u8,
227 /// Cancellation reason.
228 reason: TriggerCancelReason,
229 },
230 /// A timing window was entered.
231 TimingWindowEntered {
232 /// Timing window.
233 window: TimingWindow,
234 /// Active player index.
235 player: u8,
236 },
237 /// Priority was granted to a player within a timing window.
238 PriorityGranted {
239 /// Timing window.
240 window: TimingWindow,
241 /// Player index.
242 player: u8,
243 },
244 /// Priority was passed by a player.
245 PriorityPassed {
246 /// Player index.
247 player: u8,
248 /// Timing window.
249 window: TimingWindow,
250 /// Pass count within the window.
251 pass_count: u8,
252 },
253 /// Stack group was presented for ordering/selection.
254 StackGroupPresented {
255 /// Stable group id.
256 group_id: u32,
257 /// Player index controlling the stack group.
258 controller: u8,
259 /// Items in the stack group.
260 items: Vec<StackItem>,
261 },
262 /// Stack order was chosen for a presented stack group.
263 StackOrderChosen {
264 /// Stable group id.
265 group_id: u32,
266 /// Player index controlling the stack group.
267 controller: u8,
268 /// Stack id chosen.
269 stack_id: u32,
270 },
271 /// A stack item was pushed.
272 StackPushed {
273 /// Stack item pushed.
274 item: StackItem,
275 },
276 /// A stack item was resolved.
277 StackResolved {
278 /// Stack item resolved.
279 item: StackItem,
280 },
281 /// Automatic resolution cap was exceeded.
282 AutoResolveCapExceeded {
283 /// Cap value.
284 cap: u32,
285 /// Stack length at the time of cap exceed.
286 stack_len: u32,
287 /// Timing window (if known).
288 window: Option<TimingWindow>,
289 },
290 /// Timing window advanced.
291 WindowAdvanced {
292 /// Previous timing window.
293 from: TimingWindow,
294 /// Next timing window (or None if leaving timing windows).
295 to: Option<TimingWindow>,
296 },
297 /// A choice was presented to a player.
298 ChoicePresented {
299 /// Stable choice id.
300 choice_id: u32,
301 /// Player index.
302 player: u8,
303 /// Reason for the choice.
304 reason: ChoiceReason,
305 /// Current page options.
306 options: Vec<ChoiceOptionSnapshot>,
307 /// Total candidate count (before paging).
308 total_candidates: u16,
309 /// Page start index.
310 page_start: u16,
311 },
312 /// A choice page was changed.
313 ChoicePageChanged {
314 /// Stable choice id.
315 choice_id: u32,
316 /// Player index.
317 player: u8,
318 /// Previous page start index.
319 from_start: u16,
320 /// New page start index.
321 to_start: u16,
322 },
323 /// A player made a choice selection.
324 ChoiceMade {
325 /// Stable choice id.
326 choice_id: u32,
327 /// Player index.
328 player: u8,
329 /// Reason for the choice.
330 reason: ChoiceReason,
331 /// Selected option reference.
332 option: ChoiceOptionRef,
333 },
334 /// A choice was autopicked by the engine.
335 ChoiceAutopicked {
336 /// Stable choice id.
337 choice_id: u32,
338 /// Player index.
339 player: u8,
340 /// Reason for the choice.
341 reason: ChoiceReason,
342 /// Selected option reference.
343 option: ChoiceOptionRef,
344 },
345 /// A choice was skipped.
346 ChoiceSkipped {
347 /// Stable choice id.
348 choice_id: u32,
349 /// Player index.
350 player: u8,
351 /// Reason for the choice.
352 reason: ChoiceReason,
353 /// Skip reason.
354 skip_reason: ChoiceSkipReason,
355 },
356 /// A card moved between zones.
357 ZoneMove {
358 /// Player index.
359 player: u8,
360 /// Card id moved.
361 card: CardId,
362 /// Source zone.
363 from: Zone,
364 /// Destination zone.
365 to: Zone,
366 /// Source slot (if applicable).
367 from_slot: Option<u8>,
368 /// Destination slot (if applicable).
369 to_slot: Option<u8>,
370 },
371 /// Control of a card changed.
372 ControlChanged {
373 /// Card id whose controller changed.
374 card: CardId,
375 /// Owner player index.
376 owner: u8,
377 /// Previous controller index.
378 from_controller: u8,
379 /// New controller index.
380 to_controller: u8,
381 /// Previous stage slot index.
382 from_slot: u8,
383 /// New stage slot index.
384 to_slot: u8,
385 },
386 /// A modifier was added.
387 ModifierAdded {
388 /// Modifier id.
389 id: u32,
390 /// Source card id.
391 source: CardId,
392 /// Target player index.
393 target_player: u8,
394 /// Target stage slot index.
395 target_slot: u8,
396 /// Target card id.
397 target_card: CardId,
398 /// Modifier kind.
399 kind: ModifierKind,
400 /// Signed modifier magnitude.
401 magnitude: i32,
402 /// Modifier duration.
403 duration: ModifierDuration,
404 },
405 /// A modifier was removed.
406 ModifierRemoved {
407 /// Modifier id.
408 id: u32,
409 /// Removal reason.
410 reason: ModifierRemoveReason,
411 },
412 /// Player conceded the game.
413 Concede {
414 /// Player index.
415 player: u8,
416 },
417 /// Player played a character to a stage slot.
418 Play {
419 /// Player index.
420 player: u8,
421 /// Card id played.
422 card: CardId,
423 /// Stage slot index.
424 slot: u8,
425 },
426 /// Player played an event card.
427 PlayEvent {
428 /// Player index.
429 player: u8,
430 /// Event card id played.
431 card: CardId,
432 },
433 /// Player played a climax card.
434 PlayClimax {
435 /// Player index.
436 player: u8,
437 /// Climax card id played.
438 card: CardId,
439 },
440 /// Trigger step processed a trigger icon.
441 Trigger {
442 /// Player index.
443 player: u8,
444 /// Trigger icon.
445 icon: crate::db::TriggerIcon,
446 /// Triggered card id (if present).
447 card: Option<CardId>,
448 },
449 /// Player declared an attack with a slot.
450 Attack {
451 /// Player index.
452 player: u8,
453 /// Attacker stage slot index.
454 slot: u8,
455 },
456 /// Attack type was chosen (frontal/side/direct).
457 AttackType {
458 /// Player index.
459 player: u8,
460 /// Attacker stage slot index.
461 attacker_slot: u8,
462 /// Declared attack type.
463 attack_type: AttackType,
464 },
465 /// Player played a counter (backup) during counter step.
466 Counter {
467 /// Player index.
468 player: u8,
469 /// Counter card id.
470 card: CardId,
471 /// Power granted by the counter.
472 power: i32,
473 },
474 /// A card was placed into clock (e.g., from hand or damage).
475 Clock {
476 /// Player index.
477 player: u8,
478 /// Card id placed into clock (if known).
479 card: Option<CardId>,
480 },
481 /// A zone was shuffled.
482 Shuffle {
483 /// Player index.
484 player: u8,
485 /// Zone shuffled.
486 zone: Zone,
487 },
488 /// Refresh occurred (deck refilled from waiting room).
489 Refresh {
490 /// Player index.
491 player: u8,
492 },
493 /// Refresh penalty card was applied to clock.
494 RefreshPenalty {
495 /// Player index.
496 player: u8,
497 /// Card id moved to clock as penalty.
498 card: CardId,
499 },
500 /// Level-up choice was made.
501 LevelUpChoice {
502 /// Player index.
503 player: u8,
504 /// Card id selected for level.
505 card: CardId,
506 },
507 /// Encore resolution occurred for a stage slot.
508 Encore {
509 /// Player index.
510 player: u8,
511 /// Stage slot index.
512 slot: u8,
513 /// Whether the character was kept (encored) on stage.
514 kept: bool,
515 },
516 /// Stand phase occurred for a player.
517 Stand {
518 /// Player index.
519 player: u8,
520 },
521 /// Turn ended for a player.
522 EndTurn {
523 /// Player index.
524 player: u8,
525 },
526 /// Terminal game event.
527 Terminal {
528 /// Winner player index, or None for draw/timeout.
529 winner: Option<u8>,
530 },
531}
532
533/// Reason a modifier was removed.
534#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
535pub enum ModifierRemoveReason {
536 /// Removed during end-phase cleanup.
537 EndOfTurn,
538 /// Removed because the target left stage.
539 TargetLeftStage,
540 /// Removed due to continuous refresh/recompute of continuous effects.
541 ContinuousRefresh,
542}