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

    Namco Pac Man

**************************************************************************

    This file is used by the Pac Man, Pengo & Jr Pac Man drivers.

    Pengo & Pac Man are almost identical, the only differences being the
    extra gfx bank in Pengo, and the need to compensate for an hardware
    sprite positioning "bug" in Pac Man.

    Jr Pac Man has the same sprite hardware as Pac Man, the extra bank
    from Pengo and a scrolling playfield at the expense of one color per row
    for the playfield so it can fit in the same amount of ram.

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

#include "driver.h"
#include "includes/pacman.h"
#include "video/resnet.h"

static tilemap *bg_tilemap;
static UINT8 charbank;
static UINT8 spritebank;
static UINT8 palettebank;
static UINT8 colortablebank;
static UINT8 colourbank;
static UINT8 flipscreen;
static UINT8 bgpriority;

static int xoffsethack;
UINT8 *s2650games_spriteram;
UINT8 *s2650games_tileram;

static rectangle spritevisiblearea =
{
	2*8, 34*8-1,
	0*8, 28*8-1
};

static rectangle xspritevisiblearea =
{
	2*16, 34*16-1,
	0*16, 28*16-1
};


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

  Convert the color PROMs into a more useable format.


  Pac Man has a 32x8 palette PROM and a 256x4 color lookup table PROM.

  Pengo has a 32x8 palette PROM and a 1024x4 color lookup table PROM.

  The palette PROM is connected to the RGB output this way:

  bit 7 -- 220 ohm resistor  -- BLUE
        -- 470 ohm resistor  -- BLUE
        -- 220 ohm resistor  -- GREEN
        -- 470 ohm resistor  -- GREEN
        -- 1  kohm resistor  -- GREEN
        -- 220 ohm resistor  -- RED
        -- 470 ohm resistor  -- RED
  bit 0 -- 1  kohm resistor  -- RED


  Jr. Pac Man has two 256x4 palette PROMs (the three msb of the address are
  grounded, so the effective colors are only 32) and one 256x4 color lookup
  table PROM.

  The palette PROMs are connected to the RGB output this way:

  bit 3 -- 220 ohm resistor  -- BLUE
     -- 470 ohm resistor  -- BLUE
     -- 220 ohm resistor  -- GREEN
  bit 0 -- 470 ohm resistor  -- GREEN

  bit 3 -- 1  kohm resistor  -- GREEN
     -- 220 ohm resistor  -- RED
     -- 470 ohm resistor  -- RED
  bit 0 -- 1  kohm resistor  -- RED

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

static gfx_element *led_font;

