/*******************************************************************************
 Ninja Kid / Ninjakun Majou no Bouken | (c) 1984 UPL / Taito
********************************************************************************
 Driver by David Haywood
 with help from Steph and Phil Stroffolino

 Last Changes: 5 Mar 2001

 This driver was started after interest was shown in the game by a poster at
 various messageboards going under the name of 'ninjakid'  I decided to attempt
 a driver for this game to gain some experience with Z80 & Multi-processor
 games.

Hold P1 Start after a reset to skip the startup memory tests.

Change Log:
5 Mar - Added Saved State Support (DJH)
8 Jun - Added palette animation, Fixed FG priority. (Uki)
9 Jun - Fixed BG scroll handling, Fixed CPU clock.
*******************************************************************************/

#include "driver.h"
#include "cpu/z80/z80.h"
#include "sound/ay8910.h"

extern WRITE8_HANDLER( ninjakid_bg_videoram_w );
extern WRITE8_HANDLER( ninjakid_fg_videoram_w );
extern READ8_HANDLER( ninjakid_bg_videoram_r );

extern READ8_HANDLER( ninjakun_io_8000_r );
extern WRITE8_HANDLER( ninjakun_io_8000_w );

extern VIDEO_START( ninjakid );
extern VIDEO_UPDATE( ninjakid );
extern WRITE8_HANDLER( ninjakun_flipscreen_w );

extern WRITE8_HANDLER( ninjakun_paletteram_w );

/******************************************************************************/

static UINT8 *ninjakid_gfx_rom;

static READ8_HANDLER( ninjakid_shared_rom_r ){
	return ninjakid_gfx_rom[offset];
}

/* working RAM is shared, but an address line is inverted */
static UINT8 *shareram;

static WRITE8_HANDLER( shareram_w ){
	shareram[offset^0x400] = data;
}
static READ8_HANDLER( shareram_r ){
	return shareram[offset^0x400];
}

/*******************************************************************************
 0xA000 Read / Write Handlers
*******************************************************************************/

static UINT8 ninjakun_io_a002_ctrl;

static READ8_HANDLER( ninjakun_io_A002_r ){
	return ninjakun_io_a002_ctrl | readinputport(2); /* vblank */
}

static WRITE8_HANDLER( cpu1_A002_w ){
	if( data == 0x80 ) ninjakun_io_a002_ctrl |= 0x04;
	if( data == 0x40 ) ninjakun_io_a002_ctrl &= ~0x08;
}

static WRITE8_HANDLER( cpu2_A002_w ){
	if( data == 0x40 ) ninjakun_io_a002_ctrl |= 0x08;
	if( data == 0x80 ) ninjakun_io_a002_ctrl &= ~0x04;
}

/*******************************************************************************
 Init
*******************************************************************************/

static MACHINE_START( ninjakid )
{
	/* Save State Stuff */
	state_save_register_global(ninjakun_io_a002_ctrl);
}

/*******************************************************************************
 Memory Maps
*******************************************************************************/

static ADDRESS_MAP_START( ninjakid_primary_readmem, ADDRESS_SPACE_PROGRAM, 8 )
    AM_RANGE(0x0000, 0x7fff) AM_READ(MRA8_ROM)
	AM_RANGE(0x8000, 0x8003) AM_READ(ninjakun_io_8000_r)
	AM_RANGE(0xa000, 0xa000) AM_READ(input_port_0_r)
	AM_RANGE(0xa001, 0xa001) AM_READ(input_port_1_r)
	AM_RANGE(0xa002, 0xa002) AM_READ(ninjakun_io_A002_r)
	AM_RANGE(0xc000, 0xc7ff) AM_READ(MRA8_RAM)	/* tilemaps */
	AM_RANGE(0xc800, 0xcfff) AM_READ(ninjakid_bg_videoram_r)
    AM_RANGE(0xd000, 0xd7ff) AM_READ(MRA8_RAM)	/* spriteram */
    AM_RANGE(0xd800, 0xd9ff) AM_READ(paletteram_r)
    AM_RANGE(0xe000, 0xe7ff) AM_READ(MRA8_RAM)
