1#![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#[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#[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 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 }
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 }
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}