static void build_led_font(void)
{
	static const UINT8 fontdata[10 * 8] =
	{
		0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,
		0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x00,
		0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00,
		0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00,
		0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,
		0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00,
		0x70,0x80,0xf0,0x88,0x88,0x88,0x70,0x00,
		0xf8,0x08,0x08,0x10,0x20,0x20,0x20,0x00,
		0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,
		0x70,0x88,0x88,0x88,0x78,0x08,0x70,0x00
	};
	static const gfx_layout layout =
	{
		8,6,
		10,
		1,
		{ 0 },
		{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
		{ 0, 1, 2, 3, 4, 5 },
		8*8
	};

	led_font = allocgfx(&layout);
	if (!led_font)
		fatalerror("Fatal error: could not allocate memory for decimal font!");

	decodegfx(led_font, fontdata, 0, led_font->total_elements);

	led_font->color_base = 0;
	led_font->total_colors = 16;
}

PALETTE_INIT( pacman )
{
	static const int resistances[3] = { 1000, 470, 220 };
	double rweights[3], gweights[3], bweights[2];
	int i;

	/* compute the color output resistor weights */
	compute_resistor_weights(0,	255, -1.0,
			3, &resistances[0], rweights, 0, 0,
			3, &resistances[0], gweights, 0, 0,
			2, &resistances[1], bweights, 0, 0);

	/* allocate the colortable */
	machine->colortable = colortable_alloc(machine, 32);

	/* create a lookup table for the palette */
	for (i = 0; i < 32; i++)
	{
		int bit0, bit1, bit2;
		int r, g, b;

		/* red component */
		bit0 = (color_prom[i] >> 0) & 0x01;
		bit1 = (color_prom[i] >> 1) & 0x01;
		bit2 = (color_prom[i] >> 2) & 0x01;
		r = combine_3_weights(rweights, bit0, bit1, bit2);

		/* green component */
		bit0 = (color_prom[i] >> 3) & 0x01;
		bit1 = (color_prom[i] >> 4) & 0x01;
		bit2 = (color_prom[i] >> 5) & 0x01;
		g = combine_3_weights(gweights, bit0, bit1, bit2);

		/* blue component */
		bit0 = (color_prom[i] >> 6) & 0x01;
		bit1 = (color_prom[i] >> 7) & 0x01;
		b = combine_2_weights(bweights, bit0, bit1);

		colortable_palette_set_color(machine->colortable, i, MAKE_RGB(r, g, b));
	}

	/* color_prom now points to the beginning of the lookup table */
	color_prom += 32;

	/* allocate the colortable */
	for (i = 0; i < 64*4; i++)
	{
		UINT8 ctabentry = color_prom[i] & 0x0f;

		/* first palette bank */
		colortable_entry_set_value(machine->colortable, i, ctabentry);

		/* second palette bank */
		colortable_entry_set_value(machine->colortable, i + 64*4, 0x10 + ctabentry);
	}
}

static TILEMAP_MAPPER( pacman_scan_rows )
{
	int offs;

	row += 2;
	col -= 2;
	if (col & 0x20)
		offs = row + ((col & 0x1f) << 5);
	else
		offs = col + (row << 5);

	return offs;
}

static TILE_GET_INFO( pacman_get_tile_info )
{
	int code = videoram[tile_index] | (charbank << 8);
	int attr = (colorram[tile_index] & 0x1f) | (colortablebank << 5) | (palettebank << 6 );

	SET_TILE_INFO(0,code,attr,0);
}


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

  Start the video hardware emulation.

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

static void init_save_state(void)
{
	state_save_register_global(charbank);
	state_save_register_global(spritebank);
	state_save_register_global(palettebank);
	state_save_register_global(colortablebank);
	state_save_register_global(flipscreen);
	state_save_register_global(bgpriority);
}


VIDEO_START( pacman )
{
	init_save_state();

	charbank = 0;
	spritebank = 0;
	palettebank = 0;
	colortablebank = 0;
	flipscreen = 0;
	bgpriority = 0;
	xoffsethack = 1;

	bg_tilemap = tilemap_create( pacman_get_tile_info, pacman_scan_rows, 8, 8, 36, 28 );

	tilemap_set_scrolldx( bg_tilemap, 0, 384 - 288 );
	tilemap_set_scrolldy( bg_tilemap, 0, 264 - 224 );
	build_led_font();
}

VIDEO_START( pacmanx )
{
	charbank = 0;
	spritebank = 0;
	palettebank = 0;
	colortablebank = 0;
	flipscreen = 0;
	bgpriority = 0;
	xoffsethack = 2;

	bg_tilemap = tilemap_create( pacman_get_tile_info, pacman_scan_rows, 16, 16, 36, 28 );

	tilemap_set_scrolldx( bg_tilemap, 0, 384*2 - 288*2 );
	tilemap_set_scrolldy( bg_tilemap, 0, 264*2 - 224*2 );
	build_led_font();
}


WRITE8_HANDLER( pacman_videoram_w )
{
	videoram[offset] = data;
	tilemap_mark_tile_dirty( bg_tilemap, offset );
}

WRITE8_HANDLER( pacman_colorram_w )
{
	colorram[offset] = data;
	tilemap_mark_tile_dirty( bg_tilemap, offset );
}

WRITE8_HANDLER( pacman_flipscreen_w )
{
	flipscreen = data & 1;
	tilemap_set_flip( bg_tilemap, flipscreen * ( TILEMAP_FLIPX + TILEMAP_FLIPY ) );
}

VIDEO_UPDATE( pacman )
{
	if (bgpriority != 0)
		fillbitmap(bitmap,0,cliprect);
	else
		tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0);

	if( spriteram_size )
	{
		int offs;

		rectangle spriteclip = spritevisiblearea;
		sect_rect(&spriteclip, cliprect);

		/* Draw the sprites. Note that it is important to draw them exactly in this */
		/* order, to have the correct priorities. */
		for (offs = spriteram_size - 2;offs > 2*2;offs -= 2)
		{
			int color;
			int sx,sy;

			sx = 272 - spriteram_2[offs + 1];
			sy = spriteram_2[offs] - 31;
			color = ( spriteram[offs + 1] & 0x1f ) | (colortablebank << 5) | (palettebank << 6 );

			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx,sy,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));

			/* also plot the sprite with wraparound (tunnel in Crush Roller) */
			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx - 256,sy,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));
		}
		/* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
		/* one pixel to the left to get a more correct placement */
		for (offs = 2*2;offs >= 0;offs -= 2)
		{
			int color;
			int sx,sy;

			sx = 272 - spriteram_2[offs + 1];
			sy = spriteram_2[offs] - 31;
			color = ( spriteram[offs + 1] & 0x1f ) | (colortablebank << 5) | (palettebank << 6 );

			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx,sy + xoffsethack,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));

			/* also plot the sprite with wraparound (tunnel in Crush Roller) */
			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 2,spriteram[offs] & 1,
					sx - 256,sy + xoffsethack,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));
		}
	}

	if (bgpriority != 0)
		tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);


	/* Display the level number under the high score. The level is at 0x4e13, offset by 1.
	Check to see we are in game play mode, that the font exists, and the user wants to see it */

	if ((program_read_byte(0x4e00) == 3) && (program_read_byte(0x4e04)==3) && (led_font) && (input_port_read(screen->machine, "CONFIG")&1))
	{
		UINT8 data = program_read_byte(0x4e13)+1;
		int i;
		for( i=2; i>=0; i-- )
		{
			if (data)					/* remove leading zeroes */
				drawgfx( bitmap, led_font,		/* bitmap to use, character set to use */
					data%10,14,			/* char number to display, colour */
					flipscreen,flipscreen^1,	/* flipx, flipy */
					flipscreen ? 263 : 17,		/* x position */
					flipscreen ? 118+i*6 : 102-i*6,	/* y position */
					NULL, TRANSPARENCY_PEN,0 );	/* make background transparent */
			data = data/10;					/* adjust for next digit */
		}
	}

	return 0;
}