ADDRESS_MAP_END

static ADDRESS_MAP_START( ninjakid_primary_writemem, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x1fff) AM_WRITE(MWA8_ROM)
	AM_RANGE(0x2000, 0x7fff) AM_WRITE(MWA8_ROM) AM_BASE(&ninjakid_gfx_rom)
	AM_RANGE(0x8000, 0x8003) AM_WRITE(ninjakun_io_8000_w)
	AM_RANGE(0xa002, 0xa002) AM_WRITE(cpu1_A002_w)
	AM_RANGE(0xa003, 0xa003) AM_WRITE(ninjakun_flipscreen_w)
	AM_RANGE(0xc000, 0xc7ff) AM_WRITE(ninjakid_fg_videoram_w) AM_BASE(&videoram)
	AM_RANGE(0xc800, 0xcfff) AM_WRITE(ninjakid_bg_videoram_w)
	AM_RANGE(0xd000, 0xd7ff) AM_WRITE(MWA8_RAM) AM_BASE(&spriteram)
	AM_RANGE(0xd800, 0xd9ff) AM_WRITE(ninjakun_paletteram_w) AM_BASE(&paletteram)
	AM_RANGE(0xe000, 0xe7ff) AM_WRITE(MWA8_RAM) AM_BASE(&shareram)
ADDRESS_MAP_END

static ADDRESS_MAP_START( ninjakid_secondary_readmem, ADDRESS_SPACE_PROGRAM, 8 )
    AM_RANGE(0x0000, 0x1fff) AM_READ(MRA8_ROM)
    AM_RANGE(0x2000, 0x7fff) AM_READ(ninjakid_shared_rom_r)
	AM_RANGE(0x8000, 0x8003) AM_READ(ninjakun_io_8000_r)
	AM_RANGE(0xa000, 0xa000) AM_READ(input_port_0_r)
	AM_RANGE(0xa001, 0xa001) AM_READ(input_port_1_r)
	AM_RANGE(0xa002, 0xa002) AM_READ(ninjakun_io_A002_r)
	AM_RANGE(0xc000, 0xc7ff) AM_READ(videoram_r)		/* tilemaps */
	AM_RANGE(0xc800, 0xcfff) AM_READ(ninjakid_bg_videoram_r)
    AM_RANGE(0xd000, 0xd7ff) AM_READ(spriteram_r)	/* shareram */
    AM_RANGE(0xd800, 0xd9ff) AM_READ(paletteram_r)
    AM_RANGE(0xe000, 0xe7ff) AM_READ(shareram_r)
ADDRESS_MAP_END

static ADDRESS_MAP_START( ninjakid_secondary_writemem, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x1fff) AM_WRITE(MWA8_ROM)
	AM_RANGE(0x8000, 0x8003) AM_WRITE(ninjakun_io_8000_w)
	AM_RANGE(0xa002, 0xa002) AM_WRITE(cpu2_A002_w)
	AM_RANGE(0xa003, 0xa003) AM_WRITE(ninjakun_flipscreen_w)
	AM_RANGE(0xc000, 0xc7ff) AM_WRITE(ninjakid_fg_videoram_w)
	AM_RANGE(0xc800, 0xcfff) AM_WRITE(ninjakid_bg_videoram_w)
	AM_RANGE(0xd000, 0xd7ff) AM_WRITE(spriteram_w)	/* shareram */
	AM_RANGE(0xd800, 0xd9ff) AM_WRITE(ninjakun_paletteram_w)
    AM_RANGE(0xe000, 0xe7ff) AM_WRITE(shareram_w)
ADDRESS_MAP_END

/*******************************************************************************
 GFX Decoding Information
*******************************************************************************/

