// license:BSD-3-Clause
// copyright-holders:Bryan McPhail
/***************************************************************************
Cobra Command:
2 BAC06 background generator chips, same as Dec0.
1 MXC06 chip for sprites, same as Dec0.
256 colours, palette generated by ram.
The Real Ghostbusters:
1 Deco VSC30 (M60348) (on DE-0259-1 sub board)
1 Deco HMC20 (M60232) (on DE-0259-1 sub board)
1 x BAC06 (on DE-0273-1 board)
1 playfield, same as above, with rowscroll
1024 colours from 2 proms.
Sprite hardware close to above, there are some unused (unknown) bits per sprite.
Super Real Darwin:
1 playfield, x-scroll only
Closer to earlier Darwin 4078 board than above games.
Last Mission/Shackled:
Has 1 Deco VSC30 (M60348) (From readme file)
Has 1 Deco HMC20 (M60232) (From readme file)
1 playfield
Sprite hardware same as Karnov.
(Shackled) Palettes 8-15 for tiles seem to have priority over sprites.
Gondomania:
Has two large square surface mount chips: [ DRL 40, 8053, 8649a ]
Has 1 Deco VSC30 (M60348)
Has 1 Deco HMC20 (M60232)
Priority - all tiles with *pens* 8-15 appear over sprites with palettes 8-15.
Oscar:
Uses MXC-06 custom chip for sprites.
Uses BAC-06 custom chip for background.
I can't find what makes the fix chars...
Priority - tiles with palettes 8-15 have their *pens* 8-15 appearing over
sprites.
***************************************************************************/
#include "emu.h"
#include "includes/dec8.h"
WRITE8_MEMBER(dec8_state::dec8_bg_data_w)
{
m_bg_data[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset / 2);
}
READ8_MEMBER(dec8_state::dec8_bg_data_r)
{
return m_bg_data[offset];
}
WRITE8_MEMBER(dec8_state::dec8_videoram_w)
{
m_videoram[offset] = data;
m_fix_tilemap->mark_tile_dirty(offset / 2);
}
WRITE8_MEMBER(dec8_state::srdarwin_videoram_w)
{
m_videoram[offset] = data;
m_fix_tilemap->mark_tile_dirty(offset);
}
WRITE8_MEMBER(dec8_state::dec8_scroll2_w)
{
m_scroll2[offset] = data;
}
WRITE8_MEMBER(dec8_state::srdarwin_control_w)
{
switch (offset)
{
case 0: /* Top 3 bits - bank switch, bottom 4 - scroll MSB */
m_mainbank->set_entry((data >> 5));
m_scroll2[0] = data & 0xf;
return;
case 1:
m_scroll2[1] = data;
return;
}
}
WRITE8_MEMBER(dec8_state::lastmisn_control_w)
{
/*
Bit 0x0f - ROM bank switch.
Bit 0x10 - Unused
Bit 0x20 - X scroll MSB
Bit 0x40 - Y scroll MSB
Bit 0x80 - Hold subcpu reset line high if clear, else low
*/
m_mainbank->set_entry(data & 0x0f);
m_scroll2[0] = (data >> 5) & 1;
m_scroll2[2] = (data >> 6) & 1;
if (data & 0x80)
m_subcpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
else
m_subcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
}
WRITE8_MEMBER(dec8_state::shackled_control_w)
{
/* Bottom 4 bits - bank switch, Bits 4 & 5 - Scroll MSBs */
m_mainbank->set_entry(data & 0x0f);
m_scroll2[0] = (data >> 5) & 1;
m_scroll2[2] = (data >> 6) & 1;
}
WRITE8_MEMBER(dec8_state::lastmisn_scrollx_w)
{
m_scroll2[1] = data;
}
WRITE8_MEMBER(dec8_state::lastmisn_scrolly_w)
{
m_scroll2[3] = data;
}
WRITE8_MEMBER(dec8_state::gondo_scroll_w)
{
switch (offset)
{
case 0x0:
m_scroll2[1] = data; /* X LSB */
break;
case 0x8:
m_scroll2[3] = data; /* Y LSB */
break;
case 0x10:
m_scroll2[0] = (data >> 0) & 1; /* Bit 0: X MSB */
m_scroll2[2] = (data >> 1) & 1; /* Bit 1: Y MSB */
/* Bit 2 is also used in Gondo & Garyoret */
break;
}
}
void dec8_state::allocate_buffered_spriteram16()
{
m_buffered_spriteram16 = make_unique_clear<uint16_t[]>(0x800/2);
save_pointer(NAME(m_buffered_spriteram16), 0x800/2);
}
/******************************************************************************/
void dec8_state::srdarwin_draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect, int pri )
{
uint8_t *buffered_spriteram = m_spriteram->buffer();
int offs;
/* Sprites */
for (offs = 0; offs < 0x200; offs += 4)
{
int multi, fx, sx, sy, sy2, code, color;
color = (buffered_spriteram[offs + 1] & 0x03) + ((buffered_spriteram[offs + 1] & 0x08) >> 1);
if (pri == 0 && color != 0) continue;
if (pri == 1 && color == 0) continue;
code = buffered_spriteram[offs + 3] + ((buffered_spriteram[offs + 1] & 0xe0) << 3);
if (!code) continue;
sy = buffered_spriteram[offs];
if (sy == 0xf8) continue;
sx = (241 - buffered_spriteram[offs + 2]);
fx = buffered_spriteram[offs + 1] & 0x04;
multi = buffered_spriteram[offs + 1] & 0x10;
if (flip_screen())
{
sy = 240 - sy;
sx = 240 - sx;
if (fx) fx = 0; else fx = 1;
sy2 = sy - 16;
}
else sy2 = sy + 16;
m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
code,
color,
fx,flip_screen(),
sx,sy,0);
if (multi)
m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
code+1,
color,
fx,flip_screen(),
sx,sy2,0);
}
}
/******************************************************************************/
uint32_t dec8_state::screen_update_cobracom(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bool flip = m_tilegen[0]->get_flip_state();
m_tilegen[0]->set_flip_screen(flip);
m_tilegen[1]->set_flip_screen(flip);
m_spritegen_mxc->set_flip_screen(flip);
m_fix_tilemap->set_flip(flip ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
m_tilegen[0]->deco_bac06_pf_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE, 0x00, 0x00, 0x00, 0x00);
m_spritegen_mxc->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x04, 0x00, 0x03);
m_tilegen[1]->deco_bac06_pf_draw(bitmap,cliprect,0, 0x00, 0x00, 0x00, 0x00);
m_spritegen_mxc->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x04, 0x04, 0x03);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
/******************************************************************************/
TILE_GET_INFO_MEMBER(dec8_state::get_cobracom_fix_tile_info)
{
int offs = tile_index << 1;
int tile = m_videoram[offs + 1] + (m_videoram[offs] << 8);
int color = (tile & 0xe000) >> 13;
SET_TILE_INFO_MEMBER(0,
tile & 0xfff,
color,
0);
}
VIDEO_START_MEMBER(dec8_state,cobracom)
{
allocate_buffered_spriteram16();
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_cobracom_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_game_uses_priority = 0;
m_tilegen[0]->set_colmask(0x3);
m_tilegen[1]->set_colmask(0x3);
}
/******************************************************************************/
uint32_t dec8_state::screen_update_ghostb(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_tilegen[0]->deco_bac06_pf_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE, 0x00, 0x00, 0x00, 0x00);
m_spritegen_krn->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x400, 0);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
TILE_GET_INFO_MEMBER(dec8_state::get_ghostb_fix_tile_info)
{
int offs = tile_index << 1;
int tile = m_videoram[offs + 1] + (m_videoram[offs] << 8);
int color = (tile & 0xc00) >> 10;
SET_TILE_INFO_MEMBER(0,
tile & 0x3ff,
color,
0);
}
VIDEO_START_MEMBER(dec8_state,ghostb)
{
allocate_buffered_spriteram16();
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_ghostb_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_game_uses_priority = 0;
m_tilegen[0]->set_colmask(0xf);
m_nmi_enable = false;
save_item(NAME(m_nmi_enable));
}
/******************************************************************************/
uint32_t dec8_state::screen_update_oscar(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bool flip = m_tilegen[0]->get_flip_state();
m_tilegen[0]->set_flip_screen(flip);
m_spritegen_mxc->set_flip_screen(flip);
m_fix_tilemap->set_flip(flip ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
// we mimic the priority scheme in dec0.c, this was originally a bit different, so this could be wrong
m_tilegen[0]->deco_bac06_pf_draw(bitmap,cliprect,TILEMAP_DRAW_OPAQUE, 0x00, 0x00, 0x00, 0x00);
m_spritegen_mxc->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x00, 0x00, 0x0f);
m_tilegen[0]->deco_bac06_pf_draw(bitmap,cliprect,0, 0x08,0x08,0x08,0x08);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
TILE_GET_INFO_MEMBER(dec8_state::get_oscar_fix_tile_info)
{
int offs = tile_index << 1;
int tile = m_videoram[offs + 1] + (m_videoram[offs] << 8);
int color = (tile & 0xf000) >> 14;
SET_TILE_INFO_MEMBER(0,
tile&0xfff,
color,
0);
}
VIDEO_START_MEMBER(dec8_state,oscar)
{
allocate_buffered_spriteram16();
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_oscar_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_game_uses_priority = 1;
m_tilegen[0]->set_colmask(0x7);
}
/******************************************************************************/
uint32_t dec8_state::screen_update_lastmisn(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, ((m_scroll2[0] << 8)+ m_scroll2[1]));
m_bg_tilemap->set_scrolly(0, ((m_scroll2[2] << 8)+ m_scroll2[3]));
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
m_spritegen_krn->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x400, 0);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
uint32_t dec8_state::screen_update_shackled(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, ((m_scroll2[0] << 8) + m_scroll2[1]));
m_bg_tilemap->set_scrolly(0, ((m_scroll2[2] << 8) + m_scroll2[3]));
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER1 | 0, 0);
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER1 | 1, 0);
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER0 | 0, 0);
m_spritegen_krn->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x400, 0);
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER0 | 1, 0);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
TILEMAP_MAPPER_MEMBER(dec8_state::lastmisn_scan_rows)
{
/* logical (col,row) -> memory offset */
return ((col & 0x0f) + ((row & 0x0f) << 4)) + ((col & 0x10) << 4) + ((row & 0x10) << 5);
}
TILE_GET_INFO_MEMBER(dec8_state::get_lastmisn_tile_info)
{
int offs = tile_index * 2;
int tile = m_bg_data[offs + 1] + (m_bg_data[offs] << 8);
int color = tile >> 12;
if (color & 8 && m_game_uses_priority)
tileinfo.category = 1;
else
tileinfo.category = 0;
SET_TILE_INFO_MEMBER(2,
tile & 0xfff,
color,
0);
}
TILE_GET_INFO_MEMBER(dec8_state::get_lastmisn_fix_tile_info)
{
int offs = tile_index << 1;
int tile = m_videoram[offs + 1] + (m_videoram[offs] << 8);
int color = (tile & 0xc000) >> 14;
SET_TILE_INFO_MEMBER(0,
tile&0xfff,
color,
0);
}
VIDEO_START_MEMBER(dec8_state,lastmisn)
{
allocate_buffered_spriteram16();
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_lastmisn_tile_info),this), tilemap_mapper_delegate(FUNC(dec8_state::lastmisn_scan_rows),this), 16, 16, 32, 32);
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_lastmisn_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_game_uses_priority = 0;
}
VIDEO_START_MEMBER(dec8_state,shackled)
{
allocate_buffered_spriteram16();
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_lastmisn_tile_info),this), tilemap_mapper_delegate(FUNC(dec8_state::lastmisn_scan_rows),this), 16, 16, 32, 32);
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_lastmisn_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_bg_tilemap->set_transmask(0, 0x000f, 0xfff0); /* Bottom 12 pens */
m_game_uses_priority = 1;
}
/******************************************************************************/
uint32_t dec8_state::screen_update_srdarwin(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, (m_scroll2[0] << 8) + m_scroll2[1]);
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER1, 0);
srdarwin_draw_sprites(bitmap, cliprect, 0);
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER0, 0);
srdarwin_draw_sprites(bitmap, cliprect, 1);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
TILE_GET_INFO_MEMBER(dec8_state::get_srdarwin_fix_tile_info)
{
int tile = m_videoram[tile_index];
int color = 0; /* ? */
tileinfo.category = 0;
SET_TILE_INFO_MEMBER(0,
tile,
color,
0);
}
TILE_GET_INFO_MEMBER(dec8_state::get_srdarwin_tile_info)
{
int tile = m_bg_data[2 * tile_index + 1] + (m_bg_data[2 * tile_index] << 8);
int color = tile >> 12 & 3;
int bank;
tile = tile & 0x3ff;
bank = (tile / 0x100) + 2;
SET_TILE_INFO_MEMBER(bank,
tile,
color,
0);
tileinfo.group = color;
}
VIDEO_START_MEMBER(dec8_state,srdarwin)
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_srdarwin_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 32, 16);
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_srdarwin_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_bg_tilemap->set_transmask(0, 0xffff, 0x0000); //* draw as background only
m_bg_tilemap->set_transmask(1, 0x00ff, 0xff00); /* Bottom 8 pens */
m_bg_tilemap->set_transmask(2, 0x00ff, 0xff00); /* Bottom 8 pens */
m_bg_tilemap->set_transmask(3, 0x0000, 0xffff); //* draw as foreground only
}
/******************************************************************************/
uint32_t dec8_state::screen_update_gondo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, ((m_scroll2[0] << 8) + m_scroll2[1]));
m_bg_tilemap->set_scrolly(0, ((m_scroll2[2] << 8) + m_scroll2[3]));
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER1, 0);
m_spritegen_krn->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x400, 2);
m_bg_tilemap->draw(screen, bitmap, cliprect, TILEMAP_DRAW_LAYER0, 0);
m_spritegen_krn->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x400, 1);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
uint32_t dec8_state::screen_update_garyoret(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, ((m_scroll2[0] << 8) + m_scroll2[1]));
m_bg_tilemap->set_scrolly(0, ((m_scroll2[2] << 8) + m_scroll2[3]));
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
m_spritegen_krn->draw_sprites(bitmap, cliprect, m_buffered_spriteram16.get(), 0x400, 0);
m_bg_tilemap->draw(screen, bitmap, cliprect, 1, 0);
m_fix_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
TILE_GET_INFO_MEMBER(dec8_state::get_gondo_fix_tile_info)
{
int offs = tile_index * 2;
int tile = m_videoram[offs + 1] + (m_videoram[offs] << 8);
int color = (tile & 0x7000) >> 12;
SET_TILE_INFO_MEMBER(0,
tile&0xfff,
color,
0);
}
TILE_GET_INFO_MEMBER(dec8_state::get_gondo_tile_info)
{
int offs = tile_index * 2;
int tile = m_bg_data[offs + 1] + (m_bg_data[offs] << 8);
int color = tile>> 12;
if (color & 8 && m_game_uses_priority)
tileinfo.category = 1;
else
tileinfo.category = 0;
SET_TILE_INFO_MEMBER(2,
tile&0xfff,
color,
0);
}
VIDEO_START_MEMBER(dec8_state,gondo)
{
allocate_buffered_spriteram16();
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_gondo_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_gondo_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_bg_tilemap->set_transmask(0, 0x00ff, 0xff00); /* Bottom 8 pens */
m_game_uses_priority = 0;
}
VIDEO_START_MEMBER(dec8_state,garyoret)
{
allocate_buffered_spriteram16();
m_fix_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_gondo_fix_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dec8_state::get_gondo_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 32, 32);
m_fix_tilemap->set_transparent_pen(0);
m_game_uses_priority = 1;
}
/******************************************************************************/