VIDEO_UPDATE( pacmanx )
{
	if (bgpriority != 0)
		fillbitmap(bitmap,0,cliprect);
	else
		tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0);

	if( spriteram_size )
	{
		int offs;

		rectangle spriteclip = xspritevisiblearea;
		sect_rect(&spriteclip, cliprect);

		/* Draw the sprites. Note that it is important to draw them exactly in this */
		/* order, to have the correct priorities. */
		for (offs = spriteram_size - 2;offs > 2*2;offs -= 2)
		{
			int color;
			int sx,sy;

			sx = 544 - (spriteram_2[offs + 1]) * 2;
			sy = (spriteram_2[offs] - 31) * 2;
			color = ( spriteram[offs + 1] & 0x1f ) | (colortablebank << 5) | (palettebank << 6 );

			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx,sy,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));

			/* also plot the sprite with wraparound (tunnel in Crush Roller) */
			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx - 512,sy,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));
		}
		/* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
		/* one pixel to the left to get a more correct placement */
		for (offs = 2*2;offs >= 0;offs -= 2)
		{
			int color;
			int sx,sy;

			sx = 544 - (spriteram_2[offs + 1]) * 2;
			sy = (spriteram_2[offs] - 31) * 2;
			color = ( spriteram[offs + 1] & 0x1f ) | (colortablebank << 5) | (palettebank << 6 );

			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx,sy + xoffsethack,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));

			/* also plot the sprite with wraparound (tunnel in Crush Roller) */
			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 2,spriteram[offs] & 1,
					sx - 512,sy + xoffsethack,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color & 0x3f, 0));
		}
	}

	if (bgpriority != 0)
		tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);

	if ((program_read_byte(0x4e00) == 3) && (program_read_byte(0x4e04)==3) && (led_font) && (input_port_read(screen->machine, "CONFIG")&1))
	{
		UINT8 data = program_read_byte(0x4e13)+1;
		int i;
		for( i=2; i>=0; i-- )
		{
			if (data)					/* remove leading zeroes */
				drawgfx( bitmap, led_font,		/* bitmap to use, character set to use */
					data%10,14,			/* char number to display, colour */
					flipscreen,flipscreen^1,	/* flipx, flipy */
					flipscreen ? 530 : 36,		/* x position */
					flipscreen ? 236+i*6 : 204-i*6,	/* y position */
					NULL, TRANSPARENCY_PEN,0 );	/* make background transparent */
			data = data/10;					/* adjust for next digit */
		}
	}

	return 0;
}



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

    Sega Pengo

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

