Skip to main content

ygopro_data/
constants.rs

1//! The constants and enums shared across the protocol.
2//!
3//! Holds the player positions (`Netplayer`, `CorePlayer`), card attributes, locations,
4//! phases, and the other protocol constants.
5
6#![allow(non_upper_case_globals)]
7#![allow(non_camel_case_types)]
8
9use binrw::BinRead;
10use binrw::BinWrite;
11use num_enum::IntoPrimitive;
12use num_enum::TryFromPrimitive;
13use num_enum::FromPrimitive;
14use bitflags::bitflags;
15use modular_bitfield::bitfield;
16use modular_bitfield::Specifier;
17use modular_bitfield::error::InvalidBitPattern;
18use modular_bitfield::error::OutOfBounds;
19use modular_bitfield::specifiers::B3;
20
21use crate::data::DeckErrorType;
22
23#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
24#[brw(repr=u16)]
25#[repr(u16)]
26pub enum Network {
27    ServerId = 29736,
28    ClientId = 57078,
29}
30
31/// The position where a player is in a room slot.
32///
33/// In C++, `Netplayer` is a single enum value reused in many places. The Rust version
34/// splits it into several distinct types that are no longer guaranteed to be equal. This
35/// `Netplayer` is a compromise for the ygopro crate, adding the `Undecided` category and
36/// the observer's index. In particular, `Observer(255)` means the observer's slot is
37/// unknown.
38///
39/// These added parts are dropped when serializing: `Observer` always becomes `255`, to
40/// match the original data protocol. So (de)serialization of this type loses information
41/// and must be handled carefully, especially when using [`Complex`](crate::complex::Complex).
42///
43/// See also: [`CorePlayer`],
44/// [`ChatSource`](crate::message::server_to_client::ChatSource).
45#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash)]
46#[br(map = |raw: u8| Netplayer::from_primitive(raw))]
47#[bw(map = |value: &Netplayer| u8::from(*value))]
48#[repr(u8)]
49pub enum Netplayer {
50    Player(u8),
51    Observer(u8),
52    Undecided(u8),
53    Unknown
54}
55
56impl FromPrimitive for Netplayer {
57    type Primitive = u8;
58
59    fn from_primitive(number: Self::Primitive) -> Self {
60        if number <= 6 { Netplayer::Player(number) }
61        else if number == 7 { Netplayer::Observer(255) }
62        else { Netplayer::Unknown }
63    }
64}
65
66impl From<Netplayer> for u8 {
67    fn from(value: Netplayer) -> Self {
68        match value {
69            Netplayer::Player(index) => index,
70            Netplayer::Observer(_) => 7,
71            Netplayer::Undecided(_) => 255,
72            Netplayer::Unknown => 255,
73        }
74    }
75}
76
77impl Specifier for Netplayer {
78    const BITS: usize = 4;
79    type Bytes = u8;
80    type InOut = Self;
81
82    fn into_bytes(input: Self) -> Result<Self::Bytes, OutOfBounds> {
83        let byte = u8::from(input);
84        if byte >= (1 << Self::BITS) {
85            return Err(OutOfBounds);
86        }
87        Ok(byte)
88    }
89
90    fn from_bytes(bytes: Self::Bytes) -> Result<Self, InvalidBitPattern<Self::Bytes>> {
91        let netplayer = Netplayer::from_primitive(bytes);
92        if netplayer == Netplayer::Unknown {
93            return Err(InvalidBitPattern::new(bytes));
94        }
95        Ok(netplayer)
96    }
97}
98
99/// The position where a player is in ygocore.
100///
101/// This is a new type invented by this crate. Its values are exactly the same as the
102/// player in ygocore (often written as `tp` in lua). They are unrelated to the network
103/// slot of the first-attack player, so `CorePlayer` is not equal to [`Netplayer`]. How to
104/// relate `Netplayer` and `CorePlayer` is the downstream's own responsibility.
105///
106/// See also: [`Netplayer`].
107#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug, PartialOrd, Ord, Hash)]
108#[brw(repr=u8)]
109#[repr(u8)]
110pub enum CorePlayer {
111    FirstAttackPlayer = 0,
112    SecondAttackPlayer = 1,
113    None = 2,
114    All = 3,
115    /// This value is only used as `reason_player` when reason is rule.
116    Rule = 5,
117}
118
119impl CorePlayer {
120    pub fn opponent(&self) -> CorePlayer {
121        match *self {
122            CorePlayer::FirstAttackPlayer => CorePlayer::SecondAttackPlayer,
123            CorePlayer::SecondAttackPlayer => CorePlayer::FirstAttackPlayer,
124            CorePlayer::None => CorePlayer::None,
125            CorePlayer::All => CorePlayer::All,
126            CorePlayer::Rule => CorePlayer::Rule,
127        }
128    }
129}
130
131impl From<Netplayer> for CorePlayer {
132    fn from(player: Netplayer) -> Self {
133        match player {
134            Netplayer::Player(u) => if u % 2 == 0 { CorePlayer::FirstAttackPlayer } else { CorePlayer::SecondAttackPlayer }
135            _ => CorePlayer::None
136        }
137    }
138}
139
140impl From<CorePlayer> for Netplayer {
141    fn from(player: CorePlayer) -> Self {
142        match player {
143            CorePlayer::FirstAttackPlayer => Netplayer::Player(0),
144            CorePlayer::SecondAttackPlayer => Netplayer::Player(1),
145            CorePlayer::None => Netplayer::Unknown,
146            CorePlayer::All => Netplayer::Unknown,
147            CorePlayer::Rule => Netplayer::Unknown,
148        }
149    }
150}
151
152impl std::ops::Mul for CorePlayer {
153    type Output = CorePlayer;
154
155    fn mul(self, rhs: Self) -> Self::Output {
156        if self == rhs { return self; }
157        match (self, rhs) {
158            (CorePlayer::None, _) => rhs,
159            (_, CorePlayer::None) => self,
160            (CorePlayer::Rule, _) | (_, CorePlayer::Rule) => CorePlayer::Rule,
161            (_, _) => CorePlayer::All
162        }
163    }
164}
165
166pub trait PlayerConverter {
167    fn to_net_player(&self, core_player: CorePlayer) -> Netplayer;
168    fn to_core_player(&self, net_player: Netplayer) -> CorePlayer;
169}
170
171#[bitfield]
172#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, Debug)]
173#[br(map = Self::from_bytes)]
174#[bw(map = |&x| Self::into_bytes(x))]
175#[repr(u8)]
176pub struct TypeChange {
177    pub player: Netplayer,
178    pub host: bool,
179    #[skip] __: B3,
180}
181
182#[derive(Specifier, Copy, Clone, Eq, PartialEq, Debug)]
183#[bits = 4]
184#[repr(u8)]
185pub enum PlayerChangeState {
186    Observe = 0x8,
187    Ready = 0x9,
188    Notready = 0xa,
189    Leave = 0xb,
190}
191
192#[bitfield]
193#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, Debug)]
194#[br(map = Self::from_bytes)]
195#[bw(map = |&x| Self::into_bytes(x))]
196#[repr(u8)]
197pub struct PlayerChange {
198    pub state: PlayerChangeState,
199    pub player: Netplayer,
200}
201
202#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
203#[brw(repr = u8)]
204#[repr(u8)]
205pub enum JoinError {
206    RoomFull = 0,
207    WrongPassword = 1,
208    HostRefused = 2
209}
210
211
212#[derive(Copy, Clone, PartialEq, Eq, Debug)]
213#[repr(u8)]
214pub enum ErrorMessage {
215    JoinError(JoinError) = 1,
216    DeckError(crate::data::DeckError) = 2,
217    SideError = 3,
218    VersionError(u16) = 4,
219}
220
221fn invalid_data(error: impl std::fmt::Display + Send + Sync + 'static) -> binrw::Error {
222    std::io::Error::new(std::io::ErrorKind::InvalidData, error.to_string()).into()
223}
224
225impl BinRead for ErrorMessage {
226    type Args<'a> = ();
227
228    fn read_options<R: std::io::prelude::Read + std::io::prelude::Seek>(
229        reader: &mut R,
230        endian: binrw::Endian,
231        args: Self::Args<'_>,
232    ) -> binrw::prelude::BinResult<Self> {
233        let value = u32::read_options(reader, endian, args)?;
234        let code = u32::read_options(reader, endian, args)?;
235        let res = match value {
236            1 => {
237                let err_type = u8::try_from(code).map_err(invalid_data)?;
238                ErrorMessage::JoinError(JoinError::try_from(err_type).map_err(|_| invalid_data("invalid JoinError"))?)
239            }
240            2 => ErrorMessage::DeckError(crate::data::DeckError::from_bytes(code.to_ne_bytes())),
241            3 => ErrorMessage::SideError,
242            4 => ErrorMessage::VersionError(u16::try_from(code).map_err(invalid_data)?),
243            _ => return Err(binrw::Error::NoVariantMatch { pos: 0 }),
244        };
245        Ok(res)
246    }
247}
248
249impl BinWrite for ErrorMessage {
250    type Args<'a> = ();
251
252    fn write_options<W: std::io::prelude::Write + std::io::prelude::Seek>(&self,
253        writer: &mut W,
254        endian: binrw::Endian,
255        args: Self::Args<'_>,
256    ) -> binrw::prelude::BinResult<()> {
257        match self {
258            ErrorMessage::JoinError(join_error) => {
259                u32::write_options(&1, writer, endian, args)?;
260                u32::write_options(&(*join_error as u8 as u32), writer, endian, args)?;
261            }
262            ErrorMessage::DeckError(deck_error) => {
263                u32::write_options(&2, writer, endian, args)?;
264                u32::write_options(&u32::from(*deck_error), writer, endian, args)?;
265            },
266            ErrorMessage::SideError => {
267                u32::write_options(&3, writer, endian, args)?;
268                u32::write_options(&0, writer, endian, args)?;
269            },
270            ErrorMessage::VersionError(version) => {
271                u32::write_options(&4, writer, endian, args)?;
272                u32::write_options(&(*version as u32), writer, endian, args)?;
273            },
274        }
275        Ok(())
276    }
277}
278
279#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug, Hash)]
280#[brw(repr=u8)]
281#[repr(u8)]
282pub enum Mode {
283    Single = 0,
284    Match = 1,
285    Tag = 2,
286}
287
288bitflags! {
289    #[repr(transparent)]
290    #[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, Debug)]
291    #[br(map=|x| Self::from_bits_retain(x))]
292    #[bw(map=|x: &Self| x.bits())]
293    pub struct Location: u8 {
294        const Limbo = 0;
295        const Deck = 0x1;
296        const Hand = 0x2;
297        const MZone = 0x4;
298        const SZone = 0x8;
299        const Grave = 0x10;
300        const Removed = 0x20;
301        const Extra = 0x40;
302        const Overlay = 0x80;
303        const OnField = 0xc;
304        // FZone = 0x100,
305        // PZone = 0x200,
306        // DeckBot = 0x10001,
307        // DeckShf = 0x20001,
308    }
309}
310
311bitflags! {
312    #[repr(transparent)]
313    #[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, Debug)]
314    #[br(map=|x| Self::from_bits_retain(x))]
315    #[bw(map=|x: &Self| x.bits())]
316    pub struct Position: u8 {
317        const Any = 0;
318        const FaceupAttack = 0x1;
319        const FaceDownAttack = 0x2;
320        const FaceupDefense = 0x4;
321        const FacedownDefense = 0x8;
322        const Faceup = 0x5;
323        const Facedown = 0xa;
324        const Attack = 0x3;
325        const Defense = 0xc;
326        const Reveal = 0x80;
327        // NoFlipEffect = 0x10000
328    }
329}
330
331impl Position {
332    pub fn is_face_down(&self) -> bool {
333        self.intersects(Position::Facedown)
334    }
335}
336
337bitflags! {
338    #[repr(transparent)]
339    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
340    #[br(map=|x| Self::from_bits_retain(x))]
341    #[bw(map=|x: &Self| x.bits())]
342    pub struct Timing: u32 {
343        const DrawPhase = 0x1;
344        const StandbyPhase = 0x2;
345        const MainEnd = 0x4;
346        const BattleStart = 0x8;
347        const BattleEnd = 0x10;
348        const EndPhase = 0x20;
349        const Summon = 0x40;
350        const SpecialSummon = 0x80;
351        const FlipSummon = 0x100;
352        const MonsterSet = 0x200;
353        const SpellTrapSet = 0x400;
354        const PositionChange = 0x800;
355        const Attack = 0x1000;
356        const DamageStep = 0x2000;
357        const DamageCalculate = 0x4000;
358        const ChainEnd = 0x8000;
359        const Draw = 0x10000;
360        const Damage = 0x20000;
361        const Recover = 0x40000;
362        const Destroy = 0x80000;
363        const Remove = 0x100000;
364        const ToHand = 0x200000;
365        const ToDeck = 0x400000;
366        const ToGrave = 0x800000;
367        const BattlePhase = 0x1000000;
368        const Equip = 0x2000000;
369        const BattleStepEnd = 0x4000000;
370        const Battled = 0x8000000;
371    }
372}
373
374bitflags! {
375    #[repr(transparent)]
376    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
377    #[br(map=|x| Self::from_bits_retain(x))]
378    #[bw(map=|x: &Self| x.bits())]
379    pub struct Type: u32 {
380        const Monster = 0x1;
381        const Spell = 0x2;
382        const Trap = 0x4;
383        const Normal = 0x10;
384        const Effect = 0x20;
385        const Fusion = 0x40;
386        const Ritual = 0x80;
387        const Trapmonster = 0x100;
388        const Spirit = 0x200;
389        const Union = 0x400;
390        const Dual = 0x800;
391        const Tuner = 0x1000;
392        const Synchro = 0x2000;
393        const Token = 0x4000;
394        const Quickplay = 0x10000;
395        const Continuous = 0x20000;
396        const Equip = 0x40000;
397        const Field = 0x80000;
398        const Counter = 0x100000;
399        const Flip = 0x200000;
400        const Toon = 0x400000;
401        const Xyz = 0x800000;
402        const Pendulum = 0x1000000;
403        const SpecialSummon = 0x2000000;
404        const Link = 0x4000000;
405        const ExtraDeck = 0x4802040;
406    }
407}
408
409
410bitflags! {
411    #[repr(transparent)]
412    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
413    #[br(map=|x| Self::from_bits_retain(x))]
414    #[bw(map=|x: &Self| x.bits())]
415    pub struct Race: u32 {
416        const Warrior = 0x1;
417        const Spellcaster = 0x2;
418        const Fairy = 0x4;
419        const Fiend = 0x8;
420        const Zombie = 0x10;
421        const Machine = 0x20;
422        const Aqua = 0x40;
423        const Pyro = 0x80;
424        const Rock = 0x100;
425        const Windbeast = 0x200;
426        const Plant = 0x400;
427        const Insect = 0x800;
428        const Thunder = 0x1000;
429        const Dragon = 0x2000;
430        const Beast = 0x4000;
431        const Beastwarrior = 0x8000;
432        const Dinosaur = 0x10000;
433        const Fish = 0x20000;
434        const Seaserpent = 0x40000;
435        const Reptile = 0x80000;
436        const Psycho = 0x100000;
437        const Devine = 0x200000;
438        const Creatorgod = 0x400000;
439        const Wyrm = 0x800000;
440        const Cyberse = 0x1000000;
441        const Illusion = 0x2000000;
442        const All = 0x3ffffff;
443    }
444}
445
446impl Race {
447    pub const COUNT: u8 = 26;
448}
449
450
451bitflags! {
452    #[repr(transparent)]
453    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
454    #[br(map=|x| Self::from_bits_retain(x))]
455    #[bw(map=|x: &Self| x.bits())]
456    pub struct Reason: u32 {
457        const Destroy = 0x1;
458        const Release = 0x2;
459        const Temporary = 0x4;
460        const Material = 0x8;
461        const Summon = 0x10;
462        const Battle = 0x20;
463        const Effect = 0x40;
464        const Cost = 0x80;
465        const Adjust = 0x100;
466        const LostTarget = 0x200;
467        const Rule = 0x400;
468        const SpecialSummon = 0x800;
469        const DisableSummon = 0x1000;
470        const Flip = 0x2000;
471        const Discard = 0x4000;
472        const RecoverDamage = 0x8000;
473        const RecoverRecover = 0x10000;
474        const Return = 0x20000;
475        const Fusion = 0x40000;
476        const Synchro = 0x80000;
477        const Ritual = 0x100000;
478        const Xyz = 0x200000;
479        const Replace = 0x1000000;
480        const Draw = 0x2000000;
481        const Redirect = 0x4000000;
482        const Reveal = 0x8000000;
483        const Link = 0x10000000;
484        const LostOverlay = 0x20000000;
485        const Maintenance = 0x40000000;
486        const Action = 0x80000000;
487        const Procedure = 0x10280000;
488    }
489}
490
491bitflags! {
492    #[repr(transparent)]
493    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
494    #[br(map=|x| Self::from_bits_retain(x))]
495    #[bw(map=|x: &Self| x.bits())]
496    pub struct Status: u32 {
497        const Disabled = 0x0001;
498        const ToEnable = 0x0002;
499        const ToDisable = 0x0004;
500        const ProcessComplete = 0x0008;
501        const SetTurn = 0x0010;
502        const NoLevel = 0x0020;
503        const BattleResult = 0x0040;
504        const SpecialSummonStep = 0x0080;
505        const CannotChangeForm = 0x0100;
506        const Summoning = 0x0200;
507        const EffectEnabled = 0x0400;
508        const SummonTurn = 0x0800;
509        const DestroyConfirmed = 0x1000;
510        const LeaveConfirmed = 0x2000;
511        const BattleDestroyed = 0x4000;
512        const CopyingEffect = 0x8000;
513        const Chaining = 0x10000;
514        const SummonDisabled = 0x20000;
515        const ActivateDisabled = 0x40000;
516        const EffectReplaced = 0x80000;
517        const FlipSummoning = 0x100000;
518        const AttackCanceled = 0x200000;
519        const Initializing = 0x400000;
520        const ToHandWithoutConfirm = 0x800000;
521        const JustPos = 0x1000000;
522        const ContinuousPos = 0x2000000;
523        const Forbidden = 0x4000000;
524        const ActFromHand = 0x8000000;
525        const OpponentBattle = 0x10000000;
526        const FlipSummonTurn = 0x20000000;
527        const SpecialSummonTurn = 0x40000000;
528        const FlipSummonDisabled = 0x80000000;
529    }
530}
531
532bitflags! {
533    #[repr(transparent)]
534    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
535    #[br(map=|x| Self::from_bits_retain(x))]
536    #[bw(map=|x: &Self| x.bits())]
537    pub struct Query: u32 {
538        const Code = 0x1;
539        const Position = 0x2;
540        const Alias = 0x4;
541        const Type = 0x8;
542        const Level = 0x10;
543        const Rank = 0x20;
544        const Attribute = 0x40;
545        const Race = 0x80;
546        const Attack = 0x100;
547        const Defense = 0x200;
548        const BaseAttack = 0x400;
549        const BaseDefense = 0x800;
550        const Reason = 0x1000;
551        const ReasonCard = 0x2000;
552        const EquipCard = 0x4000;
553        const TargetCard = 0x8000;
554        const OverlayCard = 0x10000;
555        const Counters = 0x20000;
556        const Owner = 0x40000;
557        const Status = 0x80000;
558        const LeftScale = 0x200000;
559        const RightScale = 0x400000;
560        const Link = 0x800000;
561    }
562}
563
564bitflags! {
565    #[repr(transparent)]
566    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
567    #[br(map=|x| Self::from_bits_retain(x))]
568    #[bw(map=|x: &Self| x.bits())]
569    pub struct Attribute: u32 {
570        const Earth = 0x1;
571        const Water = 0x2;
572        const Fire = 0x4;
573        const Wind = 0x8;
574        const Light = 0x10;
575        const Dark = 0x20;
576        const Devine = 0x40;
577        const All = 0x7f;
578    }
579}
580
581impl Attribute {
582    pub const COUNT: u8 = 7;
583}
584
585
586bitflags! {
587    #[repr(transparent)]
588    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
589    #[br(map=|x| Self::from_bits_retain(x))]
590    #[bw(map=|x: &Self| x.bits())]
591    pub struct Linkmarkers: u32 {
592        const BottomLeft = 0x1;
593        const Bottom = 0x2;
594        const BottomRight = 0x4;
595        const Left = 0x8;
596        const Right = 0x20;
597        const TopLeft = 0x40;
598        const Top = 0x80;
599        const TopRight = 0x100;
600    }
601}
602
603#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TryFromPrimitive, IntoPrimitive, Debug)]
604#[brw(repr=u8)]
605#[repr(u8)]
606pub enum DuelStage {
607    Begin = 0,
608    Finger = 1,
609    Firstgo = 2,
610    Dueling = 3,
611    Siding = 4,
612    End = 5,
613}
614
615#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
616#[brw(repr=u8)]
617#[repr(u8)]
618pub enum Color {
619    Observer = 7,
620    Lightblue = 8,
621    Red = 11,
622    Green = 12,
623    Blue = 13,
624    Babyblue = 14,
625    Pink = 15,
626    Yellow = 16,
627    White = 17,
628    Gray = 18,
629    Darkgray = 19,
630}
631
632impl std::fmt::Display for Color {
633    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
634        formatter.write_str(match self {
635            Color::Observer => "OBSERVER",
636            Color::Lightblue => "LIGHTBLUE",
637            Color::Red => "RED",
638            Color::Green => "GREEN",
639            Color::Blue => "BLUE",
640            Color::Babyblue => "BABYBLUE",
641            Color::Pink => "PINK",
642            Color::Yellow => "YELLOW",
643            Color::White => "WHITE",
644            Color::Gray => "GRAY",
645            Color::Darkgray => "DARKGRAY",
646        })
647    }
648}
649
650impl std::str::FromStr for Color {
651    type Err = ();
652
653    fn from_str(value: &str) -> Result<Self, Self::Err> {
654        Ok(match value.to_ascii_uppercase().as_str() {
655            "OBSERVER" => Color::Observer,
656            "LIGHTBLUE" => Color::Lightblue,
657            "RED" => Color::Red,
658            "GREEN" => Color::Green,
659            "BLUE" => Color::Blue,
660            "BABYBLUE" => Color::Babyblue,
661            "PINK" => Color::Pink,
662            "YELLOW" => Color::Yellow,
663            "WHITE" => Color::White,
664            "GRAY" => Color::Gray,
665            "DARKGRAY" => Color::Darkgray,
666            _ => return Err(()),
667        })
668    }
669}
670
671#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
672#[brw(repr=u8)]
673#[repr(u8)]
674pub enum Hint {
675    Event = 1,
676    Message = 2,
677    SelectMessage = 3,
678    OpponentSelected = 4,
679    Effect = 5,
680    Race = 6,
681    Attribute = 7,
682    Code = 8,
683    Number = 9,
684    Card = 10,
685    Zone = 11,
686}
687
688#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
689#[brw(repr=u16)]
690#[repr(u16)]
691pub enum Phase {
692    Draw = 0x1,
693    Standby = 0x2,
694    Main1 = 0x4,
695    BattleStart = 0x8,
696    BattleStep = 0x10,
697    Damage = 0x20,
698    DamageCalculate = 0x40,
699    Battle = 0x80,
700    Main2 = 0x100,
701    End = 0x200,
702}
703
704
705bitflags! {
706    #[repr(transparent)]
707    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
708    #[br(map=|x| Self::from_bits_retain(x))]
709    #[bw(map=|x: &Self| x.bits())]
710    pub struct SummonType: u32 {
711        const Normal = 0x10000000;
712        const Advance = 0x11000000;
713        const Dual = 0x12000000;
714        const Flip = 0x20000000;
715        const Special = 0x40000000;
716        const Fusion = 0x43000000;
717        const Ritual = 0x45000000;
718        const Synchro = 0x46000000;
719        const Xyz = 0x49000000;
720        const Pendulum = 0x4a000000;
721        const Link = 0x4c000000;
722    }
723}
724
725#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
726#[brw(repr=u8)]
727#[repr(u8)]
728pub enum Hand {
729    Scissors = 1,
730    Rock = 2,
731    Paper = 3
732}
733
734#[derive(PartialEq, Eq)]
735pub enum HandResult {
736    Win,
737    Draw,
738    Lose
739}
740
741impl Hand {
742    pub fn judge(&self, other: &Self) -> HandResult {
743        if self == other { return HandResult::Draw; }
744        match self {
745            Hand::Scissors => if *other == Hand::Paper { HandResult::Win } else { HandResult::Lose },
746            Hand::Rock => if *other == Hand::Scissors { HandResult::Win } else { HandResult::Lose },
747            Hand::Paper => if *other == Hand::Rock { HandResult::Win } else { HandResult::Lose },
748        }
749    }
750}
751
752bitflags! {
753    #[repr(transparent)]
754    #[derive(BinRead, BinWrite, Clone, Copy, Default, Eq, PartialEq, Debug)]
755    #[br(map=|x| Self::from_bits_retain(x))]
756    #[bw(map=|x: &Self| x.bits())]
757    pub struct OT: u8 {
758        const OCG = 1;
759        const TCG = 2;
760        const Custom = 4;
761        const SC = 8;
762    }
763}
764
765#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
766#[brw(repr = u8)]
767#[repr(u8)]
768pub enum Rule {
769    OCG = 0,
770    TCG = 1,
771    SC = 2,
772    Custom = 3,
773    OCG_TCG = 4,
774    All = 5,
775}
776
777impl From<Rule> for OT {
778    fn from(rule: Rule) -> Self {
779        match rule {
780            Rule::OCG => OT::OCG,
781            Rule::TCG => OT::TCG,
782            Rule::SC => OT::SC,
783            Rule::Custom => OT::Custom,
784            Rule::OCG_TCG => OT::OCG | OT::TCG,
785            Rule::All => OT::empty(),
786        }
787    }
788}
789
790impl Rule {
791    pub fn check_ot(&self, ot: OT) -> Option<DeckErrorType> {
792        let allowed = OT::from(*self);
793        if ot.contains(allowed) { return None; }
794        if ot.contains(OT::OCG) && allowed != OT::OCG {
795            return Some(DeckErrorType::OcgOnly);
796        }
797        if ot.contains(OT::TCG) && allowed != OT::TCG {
798            return Some(DeckErrorType::TcgOnly);
799        }
800        Some(DeckErrorType::NotAvailable)
801    }
802}
803
804bitflags! {
805    #[repr(transparent)]
806    #[derive(BinRead, BinWrite, Clone, Copy, Default, Debug)]
807    #[br(map=|x| Self::from_bits_retain(x))]
808    #[bw(map=|x: &Self| x.bits())]
809    pub struct Category: u32 {
810        const Destroy = 0x1;
811        const Release = 0x2;
812        const Remove = 0x4;
813        const ToHand = 0x8;
814        const ToDeck = 0x10;
815        const ToGrave = 0x20;
816        const DeckDestroy = 0x40;
817        const HandDestroy = 0x80;
818        const Summon = 0x100;
819        const SpecialSummon = 0x200;
820        const Token = 0x400;
821        const GraveAction = 0x800;
822        const Position = 0x1000;
823        const Control = 0x2000;
824        const Disable = 0x4000;
825        const DisableSummon = 0x8000;
826        const Draw = 0x10000;
827        const Search = 0x20000;
828        const Equip = 0x40000;
829        const Damage = 0x80000;
830        const Recover = 0x100000;
831        const AttackChange = 0x200000;
832        const DefenseChange = 0x400000;
833        const Counter = 0x800000;
834        const Coin = 0x1000000;
835        const Dice = 0x2000000;
836        const LeaveGrave = 0x4000000;
837        const GraveSpecialSummon = 0x8000000;
838        const Negate = 0x10000000;
839        const Announce = 0x20000000;
840        const FusionSummon = 0x40000000;
841        const ToExtra = 0x80000000;
842    }
843}
844
845#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, FromPrimitive, IntoPrimitive, Debug)]
846#[br(map = |v: u32| Operation::from(v))]
847#[bw(map = |v: &Operation| u32::from(*v))]
848#[repr(u32)]
849pub enum Operation {
850    Add = 0x40000000,
851    Subtract = 0x40000001,
852    Multiply = 0x40000002,
853    Divide = 0x40000003,
854    And = 0x40000004,
855    Or  = 0x40000005,
856    Negate = 0x40000006,
857    Not = 0x40000007,
858    IsCode = 0x40000100,
859    IsSetcard = 0x40000101,
860    IsType = 0x40000102,
861    IsRace = 0x40000103,
862    IsAttribute = 0x40000104,
863    #[num_enum(catch_all)]
864    Operand(u32)
865}
866
867#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
868#[brw(repr=u8)]
869#[repr(u8)]
870pub enum MasterRule {
871    MasterRule1 = 1,
872    MasterRule2 = 2,
873    MasterRule3 = 3,
874    MasterRuleNew = 4,
875    MasterRule2020 = 5,
876}
877
878#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
879#[brw(repr=u8)]
880#[repr(u8)]
881pub enum Activity {
882    Summon = 1,
883    NormalSummon = 2,
884    SpecialSummon = 3,
885    FlipSummon = 4,
886    Attack = 5,
887    BattlePhase = 6,
888    Chain = 7,
889}
890
891#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
892#[brw(repr=u8)]
893#[repr(u8)]
894pub enum CardHint {
895    Turn = 1,
896    Card = 2,
897    Race = 3,
898    Attribute = 4,
899    Number = 5,
900    DescriptionAdd = 6,
901    DescriptionRemove = 7,
902}
903
904#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
905#[brw(repr=u8)]
906#[repr(u8)]
907pub enum PlayerHint {
908    DescriptionAdd = 6,
909    DescriptionRemove = 7,
910}
911
912#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
913#[brw(repr=u8)]
914#[repr(u8)]
915pub enum EffectDescription {
916    Operation = 1,
917    Reset = 2,
918}
919
920#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
921#[brw(repr=i8)]
922#[repr(i8)]
923pub enum OperationResult {
924    Canceled = -1,
925    Fail = 0,
926    Success = 1,
927}
928
929#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, FromPrimitive, IntoPrimitive, Debug)]
930#[br(map = |v: u8| WinReason::from(v))]
931#[bw(map = |v: &WinReason| u8::from(*v))]
932#[repr(u8)]
933pub enum WinReason {
934    OpponentSurrender = 0,
935    LPZero = 1,
936    DeckOut = 2,
937    Timeout = 3,
938    OpponentLeave = 4,
939    #[num_enum(catch_all)]
940    Other(u8)
941}
942
943#[derive(BinRead, BinWrite, Copy, Clone, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Debug)]
944#[brw(repr = i8)]
945#[repr(i8)]
946pub enum SelectSumMode {
947    Exact = 0,
948    AtLeast = 1,
949}