1use crate::{
4 common::{Clock, NesRegion, Reset, ResetKind},
5 cpu::Cpu,
6 ppu::Ppu,
7};
8use bitflags::bitflags;
9use serde::{Deserialize, Serialize};
10use std::str::FromStr;
11use thiserror::Error;
12use tracing::trace;
13
14#[derive(Error, Debug)]
15#[must_use]
16#[error("failed to parse `Player`")]
17pub struct ParsePlayerError;
18
19#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20#[must_use]
21pub enum Player {
22 #[default]
23 One,
24 Two,
25 Three,
26 Four,
27}
28
29impl std::fmt::Display for Player {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 let s = match self {
32 Self::One => "One",
33 Self::Two => "Two",
34 Self::Three => "Three",
35 Self::Four => "Four",
36 };
37 write!(f, "{s}")
38 }
39}
40
41impl AsRef<str> for Player {
42 fn as_ref(&self) -> &str {
43 match self {
44 Self::One => "one",
45 Self::Two => "two",
46 Self::Three => "three",
47 Self::Four => "four",
48 }
49 }
50}
51
52impl TryFrom<usize> for Player {
53 type Error = ParsePlayerError;
54
55 fn try_from(value: usize) -> Result<Self, Self::Error> {
56 match value {
57 0 => Ok(Self::One),
58 1 => Ok(Self::Two),
59 2 => Ok(Self::Three),
60 3 => Ok(Self::Four),
61 _ => Err(ParsePlayerError),
62 }
63 }
64}
65
66pub trait InputRegisters {
67 fn read(&mut self, player: Player, ppu: &Ppu) -> u8;
68 fn peek(&self, player: Player, ppu: &Ppu) -> u8;
69 fn write(&mut self, val: u8);
70}
71
72#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
73#[must_use]
74pub enum FourPlayer {
75 #[default]
76 Disabled,
77 FourScore,
78 Satellite,
79}
80
81impl FourPlayer {
82 pub const fn as_slice() -> &'static [Self] {
83 &[Self::Disabled, Self::FourScore, Self::Satellite]
84 }
85
86 pub const fn as_str(&self) -> &'static str {
87 match self {
88 Self::Disabled => "disabled",
89 Self::FourScore => "four-score",
90 Self::Satellite => "satellite",
91 }
92 }
93}
94
95impl AsRef<str> for FourPlayer {
96 fn as_ref(&self) -> &str {
97 self.as_str()
98 }
99}
100
101impl std::fmt::Display for FourPlayer {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 let s = match self {
104 Self::Disabled => "Disabled",
105 Self::FourScore => "FourScore",
106 Self::Satellite => "Satellite",
107 };
108 write!(f, "{s}")
109 }
110}
111
112impl FromStr for FourPlayer {
113 type Err = &'static str;
114 fn from_str(s: &str) -> Result<Self, Self::Err> {
115 match s {
116 "disabled" => Ok(Self::Disabled),
117 "four-score" => Ok(Self::FourScore),
118 "satellite" => Ok(Self::Satellite),
119 _ => Err(
120 "invalid FourPlayer value. valid options: `disabled`, `four-score`, or `satellite`",
121 ),
122 }
123 }
124}
125
126#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
127#[must_use]
128pub struct Input {
129 pub joypads: [Joypad; 4],
130 pub signatures: [Joypad; 2],
131 pub zapper: Zapper,
132 pub turbo_timer: u32,
133 pub four_player: FourPlayer,
134}
135
136impl Input {
137 pub fn new(region: NesRegion) -> Self {
138 Self {
139 joypads: [Joypad::new(); 4],
140 signatures: [
142 Joypad::from_bytes(0b0000_1000),
143 Joypad::from_bytes(0b0000_0100),
144 ],
145 zapper: Zapper::new(region),
146 turbo_timer: 30,
147 four_player: FourPlayer::default(),
148 }
149 }
150
151 pub const fn joypad(&self, player: Player) -> &Joypad {
152 &self.joypads[player as usize]
153 }
154
155 pub const fn joypad_mut(&mut self, player: Player) -> &mut Joypad {
156 &mut self.joypads[player as usize]
157 }
158
159 pub fn set_region(&mut self, region: NesRegion) {
160 self.zapper.trigger_release_delay = Cpu::region_clock_rate(region) / 10.0;
161 }
162
163 pub fn set_concurrent_dpad(&mut self, enabled: bool) {
164 self.joypads
165 .iter_mut()
166 .for_each(|pad| pad.concurrent_dpad = enabled);
167 }
168
169 pub const fn connect_zapper(&mut self, connected: bool) {
170 self.zapper.connected = connected;
171 }
172
173 pub fn set_four_player(&mut self, four_player: FourPlayer) {
174 self.four_player = four_player;
175 self.reset(ResetKind::Hard);
176 }
177
178 pub fn clear(&mut self) {
179 for pad in &mut self.joypads {
180 pad.clear();
181 }
182 self.zapper.clear();
183 }
184}
185
186impl InputRegisters for Input {
187 fn read(&mut self, player: Player, ppu: &Ppu) -> u8 {
188 let zapper = if player == Player::Two {
192 self.zapper.read(ppu)
193 } else {
194 0x00
195 };
196
197 let player = player as usize;
198 assert!(player < 4);
199 let val = match self.four_player {
200 FourPlayer::Disabled => self.joypads[player].read(),
201 FourPlayer::FourScore => {
202 if self.joypads[player].index() < 8 {
203 self.joypads[player].read()
204 } else if self.joypads[player + 2].index() < 8 {
205 self.joypads[player + 2].read()
206 } else if self.signatures[player].index() < 8 {
207 self.signatures[player].read()
208 } else {
209 0x01
210 }
211 }
212 FourPlayer::Satellite => {
213 self.joypads[player].read() | (self.joypads[player + 2].read() << 1)
214 }
215 };
216
217 zapper | val | 0x40
218 }
219
220 fn peek(&self, player: Player, ppu: &Ppu) -> u8 {
221 let zapper = if player == Player::Two {
225 self.zapper.read(ppu)
226 } else {
227 0x00
228 };
229
230 let player = player as usize;
231 assert!(player < 4);
232 let val = match self.four_player {
233 FourPlayer::Disabled => self.joypads[player].peek(),
234 FourPlayer::FourScore => {
235 if self.joypads[player].index() < 8 {
236 self.joypads[player].peek()
237 } else if self.joypads[player + 2].index() < 8 {
238 self.joypads[player + 2].peek()
239 } else if self.signatures[player].index() < 8 {
240 self.signatures[player].peek()
241 } else {
242 0x01
243 }
244 }
245 FourPlayer::Satellite => {
246 self.joypads[player].peek() | (self.joypads[player + 2].peek() << 1)
247 }
248 };
249
250 zapper | val | 0x40
251 }
252
253 fn write(&mut self, val: u8) {
254 for pad in &mut self.joypads {
255 pad.write(val);
256 }
257 for sig in &mut self.signatures {
258 sig.write(val);
259 }
260 }
261}
262
263impl Clock for Input {
264 fn clock(&mut self) -> u64 {
265 self.zapper.clock();
266 if self.turbo_timer > 0 {
267 self.turbo_timer -= 1;
268 }
269 if self.turbo_timer == 0 {
270 self.turbo_timer += 89500;
272 for pad in &mut self.joypads {
273 if pad.button(JoypadBtnState::TURBO_A) {
274 let pressed = pad.button(JoypadBtnState::A);
275 pad.set_button(JoypadBtnState::A, !pressed);
276 }
277 if pad.button(JoypadBtnState::TURBO_B) {
278 let pressed = pad.button(JoypadBtnState::B);
279 pad.set_button(JoypadBtnState::B, !pressed);
280 }
281 }
282 }
283 1
284 }
285}
286
287impl Reset for Input {
288 fn reset(&mut self, kind: ResetKind) {
289 for pad in &mut self.joypads {
290 pad.reset(kind);
291 }
292 self.signatures[0] = Joypad::from_bytes(0b0000_1000);
293 self.signatures[1] = Joypad::from_bytes(0b0000_0100);
294 self.zapper.reset(kind);
295 }
296}
297
298#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
299pub enum JoypadBtn {
300 Left,
302 Right,
304 Up,
306 Down,
308 A,
310 B,
312 TurboA,
314 TurboB,
316 Select,
318 Start,
320}
321
322impl AsRef<str> for JoypadBtn {
323 fn as_ref(&self) -> &str {
324 match *self {
325 JoypadBtn::A => "A",
326 JoypadBtn::B => "B",
327 JoypadBtn::Select => "Select",
328 JoypadBtn::Start => "Start",
329 JoypadBtn::Up => "Up",
330 JoypadBtn::Down => "Down",
331 JoypadBtn::Left => "Left",
332 JoypadBtn::Right => "Right",
333 JoypadBtn::TurboA => "A (Turbo)",
334 JoypadBtn::TurboB => "B (Turbo)",
335 }
336 }
337}
338
339bitflags! {
340 #[derive(Default, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
341 #[must_use]
342 pub struct JoypadBtnState: u16 {
343 const A = 0x01;
344 const B = 0x02;
345 const SELECT = 0x04;
346 const START = 0x08;
347 const UP = 0x10;
348 const DOWN = 0x20;
349 const LEFT = 0x40;
350 const RIGHT = 0x80;
351 const TURBO_A = 0x100;
352 const TURBO_B = 0x200;
353 }
354}
355
356impl From<JoypadBtn> for JoypadBtnState {
357 fn from(button: JoypadBtn) -> Self {
358 match button {
359 JoypadBtn::A => Self::A,
360 JoypadBtn::B => Self::B,
361 JoypadBtn::Select => Self::SELECT,
362 JoypadBtn::Start => Self::START,
363 JoypadBtn::Up => Self::UP,
364 JoypadBtn::Down => Self::DOWN,
365 JoypadBtn::Left => Self::LEFT,
366 JoypadBtn::Right => Self::RIGHT,
367 JoypadBtn::TurboA => Self::TURBO_A,
368 JoypadBtn::TurboB => Self::TURBO_B,
369 }
370 }
371}
372
373#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
374#[must_use]
375pub struct Joypad {
376 pub buttons: JoypadBtnState,
377 pub concurrent_dpad: bool,
378 pub index: u8,
379 pub strobe: bool,
380}
381
382impl Joypad {
383 pub const fn new() -> Self {
384 Self {
385 buttons: JoypadBtnState::empty(),
386 concurrent_dpad: false,
387 index: 0,
388 strobe: false,
389 }
390 }
391
392 #[must_use]
393 pub const fn button(&self, button: JoypadBtnState) -> bool {
394 self.buttons.contains(button)
395 }
396
397 pub fn set_button(&mut self, button: impl Into<JoypadBtnState>, pressed: bool) {
398 let button = button.into();
399 if pressed && !self.concurrent_dpad {
400 if let Some(button) = match button {
401 JoypadBtnState::LEFT => Some(JoypadBtnState::RIGHT),
402 JoypadBtnState::RIGHT => Some(JoypadBtnState::LEFT),
403 JoypadBtnState::UP => Some(JoypadBtnState::DOWN),
404 JoypadBtnState::DOWN => Some(JoypadBtnState::UP),
405 _ => None,
406 } {
407 self.buttons.set(button, false);
408 }
409 }
410 self.buttons.set(button, pressed);
411 }
412
413 pub const fn from_bytes(val: u16) -> Self {
414 Self {
415 buttons: JoypadBtnState::from_bits_truncate(val),
416 concurrent_dpad: false,
417 index: 0,
418 strobe: false,
419 }
420 }
421
422 #[must_use]
423 pub const fn read(&mut self) -> u8 {
424 let val = self.peek();
425 if !self.strobe && self.index < 8 {
426 self.index += 1;
427 }
428 val
429 }
430
431 #[must_use]
432 pub const fn peek(&self) -> u8 {
433 if self.index < 8 {
434 ((self.buttons.bits() as u8) & (1 << self.index)) >> self.index
435 } else {
436 0x01
437 }
438 }
439
440 pub const fn write(&mut self, val: u8) {
441 let prev_strobe = self.strobe;
442 self.strobe = val & 0x01 == 0x01;
443 if prev_strobe && !self.strobe {
444 self.index = 0;
445 }
446 }
447
448 #[must_use]
449 pub const fn index(&self) -> u8 {
450 self.index
451 }
452
453 pub const fn clear(&mut self) {
454 self.buttons = JoypadBtnState::empty();
455 }
456}
457
458impl Reset for Joypad {
459 fn reset(&mut self, _kind: ResetKind) {
460 self.buttons = JoypadBtnState::empty();
461 self.index = 0;
462 self.strobe = false;
463 }
464}
465
466#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
467#[must_use]
468pub struct Zapper {
469 #[serde(skip)] pub triggered: f32,
471 pub trigger_release_delay: f32,
472 #[serde(skip)] pub x: u32,
474 #[serde(skip)] pub y: u32,
476 pub radius: u32,
477 pub connected: bool,
478}
479
480impl Zapper {
481 #[must_use]
482 pub const fn x(&self) -> u32 {
483 self.x
484 }
485
486 #[must_use]
487 pub const fn y(&self) -> u32 {
488 self.y
489 }
490
491 pub fn trigger(&mut self) {
492 if self.triggered <= 0.0 {
493 self.triggered = self.trigger_release_delay;
494 }
495 }
496
497 pub fn aim(&mut self, x: u32, y: u32) {
498 if x != self.x || y != self.y {
499 trace!("zapper aim: {x}, {y}");
500 }
501 self.x = x;
502 self.y = y;
503 }
504
505 pub const fn clear(&mut self) {
506 self.triggered = 0.0;
507 }
508}
509
510impl Zapper {
511 fn new(region: NesRegion) -> Self {
512 Self {
513 triggered: 0.0,
514 trigger_release_delay: Cpu::region_clock_rate(region) / 10.0,
516 x: 0,
517 y: 0,
518 radius: 3,
519 connected: false,
520 }
521 }
522
523 #[must_use]
524 fn read(&self, ppu: &Ppu) -> u8 {
525 if self.connected {
526 self.triggered() | self.light_sense(ppu)
527 } else {
528 0x00
529 }
530 }
531
532 fn triggered(&self) -> u8 {
533 if self.triggered > 0.0 { 0x10 } else { 0x00 }
534 }
535
536 fn light_sense(&self, ppu: &Ppu) -> u8 {
537 let width = Ppu::WIDTH;
538 let height = Ppu::HEIGHT;
539 let scanline = ppu.scanline;
540 let cycle = ppu.cycle;
541 let min_y = self.y.saturating_sub(self.radius);
542 let max_y = (self.y + self.radius).min(height - 1);
543 let min_x = self.x.saturating_sub(self.radius);
544 let max_x = (self.x + self.radius).min(width - 1);
545 for y in min_y..=max_y {
546 for x in min_x..=max_x {
547 let behind_ppu =
548 scanline >= y && (scanline - y) <= 20 && (scanline != y || cycle > x);
549 let brightness = ppu.pixel_brightness(x, y);
550 if behind_ppu && brightness >= 85 {
551 trace!("zapper light: {brightness}");
552 return 0x00;
553 }
554 }
555 }
556 0x08
557 }
558}
559
560impl Clock for Zapper {
561 fn clock(&mut self) -> u64 {
562 if self.triggered > 0.0 {
563 self.triggered -= 1.0;
564 1
565 } else {
566 0
567 }
568 }
569}
570
571impl Reset for Zapper {
572 fn reset(&mut self, _kind: ResetKind) {
573 self.triggered = 0.0;
574 }
575}