// license:BSD-3-Clause // copyright-holders:Stefan Jokisch /*************************************************************************** Atari Tank 8 video emulation ***************************************************************************/ #include "emu.h" #include "includes/tank8.h" void tank8_state::tank8_palette(palette_device &palette) const { palette.set_indirect_color(8, rgb_t(0x00, 0x00, 0x00)); palette.set_indirect_color(9, rgb_t(0xff, 0xff, 0xff)); for (int i = 0; i < 8; i++) { palette.set_pen_indirect(2 * i + 0, 8); palette.set_pen_indirect(2 * i + 1, i); } /* walls */ palette.set_pen_indirect(0x10, 8); palette.set_pen_indirect(0x11, 9); /* mines */ palette.set_pen_indirect(0x12, 8); palette.set_pen_indirect(0x13, 9); } void tank8_state::set_pens() { if (*m_team & 0x01) { m_palette->set_indirect_color(0, rgb_t(0xff, 0x00, 0x00)); /* red */ m_palette->set_indirect_color(1, rgb_t(0x00, 0x00, 0xff)); /* blue */ m_palette->set_indirect_color(2, rgb_t(0xff, 0xff, 0x00)); /* yellow */ m_palette->set_indirect_color(3, rgb_t(0x00, 0xff, 0x00)); /* green */ m_palette->set_indirect_color(4, rgb_t(0xff, 0x00, 0xff)); /* magenta */ m_palette->set_indirect_color(5, rgb_t(0xe0, 0xc0, 0x70)); /* puce */ m_palette->set_indirect_color(6, rgb_t(0x00, 0xff, 0xff)); /* cyan */ m_palette->set_indirect_color(7, rgb_t(0xff, 0xaa, 0xaa)); /* pink */ } else { m_palette->set_indirect_color(0, rgb_t(0xff, 0x00, 0x00)); /* red */ m_palette->set_indirect_color(2, rgb_t(0xff, 0x00, 0x00)); /* red */ m_palette->set_indirect_color(4, rgb_t(0xff, 0x00, 0x00)); /* red */ m_palette->set_indirect_color(6, rgb_t(0xff, 0x00, 0x00)); /* red */ m_palette->set_indirect_color(1, rgb_t(0x00, 0x00, 0xff)); /* blue */ m_palette->set_indirect_color(3, rgb_t(0x00, 0x00, 0xff)); /* blue */ m_palette->set_indirect_color(5, rgb_t(0x00, 0x00, 0xff)); /* blue */ m_palette->set_indirect_color(7, rgb_t(0x00, 0x00, 0xff)); /* blue */ } } WRITE8_MEMBER(tank8_state::video_ram_w) { m_video_ram[offset] = data; m_tilemap->mark_tile_dirty(offset); } TILE_GET_INFO_MEMBER(tank8_state::get_tile_info) { uint8_t code = m_video_ram[tile_index]; int color = 0; if ((code & 0x38) == 0x28) { if ((code & 7) != 3) color = 8; /* walls */ else color = 9; /* mines */ } else { if (tile_index & 0x010) color |= 1; if (code & 0x80) color |= 2; if (tile_index & 0x200) color |= 4; } SET_TILE_INFO_MEMBER(code >> 7, code, color, (code & 0x40) ? (TILE_FLIPX | TILE_FLIPY) : 0); } void tank8_state::video_start() { m_collision_timer = timer_alloc(TIMER_COLLISION); m_screen->register_screen_bitmap(m_helper1); m_screen->register_screen_bitmap(m_helper2); m_screen->register_screen_bitmap(m_helper3); m_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tank8_state::get_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 32, 32); // VBLANK starts on scanline #256 and ends on scanline #24 m_tilemap->set_scrolly(0, 2 * 24); save_item(NAME(m_collision_index)); } int tank8_state::get_x_pos(int n) { return 498 - m_pos_h_ram[n] - 2 * (m_pos_d_ram[n] & 128); /* ? */ } int tank8_state::get_y_pos(int n) { return 2 * m_pos_v_ram[n] - 62; } void tank8_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect) { int i; for (i = 0; i < 8; i++) { uint8_t code = ~m_pos_d_ram[i]; int x = get_x_pos(i); int y = get_y_pos(i); m_gfxdecode->gfx((code & 0x04) ? 2 : 3)->transpen(bitmap,cliprect, code & 0x03, i, code & 0x10, code & 0x08, x, y, 0); } } void tank8_state::draw_bullets(bitmap_ind16 &bitmap, const rectangle &cliprect) { int i; for (i = 0; i < 8; i++) { int x = get_x_pos(8 + i); int y = get_y_pos(8 + i); x -= 4; /* ? */ rectangle rect(x, x + 3, y, y + 4); rect &= cliprect; bitmap.fill((i << 1) | 0x01, rect); } } void tank8_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch (id) { case TIMER_COLLISION: set_collision(param); break; default: throw emu_fatalerror("Unknown id in tank8_state::device_timer"); } } uint32_t tank8_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { set_pens(); m_tilemap->draw(screen, bitmap, cliprect, 0, 0); draw_sprites(bitmap, cliprect); draw_bullets(bitmap, cliprect); return 0; } WRITE_LINE_MEMBER(tank8_state::screen_vblank) { // on falling edge if (!state) { int x; int y; const rectangle &visarea = m_screen->visible_area(); m_tilemap->draw(*m_screen, m_helper1, visarea, 0, 0); m_helper2.fill(8, visarea); m_helper3.fill(8, visarea); draw_sprites(m_helper2, visarea); draw_bullets(m_helper3, visarea); for (y = visarea.top(); y <= visarea.bottom(); y++) { int _state = 0; const uint16_t* p1 = &m_helper1.pix16(y); const uint16_t* p2 = &m_helper2.pix16(y); const uint16_t* p3 = &m_helper3.pix16(y); if ((m_screen->frame_number() ^ y) & 1) continue; /* video display is interlaced */ for (x = visarea.left(); x <= visarea.right(); x++) { uint8_t index; /* neither wall nor mine */ if ((p1[x] != 0x11) && (p1[x] != 0x13)) { _state = 0; continue; } /* neither tank nor bullet */ if ((p2[x] == 8) && (p3[x] == 8)) { _state = 0; continue; } /* bullets cannot hit mines */ if ((p3[x] != 8) && (p1[x] == 0x13)) { _state = 0; continue; } if (_state) continue; if (p3[x] != 8) { index = ((p3[x] & ~0x01) >> 1) | 0x18; if (1) index |= 0x20; if (0) index |= 0x40; if (1) index |= 0x80; } else { int sprite_num = (p2[x] & ~0x01) >> 1; index = sprite_num | 0x10; if (p1[x] == 0x11) index |= 0x20; if (y - get_y_pos(sprite_num) >= 8) index |= 0x40; /* collision on bottom side */ if (x - get_x_pos(sprite_num) >= 8) index |= 0x80; /* collision on right side */ } m_collision_timer->adjust(m_screen->time_until_pos(y, x), index); _state = 1; } } } }