// license:BSD-3-Clause // copyright-holders:Zsolt Vasvari #include "emu.h" #include "includes/mermaid.h" void mermaid_state::common_palette(palette_device &palette) const { uint8_t const *const color_prom = memregion("proms")->base(); for (int i = 0; i < 0x40; i++) { int const r = 0x21 * BIT(color_prom[i], 0) + 0x47 * BIT(color_prom[i], 1) + 0x97 * BIT(color_prom[i], 2); int const g = 0x21 * BIT(color_prom[i], 3) + 0x47 * BIT(color_prom[i], 4) + 0x97 * BIT(color_prom[i], 5); int const b = 0x47 * BIT(color_prom[i], 6) + 0x97 * BIT(color_prom[i], 7); palette.set_indirect_color(i, rgb_t(r, g, b)); } } void mermaid_state::mermaid_palette(palette_device &palette) const { common_palette(palette); // blue background palette.set_indirect_color(0x40, rgb_t(0, 0, 0xff)); // char/sprite palette for (int i = 0; i < 0x40; i++) palette.set_pen_indirect(i, i); // background palette palette.set_pen_indirect(0x40, 0x20); palette.set_pen_indirect(0x41, 0x21); palette.set_pen_indirect(0x42, 0x40); palette.set_pen_indirect(0x43, 0x21); } void mermaid_state::rougien_palette(palette_device &palette) const { common_palette(palette); // black background palette.set_indirect_color(0x40, rgb_t(0, 0, 0)); // char/sprite palette for (int i = 0; i < 0x40; i++) palette.set_pen_indirect(i, i); // background palette palette.set_pen_indirect(0x40, 0x40); palette.set_pen_indirect(0x41, 0x00); palette.set_pen_indirect(0x42, 0x00); palette.set_pen_indirect(0x43, 0x02); } WRITE8_MEMBER(mermaid_state::mermaid_videoram2_w) { m_videoram2[offset] = data; m_bg_tilemap->mark_tile_dirty(offset); } WRITE8_MEMBER(mermaid_state::mermaid_videoram_w) { m_videoram[offset] = data; m_fg_tilemap->mark_tile_dirty(offset); } WRITE8_MEMBER(mermaid_state::mermaid_colorram_w) { m_colorram[offset] = data; m_fg_tilemap->mark_tile_dirty(offset); } WRITE_LINE_MEMBER(mermaid_state::flip_screen_x_w) { flip_screen_x_set(state); } WRITE_LINE_MEMBER(mermaid_state::flip_screen_y_w) { flip_screen_y_set(state); } WRITE8_MEMBER(mermaid_state::mermaid_bg_scroll_w) { m_bg_scrollram[offset] = data; m_bg_tilemap->set_scrolly(offset, data); } WRITE8_MEMBER(mermaid_state::mermaid_fg_scroll_w) { m_fg_scrollram[offset] = data; m_fg_tilemap->set_scrolly(offset, data); } WRITE_LINE_MEMBER(mermaid_state::rougien_gfxbankswitch1_w) { m_rougien_gfxbank1 = state; } WRITE_LINE_MEMBER(mermaid_state::rougien_gfxbankswitch2_w) { m_rougien_gfxbank2 = state; } READ8_MEMBER(mermaid_state::mermaid_collision_r) { /* collision register active LOW: with coll = spriteram[offs + 2] & 0xc0 Bit 0 - Sprite (coll = 0x40) - Sprite (coll = 0x00) Bit 1 - Sprite (coll = 0x40) - Foreground Bit 2 - Sprite (coll = 0x40) - Background Bit 3 - Sprite (coll = 0x80) - Sprite (coll = 0x00) Bit 4 Bit 5 Bit 6 - Sprite (coll = 0x40) - Sprite (coll = 0x80) Bit 7 */ int collision = 0xff; if (m_coll_bit0) collision ^= 0x01; if (m_coll_bit1) collision ^= 0x02; if (m_coll_bit2) collision ^= 0x04; if (m_coll_bit3) collision ^= 0x08; if (m_coll_bit6) collision ^= 0x40; return collision; } TILE_GET_INFO_MEMBER(mermaid_state::get_bg_tile_info) { int code = m_videoram2[tile_index]; int sx = tile_index % 32; int color = (sx >= 26) ? 0 : 1; SET_TILE_INFO_MEMBER(2, code, color, 0); } TILE_GET_INFO_MEMBER(mermaid_state::get_fg_tile_info) { int attr = m_colorram[tile_index]; int code = m_videoram[tile_index] + ((attr & 0x30) << 4); int color = attr & 0x0f; int flags = TILE_FLIPYX((attr & 0xc0) >> 6); code |= m_rougien_gfxbank1 * 0x2800; code |= m_rougien_gfxbank2 * 0x2400; SET_TILE_INFO_MEMBER(0, code, color, flags); } void mermaid_state::video_start() { m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(mermaid_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32); m_bg_tilemap->set_scroll_cols(32); m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(mermaid_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32); m_fg_tilemap->set_scroll_cols(32); m_fg_tilemap->set_transparent_pen(0); m_screen->register_screen_bitmap(m_helper); m_screen->register_screen_bitmap(m_helper2); } void mermaid_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect ) { const rectangle spritevisiblearea(0 * 8, 26 * 8 - 1, 2 * 8, 30 * 8 - 1); const rectangle flip_spritevisiblearea(6 * 8, 31 * 8 - 1, 2 * 8, 30 * 8 - 1); uint8_t *spriteram = m_spriteram; int offs; for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4) { int attr = spriteram[offs + 2]; int bank = (attr & 0x30) >> 4; int code = (spriteram[offs] & 0x3f) | (bank << 6); int color = attr & 0x0f; int flipx = spriteram[offs] & 0x40; int flipy = spriteram[offs] & 0x80; int sx = spriteram[offs + 3] + 1; int sy = 240 - spriteram[offs + 1]; if (sx >= 0xf0) sx -= 256; code |= m_rougien_gfxbank1 * 0x2800; code |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx = !flipx; sx = 240 - sx; } if (flip_screen_y()) { flipy = !flipy; sy = 240 - sy; } m_gfxdecode->gfx(1)->transpen(bitmap,(flip_screen_x() ? flip_spritevisiblearea : spritevisiblearea), code, color, flipx, flipy, sx, sy, 0); } } uint32_t mermaid_state::screen_update_mermaid(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0); draw_sprites(bitmap, cliprect); return 0; } uint8_t mermaid_state::collision_check( rectangle& rect ) { uint8_t data = 0; int x; int y; for (y = rect.top(); y <= rect.bottom(); y++) for (x = rect.left(); x <= rect.right(); x++) { uint16_t a = m_palette->pen_indirect(m_helper.pix16(y, x)) & 0x3f; uint16_t b = m_palette->pen_indirect(m_helper2.pix16(y, x)) & 0x3f; if (b) if (a) data |= 0x01; } return data; } void mermaid_state::collision_update() { const rectangle &visarea = m_screen->visible_area(); uint8_t *spriteram = m_spriteram; int offs, offs2; m_coll_bit0 = 0; m_coll_bit1 = 0; m_coll_bit2 = 0; m_coll_bit3 = 0; m_coll_bit6 = 0; // check for bit 0 (sprite-sprite), 1 (sprite-foreground), 2 (sprite-background) for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4) { int attr = spriteram[offs + 2]; int bank = (attr & 0x30) >> 4; int coll = (attr & 0xc0) >> 6; int code = (spriteram[offs] & 0x3f) | (bank << 6); int flipx = spriteram[offs] & 0x40; int flipy = spriteram[offs] & 0x80; int sx = spriteram[offs + 3] + 1; int sy = 240 - spriteram[offs + 1]; rectangle rect; if (coll != 1) continue; code |= m_rougien_gfxbank1 * 0x2800; code |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx = !flipx; sx = 240 - sx; } if (flip_screen_y()) { flipy = !flipy; sy = 240 - sy; } rect.set( sx, sx + m_gfxdecode->gfx(1)->width() - 1, sy, sy + m_gfxdecode->gfx(1)->height() - 1); rect &= visarea; // check collision sprite - background m_helper.fill(0, rect); m_helper2.fill(0, rect); m_bg_tilemap->draw(*m_screen, m_helper, rect, 0, 0); m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0); m_coll_bit2 |= collision_check(rect); // check collision sprite - foreground m_helper.fill(0, rect); m_helper2.fill(0, rect); m_fg_tilemap->draw(*m_screen, m_helper, rect, 0, 0); m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0); m_coll_bit1 |= collision_check(rect); // check collision sprite - sprite m_helper.fill(0, rect); m_helper2.fill(0, rect); for (offs2 = m_spriteram.bytes() - 4; offs2 >= 0; offs2 -= 4) if (offs != offs2) { int attr2 = spriteram[offs2 + 2]; int bank2 = (attr2 & 0x30) >> 4; int coll2 = (attr2 & 0xc0) >> 6; int code2 = (spriteram[offs2] & 0x3f) | (bank2 << 6); int flipx2 = spriteram[offs2] & 0x40; int flipy2 = spriteram[offs2] & 0x80; int sx2 = spriteram[offs2 + 3] + 1; int sy2 = 240 - spriteram[offs2 + 1]; if (coll2 != 0) continue; code2 |= m_rougien_gfxbank1 * 0x2800; code2 |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx2 = !flipx2; sx2 = 240 - sx2; } if (flip_screen_y()) { flipy2 = !flipy2; sy2 = 240 - sy2; } m_gfxdecode->gfx(1)->transpen(m_helper,rect, code2, 0, flipx2, flipy2, sx2, sy2, 0); } m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0); m_coll_bit0 |= collision_check(rect); } // check for bit 3 (sprite-sprite) for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4) { int attr = spriteram[offs + 2]; int bank = (attr & 0x30) >> 4; int coll = (attr & 0xc0) >> 6; int code = (spriteram[offs] & 0x3f) | (bank << 6); int flipx = spriteram[offs] & 0x40; int flipy = spriteram[offs] & 0x80; int sx = spriteram[offs + 3] + 1; int sy = 240 - spriteram[offs + 1]; rectangle rect; if (coll != 2) continue; code |= m_rougien_gfxbank1 * 0x2800; code |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx = !flipx; sx = 240 - sx; } if (flip_screen_y()) { flipy = !flipy; sy = 240 - sy; } rect.set( sx, sx + m_gfxdecode->gfx(1)->width() - 1, sy, sy + m_gfxdecode->gfx(1)->height() - 1); rect &= visarea; // check collision sprite - sprite m_helper.fill(0, rect); m_helper2.fill(0, rect); for (offs2 = m_spriteram.bytes() - 4; offs2 >= 0; offs2 -= 4) if (offs != offs2) { int attr2 = spriteram[offs2 + 2]; int bank2 = (attr2 & 0x30) >> 4; int coll2 = (attr2 & 0xc0) >> 6; int code2 = (spriteram[offs2] & 0x3f) | (bank2 << 6); int flipx2 = spriteram[offs2] & 0x40; int flipy2 = spriteram[offs2] & 0x80; int sx2 = spriteram[offs2 + 3] + 1; int sy2 = 240 - spriteram[offs2 + 1]; if (coll2 != 0) continue; code2 |= m_rougien_gfxbank1 * 0x2800; code2 |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx2 = !flipx2; sx2 = 240 - sx2; } if (flip_screen_y()) { flipy2 = !flipy2; sy2 = 240 - sy2; } m_gfxdecode->gfx(1)->transpen(m_helper,rect, code2, 0, flipx2, flipy2, sx2, sy2, 0); } m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0); m_coll_bit3 |= collision_check(rect); } // check for bit 6 for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4) { int attr = spriteram[offs + 2]; int bank = (attr & 0x30) >> 4; int coll = (attr & 0xc0) >> 6; int code = (spriteram[offs] & 0x3f) | (bank << 6); int flipx = spriteram[offs] & 0x40; int flipy = spriteram[offs] & 0x80; int sx = spriteram[offs + 3] + 1; int sy = 240 - spriteram[offs + 1]; rectangle rect; if (coll != 1) continue; code |= m_rougien_gfxbank1 * 0x2800; code |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx = !flipx; sx = 240 - sx; } if (flip_screen_y()) { flipy = !flipy; sy = 240 - sy; } rect.set( sx, sx + m_gfxdecode->gfx(1)->width() - 1, sy, sy + m_gfxdecode->gfx(1)->height() - 1); rect &= visarea; // check collision sprite - sprite m_helper.fill(0, rect); m_helper2.fill(0, rect); for (offs2 = m_spriteram.bytes() - 4; offs2 >= 0; offs2 -= 4) if (offs != offs2) { int attr2 = spriteram[offs2 + 2]; int bank2 = (attr2 & 0x30) >> 4; int coll2 = (attr2 & 0xc0) >> 6; int code2 = (spriteram[offs2] & 0x3f) | (bank2 << 6); int flipx2 = spriteram[offs2] & 0x40; int flipy2 = spriteram[offs2] & 0x80; int sx2 = spriteram[offs2 + 3] + 1; int sy2 = 240 - spriteram[offs2 + 1]; if (coll2 != 2) continue; code2 |= m_rougien_gfxbank1 * 0x2800; code2 |= m_rougien_gfxbank2 * 0x2400; if (flip_screen_x()) { flipx2 = !flipx2; sx2 = 240 - sx2; } if (flip_screen_y()) { flipy2 = !flipy2; sy2 = 240 - sy2; } m_gfxdecode->gfx(1)->transpen(m_helper,rect, code2, 0, flipx2, flipy2, sx2, sy2, 0); } m_gfxdecode->gfx(1)->transpen(m_helper2,rect, code, 0, flipx, flipy, sx, sy, 0); m_coll_bit6 |= collision_check(rect); } } WRITE_LINE_MEMBER(mermaid_state::screen_vblank_mermaid) { // rising edge if (state) { collision_update(); if (m_nmi_mask) m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); } }