// license:BSD-3-Clause
// copyright-holders:David Haywood,Bryan McPhail
/***************************************************************************
Tumblepop (bootlegs) and similar hardware
Video emulation - Bryan McPhail, mish@tendril.co.uk
*********************************************************************
The original uses Data East custom chip 55 for backgrounds,
custom chip 52 for sprites. The bootlegs use generic chips to perform similar
functions
Tumblepop is one of few games to take advantage of the playfields ability
to switch between 8*8 tiles and 16*16 tiles.
***************************************************************************/
#include "emu.h"
#include "includes/tumbleb.h"
/******************************************************************************/
/******************************************************************************/
WRITE16_MEMBER(tumbleb_state::bcstory_tilebank_w)
{
data &= mem_mask;
m_tilebank = data;
m_pf1_tilemap->mark_all_dirty();
m_pf1_alt_tilemap->mark_all_dirty();
m_pf2_tilemap->mark_all_dirty();
}
WRITE16_MEMBER(tumbleb_state::chokchok_tilebank_w)
{
data &= mem_mask;
m_tilebank = data << 1;
m_pf1_tilemap->mark_all_dirty();
m_pf1_alt_tilemap->mark_all_dirty();
m_pf2_tilemap->mark_all_dirty();
}
WRITE16_MEMBER(tumbleb_state::wlstar_tilebank_w)
{
/* it just writes 0000 or ffff */
m_tilebank = data & 0x4000;
m_pf1_tilemap->mark_all_dirty();
m_pf1_alt_tilemap->mark_all_dirty();
m_pf2_tilemap->mark_all_dirty();
}
WRITE16_MEMBER(tumbleb_state::suprtrio_tilebank_w)
{
data &= mem_mask;
m_tilebank = data << 14; // shift it here, makes using bcstory_tilebank easier
m_pf1_tilemap->mark_all_dirty();
m_pf1_alt_tilemap->mark_all_dirty();
m_pf2_tilemap->mark_all_dirty();
}
WRITE16_MEMBER(tumbleb_state::tumblepb_pf1_data_w)
{
COMBINE_DATA(&m_pf1_data[offset]);
m_pf1_tilemap->mark_tile_dirty(offset);
m_pf1_alt_tilemap->mark_tile_dirty(offset);
}
WRITE16_MEMBER(tumbleb_state::tumblepb_pf2_data_w)
{
COMBINE_DATA(&m_pf2_data[offset]);
m_pf2_tilemap->mark_tile_dirty(offset);
if (m_pf2_alt_tilemap)
m_pf2_alt_tilemap->mark_tile_dirty(offset);
}
WRITE16_MEMBER(tumbleb_state::fncywld_pf1_data_w)
{
COMBINE_DATA(&m_pf1_data[offset]);
m_pf1_tilemap->mark_tile_dirty(offset / 2);
m_pf1_alt_tilemap->mark_tile_dirty(offset / 2);
}
WRITE16_MEMBER(tumbleb_state::fncywld_pf2_data_w)
{
COMBINE_DATA(&m_pf2_data[offset]);
m_pf2_tilemap->mark_tile_dirty(offset / 2);
}
WRITE16_MEMBER(tumbleb_state::tumblepb_control_0_w)
{
COMBINE_DATA(&m_control_0[offset]);
}
WRITE16_MEMBER(tumbleb_state::pangpang_pf1_data_w)
{
COMBINE_DATA(&m_pf1_data[offset]);
m_pf1_tilemap->mark_tile_dirty(offset / 2);
m_pf1_alt_tilemap->mark_tile_dirty(offset / 2);
}
WRITE16_MEMBER(tumbleb_state::pangpang_pf2_data_w)
{
COMBINE_DATA(&m_pf2_data[offset]);
m_pf2_tilemap->mark_tile_dirty(offset / 2);
if (m_pf2_alt_tilemap)
m_pf2_alt_tilemap->mark_tile_dirty(offset / 2);
}
/******************************************************************************/
TILEMAP_MAPPER_MEMBER(tumbleb_state::tumblep_scan)
{
/* logical (col,row) -> memory offset */
return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x60) << 5);
}
inline void tumbleb_state::get_bg_tile_info( tile_data &tileinfo, int tile_index, int gfx_bank, uint16_t *gfx_base)
{
int data = gfx_base[tile_index];
SET_TILE_INFO_MEMBER(gfx_bank,
(data & 0x0fff) | (m_tilebank >> 2),
data >> 12,
0);
}
TILE_GET_INFO_MEMBER(tumbleb_state::get_bg1_tile_info){ get_bg_tile_info(tileinfo, tile_index, 2, m_pf1_data); }
TILE_GET_INFO_MEMBER(tumbleb_state::get_bg2_tile_info){ get_bg_tile_info(tileinfo, tile_index, 1, m_pf2_data); }
TILE_GET_INFO_MEMBER(tumbleb_state::get_fg_tile_info)
{
int data = m_pf1_data[tile_index];
SET_TILE_INFO_MEMBER(0,
(data & 0x0fff) | m_tilebank,
data >> 12,
0);
}
inline void tumbleb_state::get_fncywld_bg_tile_info( tile_data &tileinfo, int tile_index, int gfx_bank, uint16_t *gfx_base)
{
int data = gfx_base[tile_index * 2];
int attr = gfx_base[tile_index * 2 + 1];
SET_TILE_INFO_MEMBER(gfx_bank,
data & 0x1fff,
attr & 0x1f,
0);
}
TILE_GET_INFO_MEMBER(tumbleb_state::get_fncywld_bg1_tile_info){ get_fncywld_bg_tile_info(tileinfo, tile_index, 2, m_pf1_data); }
TILE_GET_INFO_MEMBER(tumbleb_state::get_fncywld_bg2_tile_info){ get_fncywld_bg_tile_info(tileinfo, tile_index, 1, m_pf2_data); }
TILE_GET_INFO_MEMBER(tumbleb_state::get_fncywld_fg_tile_info)
{
int data = m_pf1_data[tile_index * 2];
int attr = m_pf1_data[tile_index * 2 + 1];
SET_TILE_INFO_MEMBER(0,
data & 0x1fff,
attr & 0x1f,
0);
}
inline void tumbleb_state::pangpang_get_bg_tile_info( tile_data &tileinfo, int tile_index, int gfx_bank, uint16_t *gfx_base )
{
int data = gfx_base[tile_index * 2 + 1];
int attr = gfx_base[tile_index * 2];
SET_TILE_INFO_MEMBER(gfx_bank,
data & 0x1fff,
(attr >>12) & 0xf,
0);
}
inline void tumbleb_state::pangpang_get_bg2x_tile_info( tile_data &tileinfo, int tile_index, int gfx_bank, uint16_t *gfx_base )
{
int data = gfx_base[tile_index * 2 + 1];
int attr = gfx_base[tile_index * 2];
SET_TILE_INFO_MEMBER(gfx_bank,
(data & 0xfff) + 0x1000,
(attr >>12) & 0xf,
0);
}
TILE_GET_INFO_MEMBER(tumbleb_state::pangpang_get_bg1_tile_info){ pangpang_get_bg_tile_info(tileinfo, tile_index, 2, m_pf1_data); }
TILE_GET_INFO_MEMBER(tumbleb_state::pangpang_get_bg2_tile_info){ pangpang_get_bg2x_tile_info(tileinfo, tile_index, 1, m_pf2_data); }
TILE_GET_INFO_MEMBER(tumbleb_state::pangpang_get_fg_tile_info)
{
int data = m_pf1_data[tile_index * 2 + 1];
int attr = m_pf1_data[tile_index * 2];
SET_TILE_INFO_MEMBER(0,
data & 0x1fff,
(attr >> 12)& 0x1f,
0);
}
void tumbleb_state::tumbleb_tilemap_redraw()
{
m_pf1_tilemap->mark_all_dirty();
m_pf1_alt_tilemap->mark_all_dirty();
m_pf2_tilemap->mark_all_dirty();
if (m_pf2_alt_tilemap)
m_pf2_alt_tilemap->mark_all_dirty();
}
VIDEO_START_MEMBER(tumbleb_state,pangpang)
{
m_pf1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::pangpang_get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_pf1_alt_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::pangpang_get_bg1_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::pangpang_get_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf1_tilemap->set_transparent_pen(0);
m_pf1_alt_tilemap->set_transparent_pen(0);
machine().save().register_postload(save_prepost_delegate(FUNC(tumbleb_state::tumbleb_tilemap_redraw), this));
}
VIDEO_START_MEMBER(tumbleb_state,tumblepb)
{
m_pf1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_pf1_alt_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_bg1_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf1_tilemap->set_transparent_pen(0);
m_pf1_alt_tilemap->set_transparent_pen(0);
machine().save().register_postload(save_prepost_delegate(FUNC(tumbleb_state::tumbleb_tilemap_redraw), this));
}
VIDEO_START_MEMBER(tumbleb_state,sdfight)
{
m_pf1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64); // 64*64 to prevent bad tilemap wrapping? - check real behavior
m_pf1_alt_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_bg1_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf1_tilemap->set_transparent_pen(0);
m_pf1_alt_tilemap->set_transparent_pen(0);
machine().save().register_postload(save_prepost_delegate(FUNC(tumbleb_state::tumbleb_tilemap_redraw), this));
}
VIDEO_START_MEMBER(tumbleb_state,fncywld)
{
m_pf1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_fncywld_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_pf1_alt_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_fncywld_bg1_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_fncywld_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf1_tilemap->set_transparent_pen(15);
m_pf1_alt_tilemap->set_transparent_pen(15);
machine().save().register_postload(save_prepost_delegate(FUNC(tumbleb_state::tumbleb_tilemap_redraw), this));
}
VIDEO_START_MEMBER(tumbleb_state,suprtrio)
{
m_pf1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_pf1_alt_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_bg1_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tumbleb_state::get_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(tumbleb_state::tumblep_scan)), 16, 16, 64, 32);
m_pf1_alt_tilemap->set_transparent_pen(0);
machine().save().register_postload(save_prepost_delegate(FUNC(tumbleb_state::tumbleb_tilemap_redraw), this));
}
/******************************************************************************/
void tumbleb_state::tumbleb_draw_common(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pf1x_offs, int pf1y_offs, int pf2x_offs, int pf2y_offs)
{
m_pf1_tilemap->set_scrollx(0, m_control_0[1] + pf1x_offs);
m_pf1_tilemap->set_scrolly(0, m_control_0[2] + pf1y_offs);
m_pf1_alt_tilemap->set_scrollx(0, m_control_0[1] + pf1x_offs);
m_pf1_alt_tilemap->set_scrolly(0, m_control_0[2] + pf1y_offs);
m_pf2_tilemap->set_scrollx(0, m_control_0[3] + pf2x_offs);
m_pf2_tilemap->set_scrolly(0, m_control_0[4] + pf2y_offs);
m_pf2_tilemap->draw(screen, bitmap, cliprect, 0, 0);
if (m_control_0[6] & 0x80)
m_pf1_tilemap->draw(screen, bitmap, cliprect, 0, 0);
else
m_pf1_alt_tilemap->draw(screen, bitmap, cliprect, 0, 0);
m_sprgen->set_flip_screen(flip_screen() != 0);
m_sprgen->draw_sprites(bitmap, cliprect, m_spriteram, m_spriteram.bytes()/2);
}
uint32_t tumbleb_state::screen_update_tumblepb(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
if (flip_screen())
offs = 1;
else
offs = -1;
if (flip_screen())
offs2 = -3;
else
offs2 = -5;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_jumpkids(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
if (flip_screen())
offs = 1;
else
offs = -1;
if (flip_screen())
offs2 = -3;
else
offs2 = -5;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_semicom(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
if (flip_screen())
offs = 1;
else
offs = -1;
if (flip_screen())
offs2 = -3;
else
offs2 = -5;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_semicom_altoffsets(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offsx, offsy, offsx2;
flip_screen_set(m_control_0[0] & 0x80);
offsx = -1;
offsy = 2;
offsx2 = -5;
tumbleb_draw_common(screen, bitmap, cliprect, offsx2, 0, offsx, offsy);
return 0;
}
uint32_t tumbleb_state::screen_update_bcstory(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
/* not sure of this */
if (flip_screen())
offs = 1;
else
offs = 8;
/* not sure of this */
if (flip_screen())
offs2 = -3;
else
offs2 = 8;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_semibase(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
offs = -1;
offs2 = -2;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_sdfight(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
offs = -1;
offs2 = -5; // foreground scroll..
tumbleb_draw_common(screen, bitmap, cliprect, offs2, -16, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_fncywld(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
if (flip_screen())
offs = 1;
else
offs = -1;
if (flip_screen())
offs2 = -3;
else
offs2 = -5;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_pangpang(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int offs, offs2;
flip_screen_set(m_control_0[0] & 0x80);
if (flip_screen())
offs = 1;
else
offs = -1;
if (flip_screen())
offs2 = -3;
else
offs2 = -5;
tumbleb_draw_common(screen, bitmap, cliprect, offs2, 0, offs, 0);
return 0;
}
uint32_t tumbleb_state::screen_update_suprtrio(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_pf1_alt_tilemap->set_scrollx(0, -m_control[1] - 6);
m_pf1_alt_tilemap->set_scrolly(0, -m_control[2]);
m_pf2_tilemap->set_scrollx(0, -m_control[3] - 2);
m_pf2_tilemap->set_scrolly(0, -m_control[4]);
m_pf2_tilemap->draw(screen, bitmap, cliprect, 0, 0);
m_pf1_alt_tilemap->draw(screen, bitmap, cliprect, 0, 0);
m_sprgen->draw_sprites(bitmap, cliprect, m_spriteram, m_spriteram.bytes()/2);
return 0;
}