VIDEO_START( pengo )
{
	init_save_state();

	charbank = 0;
	spritebank = 0;
	palettebank = 0;
	colortablebank = 0;
	flipscreen = 0;
	bgpriority = 0;

	xoffsethack = 0;

	bg_tilemap = tilemap_create( pacman_get_tile_info, pacman_scan_rows, 8, 8, 36, 28 );
//	build_led_font();
}

WRITE8_HANDLER( pengo_palettebank_w )
{
	if (palettebank != data)
	{
		palettebank = data;
		tilemap_mark_all_tiles_dirty( bg_tilemap );
	}
}

WRITE8_HANDLER( pengo_colortablebank_w )
{
	if (colortablebank != data)
	{
		colortablebank = data;
		tilemap_mark_all_tiles_dirty( bg_tilemap );
	}
}

WRITE8_HANDLER( pengo_gfxbank_w )
{
	if (charbank != (data & 1))
	{
		spritebank = data & 1;
		charbank = data & 1;
		tilemap_mark_all_tiles_dirty( bg_tilemap );
	}
}


/************************************************************************
  MULTIPAC adapted for MisfitMAME by Robbbert, Feb 2007
 ************************************************************************/

static void init_save_state_multipac(void)
{
	state_save_register_global(charbank);
	state_save_register_global(spritebank);
	state_save_register_global(colourbank);
	state_save_register_global(flipscreen);
	state_save_register_global(bgpriority);
}

static TILE_GET_INFO( multipac_get_tile_info )
{
	int code = videoram[tile_index] | (charbank << 8);
	int attr = (colorram[tile_index] & 0x1f) | (colourbank << 5);

	SET_TILE_INFO(0,code,attr,0);
}

VIDEO_START( multipac )
{
	init_save_state_multipac();

	charbank = 0;
	spritebank = 0;
	colourbank = 0;
	flipscreen = 0;
	bgpriority = 0;
	xoffsethack = 1;

	bg_tilemap = tilemap_create( multipac_get_tile_info, pacman_scan_rows, 8, 8, 36, 28 );

	tilemap_set_scrolldx( bg_tilemap, 0, 384 - 288 );
	tilemap_set_scrolldy( bg_tilemap, 0, 264 - 224 );
//	build_led_font();
}

PALETTE_INIT( multipac )
{
	UINT16 i,i1=0,i2,k,n=128;	/* n = size of one bank of lookup table */
	static const int resistances[3] = { 1000, 470, 220 };
	double rweights[3], gweights[3], bweights[2];
	UINT16 palette_size = machine->config->total_colors >> 2;
	UINT8 bit0, bit1, bit2, r, g, b;

	/* compute the color output resistor weights */
	compute_resistor_weights(0,	255, -1.0,
			3, &resistances[0], rweights, 0, 0,
			3, &resistances[0], gweights, 0, 0,
			2, &resistances[1], bweights, 0, 0);
	#define TOTAL_COLORS(gfxn) (machine->gfx[gfxn]->total_colors * machine->gfx[gfxn]->color_granularity)

	/* convert palette to mame equivalent. "total_colors" is size of MDRV_PALETTE_LENGTH and = size of palette roms */
	/* "color_prom" is a pointer to the start of REGION_PROMS and is used to read each byte from that region */

	/* allocate the colortable */
	machine->colortable = colortable_alloc(machine, palette_size);

	/* create a lookup table for the palette */
	for (i = 0; i < palette_size; i++)
	{

		/* red component */
		bit0 = (color_prom[i] >> 0) & 0x01;
		bit1 = (color_prom[i] >> 1) & 0x01;
		bit2 = (color_prom[i] >> 2) & 0x01;
		r = combine_3_weights(rweights, bit0, bit1, bit2);

		/* green component */
		bit0 = (color_prom[i] >> 3) & 0x01;
		bit1 = (color_prom[i] >> 4) & 0x01;
		bit2 = (color_prom[i] >> 5) & 0x01;
		g = combine_3_weights(gweights, bit0, bit1, bit2);

		/* blue component */
		bit0 = (color_prom[i] >> 6) & 0x01;
		bit1 = (color_prom[i] >> 7) & 0x01;
		b = combine_2_weights(bweights, bit0, bit1);

		colortable_palette_set_color(machine->colortable, i, MAKE_RGB(r, g, b));
	}

	color_prom += palette_size;
	/* Since lookup table immediately follows palette, color_prom now points to the beginning of the lookup table */
	/* k = bank counter; k << 5 is because each bank is 32 bytes long. TOTAL_COLORS = size of MDRV_COLORTABLE_LENGTH. */
	/* we are converting the lookup codes into the mame colour codes for each screen element */

	for (k = 0;k < (TOTAL_COLORS(0) / n); k++)
	{
		i = i1;
		i2 = i1 + n;		
		for (i = i1;i < i2;i++)
		{
			if (*color_prom & 15)
				colortable_entry_set_value(machine->colortable, i,(*color_prom & 15) + (k << 5));
			else
				colortable_entry_set_value(machine->colortable, i, 0);    /* preserve transparency */

			color_prom++;
		}
		i1 += n;
	}
}

