// license:BSD-3-Clause
// copyright-holders:David Haywood
/***************************************************************************
Omori Battle Cross
driver by David Haywood
Stephh's notes :
- I don't know exactly how to call the "Free Play" Dip Switch 8(
Its effect is the following :
* you need to insert at least one credit and start a game
* when the game is over, you can start another games WITHOUT
inserting another coins
Note that the number of credits is decremented though.
Credits are BCD coded on 3 bytes (0x000000-0x999999) at addresses
0xa039 (LSB), 0xa03a and 0xa03b (MSB), but only the LSB is displayed.
- Setting the flipscreen dip to ON also hides the copyright message (?)
Notes from Tomasz Slanina:
Tile decoding:
Each 8x8 BG tile is defined by:
- 1 bit 8x8 mask (one tile - 8 consecutive bytes - user2 region)
- 4+4 bits of color ( one tile - 8 consecutive bytes - user1 region)
- bit 3 of color = brightness ?
Single mask byte defines one row of tile pixels (FG or BG)
Single color byte defines color of FG (4 bits) and color of BG (4 bits)
of high (odd address in user1) or low (even address in user1)
nibbles of two tile pixels rows.
Here's an example (single tile):
user2 user1 colors
----------------------------
00011100 0x32 33321144
00111100 0x41 33221144
00111100 0x32 33227744
00011000 0x47 33327444
00011000 0x56 55566555
00011000 0x56 55566555
00011000 0x84 88844777
00011000 0x74 88844777
TO DO :
- missing starfield
- game speed, its seems to be controlled by the IRQ's, how fast should it
be? firing seems frustratingly inconsistant (better with PORT_IMPULSE)
- BG tilemap palette bits (in most cases paltte 0 is used,
only highlights ( battlex logo, hiscore table) uses different palettes(?).
Current implementation gives different highlight colors than on real
hardware (i.e. battlex logo should have yellow highights)
****************************************************************************
Battle Cross (c)1982 Omori
CPU: Z80A
Sound: AY-3-8910
Other: 93419 (in socket marked 93219)
RAM: 4116(x12), 2114(x2), 2114(x6)
PROMS: none
XTAL: 10.0 MHz
***************************************************************************/
#include "emu.h"
#include "includes/battlex.h"
#include "cpu/z80/z80.h"
#include "sound/ay8910.h"
#include "screen.h"
#include "speaker.h"
INTERRUPT_GEN_MEMBER(battlex_state::battlex_interrupt)
{
m_in0_b4 = 1;
device.execute().set_input_line(0, ASSERT_LINE);
}
CUSTOM_INPUT_MEMBER(battlex_state::battlex_in0_b4_r)
{
uint32_t ret = m_in0_b4;
if (m_in0_b4)
{
m_maincpu->set_input_line(0, CLEAR_LINE);
m_in0_b4 = 0;
}
return ret;
}
/*************************************
*
* Memory maps
*
*************************************/
void battlex_state::battlex_map(address_map &map)
{
map(0x0000, 0x5fff).rom();
map(0x8000, 0x8fff).ram().w(FUNC(battlex_state::battlex_videoram_w)).share("videoram");
map(0x9000, 0x91ff).ram().share("spriteram");
map(0xa000, 0xa3ff).ram();
map(0xe000, 0xe03f).ram().w(FUNC(battlex_state::battlex_palette_w));
}
void battlex_state::io_map(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0x00).portr("DSW1");
map(0x01, 0x01).portr("SYSTEM");
map(0x02, 0x02).portr("INPUTS");
map(0x03, 0x03).portr("DSW2");
map(0x10, 0x10).w(FUNC(battlex_state::battlex_flipscreen_w));
/* verify all of these */
map(0x22, 0x23).w("ay1", FUNC(ay8910_device::data_address_w));
map(0x30, 0x30).w(FUNC(battlex_state::battlex_scroll_starfield_w));
map(0x32, 0x32).w(FUNC(battlex_state::battlex_scroll_x_lsb_w));
map(0x33, 0x33).w(FUNC(battlex_state::battlex_scroll_x_msb_w));
}
void battlex_state::dodgeman_io_map(address_map &map)
{
io_map(map);
map(0x26, 0x27).w("ay2", FUNC(ay8910_device::data_address_w));
}
/*************************************
*
* Input ports
*
*************************************/
static INPUT_PORTS_START( battlex )
PORT_START("DSW1") /* IN0 */
PORT_DIPNAME( 0x03, 0x00, DEF_STR( Coin_A ) )
PORT_DIPSETTING( 0x02, DEF_STR( 2C_1C ) )
PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
PORT_DIPSETTING( 0x03, DEF_STR( 2C_3C ) )
PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ) )
PORT_DIPNAME( 0x04, 0x04, DEF_STR( Allow_Continue ) ) // Not on 1st stage
PORT_DIPSETTING( 0x00, DEF_STR( No ) )
PORT_DIPSETTING( 0x04, DEF_STR( Yes ) )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Demo_Sounds ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x08, DEF_STR( On ) )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(battlex_state, battlex_in0_b4_r)
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Cabinet ) )
PORT_DIPSETTING( 0x20, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x00, DEF_STR( Cocktail ) )
PORT_DIPNAME( 0x40, 0x00, DEF_STR( Flip_Screen ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x40, DEF_STR( On ) )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_START("SYSTEM") /* IN1 */
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_COIN2 )
// TODO: PORT_IMPULSE?
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_IMPULSE(4)
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_IMPULSE(4) PORT_COCKTAIL
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START1 )
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_START2 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN )
PORT_START("INPUTS") /* IN2 */
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL
PORT_START("DSW2") /* IN3 */
PORT_DIPNAME( 0x07, 0x00, DEF_STR( Coin_B ) )
PORT_DIPSETTING( 0x07, DEF_STR( 3C_1C ) )
PORT_DIPSETTING( 0x05, DEF_STR( 2C_1C ) )
PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
PORT_DIPSETTING( 0x06, DEF_STR( 2C_3C ) )
PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ) )
PORT_DIPSETTING( 0x02, DEF_STR( 1C_3C ) )
PORT_DIPSETTING( 0x03, DEF_STR( 1C_6C ) )
PORT_DIPSETTING( 0x04, DEF_STR( 1C_7C ) )
PORT_DIPNAME( 0x18, 0x10, DEF_STR( Lives ) )
PORT_DIPSETTING( 0x00, "1" )
PORT_DIPSETTING( 0x08, "2" )
PORT_DIPSETTING( 0x10, "3" )
PORT_DIPSETTING( 0x18, "5" )
PORT_DIPNAME( 0x60, 0x00, DEF_STR( Bonus_Life ) )
PORT_DIPSETTING( 0x00, "5000" )
PORT_DIPSETTING( 0x20, "10000" )
PORT_DIPSETTING( 0x40, "15000" )
PORT_DIPSETTING( 0x60, "20000" )
PORT_DIPNAME( 0x80, 0x00, DEF_STR( Free_Play ) ) // See notes
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x80, DEF_STR( On ) )
INPUT_PORTS_END
static INPUT_PORTS_START( dodgeman )
PORT_INCLUDE( battlex )
PORT_MODIFY("SYSTEM")
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1 )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_COCKTAIL
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_COCKTAIL
INPUT_PORTS_END
/*************************************
*
* Graphics definitions
*
*************************************/
static const gfx_layout battlex_charlayout =
{
8,8,
RGN_FRAC(1,1),
4,
{ 0,1,2,3 },
{ 0, 4, 8, 12, 16, 20, 24, 28 },
{ 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
8*8*4
};
static const gfx_layout battlex_spritelayout =
{
16,16,
RGN_FRAC(1,3),
3,
{ RGN_FRAC(0,3), RGN_FRAC(1,3), RGN_FRAC(2,3) },
{ 7,6,5,4,3,2,1,0,
15,14,13,12,11,10,9,8 },
{ 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16,
8*16, 9*16, 10*16, 11*16, 12*16, 13*16, 14*16, 15*16 },
16*16
};
static GFXDECODE_START( gfx_battlex )
GFXDECODE_ENTRY( "gfx1", 0, battlex_charlayout, 64, 8 )
GFXDECODE_ENTRY( "gfx2", 0, battlex_spritelayout, 0, 8 )
GFXDECODE_END
/*************************************
*
* Machine driver
*
*************************************/
void battlex_state::machine_start()
{
/* register for save states */
save_item(NAME(m_scroll_lsb));
save_item(NAME(m_scroll_msb));
save_item(NAME(m_starfield_enabled));
save_item(NAME(m_in0_b4));
}
void battlex_state::machine_reset()
{
m_scroll_lsb = 0;
m_scroll_msb = 0;
m_starfield_enabled = 0;
m_in0_b4 = 0;
}
void battlex_state::battlex(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, XTAL(10'000'000)/4 ); // ?
m_maincpu->set_addrmap(AS_PROGRAM, &battlex_state::battlex_map);
m_maincpu->set_addrmap(AS_IO, &battlex_state::io_map);
m_maincpu->set_periodic_int(FUNC(battlex_state::battlex_interrupt), attotime::from_hz(400)); /* controls game speed? */
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 32*8-1, 2*8, 30*8-1);
screen.set_screen_update(FUNC(battlex_state::screen_update_battlex));
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_battlex);
PALETTE(config, m_palette).set_entries(64 + 128);
/* sound hardware */
SPEAKER(config, "mono").front_center();
AY8910(config, "ay1", XTAL(10'000'000)/8).add_route(ALL_OUTPUTS, "mono", 0.40); // ?
}
void battlex_state::dodgeman(machine_config &config)
{
battlex(config);
m_maincpu->set_addrmap(AS_IO, &battlex_state::dodgeman_io_map);
MCFG_VIDEO_START_OVERRIDE(battlex_state, dodgeman)
AY8910(config, "ay2", XTAL(10'000'000)/8).add_route(ALL_OUTPUTS, "mono", 0.40); // ?
}
/*************************************
*
* ROM definition
*
*************************************/
ROM_START( battlex )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "p-rom1.6", 0x0000, 0x1000, CRC(b00ae551) SHA1(32a963fea23ea58fc3aab93cc814784a932f045e) )
ROM_LOAD( "p-rom2.5", 0x1000, 0x1000, CRC(e765bb11) SHA1(99671e63f4c7d3d8754277451f0b35cba03b532d) )
ROM_LOAD( "p-rom3.4", 0x2000, 0x1000, CRC(21675a91) SHA1(5bbd5b53b1a1b7aaed5d8c7b09b57f35e4a774dc) )
ROM_LOAD( "p-rom4.3", 0x3000, 0x1000, CRC(fff1ccc4) SHA1(2cb9b096b30e441559e57992df8f30aee46b1f1c) )
ROM_LOAD( "p-rom5.2", 0x4000, 0x1000, CRC(ceb63d38) SHA1(92cab905d009c59115f52172ba7d01c8ff8991d7) )
ROM_LOAD( "p-rom6.1", 0x5000, 0x1000, CRC(6923f601) SHA1(e6c33cbd8d8679299d7b2c568d56f96ed3073971) )
ROM_REGION( 0x4000, "gfx1", ROMREGION_ERASE00 ) // filled in later
ROM_REGION( 0x3000, "gfx2", 0 )
ROM_LOAD( "1a_f.6f", 0x0000, 0x1000, CRC(2b69287a) SHA1(30c0edaec44118b95ec390bd41c1bd49a2802451) )
ROM_LOAD( "1a_h.6h", 0x1000, 0x1000, CRC(9f4c3bdd) SHA1(e921ecafefe54c033d05d9cd289808e971ac7940) )
ROM_LOAD( "1a_j.6j", 0x2000, 0x1000, CRC(c1345b05) SHA1(17194c8ec961990222bd295ff1d036a64f497b0e) )
ROM_REGION( 0x1000, "user1", 0 ) // gfx1 colormask, bad?
ROM_LOAD( "1a_d.6d", 0x0000, 0x1000, CRC(750a46ef) SHA1(b6ab93e084ab0b7c6ad90ee6431bc1b7ab9ed46d) )
ROM_REGION( 0x1000, "user2", 0 ) // gfx1 1bpp gfxdata
ROM_LOAD( "1a_e.6e", 0x0000, 0x1000, CRC(126842b7) SHA1(2da4f64e077232c1dd0853d07d801f9781517850) )
ROM_END
ROM_START( dodgeman )
ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
ROM_LOAD( "dg0.7f", 0x0000, 0x001000, CRC(1219b5db) SHA1(e4050a5e52f7b125f317b6e2ef615774c81cf679) )
ROM_LOAD( "dg1.5f", 0x1000, 0x001000, CRC(fff9a086) SHA1(e4e528789d07755cf999054c191e242ea3ebe55f) )
ROM_LOAD( "dg2.4f", 0x2000, 0x001000, CRC(2ca9ac99) SHA1(7fe81626ab2b5c01189fbb578999157863fcc29f) )
ROM_LOAD( "dg3.3f", 0x3000, 0x001000, CRC(55a51c0e) SHA1(a5b253f096e1fe85ee391ad2aa0373809a3b48c2) )
ROM_LOAD( "dg4.2f", 0x4000, 0x001000, CRC(14169361) SHA1(86d3cd1fa0aa4f21029daea2eba99bdaa34372e8) )
ROM_LOAD( "dg5.1f", 0x5000, 0x001000, CRC(8f83ae2f) SHA1(daad41b61ba3d55531021d444bbe4acfc275cfc9) )
ROM_REGION( 0x8000, "gfx1", ROMREGION_ERASE00 ) // filled in later
ROM_REGION( 0x6000, "gfx2", ROMREGION_ERASE00 )
ROM_LOAD( "f.6f", 0x0000, 0x002000, CRC(dfaaf4c8) SHA1(1e09f1d72e7e5e6782d73ae60bca7982fc04df0e) )
ROM_LOAD( "h.6h", 0x2000, 0x002000, CRC(e2525ffe) SHA1(a17b608b4089014be381b26f16597b83d4a66ebd) )
ROM_LOAD( "j.6j", 0x4000, 0x002000, CRC(2731ee46) SHA1(15b9350e19f31b1cea99deb9935543777644e6a8) )
ROM_REGION( 0x2000, "user1", 0 ) // gfx1 1bpp gfxdata
ROM_LOAD( "d.6d", 0x0000, 0x002000, CRC(451c1c3a) SHA1(214f775e242f7f29ac799cdd554708acddd1e34f) )
ROM_REGION( 0x2000, "user2", 0 ) // gfx1 colormask, bad?
ROM_LOAD( "e.6e", 0x0000, 0x002000, CRC(c9a515df) SHA1(5232d2d1bd02b89cb651d817995daf33469f0e2f) )
ROM_END
/*************************************
*
* Driver initialization
*
*************************************/
void battlex_state::init_battlex()
{
uint8_t *colormask = memregion("user1")->base();
uint8_t *gfxdata = memregion("user2")->base();
uint8_t *dest = memregion("gfx1")->base();
int tile_size = memregion("gfx1")->bytes() / 32;
int offset = 0;
for (int tile = 0; tile < tile_size; tile++)
{
for (int line = 0; line < 8; line ++)
{
for (int bit = 0; bit < 8 ; bit ++)
{
int color = colormask[(tile << 3) | ((line & 0x6) + (bit > 3 ? 1 : 0))];
int data = BIT(gfxdata[(tile << 3) | line], bit);
if (!data)
color >>= 4;
color &= 0x0f;
if (offset&1)
dest[offset >> 1] |= color;
else
dest[offset >> 1] = color<<4;
++offset;
}
}
}
}
/*************************************
*
* Game driver
*
*************************************/
GAME( 1982, battlex, 0, battlex, battlex, battlex_state, init_battlex, ROT180, "Omori Electric Co., Ltd.", "Battle Cross", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE | MACHINE_NO_COCKTAIL )
GAME( 1983, dodgeman, 0, dodgeman, dodgeman, battlex_state, init_battlex, ROT180, "Omori Electric Co., Ltd.", "Dodge Man", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE | MACHINE_NO_COCKTAIL )