mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
malzak.cpp: convert playfield to tilemap, improve playfield colors, add playfield tile bank, add base mixing and priority, misc cleanups [Angelo Salese]
This commit is contained in:
parent
d8c098b24d
commit
ed55a9d407
@ -25,11 +25,14 @@
|
||||
0x1700 - 0x17ff | Work RAM - contains hiscore table, coin count
|
||||
0x1800 - 0x1fff | SAA 5050 video RAM
|
||||
|
||||
TODO - I/O ports (0x00 for sprite->background collisions)
|
||||
sound (2x SN76477)
|
||||
playfield graphics may be banked, tiles above 0x1f are incorrect
|
||||
sprite->sprite collisions aren't quite perfect
|
||||
(you can often fly through flying missiles)
|
||||
TODO:
|
||||
- implement sprite-playfield collisions;
|
||||
- sprite-playfield colors are dubious at best;
|
||||
- Tiles may be flipped for playfield in final stage;
|
||||
- improve gfx layers superimposing, honor PAL timings;
|
||||
- sound (2x SN76477)
|
||||
- sprite->sprite collisions aren't quite perfect
|
||||
(you can often fly through flying missiles) <- does this still occur -AS?
|
||||
|
||||
Notes:
|
||||
- Test mode in Malzak II should be enabled by setting a POT to position
|
||||
@ -111,7 +114,7 @@ void malzak_state::malzak_map(address_map &map)
|
||||
map(0x1400, 0x14ff).mirror(0x6000).rw(m_s2636[0], FUNC(s2636_device::read_data), FUNC(s2636_device::write_data));
|
||||
map(0x14cb, 0x14cb).mirror(0x6000).r(FUNC(malzak_state::fake_VRLE_r));
|
||||
map(0x1500, 0x15ff).mirror(0x6000).rw(m_s2636[1], FUNC(s2636_device::read_data), FUNC(s2636_device::write_data));
|
||||
map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::malzak_playfield_w));
|
||||
map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::playfield_w));
|
||||
map(0x1700, 0x17ff).mirror(0x6000).ram();
|
||||
map(0x1800, 0x1fff).mirror(0x6000).ram().share("videoram");
|
||||
map(0x2000, 0x2fff).rom();
|
||||
@ -133,7 +136,7 @@ void malzak_state::malzak2_map(address_map &map)
|
||||
map(0x14cb, 0x14cb).mirror(0x6000).r(FUNC(malzak_state::fake_VRLE_r));
|
||||
map(0x14cc, 0x14cc).mirror(0x6000).r(FUNC(malzak_state::s2636_portA_r));
|
||||
map(0x1500, 0x15ff).mirror(0x6000).rw(m_s2636[1], FUNC(s2636_device::read_data), FUNC(s2636_device::write_data));
|
||||
map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::malzak_playfield_w));
|
||||
map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::playfield_w));
|
||||
map(0x1700, 0x17ff).mirror(0x6000).ram().share("nvram");
|
||||
map(0x1800, 0x1fff).mirror(0x6000).ram().share("videoram");
|
||||
map(0x2000, 0x2fff).rom();
|
||||
@ -144,7 +147,7 @@ void malzak_state::malzak2_map(address_map &map)
|
||||
|
||||
READ8_MEMBER(malzak_state::s2650_data_r)
|
||||
{
|
||||
popmessage("S2650 data port read");
|
||||
// popmessage("S2650 data port read");
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
@ -158,22 +161,25 @@ WRITE8_MEMBER(malzak_state::port40_w)
|
||||
// the selected version
|
||||
// logerror("%s S2650: port 0x40 write: 0x%02x\n", machine().describe_context(), data);
|
||||
m_mainbank->set_entry((data & 0x40) >> 6);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(malzak_state::port60_w)
|
||||
{
|
||||
m_malzak_x = data;
|
||||
// logerror("I/O: port 0x60 write 0x%02x\n", data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(malzak_state::portc0_w)
|
||||
{
|
||||
m_malzak_y = data;
|
||||
// logerror("I/O: port 0xc0 write 0x%02x\n", data);
|
||||
// bit 7 is set at final stage
|
||||
u8 gfx_bank = ((data & 0x80) >> 7);
|
||||
if (m_playfield_bank != gfx_bank)
|
||||
{
|
||||
m_playfield_bank = gfx_bank;
|
||||
m_playfield_tilemap->mark_all_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(malzak_state::collision_r)
|
||||
{
|
||||
// s2636 (0 only?) <-> tilemap collision detection
|
||||
// yyyy ---- y collision
|
||||
// 0100 -> upper tilemap border (pixel 160)
|
||||
// 1101 -> lower (pixel 448)
|
||||
// pix / 32 = suggested value+1
|
||||
// ---- xxxx x collision
|
||||
// TODO: verify scroll offsets
|
||||
|
||||
// High 4 bits seem to refer to the row affected.
|
||||
if(++m_collision_counter > 15)
|
||||
m_collision_counter = 0;
|
||||
@ -259,41 +265,22 @@ static const gfx_layout charlayout =
|
||||
|
||||
|
||||
static GFXDECODE_START( gfx_malzak )
|
||||
GFXDECODE_ENTRY( "gfx1", 0x0000, charlayout, 0, 16 )
|
||||
GFXDECODE_ENTRY( "gfx1", 0x0000, charlayout, 0, 16*16 )
|
||||
GFXDECODE_END
|
||||
|
||||
|
||||
void malzak_state::malzak_palette(palette_device &palette) const
|
||||
{
|
||||
for (int i = 0; i < 8 * 8; i++)
|
||||
{
|
||||
palette.set_pen_color(i * 2 + 0, pal1bit(i >> 3), pal1bit(i >> 4), pal1bit(i >> 5));
|
||||
palette.set_pen_color(i * 2 + 1, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
READ8_MEMBER(malzak_state::videoram_r)
|
||||
{
|
||||
return m_videoram[offset];
|
||||
}
|
||||
|
||||
void malzak_state::machine_start()
|
||||
{
|
||||
m_mainbank->configure_entries(0, 2, memregion("user2")->base(), 0x400);
|
||||
|
||||
save_item(NAME(m_playfield_code));
|
||||
save_item(NAME(m_malzak_x));
|
||||
save_item(NAME(m_malzak_y));
|
||||
save_item(NAME(m_scrollx));
|
||||
save_item(NAME(m_scrolly));
|
||||
save_item(NAME(m_collision_counter));
|
||||
}
|
||||
|
||||
void malzak_state::machine_reset()
|
||||
{
|
||||
std::fill(std::begin(m_playfield_code), std::end(m_playfield_code), 0);
|
||||
|
||||
m_malzak_x = 0;
|
||||
m_malzak_y = 0;
|
||||
}
|
||||
|
||||
void malzak_state::malzak(machine_config &config)
|
||||
@ -307,6 +294,7 @@ void malzak_state::malzak(machine_config &config)
|
||||
|
||||
/* video hardware */
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
// TODO: convert to PAL set_raw
|
||||
m_screen->set_refresh_hz(50);
|
||||
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500));
|
||||
m_screen->set_size(480, 512); /* vert size is a guess */
|
||||
@ -314,7 +302,7 @@ void malzak_state::malzak(machine_config &config)
|
||||
m_screen->set_screen_update(FUNC(malzak_state::screen_update));
|
||||
|
||||
GFXDECODE(config, m_gfxdecode, m_palette, gfx_malzak);
|
||||
PALETTE(config, m_palette, FUNC(malzak_state::malzak_palette), 128);
|
||||
PALETTE(config, m_palette, FUNC(malzak_state::palette_init), 128);
|
||||
|
||||
S2636(config, m_s2636[0], 0);
|
||||
m_s2636[0]->set_offsets(0, -16); // -8, -16
|
||||
@ -415,5 +403,5 @@ ROM_START( malzak2 )
|
||||
ROM_END
|
||||
|
||||
|
||||
GAME( 19??, malzak, 0, malzak, malzak, malzak_state, empty_init, ROT0, "Kitronix", "Malzak", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
|
||||
GAME( 19??, malzak2, malzak, malzak2, malzak2, malzak_state, empty_init, ROT0, "Kitronix", "Malzak II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
|
||||
GAME( 19??, malzak, 0, malzak, malzak, malzak_state, empty_init, ROT0, "Kitronix", "Malzak", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE )
|
||||
GAME( 19??, malzak2, malzak, malzak2, malzak2, malzak_state, empty_init, ROT0, "Kitronix", "Malzak II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE )
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "video/saa5050.h"
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
#include "tilemap.h"
|
||||
|
||||
class malzak_state : public driver_device
|
||||
{
|
||||
@ -48,13 +49,6 @@ private:
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_memory_bank m_mainbank;
|
||||
/* misc */
|
||||
// int playfield_x[256];
|
||||
// int playfield_y[256];
|
||||
int m_playfield_code[256];
|
||||
int m_malzak_x;
|
||||
int m_malzak_y;
|
||||
int m_collision_counter;
|
||||
|
||||
DECLARE_READ8_MEMBER(fake_VRLE_r);
|
||||
DECLARE_READ8_MEMBER(s2636_portA_r);
|
||||
@ -63,16 +57,27 @@ private:
|
||||
DECLARE_WRITE8_MEMBER(port60_w);
|
||||
DECLARE_WRITE8_MEMBER(portc0_w);
|
||||
DECLARE_READ8_MEMBER(collision_r);
|
||||
DECLARE_WRITE8_MEMBER(malzak_playfield_w);
|
||||
DECLARE_WRITE8_MEMBER(playfield_w);
|
||||
DECLARE_READ8_MEMBER(videoram_r);
|
||||
|
||||
void malzak_palette(palette_device &palette) const;
|
||||
void palette_init(palette_device &palette) const;
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
virtual void video_start() override;
|
||||
|
||||
void malzak2_map(address_map &map);
|
||||
void malzak_data_map(address_map &map);
|
||||
void malzak_io_map(address_map &map);
|
||||
void malzak_map(address_map &map);
|
||||
|
||||
TILE_GET_INFO_MEMBER(get_tile_info);
|
||||
std::unique_ptr<bitmap_rgb32> m_trom_bitmap;
|
||||
std::unique_ptr<bitmap_rgb32> m_playfield_bitmap;
|
||||
tilemap_t *m_playfield_tilemap;
|
||||
int m_playfield_code[256];
|
||||
int m_scrollx;
|
||||
int m_scrolly;
|
||||
int m_collision_counter;
|
||||
u8 m_playfield_bank;
|
||||
};
|
||||
|
||||
#endif // MAME_INCLUDES_MALZAK_H
|
||||
|
@ -17,68 +17,100 @@
|
||||
#include "emu.h"
|
||||
#include "includes/malzak.h"
|
||||
|
||||
void malzak_state::palette_init(palette_device &palette) const
|
||||
{
|
||||
for (int i = 0; i < 8 * 8; i++)
|
||||
{
|
||||
palette.set_pen_color(i * 2 + 0, pal1bit(i >> 3), pal1bit(i >> 4), pal1bit(i >> 5));
|
||||
palette.set_pen_color(i * 2 + 1, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(malzak_state::videoram_r)
|
||||
{
|
||||
return m_videoram[offset];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(malzak_state::port60_w)
|
||||
{
|
||||
m_scrollx = data;
|
||||
// logerror("I/O: port 0x60 write 0x%02x\n", data);
|
||||
m_playfield_tilemap->set_scrollx(0, m_scrollx + 48);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(malzak_state::portc0_w)
|
||||
{
|
||||
m_scrolly = data;
|
||||
// logerror("I/O: port 0xc0 write 0x%02x\n", data);
|
||||
m_playfield_tilemap->set_scrolly(0, m_scrolly);
|
||||
}
|
||||
|
||||
//TODO: how readback works with this arrangement? Never occurs in-game
|
||||
WRITE8_MEMBER(malzak_state::playfield_w)
|
||||
{
|
||||
int tile = ((m_scrollx / 16) * 16) + (offset / 16);
|
||||
|
||||
// m_playfield_x[tile] = m_malzak_x / 16;
|
||||
// m_playfield_y[tile] = m_malzak_y;
|
||||
m_playfield_code[tile] = data;
|
||||
m_playfield_tilemap->mark_tile_dirty(tile);
|
||||
// POST only, adds to the scrollx base address?
|
||||
// if (offset & 0xf)
|
||||
// popmessage("GFX: 0x16%02x write 0x%02x\n", offset, data);
|
||||
}
|
||||
|
||||
TILE_GET_INFO_MEMBER(malzak_state::get_tile_info)
|
||||
{
|
||||
u8 code = (m_playfield_code[tile_index] & 0x1f) | (m_playfield_bank << 5);
|
||||
u8 color = ((m_playfield_code[tile_index] & 0xe0) >> 5);
|
||||
tileinfo.set(0, code, color, 0);
|
||||
}
|
||||
|
||||
void malzak_state::video_start()
|
||||
{
|
||||
int width = m_screen->width();
|
||||
int height = m_screen->height();
|
||||
m_trom_bitmap = std::make_unique<bitmap_rgb32>(width, height);
|
||||
m_playfield_bitmap = std::make_unique<bitmap_rgb32>(width, height);
|
||||
m_playfield_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(malzak_state::get_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 16, 16);
|
||||
}
|
||||
|
||||
uint32_t malzak_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
const rgb_t *palette = m_palette->palette()->entry_list_raw();
|
||||
|
||||
bitmap.fill(rgb_t::black(), cliprect);
|
||||
|
||||
m_trom->screen_update(screen, bitmap, cliprect);
|
||||
|
||||
// playfield - not sure exactly how this works...
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
int sx = ((x * 16 - 48) - m_malzak_x) * 2;
|
||||
int sy = ((y * 16) - m_malzak_y) * 2;
|
||||
|
||||
if (sx < -271*2)
|
||||
sx += 512*2;
|
||||
if (sx < -15*2)
|
||||
sx += 256*2;
|
||||
|
||||
m_gfxdecode->gfx(0)->zoom_transpen(bitmap,cliprect, m_playfield_code[x * 16 + y], 2, 0, 0, sx, sy, 0x20000, 0x20000, 0);
|
||||
}
|
||||
|
||||
/* update the S2636 chips */
|
||||
// prepare bitmaps
|
||||
m_trom->screen_update(screen, *m_trom_bitmap, cliprect);
|
||||
m_playfield_tilemap->draw(screen, *m_playfield_bitmap, cliprect, 0, 0);
|
||||
bitmap_ind16 const &s2636_0_bitmap = m_s2636[0]->update(cliprect);
|
||||
bitmap_ind16 const &s2636_1_bitmap = m_s2636[1]->update(cliprect);
|
||||
|
||||
/* copy the S2636 images into the main bitmap */
|
||||
// Superimpose
|
||||
// TODO: update for PAL size
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
|
||||
{
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y / 2; y++)
|
||||
int sy = y / 2;
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x; ++x)
|
||||
{
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x / 2; x++)
|
||||
{
|
||||
int pixel0 = s2636_0_bitmap.pix16(y, x);
|
||||
int pixel1 = s2636_1_bitmap.pix16(y, x);
|
||||
|
||||
if (S2636_IS_PIXEL_DRAWN(pixel0)) {
|
||||
bitmap.pix32(y*2, x*2) = palette[S2636_PIXEL_COLOR(pixel0)];
|
||||
bitmap.pix32(y*2+1, x*2) = palette[S2636_PIXEL_COLOR(pixel0)];
|
||||
bitmap.pix32(y*2, x*2+1) = palette[S2636_PIXEL_COLOR(pixel0)];
|
||||
bitmap.pix32(y*2+1, x*2+1) = palette[S2636_PIXEL_COLOR(pixel0)];
|
||||
}
|
||||
|
||||
if (S2636_IS_PIXEL_DRAWN(pixel1)) {
|
||||
bitmap.pix32(y*2, x*2) = palette[S2636_PIXEL_COLOR(pixel1)];
|
||||
bitmap.pix32(y*2+1, x*2) = palette[S2636_PIXEL_COLOR(pixel1)];
|
||||
bitmap.pix32(y*2, x*2+1) = palette[S2636_PIXEL_COLOR(pixel1)];
|
||||
bitmap.pix32(y*2+1, x*2+1) = palette[S2636_PIXEL_COLOR(pixel1)];
|
||||
}
|
||||
}
|
||||
int sx = x / 2;
|
||||
int s2636_pix_0 = s2636_0_bitmap.pix16(sy, sx);
|
||||
int s2636_pix_1 = s2636_1_bitmap.pix16(sy, sx);
|
||||
rgb_t trom_pix = m_trom_bitmap->pix32(y, x);
|
||||
rgb_t play_pix = m_playfield_bitmap->pix32(sy, sx);
|
||||
|
||||
// SAA5050 > s2636[1] > s2636[0] > playfield
|
||||
if (trom_pix != rgb_t::black())
|
||||
bitmap.pix32(y, x) = trom_pix;
|
||||
else if (S2636_IS_PIXEL_DRAWN(s2636_pix_1))
|
||||
bitmap.pix32(y, x) = palette[S2636_PIXEL_COLOR(s2636_pix_1)];
|
||||
else if (S2636_IS_PIXEL_DRAWN(s2636_pix_0))
|
||||
bitmap.pix32(y, x) = palette[S2636_PIXEL_COLOR(s2636_pix_0)];
|
||||
else
|
||||
bitmap.pix32(y, x) = play_pix;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(malzak_state::malzak_playfield_w)
|
||||
{
|
||||
int tile = ((m_malzak_x / 16) * 16) + (offset / 16);
|
||||
|
||||
// m_playfield_x[tile] = m_malzak_x / 16;
|
||||
// m_playfield_y[tile] = m_malzak_y;
|
||||
m_playfield_code[tile] = (data & 0x1f);
|
||||
logerror("GFX: 0x16%02x write 0x%02x\n", offset, data);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user