1use std::collections::{BTreeMap, HashMap};
2
3use serde::{Deserialize, Serialize};
4use ts_rs::TS;
5
6use crate::prompts::common::TargetRef;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, TS)]
9#[ts(export, export_to = "game/index.ts")]
10pub enum ManaColor {
11 #[serde(rename = "W")]
12 White,
13 #[serde(rename = "U")]
14 Blue,
15 #[serde(rename = "B")]
16 Black,
17 #[serde(rename = "R")]
18 Red,
19 #[serde(rename = "G")]
20 Green,
21 #[serde(rename = "C")]
22 Colorless,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)]
26#[serde(rename_all = "camelCase")]
27#[ts(export, export_to = "game/index.ts")]
28pub struct Mana {
29 pub color: ManaColor,
30 pub amount: i32,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, TS)]
34#[serde(rename_all = "camelCase")]
35#[ts(export, export_to = "game/index.ts")]
36pub enum PlayerCounterKind {
37 Poison,
38 Energy,
39 Experience,
40 Radiation,
41 Ticket,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS)]
45#[serde(rename_all = "camelCase")]
46#[ts(export, export_to = "game/index.ts")]
47pub enum ZoneKind {
48 Battlefield,
49 Hand,
50 Library,
51 Graveyard,
52 Exile,
53 Command,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, TS)]
57#[serde(rename_all = "camelCase")]
58#[ts(export, export_to = "game/index.ts")]
59pub enum StepKind {
60 #[default]
61 Untap,
62 Upkeep,
63 Draw,
64 Main1,
65 CombatBegin,
66 CombatDeclareAttackers,
67 CombatDeclareBlockers,
68 CombatFirstStrikeDamage,
69 CombatDamage,
70 CombatEnd,
71 Main2,
72 EndOfTurn,
73 Cleanup,
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, TS)]
77#[serde(rename_all = "camelCase")]
78#[ts(export, export_to = "game/index.ts")]
79pub enum DayTime {
80 #[default]
81 Neither,
82 Day,
83 Night,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, TS)]
87#[serde(
88 tag = "visibility",
89 rename_all = "camelCase",
90 rename_all_fields = "camelCase"
91)]
92#[ts(export, export_to = "game/index.ts")]
93pub enum CardView {
94 Visible(CardDto),
95 Hidden { id: String },
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, TS)]
100#[serde(rename_all = "camelCase")]
101#[ts(export, export_to = "game/index.ts")]
102pub struct ZoneDto {
103 pub zone: ZoneKind,
104 pub owner_id: String,
105 pub cards: Vec<CardView>,
108 pub count: usize,
109}
110
111#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
112#[serde(rename_all = "camelCase")]
113#[ts(export, export_to = "game/index.ts")]
114pub struct GameViewDto {
115 pub game_id: String,
116 pub turn: u32,
117 pub step: StepKind,
118 pub combat_assignments: Vec<CombatAssignmentDto>,
119 pub active_player_id: String,
120 pub priority_player_id: String,
121 pub players: Vec<PlayerDto>,
122 pub zones: Vec<ZoneDto>,
123 pub stack: Vec<StackObjectDto>,
124 pub game_over: bool,
125 pub winner_id: Option<String>,
126 pub monarch_id: Option<String>,
127 pub initiative_holder_id: Option<String>,
128 pub day_time: DayTime,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, TS)]
132#[serde(rename_all = "camelCase")]
133#[ts(export, export_to = "game/index.ts")]
134pub struct CombatAssignmentDto {
135 pub blocker_id: String,
136 pub attacker_id: String,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, TS)]
140#[serde(rename_all = "camelCase")]
141#[ts(export, export_to = "game/index.ts")]
142pub enum PlayerStatus {
143 #[default]
144 Playing,
145 Lost,
146 Conceded,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize, TS)]
150#[serde(rename_all = "camelCase")]
151#[ts(export, export_to = "game/index.ts")]
152pub struct PlayerDto {
153 pub id: String,
154 pub name: String,
155 pub status: PlayerStatus,
156 pub is_human: bool,
157 pub life: i32,
158 pub counters: BTreeMap<PlayerCounterKind, u32>,
159 pub mana_pool: BTreeMap<ManaColor, u32>,
160 #[ts(type = "Record<string, number>")]
161 pub commander_damage: HashMap<String, i32>,
162 pub has_city_blessing: bool,
163 pub ring_level: i32,
164 pub speed: i32,
165}
166
167#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
168#[serde(rename_all = "camelCase", default)]
169#[ts(export, export_to = "game/index.ts")]
170pub struct CardIdentity {
171 pub name: String,
172 pub set_code: String,
173 pub card_number: String,
174 pub is_token: bool,
175}
176
177#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
178#[serde(rename_all = "camelCase", default)]
179#[ts(export, export_to = "game/index.ts")]
180pub struct CardDto {
181 pub id: String,
182 pub identity: CardIdentity,
183 pub color: String,
184 pub mana_cost: String,
185 pub cmc: i32,
186 pub types: Vec<String>,
187 pub subtypes: Vec<String>,
188 pub supertypes: Vec<String>,
189 pub power: Option<String>,
190 pub toughness: Option<String>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 #[ts(optional)]
193 pub base_power: Option<i32>,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 #[ts(optional)]
196 pub base_toughness: Option<i32>,
197 pub text: String,
198 pub controller_id: String,
199 pub owner_id: String,
200 pub tapped: bool,
201 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
202 pub is_crewed: bool,
203 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
204 pub is_attacking: bool,
205 #[serde(default, skip_serializing_if = "Option::is_none")]
206 #[ts(optional)]
207 pub attacking_player_id: Option<String>,
208 #[serde(default, skip_serializing_if = "Option::is_none")]
209 #[ts(optional)]
210 pub attack_target_id: Option<String>,
211 pub keywords: Vec<String>,
212 #[ts(type = "Record<string, number>")]
215 pub counters: BTreeMap<String, u32>,
216 pub damage: i32,
217 pub summoning_sick: bool,
218 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
219 pub is_copy: bool,
220 pub is_double_faced: bool,
221 pub is_transformed: bool,
222 pub is_face_down: bool,
223 pub is_bestowed: bool,
224 pub phased_out: bool,
225 pub exerted: bool,
226 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
227 pub is_ring_bearer: bool,
228 #[serde(skip_serializing_if = "Option::is_none")]
229 #[ts(optional)]
230 pub attached_to: Option<String>,
231 #[serde(default, skip_serializing_if = "Vec::is_empty")]
232 pub attachment_ids: Vec<String>,
233 #[serde(default, skip_serializing_if = "Vec::is_empty")]
235 pub merged_card_ids: Vec<String>,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 #[ts(optional)]
238 pub flashback_cost: Option<String>,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 #[ts(optional)]
241 pub kicker_cost: Option<String>,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 #[ts(optional)]
244 pub effective_mana_cost: Option<String>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 #[ts(optional)]
247 pub madness_cost: Option<String>,
248 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
249 pub is_madness_exiled: bool,
250 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
251 pub is_plotted: bool,
252 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
253 pub is_warp_exiled: bool,
254 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
255 pub foil: bool,
256 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
257 pub would_die_in_combat: bool,
258}
259
260#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
261#[serde(rename_all = "camelCase", default)]
262#[ts(export, export_to = "game/index.ts")]
263pub struct StackObjectDto {
264 pub id: String,
265 pub source_id: String,
266 pub controller_id: String,
267 pub identity: CardIdentity,
268 pub text: String,
269 pub is_permanent_spell: bool,
270 pub is_casting: bool,
271 pub targets: Vec<TargetRef>,
272}
273
274#[derive(
275 Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, TS, strum_macros::Display,
276)]
277#[serde(rename_all = "camelCase")]
278#[ts(export, export_to = "game/index.ts")]
279pub enum TargetingIntent {
280 #[default]
281 Damage,
282 Destroy,
283 Sacrifice,
284 Exile,
285 Bounce,
286 Mill,
287 Discard,
288 Counter,
289 Tap,
290 Untap,
291 Copy,
292 Buff,
293 Debuff,
294 Heal,
295 LoseLife,
296 Reveal,
297 Draw,
298 GainControl,
299 Fight,
300 Attach,
301 Attack,
302 Block,
303 Hostile,
304 Friendly,
305}
306
307#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
308#[serde(rename_all = "camelCase")]
309#[ts(export, export_to = "game/index.ts")]
310pub struct PlaymatSettings {
311 #[serde(default, skip_serializing_if = "Option::is_none")]
312 #[ts(optional)]
313 pub opacity: Option<f32>,
314 #[serde(default, skip_serializing_if = "Option::is_none")]
315 #[ts(optional)]
316 pub texture: Option<f32>,
317 #[serde(default, skip_serializing_if = "Option::is_none")]
318 #[ts(optional)]
319 pub border_width: Option<f32>,
320 #[serde(default, skip_serializing_if = "Option::is_none")]
321 #[ts(optional)]
322 pub border_color: Option<String>,
323 #[serde(default, skip_serializing_if = "Option::is_none")]
324 #[ts(optional)]
325 pub fit: Option<String>,
326 #[serde(default, skip_serializing_if = "Option::is_none")]
327 #[ts(optional)]
328 pub offset_x: Option<f32>,
329 #[serde(default, skip_serializing_if = "Option::is_none")]
330 #[ts(optional)]
331 pub offset_y: Option<f32>,
332 #[serde(default, skip_serializing_if = "Option::is_none")]
333 #[ts(optional)]
334 pub zoom: Option<f32>,
335 #[serde(default, skip_serializing_if = "Option::is_none")]
336 #[ts(optional)]
337 pub blur: Option<f32>,
338 #[serde(default, skip_serializing_if = "Option::is_none")]
339 #[ts(optional)]
340 pub brightness: Option<f32>,
341 #[serde(default, skip_serializing_if = "Option::is_none")]
342 #[ts(optional)]
343 pub color: Option<String>,
344}