summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author 0kmg <9137159+0kmg@users.noreply.github.com>2022-02-09 09:18:19 -0900
committer GitHub <noreply@github.com>2022-02-09 13:18:19 -0500
commit0d8ac5b7608e87160071d41d2b98040f98f11132 (patch)
treef594b52646cae5a2f980f228aeed2996f001ffa2
parent56db643ab0315a0d6ffbaf708afc1c6f599bdbf2 (diff)
nes.cpp, playch10.cpp, vsnes.cpp: Made zapper less bad. (#9284)
- Limited light detection to scanlines recently drawn by CRT. - Lowered light detection threshold to better reflect how real zapper behaves; color doesn't need to be white. - Bugs fixed: * not detecting hits on certain white objects * misdetecting hits on objects far away from the pointer * not being able to track where zapper is pointed in demo/test software
-rw-r--r--src/devices/bus/nes_ctrl/arkpaddle.cpp4
-rw-r--r--src/devices/bus/nes_ctrl/zapper.cpp51
-rw-r--r--src/mame/drivers/playch10.cpp10
-rw-r--r--src/mame/drivers/vsnes.cpp8
-rw-r--r--src/mame/machine/playch10.cpp58
-rw-r--r--src/mame/machine/vsnes.cpp75
6 files changed, 109 insertions, 97 deletions
diff --git a/src/devices/bus/nes_ctrl/arkpaddle.cpp b/src/devices/bus/nes_ctrl/arkpaddle.cpp
index e322d10eeed..c529070bc12 100644
--- a/src/devices/bus/nes_ctrl/arkpaddle.cpp
+++ b/src/devices/bus/nes_ctrl/arkpaddle.cpp
@@ -33,9 +33,9 @@ DEFINE_DEVICE_TYPE(NES_ARKPADDLE_FC, nes_vausfc_device, "nes_vausfc", "FC Arkano
static INPUT_PORTS_START( arkanoid_paddle )
PORT_START("PADDLE")
- PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x4e,0xf2) // this minmax is from what Arkanoid 2 clamps values to, so an actual paddle's range may be greater
+ PORT_BIT( 0xff, 0x7f, IPT_PADDLE ) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x4e, 0xf2) // this minmax is from what Arkanoid 2 clamps values to, so an actual paddle's range may be greater
PORT_START("BUTTON")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Paddle button")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Paddle button")
INPUT_PORTS_END
diff --git a/src/devices/bus/nes_ctrl/zapper.cpp b/src/devices/bus/nes_ctrl/zapper.cpp
index e19c63fa2d2..4a1a2dd9408 100644
--- a/src/devices/bus/nes_ctrl/zapper.cpp
+++ b/src/devices/bus/nes_ctrl/zapper.cpp
@@ -21,11 +21,11 @@ DEFINE_DEVICE_TYPE(NES_BANDAIHS, nes_bandaihs_device, "nes_bandaihs", "Bandai Hy
static INPUT_PORTS_START( nes_zapper )
PORT_START("ZAPPER_X")
- PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255)
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0, 255)
PORT_START("ZAPPER_Y")
- PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255)
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0, 239)
PORT_START("ZAPPER_T")
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Lightgun Trigger")
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Lightgun Trigger")
INPUT_PORTS_END
@@ -116,25 +116,40 @@ u8 nes_zapper_device::read_bit34()
int x = m_lightx->read();
int y = m_lighty->read();
+ // effective range picked up by photodiode, i.e. gun position +- radius
+ constexpr int xrad = 0;
+ constexpr int yrad = 0;
+ // brightness threshold
+ constexpr int bright = 0x70;
+ // # of CRT scanlines that sustain brightness
+ constexpr int sustain = 20;
+
+ int vpos = m_port->m_screen->vpos();
+ int hpos = m_port->m_screen->hpos();
+
// update the screen if necessary
if (!m_port->m_screen->vblank())
- {
- int vpos = m_port->m_screen->vpos();
- int hpos = m_port->m_screen->hpos();
-
- if (vpos > y || (vpos == y && hpos >= x))
+ if (vpos > y - yrad || (vpos == y - yrad && hpos >= x - xrad))
m_port->m_screen->update_now();
- }
-
- // get the pixel at the gun position
- rgb_t pix = m_port->m_screen->pixel(x, y);
- // check if the cursor is over a bright pixel
- // FIXME: still a gross hack
- if (pix.r() == 0xff && pix.b() == 0xff && pix.g() > 0x90)
- ret &= ~0x08; // sprite hit
- else
- ret |= 0x08; // no sprite hit
+ // default to no light detected
+ ret |= 0x08;
+
+ // check brightness of pixels nearby the gun position
+ for (int i = x - xrad; i <= x + xrad; i++)
+ for (int j = y - yrad; j <= y + yrad; j++)
+ {
+ rgb_t pix = m_port->m_screen->pixel(i, j);
+
+ // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki:
+ // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray."
+ if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos) && pix.brightness() >= bright)
+ {
+ ret &= ~0x08; // light detected
+ i = x + xrad;
+ break;
+ }
+ }
return ret;
}
diff --git a/src/mame/drivers/playch10.cpp b/src/mame/drivers/playch10.cpp
index 4184b48c54c..da5754a9bf4 100644
--- a/src/mame/drivers/playch10.cpp
+++ b/src/mame/drivers/playch10.cpp
@@ -711,15 +711,15 @@ static INPUT_PORTS_START( playch10 )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
INPUT_PORTS_END
-/*Input Ports for gun games*/
+// Input Ports for gun games
static INPUT_PORTS_START( playc10g )
PORT_INCLUDE(playch10)
- PORT_START("GUNX") /* IN2 - FAKE - Gun X pos */
- PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30)
+ PORT_START("GUNX") // IN2 - FAKE - Gun X pos
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0, 255)
- PORT_START("GUNY") /* IN3 - FAKE - Gun Y pos */
- PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30)
+ PORT_START("GUNY") // IN3 - FAKE - Gun Y pos
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0, 239)
INPUT_PORTS_END
diff --git a/src/mame/drivers/vsnes.cpp b/src/mame/drivers/vsnes.cpp
index 66f8498a6ab..e5352b3c1a3 100644
--- a/src/mame/drivers/vsnes.cpp
+++ b/src/mame/drivers/vsnes.cpp
@@ -496,11 +496,11 @@ static INPUT_PORTS_START( vsnes_zapper )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_COIN2 ) PORT_IMPULSE(1)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN )
- PORT_START("GUNX") /* FAKE - Gun X pos */
- PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30)
+ PORT_START("GUNX") // FAKE - Gun X pos
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0, 255)
- PORT_START("GUNY") /* FAKE - Gun Y pos */
- PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30)
+ PORT_START("GUNY") // FAKE - Gun Y pos
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0, 239)
INPUT_PORTS_END
diff --git a/src/mame/machine/playch10.cpp b/src/mame/machine/playch10.cpp
index 37708486976..ff3215ab4a5 100644
--- a/src/mame/machine/playch10.cpp
+++ b/src/mame/machine/playch10.cpp
@@ -212,50 +212,60 @@ uint8_t playch10_state::pc10_in0_r()
uint8_t playch10_state::pc10_in1_r()
{
- int ret = (m_input_latch[1]) & 1;
+ int ret = m_input_latch[1] & 1;
- /* shift */
+ // shift
m_input_latch[1] >>= 1;
- /* do the gun thing */
+ // do the gun thing
if (m_pc10_gun_controller)
{
int trigger = ioport("P1")->read();
int x = ioport("GUNX")->read();
int y = ioport("GUNY")->read();
- /* no sprite hit (yet) */
- ret |= 0x08;
+ // effective range picked up by photodiode, i.e. gun position +- radius
+ constexpr int xrad = 0;
+ constexpr int yrad = 0;
+ // brightness threshold
+ constexpr int bright = 0x70;
+ // # of CRT scanlines that sustain brightness
+ constexpr int sustain = 20;
+
+ int vpos = m_ppu->screen().vpos();
+ int hpos = m_ppu->screen().hpos();
// update the screen if necessary
if (!m_ppu->screen().vblank())
- {
- int vpos = m_ppu->screen().vpos();
- int hpos = m_ppu->screen().hpos();
-
- if (vpos > y || (vpos == y && hpos >= x))
+ if (vpos > y - yrad || (vpos == y - yrad && hpos >= x - xrad))
m_ppu->screen().update_now();
- }
- /* get the pixel at the gun position */
- rgb_t pix = m_ppu->screen().pixel(x, y);
+ // default to no light detected
+ ret |= 0x08;
- /* look at the screen and see if the cursor is over a bright pixel */
- // FIXME: still a gross hack
- if (pix.r() == 0xff && pix.b() == 0xff && pix.g() > 0x90)
- {
- ret &= ~0x08; /* sprite hit */
- }
+ // check brightness of pixels nearby the gun position
+ for (int i = x - xrad; i <= x + xrad; i++)
+ for (int j = y - yrad; j <= y + yrad; j++)
+ {
+ rgb_t pix = m_ppu->screen().pixel(i, j);
- /* now, add the trigger if not masked */
+ // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki:
+ // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray."
+ if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos) && pix.brightness() >= bright)
+ {
+ ret &= ~0x08; // light detected
+ i = x + xrad;
+ break;
+ }
+ }
+
+ // now, add the trigger if not masked
if (!m_cntrl_mask)
- {
ret |= (trigger & 2) << 3;
- }
}
- /* some games expect bit 6 to be set because the last entry on the data bus shows up */
- /* in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there. */
+ // some games expect bit 6 to be set because the last entry on the data bus shows up
+ // in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there.
ret |= 0x40;
return ret;
diff --git a/src/mame/machine/vsnes.cpp b/src/mame/machine/vsnes.cpp
index 3a22c4795c3..855dc5d9b27 100644
--- a/src/mame/machine/vsnes.cpp
+++ b/src/mame/machine/vsnes.cpp
@@ -259,71 +259,58 @@ void vsnes_state::init_vsnormal()
}
/**********************************************************************************/
-/* Gun games: VROM Banking in controller 0 write */
+// Gun games: VROM Banking in controller 0 write
void vsnes_state::gun_in0_w(uint8_t data)
{
if (m_do_vrom_bank)
{
- /* switch vrom */
+ // switch vrom
v_set_videorom_bank(0, 8, (data & 4) ? 8 : 0);
}
- /* here we do things a little different */
+ // here we do things a little different
if (m_input_strobe[0] & ~data & 1)
{
- /* load up the latches */
+ // load up the latches
m_input_latch[0] = ioport("IN0")->read();
+ m_input_latch[1] = ioport("IN1")->read();
- /* do the gun thing */
+ // do the gun thing
int x = ioport("GUNX")->read();
- float y = ioport("GUNY")->read();
+ int y = ioport("GUNY")->read();
- y = y * 0.9375f; // scale 256 (our gun input range is 0 - 255) to 240 (screen visible area / bitmap we're using is 0 - 239)
+ // effective range picked up by photodiode, i.e. gun position +- radius
+ constexpr int xrad = 0;
+ constexpr int yrad = 0;
+ // brightness threshold
+ constexpr int bright = 0x70;
+ // # of CRT scanlines that sustain brightness
+ constexpr int sustain = 20;
- uint8_t realy = (int)y;
+ int vpos = m_ppu1->screen().vpos();
+ int hpos = m_ppu1->screen().hpos();
// update the screen if necessary
if (!m_ppu1->screen().vblank())
- {
- int vpos = m_ppu1->screen().vpos();
- int hpos = m_ppu1->screen().hpos();
-
- if (vpos > realy || (vpos == realy && hpos >= x))
+ if (vpos > y - yrad || (vpos == y - yrad && hpos >= x - xrad))
m_ppu1->screen().update_now();
- }
-
- /* get the pixel at the gun position */
- rgb_t col = m_ppu1->screen().pixel(x, realy);
- uint8_t bright = col.brightness();
- // todo, calculate how bright it is with pix.r * 0.3 + pix.g * 0.59 + pix.b * 0.11 ?
- // the mame calc above is uint8_t brightness() const { return (r() * 222 + g() * 707 + b() * 71) / 1000; } (from lib/util/palette.h)
-#if 0
- uint8_t r = col.r();
- uint8_t g = col.g();
- uint8_t b = col.b();
- printf("pix is %02x %02x %02x | %02x\n", r,g,b,bright);
-#endif
- if (bright == 0xff)
- {
- m_input_latch[0] |= 0x40;
- }
-
-
-#if 0 // this is junk code, only works for NES palette..
- /* get the color base from the ppu */
- uint32_t color_base = 0;
-
- /* look at the screen and see if the cursor is over a bright pixel */
- if ((pix == color_base + 0x20 ) || (pix == color_base + 0x30) ||
- (pix == color_base + 0x33 ) || (pix == color_base + 0x34))
- {
- m_input_latch[0] |= 0x40;
- }
-#endif
+ // check brightness of pixels nearby the gun position
+ for (int i = x - xrad; i <= x + xrad; i++)
+ for (int j = y - yrad; j <= y + yrad; j++)
+ {
+ rgb_t pix = m_ppu1->screen().pixel(i, j);
- m_input_latch[1] = ioport("IN1")->read();
+ // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki:
+ // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray."
+ if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos) && pix.brightness() >= bright)
+ {
+ m_input_latch[0] |= 0x40;
+ i = x + xrad;
+ break;
+ }
+ }
}
m_input_strobe[0] = data;