atari/toobin.cpp, atari/triplhnt.cpp, atari/tunhunt.cpp. atari/videopin.cpp: consolidated drivers in single files

This commit is contained in:
Ivan Vangelista 2023-02-09 18:05:45 +01:00
parent 2f30101bbd
commit ab56f7de85
17 changed files with 1397 additions and 1465 deletions

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
Atari Toobin' hardware
@ -23,16 +24,330 @@
#include "emu.h"
#include "toobin.h"
#include "atarijsa.h"
#include "atarimo.h"
#include "cpu/m68000/m68010.h"
#include "machine/eeprompar.h"
#include "machine/watchdog.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
static constexpr XTAL MASTER_CLOCK = 32_MHz_XTAL;
#include "tilemap.h"
namespace {
class toobin_state : public driver_device
{
public:
toobin_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_jsa(*this, "jsa"),
m_playfield_tilemap(*this, "playfield"),
m_alpha_tilemap(*this, "alpha"),
m_mob(*this, "mob"),
m_palette(*this, "palette"),
m_paletteram(*this, "paletteram"),
m_interrupt_scan(*this, "interrupt_scan"),
m_xscroll(*this, "xscroll"),
m_yscroll(*this, "yscroll")
{ }
void toobin(machine_config &config);
protected:
virtual void machine_start() override;
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<atari_jsa_i_device> m_jsa;
required_device<tilemap_device> m_playfield_tilemap;
required_device<tilemap_device> m_alpha_tilemap;
required_device<atari_motion_objects_device> m_mob;
required_device<palette_device> m_palette;
required_shared_ptr<uint16_t> m_paletteram;
required_shared_ptr<uint16_t> m_interrupt_scan;
required_shared_ptr<uint16_t> m_xscroll;
required_shared_ptr<uint16_t> m_yscroll;
double m_brightness = 0;
bitmap_ind16 m_pfbitmap;
emu_timer *m_scanline_interrupt_timer = nullptr;
TIMER_CALLBACK_MEMBER(scanline_interrupt);
void scanline_int_ack_w(uint16_t data);
void interrupt_scan_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void paletteram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void intensity_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void slip_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
TILE_GET_INFO_MEMBER(get_alpha_tile_info);
TILE_GET_INFO_MEMBER(get_playfield_tile_info);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
static const atari_motion_objects_config s_mob_config;
};
// video
/*************************************
*
* Tilemap callbacks
*
*************************************/
TILE_GET_INFO_MEMBER(toobin_state::get_alpha_tile_info)
{
uint16_t const data = m_alpha_tilemap->basemem_read(tile_index);
int const code = data & 0x3ff;
int const color = (data >> 12) & 0x0f;
tileinfo.set(2, code, color, (data >> 10) & 1);
}
TILE_GET_INFO_MEMBER(toobin_state::get_playfield_tile_info)
{
uint32_t const data = m_playfield_tilemap->basemem_read(tile_index);
int const code = data & 0x3fff;
int const color = (data >> 16) & 0x0f;
tileinfo.set(0, code, color, TILE_FLIPYX(data >> 14));
tileinfo.category = (data >> 20) & 3;
}
/*************************************
*
* Video system start
*
*************************************/
const atari_motion_objects_config toobin_state::s_mob_config =
{
1, // index to which gfx system
1, // number of motion object banks
1, // are the entries linked?
0, // are the entries split?
0, // render in reverse order?
1, // render in swapped X/Y order?
0, // does the neighbor bit affect the next object?
1024, // pixels per SLIP entry (0 for no-slip)
0, // pixel offset for SLIPs
0, // maximum number of links to visit/scanline (0=all)
0x100, // base palette entry
0x100, // maximum number of colors
0, // transparent pen index
{{ 0,0,0x00ff,0 }}, // mask for the link
{{ 0,0x3fff,0,0 }}, // mask for the code index
{{ 0,0,0,0x000f }}, // mask for the color
{{ 0,0,0,0xffc0 }}, // mask for the X position
{{ 0x7fc0,0,0,0 }}, // mask for the Y position
{{ 0x0007,0,0,0 }}, // mask for the width, in tiles
{{ 0x0038,0,0,0 }}, // mask for the height, in tiles
{{ 0,0x4000,0,0 }}, // mask for the horizontal flip
{{ 0,0x8000,0,0 }}, // mask for the vertical flip
{{ 0 }}, // mask for the priority
{{ 0 }}, // mask for the neighbor
{{ 0x8000,0,0,0 }}, // mask for absolute coordinates
{{ 0 }}, // mask for the special value
0 // resulting value to indicate "special"
};
void toobin_state::video_start()
{
// allocate a playfield bitmap for rendering
m_screen->register_screen_bitmap(m_pfbitmap);
save_item(NAME(m_brightness));
}
/*************************************
*
* Palette RAM write handler
*
*************************************/
void toobin_state::paletteram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_paletteram[offset]);
uint16_t newword = m_paletteram[offset];
{
int red = (((newword >> 10) & 31) * 224) >> 5;
int green = (((newword >> 5) & 31) * 224) >> 5;
int blue = ((newword & 31) * 224) >> 5;
if (red) red += 38;
if (green) green += 38;
if (blue) blue += 38;
m_palette->set_pen_color(offset & 0x3ff, rgb_t(red, green, blue));
if (!(newword & 0x8000))
m_palette->set_pen_contrast(offset & 0x3ff, m_brightness);
else
m_palette->set_pen_contrast(offset & 0x3ff, 1.0);
}
}
void toobin_state::intensity_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if (ACCESSING_BITS_0_7)
{
m_brightness = (double)(~data & 0x1f) / 31.0;
for (int i = 0; i < 0x400; i++)
if (!BIT(m_paletteram[i], 15))
m_palette->set_pen_contrast(i, m_brightness);
}
}
/*************************************
*
* X/Y scroll handlers
*
*************************************/
void toobin_state::xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t const oldscroll = *m_xscroll;
uint16_t newscroll = oldscroll;
COMBINE_DATA(&newscroll);
// if anything has changed, force a partial update
if (newscroll != oldscroll)
m_screen->update_partial(m_screen->vpos());
// update the playfield scrolling - hscroll is clocked on the following scanline
m_playfield_tilemap->set_scrollx(0, newscroll >> 6);
m_mob->set_xscroll(newscroll >> 6);
// update the data
*m_xscroll = newscroll;
}
void toobin_state::yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t const oldscroll = *m_yscroll;
uint16_t newscroll = oldscroll;
COMBINE_DATA(&newscroll);
// if anything has changed, force a partial update
if (newscroll != oldscroll)
m_screen->update_partial(m_screen->vpos());
// if bit 4 is zero, the scroll value is clocked in right away
m_playfield_tilemap->set_scrolly(0, newscroll >> 6);
m_mob->set_yscroll((newscroll >> 6) & 0x1ff);
// update the data
*m_yscroll = newscroll;
}
/*************************************
*
* X/Y scroll handlers
*
*************************************/
void toobin_state::slip_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t const oldslip = m_mob->slipram(offset);
uint16_t newslip = oldslip;
COMBINE_DATA(&newslip);
// if the SLIP is changing, force a partial update first
if (oldslip != newslip)
m_screen->update_partial(m_screen->vpos());
// update the data
m_mob->slipram(offset) = newslip;
}
/*************************************
*
* Main refresh
*
*************************************/
uint32_t toobin_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
// start drawing
m_mob->draw_async(cliprect);
// draw the playfield
bitmap_ind8 &priority_bitmap = screen.priority();
priority_bitmap.fill(0, cliprect);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 0, 0);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 1, 1);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 2, 2);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 3, 3);
// draw and merge the MO
bitmap_ind16 &mobitmap = m_mob->bitmap();
pen_t const *const palette = m_palette->pens();
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
uint32_t *const dest = &bitmap.pix(y);
uint16_t const *const mo = &mobitmap.pix(y);
uint16_t const *const pf = &m_pfbitmap.pix(y);
uint8_t const *const pri = &priority_bitmap.pix(y);
for (int x = cliprect.left(); x <= cliprect.right(); x++)
{
uint16_t pix = pf[x];
if (mo[x] != 0xffff)
{
/* not verified: logic is all controlled in a PAL
factors: LBPRI1-0, LBPIX3, ANPIX1-0, PFPIX3, PFPRI1-0,
(~LBPIX3 & ~LBPIX2 & ~LBPIX1 & ~LBPIX0)
*/
// only draw if not high priority PF
if (!pri[x] || !(pix & 8))
pix = mo[x];
}
dest[x] = palette[pix];
}
}
// add the alpha on top
m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
// machine
/*************************************
*
@ -61,11 +376,11 @@ void toobin_state::machine_start()
void toobin_state::interrupt_scan_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
int oldword = m_interrupt_scan[offset];
int const oldword = m_interrupt_scan[offset];
int newword = oldword;
COMBINE_DATA(&newword);
/* if something changed, update the word in memory */
// if something changed, update the word in memory
if (oldword != newword)
{
m_interrupt_scan[offset] = newword;
@ -86,7 +401,7 @@ void toobin_state::scanline_int_ack_w(uint16_t data)
*
*************************************/
/* full address map decoded from schematics */
// full address map decoded from schematics
void toobin_state::main_map(address_map &map)
{
map.global_mask(0xc7ffff);
@ -94,18 +409,18 @@ void toobin_state::main_map(address_map &map)
map(0xc00000, 0xc07fff).ram().w(m_playfield_tilemap, FUNC(tilemap_device::write16)).share("playfield");
map(0xc08000, 0xc097ff).mirror(0x046000).ram().w(m_alpha_tilemap, FUNC(tilemap_device::write16)).share("alpha");
map(0xc09800, 0xc09fff).mirror(0x046000).ram().share("mob");
map(0xc10000, 0xc107ff).mirror(0x047800).ram().w(FUNC(toobin_state::paletteram_w)).share("paletteram");
map(0x826000, 0x826001).mirror(0x4500fe).nopr(); /* who knows? read at controls time */
map(0xc10000, 0xc107ff).mirror(0x047800).ram().w(FUNC(toobin_state::paletteram_w)).share(m_paletteram);
map(0x826000, 0x826001).mirror(0x4500fe).nopr(); // who knows? read at controls time
map(0x828000, 0x828001).mirror(0x4500fe).w("watchdog", FUNC(watchdog_timer_device::reset16_w));
map(0x828101, 0x828101).mirror(0x4500fe).w(m_jsa, FUNC(atari_jsa_i_device::main_command_w));
map(0x828300, 0x828301).mirror(0x45003e).w(FUNC(toobin_state::intensity_w));
map(0x828340, 0x828341).mirror(0x45003e).w(FUNC(toobin_state::interrupt_scan_w)).share("interrupt_scan");
map(0x828340, 0x828341).mirror(0x45003e).w(FUNC(toobin_state::interrupt_scan_w)).share(m_interrupt_scan);
map(0x828380, 0x828381).mirror(0x45003e).ram().w(FUNC(toobin_state::slip_w)).share("mob:slip");
map(0x8283c0, 0x8283c1).mirror(0x45003e).w(FUNC(toobin_state::scanline_int_ack_w));
map(0x828400, 0x828401).mirror(0x4500fe).w(m_jsa, FUNC(atari_jsa_i_device::sound_reset_w));
map(0x828500, 0x828501).mirror(0x4500fe).w("eeprom", FUNC(eeprom_parallel_28xx_device::unlock_write16));
map(0x828600, 0x828601).mirror(0x4500fe).w(FUNC(toobin_state::xscroll_w)).share("xscroll");
map(0x828700, 0x828701).mirror(0x4500fe).w(FUNC(toobin_state::yscroll_w)).share("yscroll");
map(0x828600, 0x828601).mirror(0x4500fe).w(FUNC(toobin_state::xscroll_w)).share(m_xscroll);
map(0x828700, 0x828701).mirror(0x4500fe).w(FUNC(toobin_state::yscroll_w)).share(m_yscroll);
map(0x828800, 0x828801).mirror(0x4507fe).portr("FF8800");
map(0x829000, 0x829001).mirror(0x4507fe).portr("FF9000");
map(0x829801, 0x829801).mirror(0x4507fe).r(m_jsa, FUNC(atari_jsa_i_device::main_response_r));
@ -205,8 +520,10 @@ GFXDECODE_END
void toobin_state::toobin(machine_config &config)
{
/* basic machine hardware */
m68010_device &maincpu(M68010(config, m_maincpu, MASTER_CLOCK/4));
static constexpr XTAL MASTER_CLOCK = 32_MHz_XTAL;
// basic machine hardware
m68010_device &maincpu(M68010(config, m_maincpu, MASTER_CLOCK / 4));
maincpu.set_addrmap(AS_PROGRAM, &toobin_state::main_map);
maincpu.disable_interrupt_mixer();
@ -214,22 +531,22 @@ void toobin_state::toobin(machine_config &config)
WATCHDOG_TIMER(config, "watchdog").set_vblank_count(m_screen, 8);
/* video hardware */
TILEMAP(config, m_playfield_tilemap, m_gfxdecode, 4, 8,8, TILEMAP_SCAN_ROWS, 128,64).set_info_callback(FUNC(toobin_state::get_playfield_tile_info));
TILEMAP(config, m_alpha_tilemap, m_gfxdecode, 2, 8,8, TILEMAP_SCAN_ROWS, 64,48, 0).set_info_callback(FUNC(toobin_state::get_alpha_tile_info));
// video hardware
TILEMAP(config, m_playfield_tilemap, m_gfxdecode, 4, 8, 8, TILEMAP_SCAN_ROWS, 128, 64).set_info_callback(FUNC(toobin_state::get_playfield_tile_info));
TILEMAP(config, m_alpha_tilemap, m_gfxdecode, 2, 8, 8, TILEMAP_SCAN_ROWS, 64, 48, 0).set_info_callback(FUNC(toobin_state::get_alpha_tile_info));
ATARI_MOTION_OBJECTS(config, m_mob, 0, m_screen, toobin_state::s_mob_config);
m_mob->set_gfxdecode(m_gfxdecode);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_video_attributes(VIDEO_UPDATE_BEFORE_VBLANK);
m_screen->set_raw(MASTER_CLOCK/2, 640, 0, 512, 416, 0, 384);
m_screen->set_raw(MASTER_CLOCK / 2, 640, 0, 512, 416, 0, 384);
m_screen->set_screen_update(FUNC(toobin_state::screen_update));
GFXDECODE(config, m_gfxdecode, m_palette, gfx_toobin);
PALETTE(config, m_palette).set_entries(1024);
/* sound hardware */
// sound hardware
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
@ -250,7 +567,7 @@ void toobin_state::toobin(machine_config &config)
*************************************/
ROM_START( toobin )
ROM_REGION( 0x80000, "maincpu", 0 ) /* 8*64k for 68000 code */
ROM_REGION( 0x80000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "3133-1j.061", 0x000000, 0x010000, CRC(79a92d02) SHA1(72eebb96a3963f94558bb204e0afe08f2b4c1864) )
ROM_LOAD16_BYTE( "3137-1f.061", 0x000001, 0x010000, CRC(e389ef60) SHA1(24861fe5eb49de852987993a905fefe4dd43b204) )
ROM_LOAD16_BYTE( "3134-2j.061", 0x020000, 0x010000, CRC(3dbe9a48) SHA1(37fe2534fed5708a63995e53ea0cb1d2d23fc1b9) )
@ -260,7 +577,7 @@ ROM_START( toobin )
ROM_LOAD16_BYTE( "1136-5j.061", 0x060000, 0x010000, CRC(5ae3eeac) SHA1(583b6c3f61e8ad4d98449205fedecf3e21ee993c) )
ROM_LOAD16_BYTE( "1140-5f.061", 0x060001, 0x010000, CRC(dacbbd94) SHA1(0e3a93f439ff9f3dd57ee13604be02e9c74c8eec) )
ROM_REGION( 0x10000, "jsa:cpu", 0 ) /* 64k for 6502 code */
ROM_REGION( 0x10000, "jsa:cpu", 0 ) // 6502 code
ROM_LOAD( "1141-2k.061", 0x00000, 0x10000, CRC(c0dcce1a) SHA1(285c13f08020cf5827eca2afcc2fa8a3a0a073e0) )
ROM_REGION( 0x080000, "gfx1", 0 )
@ -305,7 +622,7 @@ ROM_END
ROM_START( toobine )
ROM_REGION( 0x80000, "maincpu", 0 ) /* 8*64k for 68000 code */
ROM_REGION( 0x80000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "3733-1j.061", 0x000000, 0x010000, CRC(286c7fad) SHA1(1f06168327bdc356f1bc4cf9a951f914932c491a) )
ROM_LOAD16_BYTE( "3737-1f.061", 0x000001, 0x010000, CRC(965c161d) SHA1(30d959a945cb7dc7f00ad4ca9db027a377024030) )
ROM_LOAD16_BYTE( "3134-2j.061", 0x020000, 0x010000, CRC(3dbe9a48) SHA1(37fe2534fed5708a63995e53ea0cb1d2d23fc1b9) )
@ -315,7 +632,7 @@ ROM_START( toobine )
ROM_LOAD16_BYTE( "1136-5j.061", 0x060000, 0x010000, CRC(5ae3eeac) SHA1(583b6c3f61e8ad4d98449205fedecf3e21ee993c) )
ROM_LOAD16_BYTE( "1140-5f.061", 0x060001, 0x010000, CRC(dacbbd94) SHA1(0e3a93f439ff9f3dd57ee13604be02e9c74c8eec) )
ROM_REGION( 0x10000, "jsa:cpu", 0 ) /* 64k for 6502 code */
ROM_REGION( 0x10000, "jsa:cpu", 0 ) // 6502 code
ROM_LOAD( "1141-2k.061", 0x00000, 0x10000, CRC(c0dcce1a) SHA1(285c13f08020cf5827eca2afcc2fa8a3a0a073e0) )
ROM_REGION( 0x080000, "gfx1", 0 )
@ -360,7 +677,7 @@ ROM_END
ROM_START( toobing )
ROM_REGION( 0x80000, "maincpu", 0 ) /* 8*64k for 68000 code */
ROM_REGION( 0x80000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "3233-1j.061", 0x000000, 0x010000, CRC(b04eb760) SHA1(760525b4f72fad47cfc457e14db70ade30a9ddac) )
ROM_LOAD16_BYTE( "3237-1f.061", 0x000001, 0x010000, CRC(4e41a470) SHA1(3a4c9b0d93cf4cff80978c0568bb9ef9eeb878dd) )
ROM_LOAD16_BYTE( "3234-2j.061", 0x020000, 0x010000, CRC(8c60f1b4) SHA1(0ff3f4fede83410d73027b6e7445e83044e4b21e) )
@ -370,7 +687,7 @@ ROM_START( toobing )
ROM_LOAD16_BYTE( "1136-5j.061", 0x060000, 0x010000, CRC(5ae3eeac) SHA1(583b6c3f61e8ad4d98449205fedecf3e21ee993c) )
ROM_LOAD16_BYTE( "1140-5f.061", 0x060001, 0x010000, CRC(dacbbd94) SHA1(0e3a93f439ff9f3dd57ee13604be02e9c74c8eec) )
ROM_REGION( 0x10000, "jsa:cpu", 0 ) /* 64k for 6502 code */
ROM_REGION( 0x10000, "jsa:cpu", 0 ) // 6502 code
ROM_LOAD( "1141-2k.061", 0x00000, 0x10000, CRC(c0dcce1a) SHA1(285c13f08020cf5827eca2afcc2fa8a3a0a073e0) )
ROM_REGION( 0x080000, "gfx1", 0 )
@ -415,7 +732,7 @@ ROM_END
ROM_START( toobin2e )
ROM_REGION( 0x80000, "maincpu", 0 ) /* 8*64k for 68000 code */
ROM_REGION( 0x80000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "2733-1j.061", 0x000000, 0x010000, CRC(a6334cf7) SHA1(39e540619c24af65bda44160a5bdaebf3600b64b) )
ROM_LOAD16_BYTE( "2737-1f.061", 0x000001, 0x010000, CRC(9a52dd20) SHA1(a370ae3e4c7af55ea61b57a203a900f2be3ce6b9) )
ROM_LOAD16_BYTE( "2134-2j.061", 0x020000, 0x010000, CRC(2b8164c8) SHA1(aeeaff9df9fda23b295b59efadf52160f084d256) )
@ -425,7 +742,7 @@ ROM_START( toobin2e )
ROM_LOAD16_BYTE( "1136-5j.061", 0x060000, 0x010000, CRC(5ae3eeac) SHA1(583b6c3f61e8ad4d98449205fedecf3e21ee993c) )
ROM_LOAD16_BYTE( "1140-5f.061", 0x060001, 0x010000, CRC(dacbbd94) SHA1(0e3a93f439ff9f3dd57ee13604be02e9c74c8eec) )
ROM_REGION( 0x10000, "jsa:cpu", 0 ) /* 64k for 6502 code */
ROM_REGION( 0x10000, "jsa:cpu", 0 ) // 6502 code
ROM_LOAD( "1141-2k.061", 0x00000, 0x10000, CRC(c0dcce1a) SHA1(285c13f08020cf5827eca2afcc2fa8a3a0a073e0) )
ROM_REGION( 0x080000, "gfx1", 0 )
@ -470,7 +787,7 @@ ROM_END
ROM_START( toobin2 )
ROM_REGION( 0x80000, "maincpu", 0 ) /* 8*64k for 68000 code */
ROM_REGION( 0x80000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "2133-1j.061", 0x000000, 0x010000, CRC(2c3382e4) SHA1(39919e9b5b586b630e0581adabfe25d83b2bfaef) )
ROM_LOAD16_BYTE( "2137-1f.061", 0x000001, 0x010000, CRC(891c74b1) SHA1(2f39d0e4934ccf48bb5fc0737f34fc5a65cfd903) )
ROM_LOAD16_BYTE( "2134-2j.061", 0x020000, 0x010000, CRC(2b8164c8) SHA1(aeeaff9df9fda23b295b59efadf52160f084d256) )
@ -480,7 +797,7 @@ ROM_START( toobin2 )
ROM_LOAD16_BYTE( "1136-5j.061", 0x060000, 0x010000, CRC(5ae3eeac) SHA1(583b6c3f61e8ad4d98449205fedecf3e21ee993c) )
ROM_LOAD16_BYTE( "1140-5f.061", 0x060001, 0x010000, CRC(dacbbd94) SHA1(0e3a93f439ff9f3dd57ee13604be02e9c74c8eec) )
ROM_REGION( 0x10000, "jsa:cpu", 0 ) /* 64k for 6502 code */
ROM_REGION( 0x10000, "jsa:cpu", 0 ) // 6502 code
ROM_LOAD( "1141-2k.061", 0x00000, 0x10000, CRC(c0dcce1a) SHA1(285c13f08020cf5827eca2afcc2fa8a3a0a073e0) )
ROM_REGION( 0x080000, "gfx1", 0 )
@ -525,7 +842,7 @@ ROM_END
ROM_START( toobin1 )
ROM_REGION( 0x80000, "maincpu", 0 ) /* 8*64k for 68000 code */
ROM_REGION( 0x80000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "1133-1j.061", 0x000000, 0x010000, CRC(caeb5d1b) SHA1(8036871a04b5206fd383ac0fd9a9d3218128088b) )
ROM_LOAD16_BYTE( "1137-1f.061", 0x000001, 0x010000, CRC(9713d9d3) SHA1(55791150312de201bdd330bfd4cbb132cb3959e4) )
ROM_LOAD16_BYTE( "1134-2j.061", 0x020000, 0x010000, CRC(119f5d7b) SHA1(edd0b1ab29bb9c15c3b80037635c3b6d5fb434dc) )
@ -535,7 +852,7 @@ ROM_START( toobin1 )
ROM_LOAD16_BYTE( "1136-5j.061", 0x060000, 0x010000, CRC(5ae3eeac) SHA1(583b6c3f61e8ad4d98449205fedecf3e21ee993c) )
ROM_LOAD16_BYTE( "1140-5f.061", 0x060001, 0x010000, CRC(dacbbd94) SHA1(0e3a93f439ff9f3dd57ee13604be02e9c74c8eec) )
ROM_REGION( 0x10000, "jsa:cpu", 0 ) /* 64k for 6502 code */
ROM_REGION( 0x10000, "jsa:cpu", 0 ) // 6502 code
ROM_LOAD( "1141-2k.061", 0x00000, 0x10000, CRC(c0dcce1a) SHA1(285c13f08020cf5827eca2afcc2fa8a3a0a073e0) )
ROM_REGION( 0x080000, "gfx1", 0 )
@ -578,6 +895,8 @@ ROM_START( toobin1 )
ROM_LOAD( "1142-20h.061", 0x000000, 0x004000, CRC(a6ab551f) SHA1(6a11e16f3965416c81737efcb81e751484ba5ace) )
ROM_END
} // anonymous namespace
/*************************************
*
@ -585,9 +904,9 @@ ROM_END
*
*************************************/
GAME( 1988, toobin, 0, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (rev 3)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobin, 0, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (rev 3)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobine, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (Europe, rev 3)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobing, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (German, rev 3)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobin2, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (rev 2)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobin2, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (rev 2)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobin2e, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (Europe, rev 2)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobin1, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (rev 1)", MACHINE_SUPPORTS_SAVE )
GAME( 1988, toobin1, toobin, toobin, toobin, toobin_state, empty_init, ROT270, "Atari Games", "Toobin' (rev 1)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,83 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*************************************************************************
Atari Toobin' hardware
*************************************************************************/
#ifndef MAME_ATARI_TOOBIN_H
#define MAME_ATARI_TOOBIN_H
#pragma once
#include "atarijsa.h"
#include "atarimo.h"
#include "emupal.h"
#include "screen.h"
#include "tilemap.h"
class toobin_state : public driver_device
{
public:
toobin_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_jsa(*this, "jsa"),
m_playfield_tilemap(*this, "playfield"),
m_alpha_tilemap(*this, "alpha"),
m_mob(*this, "mob"),
m_palette(*this, "palette"),
m_paletteram(*this, "paletteram"),
m_interrupt_scan(*this, "interrupt_scan"),
m_xscroll(*this, "xscroll"),
m_yscroll(*this, "yscroll")
{ }
void toobin(machine_config &config);
private:
virtual void machine_start() override;
virtual void video_start() override;
TIMER_CALLBACK_MEMBER(scanline_interrupt);
void scanline_int_ack_w(uint16_t data);
void interrupt_scan_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void paletteram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void intensity_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void slip_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
TILE_GET_INFO_MEMBER(get_alpha_tile_info);
TILE_GET_INFO_MEMBER(get_playfield_tile_info);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<atari_jsa_i_device> m_jsa;
required_device<tilemap_device> m_playfield_tilemap;
required_device<tilemap_device> m_alpha_tilemap;
required_device<atari_motion_objects_device> m_mob;
required_device<palette_device> m_palette;
required_shared_ptr<uint16_t> m_paletteram;
required_shared_ptr<uint16_t> m_interrupt_scan;
required_shared_ptr<uint16_t> m_xscroll;
required_shared_ptr<uint16_t> m_yscroll;
double m_brightness = 0;
bitmap_ind16 m_pfbitmap;
emu_timer *m_scanline_interrupt_timer = nullptr;
static const atari_motion_objects_config s_mob_config;
};
#endif // MAME_ATARI_TOOBIN_H

View File

@ -1,250 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
Atari Toobin' hardware
****************************************************************************/
#include "emu.h"
#include "toobin.h"
/*************************************
*
* Tilemap callbacks
*
*************************************/
TILE_GET_INFO_MEMBER(toobin_state::get_alpha_tile_info)
{
uint16_t data = m_alpha_tilemap->basemem_read(tile_index);
int code = data & 0x3ff;
int color = (data >> 12) & 0x0f;
tileinfo.set(2, code, color, (data >> 10) & 1);
}
TILE_GET_INFO_MEMBER(toobin_state::get_playfield_tile_info)
{
uint32_t data = m_playfield_tilemap->basemem_read(tile_index);
int code = data & 0x3fff;
int color = (data >> 16) & 0x0f;
tileinfo.set(0, code, color, TILE_FLIPYX(data >> 14));
tileinfo.category = (data >> 20) & 3;
}
/*************************************
*
* Video system start
*
*************************************/
const atari_motion_objects_config toobin_state::s_mob_config =
{
1, /* index to which gfx system */
1, /* number of motion object banks */
1, /* are the entries linked? */
0, /* are the entries split? */
0, /* render in reverse order? */
1, /* render in swapped X/Y order? */
0, /* does the neighbor bit affect the next object? */
1024, /* pixels per SLIP entry (0 for no-slip) */
0, /* pixel offset for SLIPs */
0, /* maximum number of links to visit/scanline (0=all) */
0x100, /* base palette entry */
0x100, /* maximum number of colors */
0, /* transparent pen index */
{{ 0,0,0x00ff,0 }}, /* mask for the link */
{{ 0,0x3fff,0,0 }}, /* mask for the code index */
{{ 0,0,0,0x000f }}, /* mask for the color */
{{ 0,0,0,0xffc0 }}, /* mask for the X position */
{{ 0x7fc0,0,0,0 }}, /* mask for the Y position */
{{ 0x0007,0,0,0 }}, /* mask for the width, in tiles*/
{{ 0x0038,0,0,0 }}, /* mask for the height, in tiles */
{{ 0,0x4000,0,0 }}, /* mask for the horizontal flip */
{{ 0,0x8000,0,0 }}, /* mask for the vertical flip */
{{ 0 }}, /* mask for the priority */
{{ 0 }}, /* mask for the neighbor */
{{ 0x8000,0,0,0 }}, /* mask for absolute coordinates */
{{ 0 }}, /* mask for the special value */
0 /* resulting value to indicate "special" */
};
void toobin_state::video_start()
{
/* allocate a playfield bitmap for rendering */
m_screen->register_screen_bitmap(m_pfbitmap);
save_item(NAME(m_brightness));
}
/*************************************
*
* Palette RAM write handler
*
*************************************/
void toobin_state::paletteram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_paletteram[offset]);
uint16_t newword = m_paletteram[offset];
{
int red = (((newword >> 10) & 31) * 224) >> 5;
int green = (((newword >> 5) & 31) * 224) >> 5;
int blue = (((newword ) & 31) * 224) >> 5;
if (red) red += 38;
if (green) green += 38;
if (blue) blue += 38;
m_palette->set_pen_color(offset & 0x3ff, rgb_t(red, green, blue));
if (!(newword & 0x8000))
m_palette->set_pen_contrast(offset & 0x3ff, m_brightness);
else
m_palette->set_pen_contrast(offset & 0x3ff, 1.0);
}
}
void toobin_state::intensity_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if (ACCESSING_BITS_0_7)
{
m_brightness = (double)(~data & 0x1f) / 31.0;
for (int i = 0; i < 0x400; i++)
if (!BIT(m_paletteram[i], 15))
m_palette->set_pen_contrast(i, m_brightness);
}
}
/*************************************
*
* X/Y scroll handlers
*
*************************************/
void toobin_state::xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t oldscroll = *m_xscroll;
uint16_t newscroll = oldscroll;
COMBINE_DATA(&newscroll);
/* if anything has changed, force a partial update */
if (newscroll != oldscroll)
m_screen->update_partial(m_screen->vpos());
/* update the playfield scrolling - hscroll is clocked on the following scanline */
m_playfield_tilemap->set_scrollx(0, newscroll >> 6);
m_mob->set_xscroll(newscroll >> 6);
/* update the data */
*m_xscroll = newscroll;
}
void toobin_state::yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t oldscroll = *m_yscroll;
uint16_t newscroll = oldscroll;
COMBINE_DATA(&newscroll);
/* if anything has changed, force a partial update */
if (newscroll != oldscroll)
m_screen->update_partial(m_screen->vpos());
/* if bit 4 is zero, the scroll value is clocked in right away */
m_playfield_tilemap->set_scrolly(0, newscroll >> 6);
m_mob->set_yscroll((newscroll >> 6) & 0x1ff);
/* update the data */
*m_yscroll = newscroll;
}
/*************************************
*
* X/Y scroll handlers
*
*************************************/
void toobin_state::slip_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t oldslip = m_mob->slipram(offset);
uint16_t newslip = oldslip;
COMBINE_DATA(&newslip);
/* if the SLIP is changing, force a partial update first */
if (oldslip != newslip)
m_screen->update_partial(m_screen->vpos());
/* update the data */
m_mob->slipram(offset) = newslip;
}
/*************************************
*
* Main refresh
*
*************************************/
uint32_t toobin_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
// start drawing
m_mob->draw_async(cliprect);
/* draw the playfield */
bitmap_ind8 &priority_bitmap = screen.priority();
priority_bitmap.fill(0, cliprect);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 0, 0);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 1, 1);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 2, 2);
m_playfield_tilemap->draw(screen, m_pfbitmap, cliprect, 3, 3);
/* draw and merge the MO */
bitmap_ind16 &mobitmap = m_mob->bitmap();
pen_t const *const palette = m_palette->pens();
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
uint32_t *const dest = &bitmap.pix(y);
uint16_t const *const mo = &mobitmap.pix(y);
uint16_t const *const pf = &m_pfbitmap.pix(y);
uint8_t const *const pri = &priority_bitmap.pix(y);
for (int x = cliprect.left(); x <= cliprect.right(); x++)
{
uint16_t pix = pf[x];
if (mo[x] != 0xffff)
{
/* not verified: logic is all controlled in a PAL
factors: LBPRI1-0, LBPIX3, ANPIX1-0, PFPIX3, PFPRI1-0,
(~LBPIX3 & ~LBPIX2 & ~LBPIX1 & ~LBPIX0)
*/
/* only draw if not high priority PF */
if (!pri[x] || !(pix & 8))
pix = mo[x];
}
dest[x] = palette[pix];
}
}
/* add the alpha on top */
m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Stefan Jokisch
/***************************************************************************
Atari Triple Hunt Driver
@ -9,12 +10,213 @@ Atari Triple Hunt Driver
***************************************************************************/
#include "emu.h"
#include "triplhnt.h"
#include "triplhnt_a.h"
#include "cpu/m6800/m6800.h"
#include "machine/74259.h"
#include "machine/nvram.h"
#include "machine/watchdog.h"
#include "sound/discrete.h"
#include "sound/samples.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
namespace {
class triplhnt_state : public driver_device
{
public:
triplhnt_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_latch(*this, "latch"),
m_watchdog(*this, "watchdog"),
m_discrete(*this, "discrete"),
m_samples(*this, "samples"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_playfield_ram(*this, "playfield_ram"),
m_vpos_ram(*this, "vpos_ram"),
m_hpos_ram(*this, "hpos_ram"),
m_orga_ram(*this, "orga_ram"),
m_code_ram(*this, "code_ram"),
m_0c09(*this, "0C09"),
m_0c0b(*this, "0C0B"),
m_vblank(*this, "VBLANK"),
m_stick(*this, "STICK%c", 'X'),
m_lamp(*this, "lamp0")
{ }
void triplhnt(machine_config &config);
void init_triplhnt();
protected:
virtual void machine_start() override;
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_device<f9334_device> m_latch;
required_device<watchdog_timer_device> m_watchdog;
required_device<discrete_sound_device> m_discrete;
required_device<samples_device> m_samples;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_playfield_ram;
required_shared_ptr<uint8_t> m_vpos_ram;
required_shared_ptr<uint8_t> m_hpos_ram;
required_shared_ptr<uint8_t> m_orga_ram;
required_shared_ptr<uint8_t> m_code_ram;
required_ioport m_0c09;
required_ioport m_0c0b;
required_ioport m_vblank;
required_ioport_array<2> m_stick;
output_finder<> m_lamp;
uint8_t m_cmos[16]{};
uint8_t m_da_latch = 0;
uint8_t m_cmos_latch = 0;
uint8_t m_hit_code = 0;
uint8_t m_sprite_zoom = 0;
uint8_t m_sprite_bank = 0;
bitmap_ind16 m_helper;
emu_timer *m_hit_timer = nullptr;
tilemap_t* m_bg_tilemap = nullptr;
DECLARE_WRITE_LINE_MEMBER(coin_lockout_w);
DECLARE_WRITE_LINE_MEMBER(tape_control_w);
uint8_t cmos_r(offs_t offset);
uint8_t input_port_4_r();
uint8_t misc_r(offs_t offset);
uint8_t da_latch_r(offs_t offset);
TILE_GET_INFO_MEMBER(get_tile_info);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_CALLBACK_MEMBER(set_collision);
void program_map(address_map &map);
};
// video
TILE_GET_INFO_MEMBER(triplhnt_state::get_tile_info)
{
int const code = m_playfield_ram[tile_index] & 0x3f;
tileinfo.set(2, code, code == 0x3f ? 1 : 0, 0);
}
void triplhnt_state::video_start()
{
m_screen->register_screen_bitmap(m_helper);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(triplhnt_state::get_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
m_hit_timer = timer_alloc(FUNC(triplhnt_state::set_collision), this);
save_item(NAME(m_cmos));
save_item(NAME(m_da_latch));
save_item(NAME(m_cmos_latch));
save_item(NAME(m_hit_code));
save_item(NAME(m_sprite_zoom));
save_item(NAME(m_sprite_bank));
}
void triplhnt_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int hit_line = 999;
int hit_code = 999;
for (int i = 0; i < 16; i++)
{
rectangle rect;
int const j = (m_orga_ram[i] & 15) ^ 15;
// software sorts sprites by x and stores order in orga RAM
int hpos = m_hpos_ram[j] ^ 255;
int vpos = m_vpos_ram[j] ^ 255;
int code = m_code_ram[j] ^ 255;
if (hpos == 255)
continue;
// sprite placement might be wrong
if (m_sprite_zoom)
{
rect.set(hpos - 16, hpos - 16 + 63, 196 - vpos, 196 - vpos + 63);
}
else
{
rect.set(hpos - 16, hpos - 16 + 31, 224 - vpos, 224 - vpos + 31);
}
// render sprite to auxiliary bitmap
m_gfxdecode->gfx(m_sprite_zoom)->opaque(m_helper, cliprect,
2 * code + m_sprite_bank, 0, code & 8, 0,
rect.left(), rect.top());
rect &= cliprect;
// check for collisions and copy sprite
for (int x = rect.left(); x <= rect.right(); x++)
{
for (int y = rect.top(); y <= rect.bottom(); y++)
{
pen_t const a = m_helper.pix(y, x);
pen_t const b = bitmap.pix(y, x);
if (a == 2 && b == 7)
{
hit_code = j;
hit_line = y;
}
if (a != 1)
bitmap.pix(y, x) = a;
}
}
}
if (hit_line != 999 && hit_code != 999)
m_hit_timer->adjust(m_screen->time_until_pos(hit_line), hit_code);
}
uint32_t triplhnt_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->mark_all_dirty();
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
m_discrete->write(TRIPLHNT_BEAR_ROAR_DATA, m_playfield_ram[0xfa] & 15);
m_discrete->write(TRIPLHNT_SHOT_DATA, m_playfield_ram[0xfc] & 15);
return 0;
}
// machine
void triplhnt_state::init_triplhnt()
{
@ -39,16 +241,16 @@ WRITE_LINE_MEMBER(triplhnt_state::coin_lockout_w)
WRITE_LINE_MEMBER(triplhnt_state::tape_control_w)
{
bool is_witch_hunt = ioport("0C09")->read() == 0x40;
bool bit = !state;
bool const is_witch_hunt = m_0c09->read() == 0x40;
bool const bit = !state;
/* if we're not playing the sample yet, start it */
// if we're not playing the sample yet, start it
if (!m_samples->playing(0))
m_samples->start(0, 0, true);
if (!m_samples->playing(1))
m_samples->start(1, 1, true);
/* bit 6 turns cassette on/off */
// bit 6 turns cassette on/off
m_samples->pause(0, is_witch_hunt || bit);
m_samples->pause(1, !is_witch_hunt || bit);
}
@ -65,25 +267,25 @@ uint8_t triplhnt_state::cmos_r(offs_t offset)
uint8_t triplhnt_state::input_port_4_r()
{
m_watchdog->watchdog_reset();
return ioport("0C0B")->read();
return m_0c0b->read();
}
uint8_t triplhnt_state::misc_r(offs_t offset)
{
m_latch->write_a0(offset);
return ioport("VBLANK")->read() | m_hit_code;
return m_vblank->read() | m_hit_code;
}
uint8_t triplhnt_state::da_latch_r(offs_t offset)
{
int cross_x = ioport("STICKX")->read();
int cross_y = ioport("STICKY")->read();
int const cross_x = m_stick[0]->read();
int const cross_y = m_stick[1]->read();
m_da_latch = offset;
/* the following is a slight simplification */
// the following is a slight simplification
return (offset & 1) ? cross_x : cross_y;
}
@ -97,15 +299,15 @@ void triplhnt_state::machine_start()
}
void triplhnt_state::triplhnt_map(address_map &map)
void triplhnt_state::program_map(address_map &map)
{
map.global_mask(0x7fff);
map(0x0000, 0x00ff).ram().mirror(0x300);
map(0x0400, 0x04ff).writeonly().share("playfield_ram");
map(0x0800, 0x080f).writeonly().share("vpos_ram");
map(0x0810, 0x081f).writeonly().share("hpos_ram");
map(0x0820, 0x082f).writeonly().share("orga_ram");
map(0x0830, 0x083f).writeonly().share("code_ram");
map(0x0400, 0x04ff).writeonly().share(m_playfield_ram);
map(0x0800, 0x080f).writeonly().share(m_vpos_ram);
map(0x0810, 0x081f).writeonly().share(m_hpos_ram);
map(0x0820, 0x082f).writeonly().share(m_orga_ram);
map(0x0830, 0x083f).writeonly().share(m_code_ram);
map(0x0c00, 0x0c00).portr("0C00");
map(0x0c08, 0x0c08).portr("0C08");
map(0x0c09, 0x0c09).portr("0C09");
@ -116,44 +318,44 @@ void triplhnt_state::triplhnt_map(address_map &map)
map(0x0c30, 0x0c3f).r(FUNC(triplhnt_state::misc_r)).w(m_latch, FUNC(f9334_device::write_a0));
map(0x0c40, 0x0c40).portr("0C40");
map(0x0c48, 0x0c48).portr("0C48");
map(0x7000, 0x7fff).rom(); /* program */
map(0x7000, 0x7fff).rom();
}
static INPUT_PORTS_START( triplhnt )
PORT_START("0C00") /* 0C00 */
PORT_START("0C00")
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN1 )
PORT_START("0C08") /* 0C08 */
PORT_START("0C08")
PORT_DIPNAME( 0xc0, 0x00, "Play Time" )
PORT_DIPSETTING( 0x00, "32 seconds / 16 raccoons" )
PORT_DIPSETTING( 0x40, "64 seconds / 32 raccoons" )
PORT_DIPSETTING( 0x80, "96 seconds / 48 raccoons" )
PORT_DIPSETTING( 0xc0, "128 seconds / 64 raccoons" )
PORT_START("0C09") /* 0C09 */
PORT_START("0C09")
PORT_DIPNAME( 0xc0, 0x40, "Game Select" )
PORT_DIPSETTING( 0x00, "Hit the Bear" )
PORT_DIPSETTING( 0x40, "Witch Hunt" )
PORT_DIPSETTING( 0xc0, "Raccoon Hunt" )
PORT_START("0C0A") /* 0C0A */
PORT_START("0C0A")
PORT_DIPNAME( 0xc0, 0x00, DEF_STR( Coinage ))
PORT_DIPSETTING( 0x40, DEF_STR( 2C_1C ))
PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ))
PORT_DIPSETTING( 0x80, DEF_STR( 1C_2C ))
PORT_START("0C0B") /* 0C0B */
PORT_START("0C0B")
PORT_DIPNAME( 0x80, 0x00, "Extended Play" )
PORT_DIPSETTING( 0x80, DEF_STR( Off ))
PORT_DIPSETTING( 0x00, DEF_STR( On ))
PORT_START("0C40") /* 0C40 */
PORT_START("0C40")
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_TILT )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN2 )
PORT_START("0C48") /* 0C48 */
PORT_START("0C48")
// default to service enabled to make users calibrate gun
// PORT_SERVICE( 0x40, IP_ACTIVE_LOW )
PORT_DIPNAME( 0x40, 0x00, DEF_STR( Service_Mode )) PORT_TOGGLE PORT_CODE(KEYCODE_F2)
@ -170,31 +372,31 @@ static INPUT_PORTS_START( triplhnt )
PORT_START("STICKY")
PORT_BIT( 0xfc, 0x78, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xec) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15)
PORT_START("BEAR") /* 10 */
PORT_START("BEAR") // 10
PORT_ADJUSTER( 35, "Bear Roar Frequency" )
INPUT_PORTS_END
static const gfx_layout triplhnt_small_sprite_layout =
{
32, 32, /* width, height */
16, /* total */
2, /* planes */
/* plane offsets */
32, 32, // width, height
16, // total
2, // planes
// plane offsets
{ 0x0000, 0x4000 },
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
},
{
0x000, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0C0, 0x0E0,
0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0,
0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0
0x000, 0x020, 0x040, 0x060, 0x080, 0x0a0, 0x0c0, 0x0e0,
0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0,
0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0
},
0x400 /* increment */
0x400 // increment
};
@ -202,31 +404,31 @@ static const uint32_t triplhnt_large_sprite_layout_xoffset[64] =
{
0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03,
0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07,
0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B,
0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F,
0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b,
0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f,
0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13,
0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17, 0x17,
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F
0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b,
0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f
};
static const uint32_t triplhnt_large_sprite_layout_yoffset[64] =
{
0x000, 0x000, 0x020, 0x020, 0x040, 0x040, 0x060, 0x060,
0x080, 0x080, 0x0A0, 0x0A0, 0x0C0, 0x0C0, 0x0E0, 0x0E0,
0x080, 0x080, 0x0a0, 0x0a0, 0x0c0, 0x0c0, 0x0e0, 0x0e0,
0x100, 0x100, 0x120, 0x120, 0x140, 0x140, 0x160, 0x160,
0x180, 0x180, 0x1A0, 0x1A0, 0x1C0, 0x1C0, 0x1E0, 0x1E0,
0x180, 0x180, 0x1a0, 0x1a0, 0x1c0, 0x1c0, 0x1e0, 0x1e0,
0x200, 0x200, 0x220, 0x220, 0x240, 0x240, 0x260, 0x260,
0x280, 0x280, 0x2A0, 0x2A0, 0x2C0, 0x2C0, 0x2E0, 0x2E0,
0x280, 0x280, 0x2a0, 0x2a0, 0x2c0, 0x2c0, 0x2e0, 0x2e0,
0x300, 0x300, 0x320, 0x320, 0x340, 0x340, 0x360, 0x360,
0x380, 0x380, 0x3A0, 0x3A0, 0x3C0, 0x3C0, 0x3E0, 0x3E0
0x380, 0x380, 0x3a0, 0x3a0, 0x3c0, 0x3c0, 0x3e0, 0x3e0
};
static const gfx_layout triplhnt_large_sprite_layout =
{
64, 64, /* width, height */
16, /* total */
2, /* planes */
64, 64, // width, height
16, // total
2, // planes
{ 0x0000, 0x4000 },
EXTENDED_XOFFS,
EXTENDED_YOFFS,
@ -238,10 +440,10 @@ static const gfx_layout triplhnt_large_sprite_layout =
static const gfx_layout triplhnt_tile_layout =
{
16, 16, /* width, height */
64, /* total */
1, /* planes */
{ 0 }, /* plane offsets */
16, 16, // width, height
64, // total
1, // planes
{ 0 }, // plane offsets
{
0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7
},
@ -249,18 +451,18 @@ static const gfx_layout triplhnt_tile_layout =
0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x18, 0x18,
0x20, 0x20, 0x28, 0x28, 0x30, 0x30, 0x38, 0x38
},
0x40 /* increment */
0x40 // increment
};
static GFXDECODE_START( gfx_triplhnt )
GFXDECODE_ENTRY( "gfx1", 0, triplhnt_small_sprite_layout, 0, 1 )
GFXDECODE_ENTRY( "gfx1", 0, triplhnt_large_sprite_layout, 0, 1 )
GFXDECODE_ENTRY( "gfx2", 0, triplhnt_tile_layout, 4, 2 )
GFXDECODE_ENTRY( "sprites", 0, triplhnt_small_sprite_layout, 0, 1 )
GFXDECODE_ENTRY( "sprites", 0, triplhnt_large_sprite_layout, 0, 1 )
GFXDECODE_ENTRY( "tiles", 0, triplhnt_tile_layout, 4, 2 )
GFXDECODE_END
void triplhnt_state::triplhnt_palette(palette_device &palette) const
void triplhnt_state::palette(palette_device &palette) const
{
palette.set_pen_color(0, rgb_t(0xaf, 0xaf, 0xaf)); // sprites
palette.set_pen_color(1, rgb_t(0x00, 0x00, 0x00));
@ -275,9 +477,9 @@ void triplhnt_state::triplhnt_palette(palette_device &palette) const
void triplhnt_state::triplhnt(machine_config &config)
{
/* basic machine hardware */
M6800(config, m_maincpu, 800000);
m_maincpu->set_addrmap(AS_PROGRAM, &triplhnt_state::triplhnt_map);
// basic machine hardware
M6800(config, m_maincpu, 800'000);
m_maincpu->set_addrmap(AS_PROGRAM, &triplhnt_state::program_map);
m_maincpu->set_vblank_int("screen", FUNC(triplhnt_state::irq0_line_hold));
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // battery-backed 74C89 at J5
@ -296,7 +498,7 @@ void triplhnt_state::triplhnt(machine_config &config)
WATCHDOG_TIMER(config, m_watchdog);
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_size(256, 262);
@ -305,13 +507,13 @@ void triplhnt_state::triplhnt(machine_config &config)
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_triplhnt);
PALETTE(config, m_palette, FUNC(triplhnt_state::triplhnt_palette), 8);
PALETTE(config, m_palette, FUNC(triplhnt_state::palette), 8);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
SAMPLES(config, m_samples);
m_samples->set_channels(2); /* 2 channels */
m_samples->set_channels(2);
m_samples->set_samples_names(triplhnt_sample_names);
m_samples->add_route(ALL_OUTPUTS, "mono", 0.20);
@ -331,14 +533,16 @@ ROM_START( triplhnt )
ROM_LOAD_NIB_HIGH( "8401.c1", 0x7C00, 0x400, CRC(7461b05e) SHA1(16573ae655c306a38ff0f29a3c3285d636907f38) )
ROM_LOAD_NIB_LOW ( "8405.c2", 0x7C00, 0x400, CRC(ba370b97) SHA1(5d799ce6ae56c315ff0abedea7ad9204bacc266b) )
ROM_REGION( 0x1000, "gfx1", 0 ) /* sprites */
ROM_REGION( 0x1000, "sprites", 0 )
ROM_LOAD( "8423.n1", 0x0000, 0x800, CRC(9937d0da) SHA1(abb906c2d9869b09be5172cc7639bb9cda38831b) )
ROM_LOAD( "8422.r1", 0x0800, 0x800, CRC(803621dd) SHA1(ffbd7f87a86477e5eb94f12fc20a837128a02442) )
ROM_REGION( 0x200, "gfx2", 0 ) /* tiles */
ROM_REGION( 0x200, "tiles", 0 )
ROM_LOAD_NIB_HIGH( "8409.l3", 0x0000, 0x200, CRC(ec304172) SHA1(ccbf7e117fef7fa4288e3bf68f1a150b3a492ce6) )
ROM_LOAD_NIB_LOW ( "8410.m3", 0x0000, 0x200, CRC(f75a1b08) SHA1(81b4733194462cd4cef7f4221ecb7abd1556b871) )
ROM_END
} // anonymous namespace
GAME( 1977, triplhnt, 0, triplhnt, triplhnt, triplhnt_state, init_triplhnt, 0, "Atari", "Triple Hunt", MACHINE_REQUIRES_ARTWORK | MACHINE_SUPPORTS_SAVE )

View File

@ -1,108 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Stefan Jokisch
/*************************************************************************
Atari Triple Hunt hardware
*************************************************************************/
#ifndef MAME_ATARI_TRIPLHNT_H
#define MAME_ATARI_TRIPLHNT_H
#pragma once
#include "machine/74259.h"
#include "machine/watchdog.h"
#include "sound/discrete.h"
#include "sound/samples.h"
#include "emupal.h"
#include "screen.h"
#include "tilemap.h"
/* Discrete Sound Input Nodes */
#define TRIPLHNT_BEAR_ROAR_DATA NODE_01
#define TRIPLHNT_BEAR_EN NODE_02
#define TRIPLHNT_SHOT_DATA NODE_03
#define TRIPLHNT_SCREECH_EN NODE_04
#define TRIPLHNT_LAMP_EN NODE_05
class triplhnt_state : public driver_device
{
public:
triplhnt_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_latch(*this, "latch"),
m_watchdog(*this, "watchdog"),
m_discrete(*this, "discrete"),
m_samples(*this, "samples"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_playfield_ram(*this, "playfield_ram"),
m_vpos_ram(*this, "vpos_ram"),
m_hpos_ram(*this, "hpos_ram"),
m_orga_ram(*this, "orga_ram"),
m_code_ram(*this, "code_ram"),
m_lamp(*this, "lamp0")
{ }
void triplhnt(machine_config &config);
void init_triplhnt();
protected:
virtual void machine_start() override;
virtual void video_start() override;
private:
DECLARE_WRITE_LINE_MEMBER(coin_lockout_w);
DECLARE_WRITE_LINE_MEMBER(tape_control_w);
uint8_t cmos_r(offs_t offset);
uint8_t input_port_4_r();
uint8_t misc_r(offs_t offset);
uint8_t da_latch_r(offs_t offset);
TILE_GET_INFO_MEMBER(get_tile_info);
void triplhnt_palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_CALLBACK_MEMBER(set_collision);
void triplhnt_map(address_map &map);
required_device<cpu_device> m_maincpu;
required_device<f9334_device> m_latch;
required_device<watchdog_timer_device> m_watchdog;
required_device<discrete_sound_device> m_discrete;
required_device<samples_device> m_samples;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_playfield_ram;
required_shared_ptr<uint8_t> m_vpos_ram;
required_shared_ptr<uint8_t> m_hpos_ram;
required_shared_ptr<uint8_t> m_orga_ram;
required_shared_ptr<uint8_t> m_code_ram;
output_finder<> m_lamp;
uint8_t m_cmos[16]{};
uint8_t m_da_latch = 0;
uint8_t m_cmos_latch = 0;
uint8_t m_hit_code = 0;
int m_sprite_zoom = 0;
int m_sprite_bank = 0;
bitmap_ind16 m_helper;
emu_timer *m_hit_timer = nullptr;
tilemap_t* m_bg_tilemap = nullptr;
};
/*----------- defined in audio/triplhnt.cpp -----------*/
DISCRETE_SOUND_EXTERN( triplhnt_discrete );
extern const char *const triplhnt_sample_names[];
#endif // MAME_ATARI_TRIPLHNT_H

View File

@ -1,12 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:Derrick Renaud
/*************************************************************************
audio\triplhnt.cpp
atari\triplhnt_a.cpp
*************************************************************************/
#include "emu.h"
#include "triplhnt.h"
#include "triplhnt_a.h"
#include "sound/discrete.h"

View File

@ -0,0 +1,22 @@
// license:BSD-3-Clause
// copyright-holders:Derrick Renaud
/***************************************************************************
Triple Hunt Audio
***************************************************************************/
#include "sound/discrete.h"
// discrete sound input nodes
#define TRIPLHNT_BEAR_ROAR_DATA NODE_01
#define TRIPLHNT_BEAR_EN NODE_02
#define TRIPLHNT_SHOT_DATA NODE_03
#define TRIPLHNT_SCREECH_EN NODE_04
#define TRIPLHNT_LAMP_EN NODE_05
DISCRETE_SOUND_EXTERN( triplhnt_discrete );
extern const char *const triplhnt_sample_names[];

View File

@ -1,113 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Stefan Jokisch
/***************************************************************************
Atari Triple Hunt video emulation
***************************************************************************/
#include "emu.h"
#include "triplhnt.h"
TILE_GET_INFO_MEMBER(triplhnt_state::get_tile_info)
{
int code = m_playfield_ram[tile_index] & 0x3f;
tileinfo.set(2, code, code == 0x3f ? 1 : 0, 0);
}
void triplhnt_state::video_start()
{
m_screen->register_screen_bitmap(m_helper);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(triplhnt_state::get_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
m_hit_timer = timer_alloc(FUNC(triplhnt_state::set_collision), this);
save_item(NAME(m_cmos));
save_item(NAME(m_da_latch));
save_item(NAME(m_cmos_latch));
save_item(NAME(m_hit_code));
save_item(NAME(m_sprite_zoom));
save_item(NAME(m_sprite_bank));
}
void triplhnt_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int hit_line = 999;
int hit_code = 999;
for (int i = 0; i < 16; i++)
{
rectangle rect;
int j = (m_orga_ram[i] & 15) ^ 15;
/* software sorts sprites by x and stores order in orga RAM */
int hpos = m_hpos_ram[j] ^ 255;
int vpos = m_vpos_ram[j] ^ 255;
int code = m_code_ram[j] ^ 255;
if (hpos == 255)
continue;
/* sprite placement might be wrong */
if (m_sprite_zoom)
{
rect.set(hpos - 16, hpos - 16 + 63, 196 - vpos, 196 - vpos + 63);
}
else
{
rect.set(hpos - 16, hpos - 16 + 31, 224 - vpos, 224 - vpos + 31);
}
/* render sprite to auxiliary bitmap */
m_gfxdecode->gfx(m_sprite_zoom)->opaque(m_helper,cliprect,
2 * code + m_sprite_bank, 0, code & 8, 0,
rect.left(), rect.top());
rect &= cliprect;
/* check for collisions and copy sprite */
for (int x = rect.left(); x <= rect.right(); x++)
{
for (int y = rect.top(); y <= rect.bottom(); y++)
{
pen_t const a = m_helper.pix(y, x);
pen_t const b = bitmap.pix(y, x);
if (a == 2 && b == 7)
{
hit_code = j;
hit_line = y;
}
if (a != 1)
bitmap.pix(y, x) = a;
}
}
}
if (hit_line != 999 && hit_code != 999)
m_hit_timer->adjust(m_screen->time_until_pos(hit_line), hit_code);
}
uint32_t triplhnt_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->mark_all_dirty();
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
m_discrete->write(TRIPLHNT_BEAR_ROAR_DATA, m_playfield_ram[0xfa] & 15);
m_discrete->write(TRIPLHNT_SHOT_DATA, m_playfield_ram[0xfc] & 15);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Phil Stroffolino, David Haywood
/***************************************************************************
Atari Tunnel Hunt hardware
@ -26,8 +27,8 @@
Colors:
- Hues are hardcoded. There doesn't appear to be any logical way to
map the color proms so that the correct colors appear.
See last page of schematics for details. Are color proms bad?
map the color PROMs so that the correct colors appear.
See last page of schematics for details. Are color PROMs bad?
(shouldn't be, both sets were the same)
Shell Objects:
@ -46,13 +47,462 @@
***************************************************************************/
#include "emu.h"
#include "tunhunt.h"
#include "cpu/m6502/m6502.h"
#include "machine/rescap.h"
#include "sound/pokey.h"
#include "speaker.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
namespace {
class tunhunt_state : public driver_device
{
public:
tunhunt_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_workram(*this, "workram"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_paletteram(*this, "paletteram"),
m_in0(*this, "IN0"),
m_dsw(*this, "DSW"),
m_led(*this, "led0")
{ }
void tunhunt(machine_config &config);
protected:
virtual void machine_start() override { m_led.resolve(); }
virtual void machine_reset() override;
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_workram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_paletteram;
required_ioport m_in0;
required_ioport m_dsw;
output_finder<> m_led;
uint8_t m_control = 0;
tilemap_t *m_fg_tilemap = nullptr;
bitmap_ind16 m_tmpbitmap;
uint8_t m_mobsc0 = 0;
uint8_t m_mobsc1 = 0;
uint8_t m_lineh[13]{};
uint8_t m_shl0st = 0;
uint8_t m_shl1st = 0;
uint8_t m_vstrlo = 0;
uint8_t m_linesh = 0;
uint8_t m_shl0pc = 0;
uint8_t m_shl1pc = 0;
uint8_t m_linec[13]{};
uint8_t m_shl0v = 0;
uint8_t m_shl1v = 0;
uint8_t m_mobjh = 0;
uint8_t m_linev[13]{};
uint8_t m_shl0vs = 0;
uint8_t m_shl1vs = 0;
uint8_t m_mobvs = 0;
uint8_t m_linevs[13]{};
uint8_t m_shel0h = 0;
uint8_t m_mobst = 0;
uint8_t m_shel1h = 0;
uint8_t m_mobjv = 0;
void control_w(uint8_t data);
uint8_t button_r(offs_t offset);
void videoram_w(offs_t offset, uint8_t data);
template <uint16_t Mask> uint8_t dsw2_r();
TILE_GET_INFO_MEMBER(get_fg_tile_info);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void set_pens();
void draw_motion_object(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_box(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_shell(bitmap_ind16 &bitmap, const rectangle &cliprect, int picture_code, int hposition, int vstart, int vstop, int vstretch, int hstretch);
void main_map(address_map &map);
};
// video
/****************************************************************************************/
void tunhunt_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset);
}
TILE_GET_INFO_MEMBER(tunhunt_state::get_fg_tile_info)
{
int const attr = m_videoram[tile_index];
int const code = attr & 0x3f;
int const color = attr >> 6;
int const flags = color ? TILE_FORCE_LAYER0 : 0;
tileinfo.set(0, code, color, flags);
}
void tunhunt_state::video_start()
{
/*
Motion Object RAM contains 64 lines of run-length encoded data.
We keep track of dirty lines and cache the expanded bitmap.
With max RLE expansion, bitmap size is 256x64.
*/
m_tmpbitmap.allocate(256, 64, m_screen->format());
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tunhunt_state::get_fg_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 8, 32);
m_fg_tilemap->set_transparent_pen(0);
m_fg_tilemap->set_scrollx(0, 64);
save_item(NAME(m_control));
save_item(NAME(m_mobsc0));
save_item(NAME(m_mobsc1));
save_item(NAME(m_lineh));
save_item(NAME(m_shl0st));
save_item(NAME(m_shl1st));
save_item(NAME(m_vstrlo));
save_item(NAME(m_linesh));
save_item(NAME(m_shl0pc));
save_item(NAME(m_shl1pc));
save_item(NAME(m_linec));
save_item(NAME(m_shl0v));
save_item(NAME(m_shl1v));
save_item(NAME(m_mobjh));
save_item(NAME(m_linev));
save_item(NAME(m_shl0vs));
save_item(NAME(m_shl1vs));
save_item(NAME(m_mobvs));
save_item(NAME(m_linevs));
save_item(NAME(m_shel0h));
save_item(NAME(m_mobst));
save_item(NAME(m_shel1h));
save_item(NAME(m_mobjv));
}
void tunhunt_state::palette(palette_device &palette) const
{
/* Tunnel Hunt uses a combination of color PROMs and palette RAM to specify a 16 color
* palette. Here, we manage only the mappings for alphanumeric characters and SHELL
* graphics, which are unpacked ahead of time and drawn using MAME's drawgfx primitives.
*/
// motion objects/box
for (int i = 0; i < 0x10; i++)
palette.set_pen_indirect(i, i);
/* AlphaNumerics (1bpp)
* 2 bits of hilite select from 4 different background colors
* Foreground color is always pen#4
* Background color is mapped as follows:
*/
// alpha hilite#0
palette.set_pen_indirect(0x10, 0x0); // background color#0 (transparent)
palette.set_pen_indirect(0x11, 0x4); // foreground color
// alpha hilite#1
palette.set_pen_indirect(0x12, 0x5); // background color#1
palette.set_pen_indirect(0x13, 0x4); // foreground color
// alpha hilite#2
palette.set_pen_indirect(0x14, 0x6); // background color#2
palette.set_pen_indirect(0x15, 0x4); // foreground color
// alpha hilite#3
palette.set_pen_indirect(0x16, 0xf); // background color#3
palette.set_pen_indirect(0x17, 0x4); // foreground color
/* shell graphics; these are either 1bpp (2 banks) or 2bpp. It isn't clear which.
* In any event, the following pens are associated with the shell graphics:
*/
palette.set_pen_indirect(0x18, 0);
palette.set_pen_indirect(0x19, 4);//1;
}
/*
Color Array RAM Assignments:
Location
0 Blanking, border
1 Mot Obj (10) (D), Shell (01)
2 Mot Obj (01) (G), Shell (10)
3 Mot Obj (00) (W)
4 Alpha & Shell (11) - shields
5 Hilight 1
6 Hilight 2
8-E Lines (as normal) background
F Hilight 3
*/
void tunhunt_state::set_pens()
{
/*
The actual contents of the color PROMs (unused by this driver)
are as follows:
D11 "blue/green"
0000: 00 00 8b 0b fb 0f ff 0b
00 00 0f 0f fb f0 f0 ff
C11 "red"
0020: 00 f0 f0 f0 b0 b0 00 f0
00 f0 f0 00 b0 00 f0 f0
*/
//const uint8_t *color_prom = memregion("proms")->base();
for (int i = 0; i < 16; i++)
{
int color = m_paletteram[i];
int const shade = 0xf^(color>>4);
int red, green, blue;
color &= 0xf; // hue select
switch (color)
{
default:
case 0x0: red = 0xff; green = 0xff; blue = 0xff; break; // white
case 0x1: red = 0xff; green = 0x00; blue = 0xff; break; // purple
case 0x2: red = 0x00; green = 0x00; blue = 0xff; break; // blue
case 0x3: red = 0x00; green = 0xff; blue = 0xff; break; // cyan
case 0x4: red = 0x00; green = 0xff; blue = 0x00; break; // green
case 0x5: red = 0xff; green = 0xff; blue = 0x00; break; // yellow
case 0x6: red = 0xff; green = 0x00; blue = 0x00; break; // red
case 0x7: red = 0x00; green = 0x00; blue = 0x00; break; // black?
case 0x8: red = 0xff; green = 0x7f; blue = 0x00; break; // orange
case 0x9: red = 0x7f; green = 0xff; blue = 0x00; break; // ?
case 0xa: red = 0x00; green = 0xff; blue = 0x7f; break; // ?
case 0xb: red = 0x00; green = 0x7f; blue = 0xff; break; // ?
case 0xc: red = 0xff; green = 0x00; blue = 0x7f; break; // ?
case 0xd: red = 0x7f; green = 0x00; blue = 0xff; break; // ?
case 0xe: red = 0xff; green = 0xaa; blue = 0xaa; break; // ?
case 0xf: red = 0xaa; green = 0xaa; blue = 0xff; break; // ?
}
// combine color components with shade value (0..0xf)
#define APPLY_SHADE( C,S ) ((C*S)/0xf)
red = APPLY_SHADE(red, shade);
green = APPLY_SHADE(green, shade);
blue = APPLY_SHADE(blue, shade);
m_palette->set_indirect_color(i, rgb_t(red, green, blue));
}
}
void tunhunt_state::draw_motion_object(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/*
* VSTRLO 0x1202
* normally 0x02 (gameplay, attract1)
* in attract2 (with "Tunnel Hunt" graphic), decrements from 0x2f down to 0x01
* goes to 0x01 for some enemy shots
*
* MOBSC0 0x1080
* MOBSC1 0x1081
* always 0x00?
*/
bitmap_ind16 &tmpbitmap = m_tmpbitmap;
//int skip = m_mobst;
const int x0 = 255 - m_mobjv;
const int y0 = 255 - m_mobjh;
for (int line = 0; line < 64; line++)
{
int x = 0;
const uint8_t *const source = &m_spriteram[line * 0x10];
for (int span = 0; span < 0x10; span++)
{
const int span_data = source[span];
if (span_data == 0xff) break;
const int color = ((span_data >> 6) & 0x3) ^ 0x3;
int count = (span_data & 0x1f) + 1;
while (count-- && x < 256)
tmpbitmap.pix(line, x++) = color;
}
while (x < 256)
tmpbitmap.pix(line, x++) = 0;
}
int scaley;
switch (m_vstrlo)
{
case 0x01:
scaley = (1 << 16) * 0.33; // seems correct
break;
case 0x02:
scaley = (1 << 16) * 0.50; // seems correct
break;
default:
scaley = (1 << 16) * m_vstrlo / 4; // ???
break;
}
const int scalex = 1 << 16;
copyrozbitmap_trans(
bitmap, cliprect, tmpbitmap,
-x0 * scalex, // startx
-y0 * scaley, // starty
scalex, // incxx
0, 0, // incxy, incyx
scaley, // incyy
false, // no wraparound
0);
}
void tunhunt_state::draw_box(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/*
This is unnecessarily slow, but the box priorities aren't completely understood,
yet. Once understood, this function should be converted to use bitmap_fill with
rectangular chunks instead of BITMAP_ADDR.
Tunnels:
1080: 00 00 00 01 e7 18 ae 51 94 6b 88 77 83 7c 80 7f x0
1480: 00 f0 17 00 22 22 5b 5b 75 75 81 81 86 86 89 89 y0
1400: 00 00 97 ff f1 f1 b8 b8 9e 9e 92 92 8d 8d 8a 8a y1
1280: 07 03 00 07 07 0c 0c 0d 0d 0e 0e 08 08 09 09 0a palette select
Color Bars:
1080: 00 00 00 01 00 20 40 60 80 a0 c0 e0 01 2a 50 7a x0
1480: 00 f0 00 00 40 40 40 40 40 40 40 40 00 00 00 00 y0
1400: 00 00 00 ff ff ff ff ff ff ff ff ff 40 40 40 40 y1
1280: 07 03 00 01 07 06 04 05 02 07 03 00 09 0a 0b 0c palette select
->hue 06 02 ff 60 06 05 03 04 01 06 02 ff d2 00 c2 ff
*/
for (int y = 0; y < 256; y++)
{
if (0xff - y >= cliprect.top() && 0xff - y <= cliprect.bottom())
for (int x = 0; x < 256; x++)
{
int color = 0;
int z = 0;
for (int span = 0; span < 13; span++)
{
int const x0 = m_lineh[span];
int const y0 = m_linevs[span];
int const y1 = m_linev[span];
if (y >= y0 && y <= y1 && x >= x0 && x0 >= z)
{
color = m_linec[span] & 0xf;
z = x0; // give priority to rightmost spans
}
}
if (x >= cliprect.left() && x <= cliprect.right())
bitmap.pix(0xff - y, x) = color;
}
}
}
// "shell" graphics are 16x16 pixel tiles used for player shots and targeting cursor
void tunhunt_state::draw_shell(bitmap_ind16 &bitmap,
const rectangle &cliprect,
int picture_code,
int hposition,
int vstart,
int vstop,
int vstretch,
int hstretch )
{
if (hstretch)
{
for (int sx = 0; sx < 256; sx += 16)
{
for (int sy = 0; sy < 256; sy += 16)
{
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect,
picture_code,
0, // color
0, 0, // flip
sx, sy, 0);
}
}
}
else
/*
vstretch is normally 0x01
targeting cursor:
hposition = 0x78
vstart = 0x90
vstop = 0x80
during grid test:
vstretch = 0xff
hposition = 0xff
vstart = 0xff
vstop = 0x00
*/
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect,
picture_code,
0, // color
0, 0, // flip
255 - hposition - 16, vstart - 32, 0);
}
uint32_t tunhunt_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
set_pens();
draw_box(bitmap, cliprect);
draw_motion_object(bitmap, cliprect);
draw_shell(bitmap, cliprect,
m_shl0pc, // picture code
m_shel0h, // hposition
m_shl0v, // vstart
m_shl0vs, // vstop
m_shl0st, // vstretch
m_control & 0x08); // hstretch
draw_shell(bitmap, cliprect,
m_shl1pc, // picture code
m_shel1h, // hposition
m_shl1v, // vstart
m_shl1vs, // vstop
m_shl1st, // vstretch
m_control & 0x10); // hstretch
rectangle cr = cliprect;
if (cr.min_x < 192)
cr.min_x = 192;
m_fg_tilemap->draw(screen, bitmap, cr, 0, 0);
return 0;
}
// machine
/*************************************
*
@ -75,7 +525,7 @@ void tunhunt_state::control_w(uint8_t data)
m_control = data;
machine().bookkeeping().coin_counter_w(0, BIT(data, 0));
machine().bookkeeping().coin_counter_w(1, BIT(data, 1));
m_led = BIT(data , 6); /* start */
m_led = BIT(data , 6); // start
}
@ -88,40 +538,18 @@ void tunhunt_state::control_w(uint8_t data)
uint8_t tunhunt_state::button_r(offs_t offset)
{
int data = ioport("IN0")->read();
return ((data>>offset)&1)?0x00:0x80;
int const data = m_in0->read();
return ((data >> offset) & 1) ? 0x00 : 0x80;
}
uint8_t tunhunt_state::dsw2_0r()
template <uint16_t Mask>
uint8_t tunhunt_state::dsw2_r()
{
return (ioport("DSW")->read()&0x0100)?0x80:0x00;
return (m_dsw->read()& Mask) ? 0x80 : 0x00;
}
uint8_t tunhunt_state::dsw2_1r()
{
return (ioport("DSW")->read()&0x0200)?0x80:0x00;
}
uint8_t tunhunt_state::dsw2_2r()
{
return (ioport("DSW")->read()&0x0400)?0x80:0x00;
}
uint8_t tunhunt_state::dsw2_3r()
{
return (ioport("DSW")->read()&0x0800)?0x80:0x00;
}
uint8_t tunhunt_state::dsw2_4r()
{
return (ioport("DSW")->read()&0x1000)?0x80:0x00;
}
void tunhunt_state::machine_reset()
{
m_mobsc0 = 0;
@ -159,7 +587,7 @@ void tunhunt_state::machine_reset()
void tunhunt_state::main_map(address_map &map)
{
map.global_mask(0x7fff);
map(0x0000, 0x03ff).ram().share("workram"); /* Work RAM */
map(0x0000, 0x03ff).ram().share(m_workram);
map(0x1080, 0x1080).lw8(NAME([this](uint8_t data) { m_mobsc0 = data; })); // SCAN ROM START FOR MOBJ (unused?)
map(0x1081, 0x1081).lw8(NAME([this](uint8_t data) { m_mobsc1 = data; })); // (unused?)
@ -179,18 +607,18 @@ void tunhunt_state::main_map(address_map &map)
map(0x1481, 0x1481).lw8(NAME([this](uint8_t data) { m_shl1vs = data; }));
map(0x1482, 0x1482).lw8(NAME([this](uint8_t data) { m_mobvs = data; })); // V STOP OF MOTION OBJECT (NORMAL SCREEN)
map(0x1483, 0x148f).lw8(NAME([this](offs_t offset, uint8_t data) { m_linevs[offset] = data; })); // LINES VERT STOP
map(0x1600, 0x160f).writeonly().share("paletteram"); // COLRAM (D7-D4 SHADE; D3-D0 COLOR)
map(0x1600, 0x160f).writeonly().share(m_paletteram); // COLRAM (D7-D4 SHADE; D3-D0 COLOR)
map(0x1800, 0x1800).lw8(NAME([this](uint8_t data) { m_shel0h = data; })); // SHELL H POSITON (NORMAL SCREEN)
map(0x1802, 0x1802).lw8(NAME([this](uint8_t data) { m_mobst = data; })); // STARTING LINE FOR RAM SCAN ON MOBJ
map(0x1a00, 0x1a00).lw8(NAME([this](uint8_t data) { m_shel1h = data; }));
map(0x1c00, 0x1c00).lw8(NAME([this](uint8_t data) { m_mobjv = data; })); // V POSITION (SCREEN ON SIDE)
map(0x1e00, 0x1eff).w(FUNC(tunhunt_state::videoram_w)).share("videoram"); /* ALPHA */
map(0x1e00, 0x1eff).w(FUNC(tunhunt_state::videoram_w)).share(m_videoram); // ALPHA
map(0x2000, 0x2000).nopw(); /* watchdog */
map(0x2000, 0x2000).nopw(); // watchdog
map(0x2000, 0x2007).r(FUNC(tunhunt_state::button_r));
map(0x2400, 0x2400).nopw(); /* INT ACK */
map(0x2400, 0x2400).nopw(); // INT ACK
map(0x2800, 0x2800).w(FUNC(tunhunt_state::control_w));
map(0x2c00, 0x2fff).writeonly().share("spriteram");
map(0x2c00, 0x2fff).writeonly().share(m_spriteram);
map(0x3000, 0x300f).rw("pokey1", FUNC(pokey_device::read), FUNC(pokey_device::write));
map(0x4000, 0x400f).rw("pokey2", FUNC(pokey_device::read), FUNC(pokey_device::write));
@ -283,29 +711,29 @@ static const gfx_layout alpha_layout =
static const gfx_layout obj_layout =
{
16,16,
8, /* number of objects */
1, /* number of bitplanes */
{ 4 }, /* plane offsets */
8, // number of objects
1, // number of bitplanes
{ 4 }, // plane offsets
{
0x00+0,0x00+1,0x00+2,0x00+3,
0x08+0,0x08+1,0x08+2,0x08+3,
0x10+0,0x10+1,0x10+2,0x10+3,
0x18+0,0x18+1,0x18+2,0x18+3
}, /* x offsets */
}, // x offsets
{
0x0*0x20, 0x1*0x20, 0x2*0x20, 0x3*0x20,
0x4*0x20, 0x5*0x20, 0x6*0x20, 0x7*0x20,
0x8*0x20, 0x9*0x20, 0xa*0x20, 0xb*0x20,
0xc*0x20, 0xd*0x20, 0xe*0x20, 0xf*0x20
}, /* y offsets */
}, // y offsets
0x200
};
static GFXDECODE_START( gfx_tunhunt )
GFXDECODE_ENTRY( "gfx1", 0x000, alpha_layout, 0x10, 4 )
GFXDECODE_ENTRY( "gfx2", 0x200, obj_layout, 0x18, 1 )
GFXDECODE_ENTRY( "gfx2", 0x000, obj_layout, 0x18, 1 ) /* second bank, or second bitplane? */
GFXDECODE_ENTRY( "chars", 0x000, alpha_layout, 0x10, 4 )
GFXDECODE_ENTRY( "sprites", 0x200, obj_layout, 0x18, 1 )
GFXDECODE_ENTRY( "sprites", 0x000, obj_layout, 0x18, 1 ) // second bank, or second bitplane?
GFXDECODE_END
@ -317,39 +745,39 @@ GFXDECODE_END
void tunhunt_state::tunhunt(machine_config &config)
{
/* basic machine hardware */
M6502(config, m_maincpu, 12.096_MHz_XTAL/6); /* ??? */
// basic machine hardware
M6502(config, m_maincpu, 12.096_MHz_XTAL / 6); // ???
m_maincpu->set_addrmap(AS_PROGRAM, &tunhunt_state::main_map);
m_maincpu->set_periodic_int(FUNC(tunhunt_state::irq0_line_hold), attotime::from_hz(4*60)); /* 48V, 112V, 176V, 240V */
m_maincpu->set_periodic_int(FUNC(tunhunt_state::irq0_line_hold), attotime::from_hz(4*60)); // 48V, 112V, 176V, 240V
/* video hardware */
// video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(60);
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
m_screen->set_size(256, 256-16);
m_screen->set_visarea(0, 255, 0, 255-16);
m_screen->set_screen_update(FUNC(tunhunt_state::screen_update));
m_screen->set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_tunhunt);
PALETTE(config, m_palette, FUNC(tunhunt_state::tunhunt_palette), 0x1a, 16);
PALETTE(config, m_palette, FUNC(tunhunt_state::palette), 0x1a, 16);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
pokey_device &pokey1(POKEY(config, "pokey1", 12.096_MHz_XTAL/10));
pokey_device &pokey1(POKEY(config, "pokey1", 12.096_MHz_XTAL / 10));
pokey1.allpot_r().set_ioport("DSW");
pokey1.set_output_rc(RES_K(1), CAP_U(0.047), 5.0);
pokey1.add_route(ALL_OUTPUTS, "mono", 0.50);
pokey_device &pokey2(POKEY(config, "pokey2", 12.096_MHz_XTAL/10));
pokey_device &pokey2(POKEY(config, "pokey2", 12.096_MHz_XTAL / 10));
pokey2.pot_r<0>().set_ioport("IN1");
pokey2.pot_r<1>().set_ioport("IN2");
pokey2.pot_r<2>().set(FUNC(tunhunt_state::dsw2_0r));
pokey2.pot_r<3>().set(FUNC(tunhunt_state::dsw2_1r));
pokey2.pot_r<4>().set(FUNC(tunhunt_state::dsw2_2r));
pokey2.pot_r<5>().set(FUNC(tunhunt_state::dsw2_3r));
pokey2.pot_r<6>().set(FUNC(tunhunt_state::dsw2_4r));
pokey2.pot_r<2>().set(FUNC(tunhunt_state::dsw2_r<0x100>));
pokey2.pot_r<3>().set(FUNC(tunhunt_state::dsw2_r<0x200>));
pokey2.pot_r<4>().set(FUNC(tunhunt_state::dsw2_r<0x400>));
pokey2.pot_r<5>().set(FUNC(tunhunt_state::dsw2_r<0x800>));
pokey2.pot_r<6>().set(FUNC(tunhunt_state::dsw2_r<0x1000>));
pokey2.set_output_rc(RES_K(1), CAP_U(0.047), 5.0);
pokey2.add_route(ALL_OUTPUTS, "mono", 0.50);
}
@ -392,44 +820,45 @@ ROM_START( tunhunt )
ROM_LOAD( "005.ef1", 0x7000, 0x800, CRC(e17badf0) SHA1(6afbf517486340fe54b01fa26258877b2a8fc510) )
ROM_LOAD( "006.d1", 0x7800, 0x800, CRC(c3ae8519) SHA1(2b2e49065bc38429894ef29a29ffc60f96e64840) )
ROM_REGION( 0x400, "gfx1", 0 ) /* alphanumeric characters */
ROM_REGION( 0x400, "chars", 0 )
ROM_LOAD( "019.c10", 0x000, 0x400, CRC(d6fd45a9) SHA1(c86ea3790c29c554199af8ad6f3d563dcb7723c7) )
ROM_REGION( 0x400, "gfx2", 0 ) /* "SHELL" objects (16x16 pixel sprites) */
ROM_REGION( 0x400, "sprites", 0 ) // "SHELL" objects (16x16 pixel sprites)
ROM_LOAD( "016.a8", 0x000, 0x200, CRC(830e6c34) SHA1(37a5eeb722dd80c4224c7f622b0edabb3ac1ca19) )
ROM_LOAD( "017.b8", 0x200, 0x200, CRC(5bef8b5a) SHA1(bfd9c592a34ed4861a6ad76ef10ea0d9b76a92b2) )
ROM_REGION( 0x540, "proms", 0 )
ROM_LOAD( "013.d11", 0x000, 0x020, CRC(66f1f5eb) SHA1(bcf5348ae328cf943d2bf6e38df727c0c4c466b7) ) /* hue: BBBBGGGG? */
ROM_LOAD( "014.c11", 0x020, 0x020, CRC(662444b2) SHA1(2e510c1d9b7e34a3045048a46045e61fabaf918e) ) /* hue: RRRR----? */
ROM_LOAD( "015.n4", 0x040, 0x100, CRC(00e224a0) SHA1(1a384ef488791c62566c91b18d6a1fb4a5def2ba) ) /* timing? */
ROM_LOAD( "018.h9", 0x140, 0x400, CRC(6547c208) SHA1(f19c334f9b4a1cfcbc913c0920688db2730dded0) ) /* color lookup table? */
ROM_LOAD( "013.d11", 0x000, 0x020, CRC(66f1f5eb) SHA1(bcf5348ae328cf943d2bf6e38df727c0c4c466b7) ) // hue: BBBBGGGG?
ROM_LOAD( "014.c11", 0x020, 0x020, CRC(662444b2) SHA1(2e510c1d9b7e34a3045048a46045e61fabaf918e) ) // hue: RRRR----?
ROM_LOAD( "015.n4", 0x040, 0x100, CRC(00e224a0) SHA1(1a384ef488791c62566c91b18d6a1fb4a5def2ba) ) // timing?
ROM_LOAD( "018.h9", 0x140, 0x400, CRC(6547c208) SHA1(f19c334f9b4a1cfcbc913c0920688db2730dded0) ) // color lookup table?
ROM_END
ROM_START( tunhuntc )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "001.lm1", 0x5000, 0x800, CRC(2601a3a4) SHA1(939bafc54576fdaccf688b49cc9d201b03feec3a) )
ROM_LOAD( "002.k1", 0x5800, 0x800, CRC(29bbf3df) SHA1(4a0ec4cfab362a976d3962b347f687db45095cfd) )
ROM_LOAD( "003.j1", 0x6000, 0x800, CRC(360c0f47) SHA1(8e3d815836504c7651812e0e26423b0c7045621c) ) /* bad crc? fails self-test */
/* 0xcaa6bb2a: alternate prom (re)dumped by Al also fails, they simply modified the rom without fixing the checksum routine? */
ROM_LOAD( "003.j1", 0x6000, 0x800, CRC(360c0f47) SHA1(8e3d815836504c7651812e0e26423b0c7045621c) ) // bad CRC? fails self-test
// 0xcaa6bb2a: alternate PROM (re)dumped by Al also fails, they simply modified the ROM without fixing the checksum routine?
ROM_LOAD( "004.fh1", 0x6800, 0x800, CRC(4d6c920e) SHA1(2ef274356f4b8a0170a267cd6a3758b2bda693b5) )
ROM_LOAD( "005.ef1", 0x7000, 0x800, CRC(e17badf0) SHA1(6afbf517486340fe54b01fa26258877b2a8fc510) )
ROM_LOAD( "006.d1", 0x7800, 0x800, CRC(c3ae8519) SHA1(2b2e49065bc38429894ef29a29ffc60f96e64840) )
ROM_REGION( 0x400, "gfx1", 0 ) /* alphanumeric characters */
ROM_REGION( 0x400, "chars", 0 )
ROM_LOAD( "019.c10", 0x000, 0x400, CRC(d6fd45a9) SHA1(c86ea3790c29c554199af8ad6f3d563dcb7723c7) )
ROM_REGION( 0x400, "gfx2", 0 ) /* "SHELL" objects (16x16 pixel sprites) */
ROM_REGION( 0x400, "sprites", 0 ) // "SHELL" objects (16x16 pixel sprites)
ROM_LOAD( "016.a8", 0x000, 0x200, CRC(830e6c34) SHA1(37a5eeb722dd80c4224c7f622b0edabb3ac1ca19) )
ROM_LOAD( "017.b8", 0x200, 0x200, CRC(5bef8b5a) SHA1(bfd9c592a34ed4861a6ad76ef10ea0d9b76a92b2) )
ROM_REGION( 0x540, "proms", 0 )
ROM_LOAD( "013.d11", 0x000, 0x020, CRC(66f1f5eb) SHA1(bcf5348ae328cf943d2bf6e38df727c0c4c466b7) ) /* hue: BBBBGGGG? */
ROM_LOAD( "014.c11", 0x020, 0x020, CRC(662444b2) SHA1(2e510c1d9b7e34a3045048a46045e61fabaf918e) ) /* hue: RRRR----? */
ROM_LOAD( "015.n4", 0x040, 0x100, CRC(00e224a0) SHA1(1a384ef488791c62566c91b18d6a1fb4a5def2ba) ) /* timing? */
ROM_LOAD( "018.h9", 0x140, 0x400, CRC(6547c208) SHA1(f19c334f9b4a1cfcbc913c0920688db2730dded0) ) /* color lookup table? */
ROM_LOAD( "013.d11", 0x000, 0x020, CRC(66f1f5eb) SHA1(bcf5348ae328cf943d2bf6e38df727c0c4c466b7) ) // hue: BBBBGGGG?
ROM_LOAD( "014.c11", 0x020, 0x020, CRC(662444b2) SHA1(2e510c1d9b7e34a3045048a46045e61fabaf918e) ) // hue: RRRR----?
ROM_LOAD( "015.n4", 0x040, 0x100, CRC(00e224a0) SHA1(1a384ef488791c62566c91b18d6a1fb4a5def2ba) ) // timing?
ROM_LOAD( "018.h9", 0x140, 0x400, CRC(6547c208) SHA1(f19c334f9b4a1cfcbc913c0920688db2730dded0) ) // color lookup table?
ROM_END
} // anonymous namespace
/*************************************
@ -438,6 +867,5 @@ ROM_END
*
*************************************/
/* rom parent machine inp state init */
GAME( 1979,tunhunt, 0, tunhunt, tunhunt, tunhunt_state, empty_init, ORIENTATION_SWAP_XY, "Atari", "Tunnel Hunt", MACHINE_SUPPORTS_SAVE )
GAME( 1979,tunhunt, 0, tunhunt, tunhunt, tunhunt_state, empty_init, ORIENTATION_SWAP_XY, "Atari", "Tunnel Hunt", MACHINE_SUPPORTS_SAVE )
GAME( 1981,tunhuntc, tunhunt, tunhunt, tunhunt, tunhunt_state, empty_init, ORIENTATION_SWAP_XY, "Atari (Centuri license)", "Tunnel Hunt (Centuri)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,94 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Phil Stroffolino, David Haywood
#ifndef MAME_ATARI_TUNHUNT_H
#define MAME_ATARI_TUNHUNT_H
#pragma once
#include "emupal.h"
#include "screen.h"
#include "tilemap.h"
class tunhunt_state : public driver_device
{
public:
tunhunt_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_workram(*this, "workram"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_generic_paletteram_8(*this, "paletteram"),
m_led(*this, "led0")
{ }
void tunhunt(machine_config &config);
private:
void control_w(uint8_t data);
uint8_t button_r(offs_t offset);
void videoram_w(offs_t offset, uint8_t data);
uint8_t dsw2_0r();
uint8_t dsw2_1r();
uint8_t dsw2_2r();
uint8_t dsw2_3r();
uint8_t dsw2_4r();
TILE_GET_INFO_MEMBER(get_fg_tile_info);
virtual void machine_start() override { m_led.resolve(); }
virtual void video_start() override;
void tunhunt_palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void set_pens();
void draw_motion_object(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_box(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_shell(bitmap_ind16 &bitmap, const rectangle &cliprect, int picture_code,
int hposition,int vstart,int vstop,int vstretch,int hstretch);
void main_map(address_map &map);
virtual void machine_reset() override;
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_workram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_generic_paletteram_8;
output_finder<> m_led;
uint8_t m_control = 0;
tilemap_t *m_fg_tilemap = nullptr;
bitmap_ind16 m_tmpbitmap;
uint8_t m_mobsc0 = 0;
uint8_t m_mobsc1 = 0;
uint8_t m_lineh[13]{};
uint8_t m_shl0st = 0;
uint8_t m_shl1st = 0;
uint8_t m_vstrlo = 0;
uint8_t m_linesh = 0;
uint8_t m_shl0pc = 0;
uint8_t m_shl1pc = 0;
uint8_t m_linec[13]{};
uint8_t m_shl0v = 0;
uint8_t m_shl1v = 0;
uint8_t m_mobjh = 0;
uint8_t m_linev[13]{};
uint8_t m_shl0vs = 0;
uint8_t m_shl1vs = 0;
uint8_t m_mobvs = 0;
uint8_t m_linevs[13]{};
uint8_t m_shel0h = 0;
uint8_t m_mobst = 0;
uint8_t m_shel1h = 0;
uint8_t m_mobjv = 0;
};
#endif // MAME_ATARI_TUNHUNT_H

View File

@ -1,374 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Phil Stroffolino, David Haywood
/*************************************************************************
Atari Tunnel Hunt hardware
*************************************************************************/
#include "emu.h"
#include "tunhunt.h"
/****************************************************************************************/
void tunhunt_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset);
}
TILE_GET_INFO_MEMBER(tunhunt_state::get_fg_tile_info)
{
int attr = m_videoram[tile_index];
int code = attr & 0x3f;
int color = attr >> 6;
int flags = color ? TILE_FORCE_LAYER0 : 0;
tileinfo.set(0, code, color, flags);
}
void tunhunt_state::video_start()
{
/*
Motion Object RAM contains 64 lines of run-length encoded data.
We keep track of dirty lines and cache the expanded bitmap.
With max RLE expansion, bitmap size is 256x64.
*/
m_tmpbitmap.allocate(256, 64, m_screen->format());
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tunhunt_state::get_fg_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 8, 32);
m_fg_tilemap->set_transparent_pen(0);
m_fg_tilemap->set_scrollx(0, 64);
save_item(NAME(m_control));
save_item(NAME(m_mobsc0));
save_item(NAME(m_mobsc1));
save_item(NAME(m_lineh));
save_item(NAME(m_shl0st));
save_item(NAME(m_shl1st));
save_item(NAME(m_vstrlo));
save_item(NAME(m_linesh));
save_item(NAME(m_shl0pc));
save_item(NAME(m_shl1pc));
save_item(NAME(m_linec));
save_item(NAME(m_shl0v));
save_item(NAME(m_shl1v));
save_item(NAME(m_mobjh));
save_item(NAME(m_linev));
save_item(NAME(m_shl0vs));
save_item(NAME(m_shl1vs));
save_item(NAME(m_mobvs));
save_item(NAME(m_linevs));
save_item(NAME(m_shel0h));
save_item(NAME(m_mobst));
save_item(NAME(m_shel1h));
save_item(NAME(m_mobjv));
}
void tunhunt_state::tunhunt_palette(palette_device &palette) const
{
/* Tunnel Hunt uses a combination of color proms and palette RAM to specify a 16 color
* palette. Here, we manage only the mappings for alphanumeric characters and SHELL
* graphics, which are unpacked ahead of time and drawn using MAME's drawgfx primitives.
*/
/* motion objects/box */
for (int i = 0; i < 0x10; i++)
palette.set_pen_indirect(i, i);
/* AlphaNumerics (1bpp)
* 2 bits of hilite select from 4 different background colors
* Foreground color is always pen#4
* Background color is mapped as follows:
*/
/* alpha hilite#0 */
palette.set_pen_indirect(0x10, 0x0); // background color#0 (transparent)
palette.set_pen_indirect(0x11, 0x4); // foreground color
/* alpha hilite#1 */
palette.set_pen_indirect(0x12, 0x5); // background color#1
palette.set_pen_indirect(0x13, 0x4); // foreground color
/* alpha hilite#2 */
palette.set_pen_indirect(0x14, 0x6); // background color#2
palette.set_pen_indirect(0x15, 0x4); // foreground color
/* alpha hilite#3 */
palette.set_pen_indirect(0x16, 0xf); // background color#3
palette.set_pen_indirect(0x17, 0x4); // foreground color
/* shell graphics; these are either 1bpp (2 banks) or 2bpp. It isn't clear which.
* In any event, the following pens are associated with the shell graphics:
*/
palette.set_pen_indirect(0x18, 0);
palette.set_pen_indirect(0x19, 4);//1;
}
/*
Color Array Ram Assignments:
Location
0 Blanking, border
1 Mot Obj (10) (D), Shell (01)
2 Mot Obj (01) (G), Shell (10)
3 Mot Obj (00) (W)
4 Alpha & Shell (11) - shields
5 Hilight 1
6 Hilight 2
8-E Lines (as normal) background
F Hilight 3
*/
void tunhunt_state::set_pens()
{
/*
The actual contents of the color proms (unused by this driver)
are as follows:
D11 "blue/green"
0000: 00 00 8b 0b fb 0f ff 0b
00 00 0f 0f fb f0 f0 ff
C11 "red"
0020: 00 f0 f0 f0 b0 b0 00 f0
00 f0 f0 00 b0 00 f0 f0
*/
//const uint8_t *color_prom = memregion( "proms" )->base();
int color;
int shade;
int red,green,blue;
for( int i=0; i<16; i++ )
{
color = m_generic_paletteram_8[i];
shade = 0xf^(color>>4);
color &= 0xf; /* hue select */
switch( color )
{
default:
case 0x0: red = 0xff; green = 0xff; blue = 0xff; break; /* white */
case 0x1: red = 0xff; green = 0x00; blue = 0xff; break; /* purple */
case 0x2: red = 0x00; green = 0x00; blue = 0xff; break; /* blue */
case 0x3: red = 0x00; green = 0xff; blue = 0xff; break; /* cyan */
case 0x4: red = 0x00; green = 0xff; blue = 0x00; break; /* green */
case 0x5: red = 0xff; green = 0xff; blue = 0x00; break; /* yellow */
case 0x6: red = 0xff; green = 0x00; blue = 0x00; break; /* red */
case 0x7: red = 0x00; green = 0x00; blue = 0x00; break; /* black? */
case 0x8: red = 0xff; green = 0x7f; blue = 0x00; break; /* orange */
case 0x9: red = 0x7f; green = 0xff; blue = 0x00; break; /* ? */
case 0xa: red = 0x00; green = 0xff; blue = 0x7f; break; /* ? */
case 0xb: red = 0x00; green = 0x7f; blue = 0xff; break; /* ? */
case 0xc: red = 0xff; green = 0x00; blue = 0x7f; break; /* ? */
case 0xd: red = 0x7f; green = 0x00; blue = 0xff; break; /* ? */
case 0xe: red = 0xff; green = 0xaa; blue = 0xaa; break; /* ? */
case 0xf: red = 0xaa; green = 0xaa; blue = 0xff; break; /* ? */
}
/* combine color components with shade value (0..0xf) */
#define APPLY_SHADE( C,S ) ((C*S)/0xf)
red = APPLY_SHADE(red,shade);
green = APPLY_SHADE(green,shade);
blue = APPLY_SHADE(blue,shade);
m_palette->set_indirect_color( i,rgb_t(red,green,blue) );
}
}
void tunhunt_state::draw_motion_object(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/*
* VSTRLO 0x1202
* normally 0x02 (gameplay, attract1)
* in attract2 (with "Tunnel Hunt" graphic), decrements from 0x2f down to 0x01
* goes to 0x01 for some enemy shots
*
* MOBSC0 0x1080
* MOBSC1 0x1081
* always 0x00?
*/
bitmap_ind16 &tmpbitmap = m_tmpbitmap;
//int skip = m_mobst;
const int x0 = 255 - m_mobjv;
const int y0 = 255 - m_mobjh;
for (int line = 0; line < 64; line++)
{
int x = 0;
const uint8_t *const source = &m_spriteram[line * 0x10];
for (int span = 0; span < 0x10; span++)
{
const int span_data = source[span];
if (span_data == 0xff) break;
const int color = ((span_data >> 6) & 0x3) ^ 0x3;
int count = (span_data & 0x1f) + 1;
while (count-- && x < 256)
tmpbitmap.pix(line, x++) = color;
}
while (x < 256)
tmpbitmap.pix(line, x++) = 0;
}
int scaley;
switch (m_vstrlo)
{
case 0x01:
scaley = (1 << 16) * 0.33; // seems correct
break;
case 0x02:
scaley = (1 << 16) * 0.50; // seems correct
break;
default:
scaley = (1 << 16) * m_vstrlo / 4; // ???
break;
}
const int scalex = 1 << 16;
copyrozbitmap_trans(
bitmap, cliprect, tmpbitmap,
-x0 * scalex, // startx
-y0 * scaley, // starty
scalex, // incxx
0, 0, // incxy, incyx
scaley, // incyy
false, // no wraparound
0);
}
void tunhunt_state::draw_box(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/*
This is unnecessarily slow, but the box priorities aren't completely understood,
yet. Once understood, this function should be converted to use bitmap_fill with
rectangular chunks instead of BITMAP_ADDR.
Tunnels:
1080: 00 00 00 01 e7 18 ae 51 94 6b 88 77 83 7c 80 7f x0
1480: 00 f0 17 00 22 22 5b 5b 75 75 81 81 86 86 89 89 y0
1400: 00 00 97 ff f1 f1 b8 b8 9e 9e 92 92 8d 8d 8a 8a y1
1280: 07 03 00 07 07 0c 0c 0d 0d 0e 0e 08 08 09 09 0a palette select
Color Bars:
1080: 00 00 00 01 00 20 40 60 80 a0 c0 e0 01 2a 50 7a x0
1480: 00 f0 00 00 40 40 40 40 40 40 40 40 00 00 00 00 y0
1400: 00 00 00 ff ff ff ff ff ff ff ff ff 40 40 40 40 y1
1280: 07 03 00 01 07 06 04 05 02 07 03 00 09 0a 0b 0c palette select
->hue 06 02 ff 60 06 05 03 04 01 06 02 ff d2 00 c2 ff
*/
int span,x,y;
int color;
// rectangle bbox;
int z;
int x0,y0,y1;
for( y=0; y<256; y++ )
{
if (0xff-y >= cliprect.top() && 0xff-y <= cliprect.bottom())
for( x=0; x<256; x++ )
{
color = 0;
z = 0;
for( span=0; span<13; span++ )
{
x0 = m_lineh[span];
y0 = m_linevs[span];
y1 = m_linev[span];
if( y>=y0 && y<=y1 && x>=x0 && x0>=z )
{
color = m_linec[span]&0xf;
z = x0; /* give priority to rightmost spans */
}
}
if (x >= cliprect.left() && x <= cliprect.right())
bitmap.pix(0xff-y, x) = color;
}
}
}
/* "shell" graphics are 16x16 pixel tiles used for player shots and targeting cursor */
void tunhunt_state::draw_shell(bitmap_ind16 &bitmap,
const rectangle &cliprect,
int picture_code,
int hposition,
int vstart,
int vstop,
int vstretch,
int hstretch )
{
if( hstretch )
{
int sx,sy;
for( sx=0; sx<256; sx+=16 )
{
for( sy=0; sy<256; sy+=16 )
{
m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
picture_code,
0, /* color */
0,0, /* flip */
sx,sy,0 );
}
}
}
else
/*
vstretch is normally 0x01
targeting cursor:
hposition = 0x78
vstart = 0x90
vstop = 0x80
during grid test:
vstretch = 0xff
hposition = 0xff
vstart = 0xff
vstop = 0x00
*/
m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
picture_code,
0, /* color */
0,0, /* flip */
255-hposition-16,vstart-32,0 );
}
uint32_t tunhunt_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
set_pens();
draw_box(bitmap, cliprect);
draw_motion_object(bitmap, cliprect);
draw_shell(bitmap, cliprect,
m_shl0pc, /* picture code */
m_shel0h, /* hposition */
m_shl0v, /* vstart */
m_shl0vs, /* vstop */
m_shl0st, /* vstretch */
m_control&0x08 ); /* hstretch */
draw_shell(bitmap, cliprect,
m_shl1pc, /* picture code */
m_shel1h, /* hposition */
m_shl1v, /* vstart */
m_shl1vs, /* vstop */
m_shl1st, /* vstretch */
m_control&0x10 ); /* hstretch */
rectangle cr = cliprect;
if( cr.min_x < 192 )
cr.min_x = 192;
m_fg_tilemap->draw(screen, bitmap, cr, 0, 0);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Sebastien Monassa
/*************************************************************************
Atari Video Pinball driver
@ -18,19 +19,177 @@
*************************************************************************/
#include "emu.h"
#include "videopin.h"
#include "videopin_a.h"
#include "cpu/m6502/m6502.h"
#include "machine/watchdog.h"
#include "sound/discrete.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
#include "videopin.lh"
namespace {
class videopin_state : public driver_device
{
public:
videopin_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_discrete(*this, "discrete"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_video_ram(*this, "video_ram"),
m_in(*this, "IN%u", 1U),
m_leds(*this, "LED%02u", 1U)
{ }
void videopin(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_device<discrete_device> m_discrete;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_video_ram;
required_ioport_array<2> m_in;
output_finder<32> m_leds;
attotime m_time_pushed;
attotime m_time_released;
uint8_t m_prev = 0;
uint8_t m_mask = 0;
uint8_t m_ball_x = 0;
uint8_t m_ball_y = 0;
tilemap_t *m_bg_tilemap = nullptr;
emu_timer *m_interrupt_timer = nullptr;
void main_map(address_map &map);
uint8_t misc_r();
void led_w(uint8_t data);
void ball_w(uint8_t data);
void video_ram_w(offs_t offset, uint8_t data);
void out1_w(uint8_t data);
void out2_w(uint8_t data);
void note_dvsr_w(uint8_t data);
TILEMAP_MAPPER_MEMBER(get_memory_offset);
TILE_GET_INFO_MEMBER(get_tile_info);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_CALLBACK_MEMBER(interrupt_callback);
void update_plunger();
double calc_plunger_pos();
};
// video
TILEMAP_MAPPER_MEMBER(videopin_state::get_memory_offset)
{
return num_rows * ((col + 16) % 48) + row;
}
TILE_GET_INFO_MEMBER(videopin_state::get_tile_info)
{
uint8_t const code = m_video_ram[tile_index];
tileinfo.set(0, code, 0, (code & 0x40) ? TILE_FLIPY : 0);
}
void videopin_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(videopin_state::get_tile_info)), tilemap_mapper_delegate(*this, FUNC(videopin_state::get_memory_offset)), 8, 8, 48, 32);
save_item(NAME(m_ball_x));
save_item(NAME(m_ball_y));
}
uint32_t videopin_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, -8); // account for delayed loading of shift reg C6
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
for (int row = 0; row < 32; row++)
{
for (int col = 0; col < 48; col++)
{
uint32_t const offset = m_bg_tilemap->memory_index(col, row);
if (m_video_ram[offset] & 0x80) // ball bit found
{
int x = 8 * col;
int y = 8 * row;
x += 4; // account for delayed loading of flip-flop C4
rectangle rect(x, x + 15, y, y + 15);
rect &= cliprect;
x -= m_ball_x;
y -= m_ball_y;
// ball placement is still 0.5 pixels off but don't tell anyone
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
m_gfxdecode->gfx(1)->transpen(bitmap, rect,
0, 0,
0, 0,
x + 16 * i,
y + 16 * j, 0);
}
}
return 0; // keep things simple and ignore the rest
}
}
}
return 0;
}
void videopin_state::ball_w(uint8_t data)
{
m_ball_x = data & 15;
m_ball_y = data >> 4;
}
void videopin_state::video_ram_w(offs_t offset, uint8_t data)
{
m_video_ram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
// machine
void videopin_state::update_plunger()
{
uint8_t val = ioport("IN2")->read();
uint8_t const val = m_in[1]->read();
if (m_prev != val)
{
@ -82,7 +241,7 @@ void videopin_state::machine_reset()
{
m_interrupt_timer->adjust(m_screen->time_until_pos(32), 32);
/* both output latches are cleared on reset */
// both output latches are cleared on reset
out1_w(0);
out2_w(0);
@ -108,15 +267,15 @@ uint8_t videopin_state::misc_r()
// signals received. This results in the MPU displaying the
// ball being shot onto the playfield at a certain speed.
uint8_t val = ioport("IN1")->read();
uint8_t val = m_in[0]->read();
if (plunger >= 0.000 && plunger <= 0.001)
{
val &= ~1; /* PLUNGER1 */
val &= ~1; // PLUNGER1
}
if (plunger >= 0.006 && plunger <= 0.007)
{
val &= ~2; /* PLUNGER2 */
val &= ~2; // PLUNGER2
}
return val;
@ -140,7 +299,7 @@ void videopin_state::led_w(uint8_t data)
};
// anode from 32V,64V,128V
int a = m_screen->vpos() >> 5 & 7;
int const a = m_screen->vpos() >> 5 & 7;
for (int c = 0; c < 4; c++)
m_leds[matrix[a][c] - 1] = BIT(data, c);
@ -151,14 +310,14 @@ void videopin_state::led_w(uint8_t data)
void videopin_state::out1_w(uint8_t data)
{
/* D0 => OCTAVE0 */
/* D1 => OCTACE1 */
/* D2 => OCTAVE2 */
/* D3 => LOCKOUT */
/* D4 => NMIMASK */
/* D5 => NOT USED */
/* D6 => NOT USED */
/* D7 => NOT USED */
// D0 => OCTAVE0
// D1 => OCTACE1
// D2 => OCTAVE2
// D3 => LOCKOUT
// D4 => NMIMASK
// D5 => NOT USED
// D6 => NOT USED
// D7 => NOT USED
m_mask = ~data & 0x10;
@ -167,21 +326,21 @@ void videopin_state::out1_w(uint8_t data)
machine().bookkeeping().coin_lockout_global_w(~data & 0x08);
/* Convert octave data to divide value and write to sound */
// Convert octave data to divide value and write to sound
m_discrete->write(VIDEOPIN_OCTAVE_DATA, (0x01 << (~data & 0x07)) & 0xfe);
}
void videopin_state::out2_w(uint8_t data)
{
/* D0 => VOL0 */
/* D1 => VOL1 */
/* D2 => VOL2 */
/* D3 => NOT USED */
/* D4 => COIN CNTR */
/* D5 => BONG */
/* D6 => BELL */
/* D7 => ATTRACT */
// D0 => VOL0
// D1 => VOL1
// D2 => VOL2
// D3 => NOT USED
// D4 => COIN CNTR
// D5 => BONG
// D6 => BELL
// D7 => ATTRACT
machine().bookkeeping().coin_counter_w(0, data & 0x10);
@ -194,7 +353,7 @@ void videopin_state::out2_w(uint8_t data)
void videopin_state::note_dvsr_w(uint8_t data)
{
/* note data */
// note data
m_discrete->write(VIDEOPIN_NOTE_DATA, ~data &0xff);
}
@ -208,7 +367,7 @@ void videopin_state::note_dvsr_w(uint8_t data)
void videopin_state::main_map(address_map &map)
{
map(0x0000, 0x01ff).ram();
map(0x0200, 0x07ff).ram().w(FUNC(videopin_state::video_ram_w)).share("video_ram");
map(0x0200, 0x07ff).ram().w(FUNC(videopin_state::video_ram_w)).share(m_video_ram);
map(0x0800, 0x0800).r(FUNC(videopin_state::misc_r)).w(FUNC(videopin_state::note_dvsr_w));
map(0x0801, 0x0801).w(FUNC(videopin_state::led_w));
map(0x0802, 0x0802).w("watchdog", FUNC(watchdog_timer_device::reset_w));
@ -229,7 +388,7 @@ void videopin_state::main_map(address_map &map)
*************************************/
static INPUT_PORTS_START( videopin )
PORT_START("IN0") /* IN0 */
PORT_START("IN0") // IN0
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Left Flipper") PORT_CODE(KEYCODE_LCONTROL)
@ -239,7 +398,7 @@ static INPUT_PORTS_START( videopin )
PORT_SERVICE( 0x40, IP_ACTIVE_LOW )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("DSW") /* IN1 */
PORT_START("DSW") // IN1
PORT_DIPNAME( 0xc0, 0x80, DEF_STR( Coinage ) ) PORT_DIPLOCATION("DSW:8,7")
PORT_DIPSETTING( 0xc0, DEF_STR( 2C_1C ) )
PORT_DIPSETTING( 0x80, DEF_STR( 1C_1C ) )
@ -263,9 +422,9 @@ static INPUT_PORTS_START( videopin )
PORT_DIPSETTING( 0x00, "180000 (3 balls) / 300000 (5 balls)" )
PORT_DIPSETTING( 0x01, "210000 (3 balls) / 350000 (5 balls)" )
PORT_START("IN1") /* IN2 */
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_CUSTOM ) /* PLUNGER 1 */
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_CUSTOM ) /* PLUNGER 2 */
PORT_START("IN1") // IN2
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_CUSTOM ) // PLUNGER 1
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_CUSTOM ) // PLUNGER 2
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
@ -298,22 +457,6 @@ INPUT_PORTS_END
*
*************************************/
static const gfx_layout tile_layout =
{
8, 8,
64,
1,
{ 0 },
{
0, 1, 2, 3, 4, 5, 6, 7
},
{
0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
},
0x40
};
static const gfx_layout ball_layout =
{
16, 16,
@ -334,8 +477,8 @@ static const gfx_layout ball_layout =
static GFXDECODE_START( gfx_videopin )
GFXDECODE_ENTRY( "gfx1", 0x0000, tile_layout, 0, 1 )
GFXDECODE_ENTRY( "gfx2", 0x0000, ball_layout, 0, 1 )
GFXDECODE_ENTRY( "tiles", 0x0000, gfx_8x8x1, 0, 1 )
GFXDECODE_ENTRY( "ball", 0x0000, ball_layout, 0, 1 )
GFXDECODE_END
@ -348,13 +491,13 @@ GFXDECODE_END
void videopin_state::videopin(machine_config &config)
{
/* basic machine hardware */
M6502(config, m_maincpu, 12096000 / 16);
// basic machine hardware
M6502(config, m_maincpu, 12'096'000 / 16);
m_maincpu->set_addrmap(AS_PROGRAM, &videopin_state::main_map);
WATCHDOG_TIMER(config, "watchdog");
/* video hardware */
// video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(60);
m_screen->set_size(304, 263);
@ -366,7 +509,7 @@ void videopin_state::videopin(machine_config &config)
PALETTE(config, m_palette, palette_device::MONOCHROME);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
DISCRETE(config, m_discrete, videopin_discrete).add_route(ALL_OUTPUTS, "mono", 1.0);
@ -403,15 +546,15 @@ ROM_START( videopin )
ROM_LOAD_NIB_HIGH( "34241-01.f0", 0x3c00, 0x0400, CRC(5bfb83da) SHA1(9f392b0d4a972b6ae15ec12913a7e66761f4175d) )
ROM_RELOAD( 0xfc00, 0x0400 )
ROM_REGION( 0x0200, "gfx1", 0 ) /* tiles */
ROM_REGION( 0x0200, "tiles", 0 )
ROM_LOAD_NIB_LOW ( "34259-01.d5", 0x0000, 0x0200, CRC(6cd98c06) SHA1(48bf077b7abbd2f529a19bdf85700b93014f39f9) )
ROM_LOAD_NIB_HIGH( "34258-01.c5", 0x0000, 0x0200, CRC(91a5f117) SHA1(03ac6b0b3da0ed5faf1ba6695d16918d12ceeff5) )
ROM_REGION( 0x0020, "gfx2", 0 ) /* ball */
ROM_REGION( 0x0020, "ball", 0 )
ROM_LOAD( "34257-01.m1", 0x0000, 0x0020, CRC(50245866) SHA1(b0692bc8d44f127f6e7182a1ce75a785e22ac5b9) )
ROM_REGION( 0x0100, "proms", 0 )
ROM_LOAD( "9402-01.h4", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync */
ROM_REGION( 0x0100, "sync_prom", 0 )
ROM_LOAD( "9402-01.h4", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) )
ROM_END
// This is an even later revision (marked -02) with 4 EPROMs (4096x8 according to manual, while 2048x8 in reality)
@ -423,15 +566,15 @@ ROM_START( videopina )
ROM_LOAD( "034256-01.k2", 0x3800, 0x0800, CRC(9f24428c) SHA1(df35225afebb4cc18a593ec665e94f677b3606ee) )
ROM_COPY( "maincpu" , 0x3c00, 0xfc00, 0x400 )
ROM_REGION( 0x0200, "gfx1", 0 ) // tiles
ROM_REGION( 0x0200, "tiles", 0 )
ROM_LOAD_NIB_LOW ( "34259-01.d5", 0x0000, 0x0200, CRC(6cd98c06) SHA1(48bf077b7abbd2f529a19bdf85700b93014f39f9) )
ROM_LOAD_NIB_HIGH( "34258-01.c5", 0x0000, 0x0200, CRC(91a5f117) SHA1(03ac6b0b3da0ed5faf1ba6695d16918d12ceeff5) )
ROM_REGION( 0x0020, "gfx2", 0 ) // ball
ROM_REGION( 0x0020, "ball", 0 )
ROM_LOAD( "34257-01.m1", 0x0000, 0x0020, CRC(50245866) SHA1(b0692bc8d44f127f6e7182a1ce75a785e22ac5b9) )
ROM_REGION( 0x0100, "proms", 0 )
ROM_LOAD( "9402-01.h4", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) // sync
ROM_REGION( 0x0100, "sync_prom", 0 )
ROM_LOAD( "9402-01.h4", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) )
ROM_END
ROM_START( solarwar )
@ -455,17 +598,19 @@ ROM_START( solarwar )
ROM_LOAD_NIB_HIGH( "36158-02.f0", 0x3c00, 0x0400, CRC(2606b87e) SHA1(ea72e36837eccf29cd5c82fe9a6a018a1a94730c) )
ROM_RELOAD( 0xfc00, 0x0400 )
ROM_REGION( 0x0200, "gfx1", 0 ) /* tiles */
ROM_REGION( 0x0200, "tiles", 0 )
ROM_LOAD_NIB_LOW ( "34259-01.d5", 0x0000, 0x0200, CRC(6cd98c06) SHA1(48bf077b7abbd2f529a19bdf85700b93014f39f9) )
ROM_LOAD_NIB_HIGH( "34258-01.c5", 0x0000, 0x0200, CRC(91a5f117) SHA1(03ac6b0b3da0ed5faf1ba6695d16918d12ceeff5) )
ROM_REGION( 0x0020, "gfx2", 0 ) /* ball */
ROM_REGION( 0x0020, "ball", 0 )
ROM_LOAD( "34257-01.m1", 0x0000, 0x0020, CRC(50245866) SHA1(b0692bc8d44f127f6e7182a1ce75a785e22ac5b9) )
ROM_REGION( 0x0100, "proms", 0 )
ROM_LOAD( "9402-01.h4", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync */
ROM_REGION( 0x0100, "sync_prom", 0 )
ROM_LOAD( "9402-01.h4", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) )
ROM_END
} // anonymous namespace
/*************************************
*
@ -474,5 +619,5 @@ ROM_END
*************************************/
GAMEL( 1979, videopin, 0, videopin, videopin, videopin_state, empty_init, ROT270, "Atari", "Video Pinball (16 PROMs version)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK, layout_videopin )
GAMEL( 1979, videopina, videopin, videopin, videopin, videopin_state, empty_init, ROT270, "Atari", "Video Pinball (4 ROMs version)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK, layout_videopin )
GAMEL( 1979, solarwar, 0, videopin, solarwar, videopin_state, empty_init, ROT270, "Atari", "Solar War", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK, layout_videopin )
GAMEL( 1979, videopina, videopin, videopin, videopin, videopin_state, empty_init, ROT270, "Atari", "Video Pinball (4 ROMs version)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK, layout_videopin )
GAMEL( 1979, solarwar, 0, videopin, solarwar, videopin_state, empty_init, ROT270, "Atari", "Solar War", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK, layout_videopin )

View File

@ -1,90 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Sebastien Monassa
/*************************************************************************
Atari Video Pinball hardware
*************************************************************************/
#ifndef MAME_ATARI_VIDEOPIN_H
#define MAME_ATARI_VIDEOPIN_H
#pragma once
#include "sound/discrete.h"
#include "emupal.h"
#include "screen.h"
#include "tilemap.h"
/* Discrete Sound Input Nodes */
#define VIDEOPIN_OCTAVE_DATA NODE_01
#define VIDEOPIN_NOTE_DATA NODE_02
#define VIDEOPIN_BELL_EN NODE_03
#define VIDEOPIN_BONG_EN NODE_04
#define VIDEOPIN_ATTRACT_EN NODE_05
#define VIDEOPIN_VOL_DATA NODE_06
class videopin_state : public driver_device
{
public:
videopin_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_discrete(*this, "discrete"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_video_ram(*this, "video_ram"),
m_leds(*this, "LED%02u", 1U)
{ }
void videopin(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
void main_map(address_map &map);
uint8_t misc_r();
void led_w(uint8_t data);
void ball_w(uint8_t data);
void video_ram_w(offs_t offset, uint8_t data);
void out1_w(uint8_t data);
void out2_w(uint8_t data);
void note_dvsr_w(uint8_t data);
TILEMAP_MAPPER_MEMBER(get_memory_offset);
TILE_GET_INFO_MEMBER(get_tile_info);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_CALLBACK_MEMBER(interrupt_callback);
void update_plunger();
double calc_plunger_pos();
required_device<cpu_device> m_maincpu;
required_device<discrete_device> m_discrete;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_video_ram;
output_finder<32> m_leds;
attotime m_time_pushed;
attotime m_time_released;
uint8_t m_prev = 0;
uint8_t m_mask = 0;
int m_ball_x = 0;
int m_ball_y = 0;
tilemap_t* m_bg_tilemap = nullptr;
emu_timer *m_interrupt_timer = nullptr;
};
/*----------- defined in audio/videopin.c -----------*/
DISCRETE_SOUND_EXTERN( videopin_discrete );
#endif // MAME_ATARI_VIDEOPIN_H

View File

@ -1,14 +1,14 @@
// license:BSD-3-Clause
// copyright-holders:Derrick Renaud
/*************************************************************************
audio\videopin.c
atari\videopin_a.cpp
*************************************************************************/
#include "emu.h"
#include "videopin.h"
#include "sound/discrete.h"
#include "videopin_a.h"
/************************************************************************/
/* videopin Sound System Analog emulation */
@ -22,7 +22,7 @@
DISCRETE_SOUND_START(videopin_discrete)
/************************************************/
/* videopin Effects Relataive Gain Table */
/* videopin Effects Relative Gain Table */
/* */
/* Effect V-ampIn Gain ratio Relative */
/* Vol0 3.8 10/(10+50) 1000.0 */
@ -83,11 +83,11 @@ DISCRETE_SOUND_START(videopin_discrete)
/************************************************/
/* Bell is Hsync/16 with an R/C decay amplitude */
/* the 1uF cap is rapidally charged when BELL */
/* is enabled, then dischaged through the 1M */
/* the 1uF cap is rapidly charged when BELL */
/* is enabled, then discharged through the 1M */
/* resistor when disabled. */
/* We use 180 phase because of inverter Q17, */
/* but it rally has no effect on sound. */
/* but it really has no effect on sound. */
/************************************************/
DISCRETE_RCDISC2(NODE_30, VIDEOPIN_BELL_EN, 740.2, 1, 0, 1e6, 1e-6)
DISCRETE_SQUAREWFIX(VIDEOPIN_BELL_SND, VIDEOPIN_BELL_EN, 15750.0/16.0, NODE_30, 50.0, 0, 180.0)

View File

@ -0,0 +1,22 @@
// license:BSD-3-Clause
// copyright-holders:Derrick Renaud
/***************************************************************************
Video Pinball Audio
***************************************************************************/
#include "sound/discrete.h"
// discrete sound input nodes
#define VIDEOPIN_OCTAVE_DATA NODE_01
#define VIDEOPIN_NOTE_DATA NODE_02
#define VIDEOPIN_BELL_EN NODE_03
#define VIDEOPIN_BONG_EN NODE_04
#define VIDEOPIN_ATTRACT_EN NODE_05
#define VIDEOPIN_VOL_DATA NODE_06
DISCRETE_SOUND_EXTERN( videopin_discrete );

View File

@ -1,103 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Sebastien Monassa
/*************************************************************************
Atari Video Pinball video emulation
*************************************************************************/
#include "emu.h"
#include "videopin.h"
TILEMAP_MAPPER_MEMBER(videopin_state::get_memory_offset)
{
return num_rows * ((col + 16) % 48) + row;
}
TILE_GET_INFO_MEMBER(videopin_state::get_tile_info)
{
uint8_t code = m_video_ram[tile_index];
tileinfo.set(0, code, 0, (code & 0x40) ? TILE_FLIPY : 0);
}
void videopin_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(videopin_state::get_tile_info)), tilemap_mapper_delegate(*this, FUNC(videopin_state::get_memory_offset)), 8, 8, 48, 32);
save_item(NAME(m_ball_x));
save_item(NAME(m_ball_y));
}
uint32_t videopin_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int col;
int row;
m_bg_tilemap->set_scrollx(0, -8); /* account for delayed loading of shift reg C6 */
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
for (row = 0; row < 32; row++)
{
for (col = 0; col < 48; col++)
{
uint32_t offset = m_bg_tilemap->memory_index(col, row);
if (m_video_ram[offset] & 0x80) /* ball bit found */
{
int x = 8 * col;
int y = 8 * row;
int i;
int j;
x += 4; /* account for delayed loading of flip-flop C4 */
rectangle rect(x, x + 15, y, y + 15);
rect &= cliprect;
x -= m_ball_x;
y -= m_ball_y;
/* ball placement is still 0.5 pixels off but don't tell anyone */
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
m_gfxdecode->gfx(1)->transpen(bitmap,rect,
0, 0,
0, 0,
x + 16 * i,
y + 16 * j, 0);
}
}
return 0; /* keep things simple and ignore the rest */
}
}
}
return 0;
}
void videopin_state::ball_w(uint8_t data)
{
m_ball_x = data & 15;
m_ball_y = data >> 4;
}
void videopin_state::video_ram_w(offs_t offset, uint8_t data)
{
m_video_ram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}

View File

@ -82,6 +82,10 @@ Versions known to exist but not dumped:
PCBs were shown running (and could be played) at a Cave fan show known as Cave Festival 2006. There are
videos of the game being played floating around the internet and on YouTube. AKA DDP-CV or DDP BLUE ROM
NOTE: Easter egg in Fereron SOS / Dangun Feveron:
Insert a coin and with the joystick move: Down, Up, Right, Left, Up, Down, Left, Right
If you did the above right, you'll hear a MEOW sound. Start the game and your ship is now a cat!
***************************************************************************/
#include "emu.h"