VIDEO_UPDATE( multipac )
{
	if (bgpriority != 0)
		fillbitmap(bitmap,0,cliprect);
	else
		tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0);

	if( spriteram_size )
	{
		int offs;

		rectangle spriteclip = spritevisiblearea;
		sect_rect(&spriteclip, cliprect);

		/* Draw the sprites. Note that it is important to draw them exactly in this */
		/* order, to have the correct priorities. */
		for (offs = spriteram_size - 2;offs > 2*2;offs -= 2)
		{
			int color;
			int sx,sy;

			sx = 272 - spriteram_2[offs + 1];
			sy = spriteram_2[offs] - 31;
			color = ( spriteram[offs + 1] & 0x1f ) | (colourbank << 5);

			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx,sy,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color, 0));

			/* also plot the sprite with wraparound (tunnel in Crush Roller) */
			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx - 256,sy,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color, 0));
		}
		/* In the Pac Man based games (NOT Pengo) the first two sprites must be offset */
		/* one pixel to the left to get a more correct placement */
		for (offs = 2*2;offs >= 0;offs -= 2)
		{
			int color;
			int sx,sy;

			sx = 272 - spriteram_2[offs + 1];
			sy = spriteram_2[offs] - 31;
			color = ( spriteram[offs + 1] & 0x1f ) | (colourbank << 5);

			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 1,spriteram[offs] & 2,
					sx,sy + xoffsethack,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color, 0));

			/* also plot the sprite with wraparound (tunnel in Crush Roller) */
			drawgfx(bitmap,screen->machine->gfx[1],
					( spriteram[offs] >> 2 ) | (spritebank << 6),
					color,
					spriteram[offs] & 2,spriteram[offs] & 1,
					sx - 256,sy + xoffsethack,
					&spriteclip,TRANSPARENCY_PENS,
					colortable_get_transpen_mask(screen->machine->colortable, screen->machine->gfx[1], color, 0));
		}
	}

	if (bgpriority != 0)
		tilemap_draw(bitmap,cliprect,bg_tilemap,0,0);
	return 0;
}


WRITE8_HANDLER( multipac_gfxbank_w )
{
	charbank = data;
	spritebank = data;
}

/* multipac passes bankselect info for the 4a and 7f roms on separate bytes. MAME can only use one of them */
WRITE8_HANDLER( multipac_palbank_w )
{
	if (offset) colourbank = data;
}


/* =============================================
	96in1 / Mad Pac by Robbbert, July 2007
   ============================================= */


void _96in1b_gfxbank_w ( UINT8 gfxbank )
{
	UINT8 banks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 7, 4, 2, 3, 5, 6, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 };
	charbank = gfxbank;
	spritebank = gfxbank;
	colourbank = banks[gfxbank];
}

void madpac_gfxbank_w ( UINT8 gfxbank )
{
	charbank = gfxbank;
	spritebank = gfxbank;

	if (gfxbank > 15)
		colourbank = gfxbank - 15;
	else
		colourbank = 0;
}

