Skip to main content

weiss_core/state/
attack.rs

1use serde::{Deserialize, Serialize};
2
3use crate::db::CardId;
4use crate::effects::EffectId;
5
6use super::CardInstanceId;
7
8/// Attack types available during the attack step.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum AttackType {
11    /// Frontal attack against an opposing character.
12    Frontal,
13    /// Side attack against an opposing character.
14    Side,
15    /// Direct attack (no opposing character).
16    Direct,
17}
18
19/// Attack step sub-phase.
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub enum AttackStep {
22    /// Trigger reveal/resolution step.
23    Trigger,
24    /// Counter timing step.
25    Counter,
26    /// Damage resolution step.
27    Damage,
28    /// Battle comparison step.
29    Battle,
30    /// Encore timing step.
31    Encore,
32}
33
34/// Damage type classification.
35#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub enum DamageType {
37    /// Damage caused by an attack.
38    Battle,
39    /// Damage caused by an effect.
40    Effect,
41}
42
43/// Modifier categories for damage processing.
44#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
45pub enum DamageModifierKind {
46    /// Add `delta` to the damage amount.
47    AddAmount {
48        /// Signed delta to apply.
49        delta: i32,
50    },
51    /// Set whether the damage is cancelable.
52    SetCancelable {
53        /// New cancelable flag.
54        cancelable: bool,
55    },
56    /// Cancel the next damage instance.
57    CancelNext,
58    /// Set the damage amount to an absolute value.
59    SetAmount {
60        /// Absolute damage amount.
61        amount: i32,
62    },
63}
64
65/// Applied damage modifier instance.
66#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
67pub struct DamageModifier {
68    /// Modifier behavior.
69    pub kind: DamageModifierKind,
70    /// Ordering priority for application.
71    pub priority: i16,
72    /// Insertion order used as a tie-breaker.
73    pub insertion: u32,
74    /// Source identifier for debugging/auditing.
75    pub source_id: u32,
76    /// Remaining applications or magnitude budget (variant-dependent).
77    pub remaining: i32,
78    /// Whether this modifier has been applied at least once.
79    pub used: bool,
80}
81
82/// Trigger effects resolved from trigger icons.
83#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
84pub enum TriggerEffect {
85    /// Add soul for the current attack.
86    Soul,
87    /// Draw a card.
88    Draw,
89    /// Deal shot damage.
90    Shot,
91    /// Return a character to hand.
92    Bounce,
93    /// Perform a choice selection.
94    Choice,
95    /// Add the revealed card to stock ("Pool").
96    Pool,
97    /// Add the revealed card to hand ("Treasure").
98    Treasure,
99    /// Salvage from waiting room ("Gate").
100    Gate,
101    /// Place a character from deck ("Standby").
102    Standby,
103    /// Resolve an auto ability on the trigger source card.
104    AutoAbility {
105        /// Index into the card's ability list.
106        ability_index: u8,
107    },
108    /// Resolve an auto ability that was granted at runtime.
109    GrantedAutoAbility {
110        /// Stable grant identifier referencing a `GrantedAbilityInstance`.
111        grant_id: u64,
112    },
113}
114
115/// Context for an ongoing attack.
116#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
117pub struct AttackContext {
118    /// Attacker stage slot index.
119    pub attacker_slot: u8,
120    /// Optional defender stage slot index (None for direct attacks).
121    pub defender_slot: Option<u8>,
122    /// Declared attack type.
123    pub attack_type: AttackType,
124    /// Trigger-check revealed card id (if any).
125    pub trigger_card: Option<CardId>,
126    /// Trigger-check revealed card instance id (if any).
127    pub trigger_instance_id: Option<CardInstanceId>,
128    /// Total trigger checks required.
129    pub trigger_checks_total: u8,
130    /// Trigger checks already resolved.
131    pub trigger_checks_resolved: u8,
132    /// Current damage amount.
133    pub damage: i32,
134    /// Whether counter is allowed.
135    pub counter_allowed: bool,
136    /// Whether a counter was played.
137    pub counter_played: bool,
138    /// Power added by counters.
139    pub counter_power: i32,
140    /// Active damage modifiers.
141    pub damage_modifiers: Vec<DamageModifier>,
142    /// Pending shot damage remaining to apply.
143    pub pending_shot_damage: u8,
144    /// Next id for damage modifier instances within this attack.
145    pub next_modifier_id: u32,
146    /// Last damage event id emitted for this attack (if any).
147    pub last_damage_event_id: Option<u32>,
148    /// Whether auto triggers were enqueued for this attack.
149    pub auto_trigger_enqueued: bool,
150    /// Whether auto damage effects were enqueued for this attack.
151    pub auto_damage_enqueued: bool,
152    /// Whether battle damage has been applied.
153    pub battle_damage_applied: bool,
154    /// Current sub-step within the attack.
155    pub step: AttackStep,
156    /// Whether the declaration timing window is complete.
157    pub decl_window_done: bool,
158    /// Whether the trigger timing window is complete.
159    pub trigger_window_done: bool,
160    /// Whether the damage timing window is complete.
161    pub damage_window_done: bool,
162}
163
164/// Trigger pending resolution.
165#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
166pub struct PendingTrigger {
167    /// Unique trigger id.
168    pub id: u32,
169    /// Group id for simultaneous triggers.
170    pub group_id: u32,
171    /// Player seat that owns the trigger.
172    pub player: u8,
173    /// Source card id that produced the trigger.
174    pub source_card: CardId,
175    /// Trigger effect kind.
176    pub effect: TriggerEffect,
177    /// Optional effect id for auto/granted abilities.
178    pub effect_id: Option<EffectId>,
179}
180
181/// Ordering state for multiple triggers.
182#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
183pub struct TriggerOrderState {
184    /// Group id for the set of triggers being ordered.
185    pub group_id: u32,
186    /// Player seat choosing the order.
187    pub player: u8,
188    /// Remaining trigger ids to choose from.
189    pub choices: Vec<u32>,
190}
191
192/// Derived attack information for a single slot.
193#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
194pub struct DerivedAttackSlot {
195    /// Whether the slot is unable to declare any attack.
196    pub cannot_attack: bool,
197    /// Whether side attacks are disallowed.
198    #[serde(default)]
199    pub cannot_side_attack: bool,
200    /// Whether frontal attacks are disallowed.
201    #[serde(default)]
202    pub cannot_frontal_attack: bool,
203    /// Additional stock cost required to attack from this slot.
204    pub attack_cost: u8,
205}
206
207impl DerivedAttackSlot {
208    /// Create an empty derived attack slot.
209    pub fn empty() -> Self {
210        Self {
211            cannot_attack: false,
212            cannot_side_attack: false,
213            cannot_frontal_attack: false,
214            attack_cost: 0,
215        }
216    }
217}
218
219/// Derived attack state for a turn.
220#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
221pub struct DerivedAttackState {
222    /// Per-player derived slot info for each stage slot.
223    pub per_player: [[DerivedAttackSlot; 5]; 2],
224}
225
226impl DerivedAttackState {
227    /// Create a default derived attack state.
228    pub fn new() -> Self {
229        Self {
230            per_player: [[DerivedAttackSlot::empty(); 5]; 2],
231        }
232    }
233}
234
235impl Default for DerivedAttackState {
236    fn default() -> Self {
237        Self::new()
238    }
239}
240
241/// Encore request tracking for a character.
242#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
243pub struct EncoreRequest {
244    /// Player seat that owns the encore request.
245    pub player: u8,
246    /// Stage slot index of the character requesting encore.
247    pub slot: u8,
248}