static const gfx_layout tile_layout =
{
	8,8,	/* tile size */
	0x400,	/* number of tiles */
	4,		/* bits per pixel */
	{ 0, 1, 2, 3 }, /* plane offsets */
	{ 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 }, /* x offsets */
	{ 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 }, /* y offsets */
	256
};

static const gfx_layout sprite_layout =
{
	16,16,	/* tile size */
	0x100,	/* number of tiles */
	4,		/* bits per pixel */
	{ 0, 1, 2, 3 }, /* plane offsets */
	{
		0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
		256+0*4, 256+1*4, 256+2*4, 256+3*4, 256+4*4, 256+5*4, 256+6*4, 256+7*4,
	}, /* x offsets */
	{
		0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32,
		512+0*32, 512+1*32, 512+2*32, 512+3*32, 512+4*32, 512+5*32, 512+6*32, 512+7*32
	}, /* y offsets */
	1024
};

static GFXDECODE_START( ninjakid )
	GFXDECODE_ENTRY( REGION_GFX1, 0, tile_layout,		0x000, 0x10 )
	GFXDECODE_ENTRY( REGION_GFX2, 0, tile_layout,		0x100, 0x10 )
	GFXDECODE_ENTRY( REGION_GFX1, 0, sprite_layout,	0x200, 0x10 )
GFXDECODE_END

/*******************************************************************************
 Machine Driver Structure(s)
*******************************************************************************/

static MACHINE_DRIVER_START( ninjakid )

	/* basic machine hardware */
	MDRV_CPU_ADD(Z80, 3000000) /* 3.00MHz */
	MDRV_CPU_PROGRAM_MAP(ninjakid_primary_readmem,ninjakid_primary_writemem)
	MDRV_CPU_VBLANK_INT(irq0_line_hold,1)

	MDRV_CPU_ADD(Z80, 3000000) /* 3.00MHz */
	MDRV_CPU_PROGRAM_MAP(ninjakid_secondary_readmem,ninjakid_secondary_writemem)
	MDRV_CPU_VBLANK_INT(irq0_line_hold,4) /* ? */

	MDRV_SCREEN_REFRESH_RATE(60)

	MDRV_MACHINE_START(ninjakid)
	MDRV_SCREEN_VBLANK_TIME(DEFAULT_REAL_60HZ_VBLANK_DURATION)
	MDRV_INTERLEAVE(100)	/* 100 CPU slices per frame */

    /* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
	MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
	MDRV_SCREEN_SIZE(32*8, 32*8)
	MDRV_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 4*8, (32-4)*8-1 )
	MDRV_GFXDECODE(ninjakid)
	MDRV_PALETTE_LENGTH(768)

	MDRV_VIDEO_START(ninjakid)
	MDRV_VIDEO_UPDATE(ninjakid)

	/* sound hardware */
	MDRV_SPEAKER_STANDARD_MONO("mono")

	MDRV_SOUND_ADD(AY8910, 6000000/2)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)

	MDRV_SOUND_ADD(AY8910, 6000000/2)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MACHINE_DRIVER_END

/*******************************************************************************
 Rom Definitions
*******************************************************************************/

