Skip to main content

ygopro_data/data/
response.rs

1//! A player's response to a select prompt.
2//!
3//! Provides the [`Response`] enum and its command enums ([`IdleCommand`], [`BattleCommand`]).
4
5use binrw::BinRead;
6use binrw::BinWrite;
7use binrw::VecArgs;
8use binrw::helpers::until_eof;
9use binrw::io::Cursor;
10use binrw::io::Read;
11use binrw::io::Seek;
12use binrw::io::Write;
13
14use crate::constants::*;
15use crate::message::gm;
16
17/// The idle-phase command a player picks, answered to a `SelectIdleCommand` message.
18#[derive(BinRead, BinWrite, Debug, Clone, Copy, PartialEq, Eq)]
19#[brw(repr = u16)]
20#[repr(u16)]
21pub enum IdleCommand {
22    Summon = 0,
23    SpecialSummon = 1,
24    Reposition = 2,
25    SetMonster = 3,
26    SetSpellTrap = 4,
27    Activate = 5,
28    EnterBattlePhase = 6,
29    EnterEndPhase = 7,
30    ShuffleDeck = 8,
31}
32
33/// The battle-phase command a player picks, answered to a `SelectBattleCommand` message.
34#[derive(BinRead, BinWrite, Debug, Clone, Copy, PartialEq, Eq)]
35#[brw(repr = u16)]
36#[repr(u16)]
37pub enum BattleCommand {
38    Activate = 0,
39    Attack = 1,
40    EnterMainPhase2 = 2,
41    EnterEndPhase = 3,
42}
43
44/// A player's response to a select prompt.
45///
46/// Each variant answers a particular [`gm::MessageType`](crate::message::gm::MessageType):
47/// the response is only meaningful together with the `GameMessage` that prompted it.
48/// `Unknown` holds the raw bytes when the prompting message type is not known.
49#[derive(Debug, Clone)]
50pub enum Response {
51    /// Answers [`SelectCard`](crate::message::gm::MessageType::SelectCard) /
52    /// [`SelectUnselectCard`](crate::message::gm::MessageType::SelectUnselectCard) /
53    /// [`SelectTribute`](crate::message::gm::MessageType::SelectTribute), meaning decline.
54    Cancel,
55    /// Answers [`SelectIdleCommand`](crate::message::gm::MessageType::SelectIdleCommand).
56    SelectIdleCommand(IdleCommand, u16),
57    /// Answers [`SelectBattleCommand`](crate::message::gm::MessageType::SelectBattleCommand).
58    SelectBattleCommand(BattleCommand, u16),
59    /// Answers [`SelectYesNo`](crate::message::gm::MessageType::SelectYesNo) /
60    /// [`SelectEffectYesNo`](crate::message::gm::MessageType::SelectEffectYesNo).
61    SelectYesNo(bool),
62    /// Answers [`SelectOption`](crate::message::gm::MessageType::SelectOption) /
63    /// [`AnnounceNumber`](crate::message::gm::MessageType::AnnounceNumber).
64    SelectOption(u8),
65    /// Answers [`SelectChain`](crate::message::gm::MessageType::SelectChain).
66    SelectChain(u8),
67    /// Answers [`SelectChain`](crate::message::gm::MessageType::SelectChain), meaning decline.
68    DeclineChain,
69    /// Answers [`SelectPosition`](crate::message::gm::MessageType::SelectPosition).
70    SelectPosition(Position),
71    /// Answers [`SelectCard`](crate::message::gm::MessageType::SelectCard).
72    SelectCards(Vec<u16>),
73    /// Answers [`SelectUnselectCard`](crate::message::gm::MessageType::SelectUnselectCard).
74    SelectUnselectCards(u16),
75    /// Answers [`SelectTribute`](crate::message::gm::MessageType::SelectTribute).
76    SelectTribute(Vec<u16>),
77    /// Answers [`SelectSum`](crate::message::gm::MessageType::SelectSum).
78    SelectSum(Vec<u16>),
79    /// Answers [`SelectCounter`](crate::message::gm::MessageType::SelectCounter).
80    SelectCounter(Vec<u16>),
81    /// Answers [`SelectPlace`](crate::message::gm::MessageType::SelectPlace) /
82    /// [`SelectDisableField`](crate::message::gm::MessageType::SelectDisableField).
83    SelectPlace(CorePlayer, Location, u8),
84    /// Answers [`SelectPlace`](crate::message::gm::MessageType::SelectPlace) /
85    /// [`SelectDisableField`](crate::message::gm::MessageType::SelectDisableField), meaning decline.
86    DeclinePlace,
87    /// Answers [`SortCard`](crate::message::gm::MessageType::SortCard).
88    SortCards(Vec<u16>),
89    /// Answers [`SortCard`](crate::message::gm::MessageType::SortCard), meaning keep the card order.
90    KeepCardOrder,
91    /// Answers [`AnnounceRace`](crate::message::gm::MessageType::AnnounceRace).
92    AnnounceRace(Race),
93    /// Answers [`AnnounceAttribute`](crate::message::gm::MessageType::AnnounceAttribute).
94    AnnounceAttribute(Attribute),
95    /// Answers [`AnnounceCard`](crate::message::gm::MessageType::AnnounceCard).
96    AnnounceCard(u32),
97    /// Raw bytes, when the prompting message type is unknown.
98    Unknown(Vec<u8>),
99}
100
101impl BinWrite for Response {
102    type Args<'a> = ();
103
104    fn write_options<W: Write + Seek>(&self, writer: &mut W, endian: binrw::Endian, _args: ()) -> binrw::BinResult<()> {
105        let args = ();
106        match self {
107            Response::Cancel => (-1i32).write_options(writer, endian, args)?,
108            Response::SelectIdleCommand(command, card_index) => {
109                command.write_options(writer, endian, args)?;
110                card_index.write_options(writer, endian, args)?;
111            }
112            Response::SelectBattleCommand(command, card_index) => {
113                command.write_options(writer, endian, args)?;
114                card_index.write_options(writer, endian, args)?;
115            }
116            Response::SelectYesNo(yes) => u8::from(*yes).write_options(writer, endian, args)?,
117            Response::SelectOption(index) => index.write_options(writer, endian, args)?,
118            Response::SelectChain(index) => index.write_options(writer, endian, args)?,
119            Response::DeclineChain => (-1i32).write_options(writer, endian, args)?,
120            Response::SelectPosition(position) => position.write_options(writer, endian, args)?,
121            Response::SelectCards(card_indices) => {
122                let len = card_indices.len() as u8;
123                len.write_options(writer, endian, args)?;
124                card_indices.write_options(writer, endian, args)?;
125            }
126            Response::SelectUnselectCards(card_index) => {
127                1u8.write_options(writer, endian, args)?;
128                card_index.write_options(writer, endian, args)?;
129            }
130            Response::SelectTribute(card_indices) => {
131                let len = card_indices.len() as u8;
132                len.write_options(writer, endian, args)?;
133                card_indices.write_options(writer, endian, args)?;
134            }
135            Response::SelectSum(card_indices) => {
136                let len = card_indices.len() as u8;
137                len.write_options(writer, endian, args)?;
138                card_indices.write_options(writer, endian, args)?;
139            }
140            Response::SelectCounter(counts) => counts.write_options(writer, endian, args)?,
141            Response::SelectPlace(player, location, sequence) => {
142                player.write_options(writer, endian, args)?;
143                location.write_options(writer, endian, args)?;
144                sequence.write_options(writer, endian, args)?;
145            }
146            Response::DeclinePlace => [0u8; 3].write_options(writer, endian, args)?,
147            Response::SortCards(order) => order.write_options(writer, endian, args)?,
148            Response::KeepCardOrder => 0xffu8.write_options(writer, endian, args)?,
149            Response::AnnounceRace(races) => races.write_options(writer, endian, args)?,
150            Response::AnnounceAttribute(attributes) => attributes.write_options(writer, endian, args)?,
151            Response::AnnounceCard(code) => code.write_options(writer, endian, args)?,
152            Response::Unknown(data) => data.write_options(writer, endian, args)?,
153        }
154        Ok(())
155    }
156}
157
158impl Response {
159    pub fn len(&self) -> usize {
160        match self {
161            Response::Cancel => 4,
162            Response::SelectIdleCommand(_, _) => 4,
163            Response::SelectBattleCommand(_, _) => 4,
164            Response::SelectYesNo(_) => 1,
165            Response::SelectOption(_) => 1,
166            Response::SelectChain(_) => 1,
167            Response::DeclineChain => 4,
168            Response::SelectPosition(_) => 1,
169            Response::SelectCards(card_indices) => 1 + card_indices.len() * 2,
170            Response::SelectUnselectCards(_) => 3,
171            Response::SelectTribute(card_indices) => 1 + card_indices.len() * 2,
172            Response::SelectSum(card_indices) => 1 + card_indices.len() * 2,
173            Response::SelectCounter(counts) => counts.len() * 2,
174            Response::SelectPlace(_, _, _) => 3,
175            Response::DeclinePlace => 3,
176            Response::SortCards(order) => order.len() * 2,
177            Response::KeepCardOrder => 1,
178            Response::AnnounceRace(_) => 4,
179            Response::AnnounceAttribute(_) => 4,
180            Response::AnnounceCard(_) => 4,
181            Response::Unknown(data) => data.len(),
182        }
183    }
184
185    pub fn resolve(&mut self, message_type: gm::MessageType) -> binrw::BinResult<()> {
186        let data = match self {
187            Response::Unknown(data) => data,
188            _ => return Ok(()),
189        };
190        *self = Self::parse(&mut Cursor::new(data.as_slice()), binrw::Endian::Little, message_type)?;
191        Ok(())
192    }
193
194    fn parse<R: Read + Seek>(reader: &mut R, endian: binrw::Endian, message_type: gm::MessageType) -> binrw::BinResult<Response> {
195        match message_type {
196            gm::MessageType::SelectIdleCommand => Ok(Response::SelectIdleCommand(IdleCommand::read_options(reader, endian, ())?, u16::read_options(reader, endian, ())?)),
197            gm::MessageType::SelectBattleCommand => Ok(Response::SelectBattleCommand(BattleCommand::read_options(reader, endian, ())?, u16::read_options(reader, endian, ())?)),
198            gm::MessageType::SelectEffectYesNo | gm::MessageType::SelectYesNo => Ok(Response::SelectYesNo(u8::read_options(reader, endian, ())? != 0)),
199            gm::MessageType::SelectOption | gm::MessageType::AnnounceNumber => Ok(Response::SelectOption(u8::read_options(reader, endian, ())?)),
200            gm::MessageType::SelectPosition => Ok(Response::SelectPosition(Position::read_options(reader, endian, ())?)),
201            gm::MessageType::SelectCounter => Ok(Response::SelectCounter(until_eof::<_, u16, (), Vec<u16>>(reader, endian, ())?)),
202            gm::MessageType::AnnounceRace => Ok(Response::AnnounceRace(Race::read_options(reader, endian, ())?)),
203            gm::MessageType::AnnounceAttribute => Ok(Response::AnnounceAttribute(Attribute::read_options(reader, endian, ())?)),
204            gm::MessageType::AnnounceCard => Ok(Response::AnnounceCard(u32::read_options(reader, endian, ())?)),
205            gm::MessageType::SelectChain => {
206                if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
207                    return Ok(Response::DeclineChain);
208                }
209                Ok(Response::SelectChain(u8::read_options(reader, endian, ())?))
210            }
211            gm::MessageType::SelectCard => {
212                if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
213                    return Ok(Response::Cancel);
214                }
215                let len = u8::read_options(reader, endian, ())?;
216                Ok(Response::SelectCards(Vec::<u16>::read_options(reader, endian, VecArgs { count: len as usize, inner: () })?))
217            }
218            gm::MessageType::SelectUnselectCard => {
219                if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
220                    return Ok(Response::Cancel);
221                }
222                let marker = u8::read_options(reader, endian, ())?;
223                if marker != 1 {
224                    return Err(binrw::Error::NoVariantMatch { pos: reader.stream_position()? });
225                }
226                Ok(Response::SelectUnselectCards(u16::read_options(reader, endian, ())?))
227            }
228            gm::MessageType::SelectTribute => {
229                if read_all_remaining(reader)? == &(-1i32).to_le_bytes() {
230                    return Ok(Response::Cancel);
231                }
232                let len = u8::read_options(reader, endian, ())?;
233                Ok(Response::SelectTribute(Vec::<u16>::read_options(reader, endian, VecArgs { count: len as usize, inner: () })?))
234            }
235            gm::MessageType::SelectSum => {
236                let len = u8::read_options(reader, endian, ())?;
237                Ok(Response::SelectSum(Vec::<u16>::read_options(reader, endian, VecArgs { count: len as usize, inner: () })?))
238            }
239            gm::MessageType::SelectPlace | gm::MessageType::SelectDisableField => {
240                let player = CorePlayer::read_options(reader, endian, ())?;
241                let location = Location::read_options(reader, endian, ())?;
242                let sequence = u8::read_options(reader, endian, ())?;
243                if player == CorePlayer::FirstAttackPlayer && location.is_empty() && sequence == 0 {
244                    Ok(Response::DeclinePlace)
245                } else {
246                    Ok(Response::SelectPlace(player, location, sequence))
247                }
248            }
249            gm::MessageType::SortCard => {
250                if read_all_remaining(reader)? == &[0xffu8] {
251                    return Ok(Response::KeepCardOrder);
252                }
253                Ok(Response::SortCards(until_eof::<_, u16, (), Vec<u16>>(reader, endian, ())?))
254            }
255            _ => Err(binrw::Error::NoVariantMatch { pos: reader.stream_position()? }),
256        }
257    }
258}
259
260impl BinRead for Response {
261    type Args<'a> = Option<gm::MessageType>;
262
263    fn read_options<R: Read + Seek>(reader: &mut R, endian: binrw::Endian, message_type: Self::Args<'_>) -> binrw::BinResult<Self> {
264        match message_type {
265            Some(message_type) => Self::parse(reader, endian, message_type),
266            None => Ok(Response::Unknown(until_eof::<_, u8, (), Vec<u8>>(reader, endian, ())?)),
267        }
268    }
269}
270
271fn read_all_remaining<R: Read + Seek>(reader: &mut R) -> binrw::BinResult<Vec<u8>> {
272    let pos = reader.stream_position()?;
273    let mut data = Vec::new();
274    reader.read_to_end(&mut data)?;
275    reader.seek(std::io::SeekFrom::Start(pos))?;
276    Ok(data)
277}