/* ==============================================
	8in1 / 12in1 by Robbbert, July 2007
   ============================================== */

void pm8in1_gfxbank_w ( UINT8 gfxbank )
{
	UINT8 banks[] = { 0, 0, 0, 0, 1, 1, 1, 2 };
	charbank = banks[gfxbank];
	spritebank = charbank;
}

void pm12in1_gfxbank_w ( UINT8 gfxbank )
{
	UINT8 banks[] = { 0, 0, 0, 2, 0, 0, 0, 2, 1, 99, 1, 99, 1, 99, 1, 99 };
	charbank = banks[gfxbank];
	spritebank = charbank;
}


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

Jr. Pac-Man

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

/*
   0 -   31 = column 2 - 33 attr (used for all 54 rows)
  64 - 1791 = column 2 - 33 code (54 rows)
1794 - 1821 = column 34 code (28 rows)
1826 - 1853 = column 35 code (28 rows)
1858 - 1885 = column 0 code (28 rows)
1890 - 1917 = column 1 code (28 rows)
1922 - 1949 = column 34 attr (28 rows)
1954 - 1981 = column 35 attr (28 rows)
1986 - 2013 = column 0 attr (28 rows)
2018 - 2045 = column 1 attr (28 rows)
*/

static TILEMAP_MAPPER( jrpacman_scan_rows )
{
	int offs;

	row += 2;
	col -= 2;
	if ((col & 0x20) && (row & 0x20))
		offs = 0;
	else if (col & 0x20)
		offs = row + (((col&0x3) | 0x38)<< 5);
	else
		offs = col + (row << 5);
	return offs;
}

static TILE_GET_INFO( jrpacman_get_tile_info )
{
	int color_index, code, attr;
	if( tile_index < 1792 )
	{
		color_index = tile_index & 0x1f;
	}
	else
	{
		color_index = tile_index + 0x80;
	}

	code = videoram[tile_index] | (charbank << 8);
	attr = (videoram[color_index] & 0x1f) | (colortablebank << 5) | (palettebank << 6 );

	SET_TILE_INFO(0,code,attr,0);
}

static void jrpacman_mark_tile_dirty( int offset )
{
	if( offset < 0x20 )
	{
		/* line color - mark whole line as dirty */
		int i;
		for( i = 2 * 0x20; i < 56 * 0x20; i += 0x20 )
		{
			tilemap_mark_tile_dirty( bg_tilemap, offset + i );
		}
	}
	else if (offset < 1792)
	{
		/* tiles for playfield */
		tilemap_mark_tile_dirty( bg_tilemap, offset );
	}
	else
	{
		/* tiles & colors for top and bottom two rows */
		tilemap_mark_tile_dirty( bg_tilemap, offset & ~0x80 );
	}
}

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

  Start the video hardware emulation.

***************************************************************************/
VIDEO_START( jrpacman )
{
	init_save_state();

	charbank = 0;
	spritebank = 0;
	palettebank = 0;
	colortablebank = 0;
	flipscreen = 0;
	bgpriority = 0;

	xoffsethack = 1;

	bg_tilemap = tilemap_create( jrpacman_get_tile_info,jrpacman_scan_rows,8,8,36,54 );

	tilemap_set_transparent_pen( bg_tilemap, 0 );
	tilemap_set_scroll_cols( bg_tilemap, 36 );
	build_led_font();
}

WRITE8_HANDLER( jrpacman_videoram_w )
{
	videoram[offset] = data;
	jrpacman_mark_tile_dirty(offset);
}

WRITE8_HANDLER( jrpacman_charbank_w )
{
	if (charbank != (data & 1))
	{
		charbank = data & 1;
		tilemap_mark_all_tiles_dirty(bg_tilemap);
	}
}

WRITE8_HANDLER( jrpacman_spritebank_w )
{
	spritebank = (data & 1);
}

WRITE8_HANDLER( jrpacman_scroll_w )
{
	int i;
	for( i = 2; i < 34; i++ )
	{
		tilemap_set_scrolly( bg_tilemap, i, data );
	}
}

WRITE8_HANDLER( jrpacman_bgpriority_w )
{
	bgpriority = (data & 1);
}