ROM_START( ninjakun ) /* Original Board? */
	ROM_REGION( 0x10000, REGION_CPU1, 0 ) /* Main CPU */
	ROM_LOAD( "ninja-1.7a",  0x0000, 0x02000, CRC(1c1dc141) SHA1(423d3ed35e73a8d5bfce075a889b0322b207bd0d) )
	ROM_LOAD( "ninja-2.7b",  0x2000, 0x02000, CRC(39cc7d37) SHA1(7f0d0e1e92cb6a57f15eb7fc51a67112f1c5fc8e) )
	ROM_LOAD( "ninja-3.7d",  0x4000, 0x02000, CRC(d542bfe3) SHA1(3814d8f5b1acda21438fff4f71670fa653dc7b30) )
	ROM_LOAD( "ninja-4.7e",  0x6000, 0x02000, CRC(a57385c6) SHA1(77925a281e64889bfe967c3d42a388529aaf7eb6) )

	ROM_REGION( 0x10000, REGION_CPU2, 0 ) /* Secondary CPU */
	ROM_LOAD( "ninja-5.7h",  0x0000, 0x02000, CRC(164a42c4) SHA1(16b434b33b76b878514f67c23315d4c6da7bfc9e) )

	ROM_REGION( 0x08000, REGION_GFX1, ROMREGION_DISPOSE ) /* Graphics */
	ROM_LOAD16_BYTE( "ninja-6.7n",  0x0000, 0x02000, CRC(a74c4297) SHA1(87184d14c67331f2c8a2412e28f31427eddae799) )
	ROM_LOAD16_BYTE( "ninja-7.7p",  0x0001, 0x02000, CRC(53a72039) SHA1(d77d608ce9388a8956831369badd88a8eda8e102) )
	ROM_LOAD16_BYTE( "ninja-8.7s",  0x4000, 0x02000, CRC(4a99d857) SHA1(6aadb6a5c721a161a5c1bef5569c1e323e380cff) )
	ROM_LOAD16_BYTE( "ninja-9.7t",  0x4001, 0x02000, CRC(dede49e4) SHA1(8ce4bc02ec583b3885ca63fb5e2d5dad185fe192) )

	ROM_REGION( 0x08000, REGION_GFX2, ROMREGION_DISPOSE ) /* Graphics */
	ROM_LOAD16_BYTE( "ninja-10.2c", 0x0000, 0x02000, CRC(0d55664a) SHA1(955a607b4401ce9f3f807d53833a766152b0ef9b) )
	ROM_LOAD16_BYTE( "ninja-11.2d", 0x0001, 0x02000, CRC(12ff9597) SHA1(10b572844ab32e3ae54abe3600fecc1a811ac713) )
	ROM_LOAD16_BYTE( "ninja-12.4c", 0x4000, 0x02000, CRC(e9b75807) SHA1(cf4c8ac962f785e9de5502df58eab9b3725aaa28) )
	ROM_LOAD16_BYTE( "ninja-13.4d", 0x4001, 0x02000, CRC(1760ed2c) SHA1(ee4c8efcce483c8051873714856824a1a1e14b61) )
ROM_END

/*******************************************************************************
 Input Ports
********************************************************************************
 2 Sets of Controls
 2 Sets of Dipsiwtches
*******************************************************************************/

INPUT_PORTS_START( ninjakid )
	PORT_START_TAG("IN0")	/* 0xa000 */
	PORT_BIT( 0x01, IP_ACTIVE_LOW,	IPT_JOYSTICK_LEFT ) PORT_2WAY /* "XPOS1" */
	PORT_BIT( 0x02, IP_ACTIVE_LOW,	IPT_JOYSTICK_RIGHT ) PORT_2WAY
	PORT_BIT( 0x04, IP_ACTIVE_LOW,	IPT_BUTTON2 )
	PORT_BIT( 0x08, IP_ACTIVE_LOW,	IPT_BUTTON1 )
	PORT_BIT( 0x10, IP_ACTIVE_LOW,	IPT_UNKNOWN )
	PORT_BIT( 0x20, IP_ACTIVE_LOW,	IPT_START1  )
	PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN )
	PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN )

	PORT_START_TAG("IN1")	/* 0xa001 */
	PORT_BIT( 0x01, IP_ACTIVE_LOW,	IPT_JOYSTICK_LEFT) PORT_2WAY PORT_COCKTAIL /* "YPOS1" */
	PORT_BIT( 0x02, IP_ACTIVE_LOW,	IPT_JOYSTICK_RIGHT) PORT_2WAY PORT_COCKTAIL
	PORT_BIT( 0x04, IP_ACTIVE_LOW,	IPT_BUTTON2 ) PORT_COCKTAIL
	PORT_BIT( 0x08, IP_ACTIVE_LOW,	IPT_BUTTON1 ) PORT_COCKTAIL
	PORT_BIT( 0x10, IP_ACTIVE_LOW,	IPT_UNKNOWN )
	PORT_BIT( 0x20, IP_ACTIVE_LOW,	IPT_START2  )
	PORT_SERVICE( 0x40, IP_ACTIVE_HIGH )
	PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN1 )

	PORT_START_TAG("IN2")	/* 0xa002 */
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_VBLANK )

	PORT_START_TAG("DSW1")
	PORT_DIPNAME( 0x01, 0x00, DEF_STR( Cabinet ) )
	PORT_DIPSETTING(    0x00, DEF_STR( Upright ) )
	PORT_DIPSETTING(    0x01, DEF_STR( Cocktail ) )
	PORT_DIPNAME( 0x06, 0x04, DEF_STR( Lives ) )
	PORT_DIPSETTING(    0x02, "2" )
	PORT_DIPSETTING(    0x04, "3" )
	PORT_DIPSETTING(    0x06, "4" )
	PORT_DIPSETTING(    0x00, "5" )
	PORT_DIPNAME( 0x08, 0x08, "First Bonus" )
	PORT_DIPSETTING(    0x08, "30000" )
	PORT_DIPSETTING(    0x00, "40000" )
	PORT_DIPNAME( 0x30, 0x30, "Second Bonus" )
	PORT_DIPSETTING(    0x00, "No Bonus" )
	PORT_DIPSETTING(    0x10, "Every 30000" )
	PORT_DIPSETTING(    0x30, "Every 50000" )
	PORT_DIPSETTING(    0x20, "Every 70000" )
	PORT_DIPNAME( 0x40, 0x00, DEF_STR( Demo_Sounds ) )
	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
	PORT_DIPNAME( 0x80, 0x80, DEF_STR( Difficulty ) )
	PORT_DIPSETTING(    0x80, DEF_STR( Normal ) )
	PORT_DIPSETTING(    0x00, DEF_STR( Hard )   )

	PORT_START_TAG("DSW2")
	PORT_DIPNAME( 0x07, 0x07, DEF_STR( Coinage ) )
	PORT_DIPSETTING(    0x04, DEF_STR( 4C_1C ) )
	PORT_DIPSETTING(    0x05, DEF_STR( 3C_1C ) )
	PORT_DIPSETTING(    0x00, DEF_STR( 4C_2C ) )
	PORT_DIPSETTING(    0x06, DEF_STR( 2C_1C ) )
	PORT_DIPSETTING(    0x01, DEF_STR( 3C_2C ) )
	PORT_DIPSETTING(    0x02, DEF_STR( 2C_2C ) )
	PORT_DIPSETTING(    0x07, DEF_STR( 1C_1C ) )
	PORT_DIPSETTING(    0x03, DEF_STR( 1C_2C ) )
	PORT_DIPNAME( 0x08, 0x08, "High Score Names" )
	PORT_DIPSETTING(    0x00, "3 Letters" )
	PORT_DIPSETTING(    0x08, "8 Letters" )
	PORT_DIPNAME( 0x10, 0x10, DEF_STR( Allow_Continue ) )
	PORT_DIPSETTING(    0x10, DEF_STR( No ) )
	PORT_DIPSETTING(    0x00, DEF_STR( Yes ) )
	PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )/* Probably Unused */
	PORT_DIPSETTING(    0x20, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
	PORT_DIPNAME( 0x40, 0x40, DEF_STR( Free_Play ) )
	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
	PORT_DIPNAME( 0x80, 0x80, "Endless Game (If Free Play)" )
	PORT_DIPSETTING(    0x80, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
INPUT_PORTS_END

/*******************************************************************************
 Game Drivers
*******************************************************************************/

GAME( 1984, ninjakun, 0, ninjakid, ninjakid, 0, ROT0, "[UPL] (Taito license)", "Ninjakun Majou no Bouken", 0 )
