/* Seeing mame source, it would seem the original driver used an intel chip for
   input/output (controls and sound). This makes the driver much more complex, and
   it does not seem necessary, so I have just skipped the intel chip and taken directly
   controls and sound commands.
   Also this driver has emudx support, dx sounds + ay8910 sound (for the music).
*/

#include "gameinc.h"
#include "decode.h"
#include "ay8910.h"
#include "sasound.h"
#include "froggerm.h"
#include "emudx.h"
#include "dxsmp.h"

// defined in rgui.c for allegro, but it should be generic...
extern int raine_alert(char *title, char *s1, char *s2, char *s3, char *b1, char *b2, int c1, int c2);

static struct ROM_INFO frogger_roms[] =
{
  { "frogger.26", 0x1000, 0x597696d6, REGION_ROM1, 0x0000, LOAD_NORMAL },
  { "frogger.27", 0x1000, 0xb6e6fcc3, REGION_ROM1, 0x1000, LOAD_NORMAL },
  { "frsm3.7", 0x1000, 0xaca22ae0, REGION_ROM1, 0x2000, LOAD_NORMAL },
  { "frogger.608", 0x0800, 0xe8ab0256, REGION_ROM2, 0x0000, LOAD_NORMAL },
  { "frogger.609", 0x0800, 0x7380a48f, REGION_ROM2, 0x0800, LOAD_NORMAL },
  { "frogger.610", 0x0800, 0x31d7eb27, REGION_ROM2, 0x1000, LOAD_NORMAL },
  { "frogger.607", 0x0800, 0x05f7d883, REGION_GFX1, 0x0000, LOAD_NORMAL },
  { "frogger.606", 0x0800, 0xf524ee30, REGION_GFX1, 0x0800, LOAD_NORMAL },
  { "pr-91.6l", 0x0020, 0x413703bf, REGION_PROMS, 0x0000, LOAD_NORMAL },
  { NULL, 0, 0, 0, 0, 0 }
};

/* If there is a difference except the sega name instead of konami in frogger1 and
   frogger2, then this difference is well hidden !!! */

static struct DSW_DATA dsw_data_frogger_1[] =
{
  { MSG_LIVES, 0x03, 4 },
  { "3", 	0x00, 0x00 },
  { "5", 	0x01, 0x00 },
  { "7", 	0x02, 0x00 },
  { "256 (Cheat)", 	0x03, 0x00 },
  { NULL, 0, 0}
};

static struct DSW_DATA dsw_data_frogger_2[] =
{
  { MSG_COINAGE, 0x06, 4 },
  { "A 2/1 B 2/1 C 2/1", 	0x02, 0x00 },
  { "A 2/1 B 1/3 C 2/1", 	0x04, 0x00 },
  { "A 1/1 B 1/1 C 1/1", 	0x00, 0x00 },
  { "A 1/1 B 1/6 C 1/1", 	0x06, 0x00 },
  { MSG_CABINET, 0x08, 2 },
  { MSG_UPRIGHT, 	0x00, 0x00 },
  { MSG_TABLE, 	0x08, 0x00 },
  { NULL, 0, 0}
};

static struct DSW_INFO frogger_dsw[] =
{
  { 0x2, 0x00, dsw_data_frogger_1 },
  { 0x4, 0x00, dsw_data_frogger_2 },
  { 0, 0, NULL }
};

static struct INPUT_INFO frogger_inputs[] =
{
  { KB_DEF_P1_UP, MSG_P1_UP, 0x00, 0x01, BIT_ACTIVE_0 },
  { KB_DEF_SERVICE, MSG_SERVICE, 0x00, 0x04, BIT_ACTIVE_0 },
  { KB_DEF_P1_RIGHT, MSG_P1_RIGHT, 0x00, 0x10, BIT_ACTIVE_0 },
  { KB_DEF_P1_LEFT, MSG_P1_LEFT, 0x00, 0x20, BIT_ACTIVE_0 },
  { KB_DEF_COIN2, MSG_COIN2, 0x00, 0x40, BIT_ACTIVE_0 },
  { KB_DEF_COIN1, MSG_COIN1, 0x00, 0x80, BIT_ACTIVE_0 },

  { KB_DEF_P1_RIGHT, MSG_P1_RIGHT, 0x02, 0x10, BIT_ACTIVE_0 },
  { KB_DEF_P1_LEFT, MSG_P1_LEFT, 0x02, 0x20, BIT_ACTIVE_0 },
  { KB_DEF_P2_START, MSG_P2_START, 0x02, 0x40, BIT_ACTIVE_0 },
  { KB_DEF_P1_START, MSG_P1_START, 0x02, 0x80, BIT_ACTIVE_0 },

  { KB_DEF_P1_DOWN, MSG_P1_DOWN, 0x04, 0x01, BIT_ACTIVE_0 },

  { KB_DEF_P1_UP, MSG_P1_UP, 0x04, 0x10, BIT_ACTIVE_0 },
  { KB_DEF_P1_DOWN, MSG_P1_DOWN, 0x04, 0x40, BIT_ACTIVE_0 },
#ifdef RAINE_DEBUG
  { KB_DEF_P1_B2, MSG_P1_B2, 0x08, 0x8, BIT_ACTIVE_1 },
#endif
   { 0, NULL, 0, 0, 0 },
};

static struct GfxLayout galaxian_charlayout =
{
	8,8,
	RGN_FRAC(1,2),
	2,
	{ RGN_FRAC(0,2), RGN_FRAC(1,2) },
	{ 0, 1, 2, 3, 4, 5, 6, 7 },
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
	8*8
};
static struct GfxLayout galaxian_spritelayout =
{
	16,16,
	RGN_FRAC(1,2),
	2,
	{ RGN_FRAC(0,2), RGN_FRAC(1,2) },
	{ 0, 1, 2, 3, 4, 5, 6, 7,
			8*8+0, 8*8+1, 8*8+2, 8*8+3, 8*8+4, 8*8+5, 8*8+6, 8*8+7 },
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,
			16*8, 17*8, 18*8, 19*8, 20*8, 21*8, 22*8, 23*8 },
	32*8
};

/* Don't know how mame found this frogger timer ??!!! What is sure is that without
   the timer, the ay8910 will produce no sounds at all ! Which made its emulation rather
   hard... */
static int frogger_timer[10] =
{
	0x00, 0x10, 0x08, 0x18, 0x40, 0x90, 0x88, 0x98, 0x88, 0xd0
};

static UINT8 frogger_portB_r(UINT32 offset)
{
	/* need to protect from totalcycles overflow */
	static int last_totalcycles = 0;

	/* number of Z80 clock cycles to count */
	static int clock;

	int current_totalcycles;

	current_totalcycles = dwElapsedTicks;
	clock = (clock + (current_totalcycles-last_totalcycles)) % 5120;

	last_totalcycles = current_totalcycles;
	return frogger_timer[clock/512];
}

struct AY8910interface frogger_ay8910_interface =
{
	1,	/* 1 chip */
	14318000/8,	/* 1.78975 MHz */
	{ 255 | (0x80<<8) },
	{ soundlatch_lo_r },
	{ frogger_portB_r },
	{ 0 },
	{ 0 }
};

struct dxsmpinterface frogger_emudx_interface =
  {
    "froggerm.dx",
    YM3012_VOL(255,MIXER_PAN_LEFT,255,MIXER_PAN_RIGHT)
  };

static struct SOUND_INFO frogger_sound[] =
{
   { SOUND_AY8910,  &frogger_ay8910_interface,  },
   { SOUND_DXSMP, &frogger_emudx_interface, },
   { 0,             NULL,               },
};

static UINT8 *gfx_ram,*attributes, *spriteram, *nmi_enable,*GFX_SOLID[2],*gfx,*spr,
  *flip_screen_x,*flip_screen_y;

static UINT16 RAM_PAL[10*4];

static UINT8 *copy_sprites(UINT8 *region) {
  UINT8 *dest = AllocateMem(0x1000);
  memcpy(dest, region, 0x1000);
  return dest;
}

static int layer_id_data[2];
static UINT8 cursam=music1;

static void frogger_sound_w(UINT32 offset, UINT16 data) {
/* Sound cpu codes:
   (directly from emudx)

1 - Credit?
2 - Splash
3 - Splat
4 - Frog Jump
5 - Time running out?
6 - dead (but be carefull this command is also sent at the start of the game)
7
8
9
10 - Intro
11 - Start main tune when samples stop?
12
13 - Game over ?
14 - Next tune
15 - Main tune
16 - All frogs home?

24 - Lady Frog

8/240 - Frog home?

208 - Racing car?

255 - Theme?

Mike

*/

/* I commented the music sounds to have the ay8910 playing the music instead */

  static int dont_play_dead;

  if (!raine_nb_samples) {
    latch = data;
    cpu_interrupt(CPU_Z80_1,0x38);

    return;
  }

  if(data==1) raine_play_sample(coin,200);
  else
    if(data==2)
    {
      raine_stop_samples();
      raine_play_sample(splash,100);
    }
  else if(data==3)
    {
      raine_stop_samples();
      raine_play_sample(splat,255);
    }
  else if(data==4) raine_play_sample(jump,100);
  else if(data==5) raine_play_sample(timeout,100);
/*   else if(data==10) raine_play_sample(start,40); */

  else if(data==13)
    {
      raine_stop_samples();
      raine_play_sample(gameover,100);
    }

  else if(data==14)
    {
      raine_stop_samples();
      raine_play_sample(cursam++,100);
      if(cursam>music6) cursam=music1;
    }

  else if(data==16)
    {
      raine_stop_samples();
      raine_play_sample(allhome,250);
    }
  else if(data==24) raine_play_sample(coin,200);
  else if(data==15) {
    raine_stop_samples();
    raine_play_sample(maintune,100);
  }
  else if(data==208) raine_play_sample(car,100);

  else if(data==240 || data==8) raine_play_sample(home,250);
  else if(data==0x6) {
    if (dont_play_dead) {
      dont_play_dead = 0;
    } else {
      raine_stop_samples();
      raine_play_sample(dead,250);
    }
  } else if (data == 11) // start of game
    dont_play_dead = 1;
  else if (data != 6 && data != 12){
    // 6 seems to be a generic command : sent when the game starts, and also when you
    // loose a life...
    latch = data;
/*     printf("unknown command %x\n",data); */
    cpu_interrupt(CPU_Z80_1,0x38);
    if (data == 13 || data == 14 || data == 16) // game over, music start, all home
      raine_stop_samples();
  }
}

static UINT16 corresp_tiles[256];

static UINT16 char_map[32*7];
static UINT8 *char_tab;

static void setup_frog_gfx(void)
{
  int h[]={1,28,-2,25};
  int a,x=0,chr=0;
  UINT16 *src;
  UINT8 *dest;

  for(a=0;a<256;a++)
    {
      corresp_tiles[a] = a+h[x]-(chr*2);
      x++;
      if(x==4)
	{
	  x=0;
	  chr++;
	  if(chr==14) chr=0;
	}
    }

  if (!(char_tab = AllocateMem(45*256))) return;

  /* This crazy function tries to keep the pseudo 3d mapping for the chars
     This can't be handled by the emudx module because the characters are not contiguous
     I must use the correspondance table here. And moreover they use this pseudo 3d look
     which requires more than 1 color ! */
  for (chr=0; chr<45; chr++) {
    if (chr==44)
      src = (UINT16*)&emudx_sprites[corresp_tiles[0x4e]<<9];
    else
      src = (UINT16*)&emudx_sprites[corresp_tiles[chr]<<9];
    dest = char_tab + chr*16*16;
    for (a=0; a<0x100; a++) {
      if (src[a] != emudx_transp) {
	int red = (src[a] & 0xf800)>>11;
	if ((src[a] & 0x1f) > red) red = src[a] & 0x1f; // some are mapped to blue...
	if (!red) red = 1; // avoid transparency !
	dest[a] = red;
      } else {
	dest[a] = 0;
      }
    }
  }

  for (a=0; a<0x20; a++) {
    int c=a<<3;
    if (display_cfg.bpp == 15) {
      GET_PEN_FOR_COLOUR_15(c,c,c,char_map[a]); // white
      GET_PEN_FOR_COLOUR_15(c,0,c,char_map[a+32]); // magenta
      GET_PEN_FOR_COLOUR_15(c,0,0,char_map[a+32*2]); // red
      GET_PEN_FOR_COLOUR_15(0,c,c,char_map[a+32*3]); // cyan
      GET_PEN_FOR_COLOUR_15(c,c,0,char_map[a+32*4]); // yellow
      GET_PEN_FOR_COLOUR_15(0,c,0,char_map[a+32*5]); // green
    } else { // 16
      GET_PEN_FOR_COLOUR_16(c,c,c,char_map[a]); // white
      GET_PEN_FOR_COLOUR_16(c,c,c,char_map[a+32]); // white (undefined in fact)
      GET_PEN_FOR_COLOUR_16(c,0,c,char_map[a+32*2]); // magenta
      GET_PEN_FOR_COLOUR_16(c,0,0,char_map[a+32*3]); // red
      GET_PEN_FOR_COLOUR_16(0,c,c,char_map[a+32*4]); // cyan
      GET_PEN_FOR_COLOUR_16(c,c,0,char_map[a+32*5]); // yellow
      GET_PEN_FOR_COLOUR_16(0,c,0,char_map[a+32*6]); // green
    }
  }
}

/* We need at least 32 for the emudx sprites (32x32) */
#define BORDER 32

static int draw_emudx_tile;

#ifdef RAINE_DEBUG
static void draw_debug_layer() {
  UINT8 code, color;
  SCROLL_REGS;
  UINT8 *map,*solid;
  int coul1, coul2,sx,sy;
  char str[4];

  // background color
  MAP_PALETTE_MAPPED_NEW(
			 8,
			 4,
			 map
			 );
  /* The screen is split by 2 bands of colour. These colors are not actually drawn by
     the game, but it was verified on the original hardware (as mentioned in the mame
     driver) */
  switch(display_cfg.bpp) {
  case 8: coul1 = map[0]; coul2 = map[1]; break;
  case 15:
  case 16: coul1 = ReadWord(&map[0]); coul2 = ReadWord(&map[2]); break;
  default: coul1 = ReadLong(&map[0]); coul2 = ReadLong(&map[4]); break;
  }
  rectfill(GameBitmap,BORDER,BORDER,BORDER+224*2,BORDER+256*2/2,coul2);
  rectfill(GameBitmap,BORDER,BORDER+256*2/2,BORDER+224*2,BORDER+256*2,coul1);

  if( check_layer_enabled(layer_id_data[0])) {
    solid = GFX_SOLID[0];

    /* No scroll register for this layer (0,0) */
    MAKE_SCROLL_n_8(256,224,1,0, 0);

    /* These complex looking lines are just the unrolling of START_SCROLL_8(BORDER,BORDER,256,224)
       + the line scroll handling between the fors */

    zz=zzzz;
    for(x=(BORDER);(UINT32)x<(256+BORDER);x+=8){
      int coffs = attributes[(x-BORDER)/8*2];
      int xoffs=0;

      /* In fact it's not a true line scroll it would rather be some sort of "character"
	 scroll, which means that the offset is applied to the whole character line (8
	 pixels). As such, we can just change the offset, without calling the ldraw
	 functions which become unnecessary here ! The offset is in pixels though, not in
	 characters, so we compute an intermediate xoffs...
	 It's more like changing the layer scroll offset every 8 pixels or every row */

      if (coffs) {
	coffs = ((coffs << 4) | (coffs >> 4)) & 0xff; // frogger modify
	xoffs = (coffs&7);
	coffs /= 8;
      }

      for(y=(int)(8-xoffs);(int)y<(224+24-xoffs);y+=8){
	zz = ((((y+xoffs)/8)+coffs)&31)*32+(x-BORDER)/8; // direct access (ignores scrollx, scrolly)
	code = gfx_ram[zz];
	color = attributes[((zz & 0x1f) << 1) | 1];
	color = ((color >> 1) & 0x03) | ((color << 2) & 0x04); // frogger modify

	if (solid[code]) {
	  MAP_PALETTE_MAPPED_NEW(
				 color,
				 4,
				 map
				 );
	  sy = (y-8)*2+BORDER-16; // convert to 16x16
	  sx = (x-BORDER)*2+BORDER;
	  if (solid[code] == 1) // transp
	    Draw8x8_Trans_Mapped_Rot(&gfx[code<<6],sx,sy,map);
	  else
	    Draw8x8_Mapped_Rot(&gfx[code<<6],sx,sy,map);
	  sprintf(str,"%02x",code);
	  textout_fast(str,448+BORDER*2-8-sy,sx+8,get_white_pen());
	  sprintf(str,"%x",color);
	  textout_fast(str,448+BORDER*2-8-sy+8,sx,get_white_pen());
	}
      }
    }
  }
}
#endif

static void draw_emudx() {
  UINT8 code,color;
  SCROLL_REGS;
  UINT8 *map,*solid;
  int coul1, coul2;

#ifdef RAINE_DEBUG
  if (input_buffer[8] & 8) {
    draw_debug_layer();
    return;
  }
#endif

  if (display_cfg.bpp > 16 || display_cfg.bpp < 15) {
    print_ingame(1,"switch to 16bpp color depth and reload");
    return;
  }

  if (draw_emudx_tile) {
    blit(emudx_tiles[0], GameBitmap, 0, 0, BORDER, BORDER, 448, 512);
    draw_emudx_tile = 0;
    // Make sure the fps counter is visible
    switch(raine_cfg.show_fps_mode) {
    case 1:
    case 2: rectfill(GameBitmap, BORDER+224*2-9*6,BORDER, BORDER+224*2, BORDER+8,0);
      break;
    case 3:
    case 4:
      rectfill(GameBitmap,BORDER+224*2-10*6,BORDER, BORDER+224*2, BORDER+8*7,0);
      break;
    }
  } else {
    /* The screen is split by 2 bands of colour. These colors are not actually drawn by
       the game, but it was verified on the original hardware (as mentioned in the mame
       driver) */
    // background color
    MAP_PALETTE_MAPPED_NEW(
			   8,
			   4,
			   map
			   );
    switch(display_cfg.bpp) {
    case 8: coul1 = map[0]; coul2 = map[1]; break;
    case 15:
    case 16: coul1 = ReadWord(&map[0]); coul2 = ReadWord(&map[2]); break;
    default: coul1 = ReadLong(&map[0]); coul2 = ReadLong(&map[4]); break;
    }
    rectfill(GameBitmap,BORDER,BORDER,BORDER+224*2,BORDER+256*2/2,coul2);
    rectfill(GameBitmap,BORDER,BORDER+256*2/2,BORDER+224*2,BORDER+256*2,coul1);
  }

  /* A note about optimization : mame and emudx thought it was nice to have a buffer
     to handle dirty areas to redraw here. The point is that during the game most of the
     screen is moving because of linescrolls effects (cars on bottom part, trees on the
     top). So in fact your dirty buffer is not really usefull, I am not even sure it does
     not make things slower than what they should be ! */

  if( check_layer_enabled(layer_id_data[0])) {
    solid = GFX_SOLID[0];

    /* No scroll register for this layer (0,0) */
    MAKE_SCROLL_n_8(512,448,1,0, 0);

    /* These complex looking lines are just the unrolling of START_SCROLL_8(BORDER,BORDER,256,224)
       + the line scroll handling between the fors */

    zz=zzzz;
    for(x=(BORDER);(UINT32)x<(256*2+BORDER);x+=16){
      int coffs = attributes[(x-BORDER)/16*2];
      int xoffs=0;

      /* In fact it's not a true line scroll it would rather be some sort of "character"
	 scroll, which means that the offset is applied to the whole character line (8
	 pixels). As such, we can just change the offset, without calling the ldraw
	 functions which become unnecessary here ! The offset is in pixels though, not in
	 characters, so we compute an intermediate xoffs...
	 It's more like changing the layer scroll offset every 8 pixels or every row */

      if (coffs) { // don't touch that : these offsets are inteded for 8x8 sprites !
	coffs = ((coffs << 4) | (coffs >> 4)) & 0xff; // frogger modify
	xoffs = (coffs&7);
	coffs /= 8;
      }

      for(y=(int)(0-xoffs);(int)y<(256-xoffs);y+=8){
	int sy;
	if (y<0) continue;
	zz = ((((y+xoffs)/8)+coffs)&31)*32+(x-BORDER)/16; // direct access (ignores scrollx, scrolly)
	code = gfx_ram[zz];
	color = attributes[((zz & 0x1f) << 1) | 1];
	color = ((color >> 1) & 0x03) | ((color << 2) & 0x04); // frogger modify

	if (solid[code]) {
/* 	  MAP_PALETTE_MAPPED_NEW( */
/* 				 color, */
/* 				 4, */
/* 				 map */
/* 				 ); */
	  sy = (y-8)*2 +BORDER-16; // convert to 16x16
	  if (y<0) continue;
	  if (code==16 || (code>63 && code<76)) {
	    draw_emudx_tile = 1;
	    continue;
	  }
	  else if (code<=43 || (code>63 && code<80) || (code>207 && code<212)) {
	    // Normal character
	    /* Actually the real characters seem to be codes from 0 to 9 for digits
	       and then from 0x11 for A to 42 (?) and included 4e for copyright
	       The progress bar for time uses characters $c and $f at least, but it has
	       the same problems as normal chars : not the right colors (does not switch
	       to red).
	    */
	    if (code <= 43 || code == 0x4e) {
	      // special mapping for the chars to retrieve the original colors
	      if (code >= 10 && code <= 16) { // pseudo graphic (progress bar)
		// special color mapping for these
		if (color == 5) color = 6;
		else if (color == 0) color = 3;
	      } else if (code == 0x4e) code = 44; // copyright symbol

	      if (solid[code] == 1) // transp
		Draw16x16_Trans_Mapped_Rot(&char_tab[code<<8],x,sy,(UINT8*)&char_map[32*color]);
	      else
		Draw16x16_Mapped_Rot(&char_tab[code<<8],x,sy,(UINT8*)&char_map[32*color]);
	    } else {
	      if (solid[code] == 1) // transp
		Draw16x16_Trans_16_Rot(&emudx_sprites[corresp_tiles[code]<<9],x,sy,0);
	      else
		Draw16x16_16_Rot(&emudx_sprites[corresp_tiles[code]<<9],x,sy,0);
	    }
	  }
	  else if((((code+3)&3)==3)) {
	    /* We can't do the replacement of the chars by the sprites like what emudx
	       does (x-24,y-24) because it's incompatible with screen rotation.
	       So the test ((code+3)&3)==3 is here to detect the upper left corner of
	       the big tile (formed by 4 16x16 tiles) instead of the lower right corner
	       in emudx */
	    if(code>135 && code<156)
	      {
		Draw32x32_Trans_Alpha50_16_flip_Rot(&emudx_sprites32[(code/4)<<11],x,sy,0,0);
		continue;
	      }
	    else
	      {
		Draw32x32_Trans_16_flip_Rot(&emudx_sprites32[(code/4)<<11],x,sy,0,0);
		continue;
	      }
	  }
	}
      }
    }
  }

  if( check_layer_enabled(layer_id_data[1])) {
    int offs;
    UINT8 color;
    solid = GFX_SOLID[1];

    for (offs = 0x20 - 4;offs >= 0;offs -= 4) {
      UINT8 sx,sy;
      int flipx,flipy,code;

      sx = spriteram[offs + 3] + 1; /* the existence of +1 is supported by a LOT of games */
      sy = spriteram[offs];			/* Anteater, Mariner, for example */
      flipx = spriteram[offs + 1] & 0x40;
      flipy = spriteram[offs + 1] & 0x80;
      code = spriteram[offs + 1] & 0x3f;
      color = spriteram[offs + 2] & 7;

      color = ((color >> 1) & 0x03) | ((color << 2) & 0x04); // frogger modify
      sy = ((sy << 4) | (sy >> 4)); // frogger modify
      /* Notice : flip_screen_x and flip_screen_y are not yet handled for the layer.
	 Not sure if it's usefull or not */
      if (*flip_screen_x & 1) {
	sx = 240 - sx;
	flipx = !flipx;
      }

      if (*flip_screen_y & 1) {
	flipy = !flipy;
      } else {
	sy = 240 - sy;
      }

      if (solid[code]) {
/* 	MAP_PALETTE_MAPPED_NEW( */
/* 			       color, */
/* 			       4, */
/* 			       map */
/* 			       ); */
	if (sy >= 8 && sy <= 8+224) {
	  x = sx*2 + BORDER;
	  y = (sy-16)*2 + BORDER;
	  if (x>=0 && y>=0) {
	    if(code>33 && code<37) {
	      Draw32x32_Trans_Alpha50_16_flip_Rot(&emudx_sprites32[(code)<<11],x,y,0,(flipx ? 1 : 0) | (flipy?2:0));
	    } else {
	      if (solid[code] == 1) { // transp
		if (color==2 && (code>27 && code<34)) code +=36;
		Draw32x32_Trans_16_flip_Rot(&emudx_sprites32[code<<11],x,y,0,(flipx ? 1 : 0) | (flipy?2:0));
	      } else {// solid
		if (color==2 && (code>27 && code<34)) code +=36;

		Draw32x32_16_flip_Rot(&emudx_sprites32[code<<11],x,y,0,(flipx ? 1 : 0) | (flipy?2:0));
	      }
	    }
	  }
	}
      }
    }
  }
}

static void load_frogger() {
  UINT8 *color_prom = load_region[REGION_PROMS],*decode1,*decode2,*ram2,*rom2 = load_region[REGION_CPU2];
  int i,dest_size;

  /* the first ROM of the second CPU has data lines D0 and D1 swapped. Decode it. */
  ROM = load_region[REGION_CPU2];
  for (i = 0;i < 0x0800;i++)
    ROM[i] = BITSWAP8(ROM[i],7,6,5,4,3,2,0,1);

  /* likewise, the 2nd gfx ROM has data lines D0 and D1 swapped. Decode it. */
  ROM = load_region[REGION_GFX1];
  for (i = 0x0800;i < 0x1000;i++)
    ROM[i] = BITSWAP8(ROM[i],7,6,5,4,3,2,0,1);

  ROM = load_region[REGION_CPU1];
  RAMSize = 0x800 + 0x400 + 0x100 + 10 + 0x400;
  if (!(RAM = AllocateMem(RAMSize))) return;

  gfx_ram = RAM+0x800;
  attributes = gfx_ram + 0x400;
  spriteram = attributes + 0x40;

  nmi_enable = RAM + 0x800 + 0x400 + 0x100;
  flip_screen_x = nmi_enable + 1;
  flip_screen_y = nmi_enable + 2;
  ram2 = flip_screen_y + 1;

  AddZ80AROMBase(ROM, 0x0038, 0x0066); // ???!
  AddZ80ARead(0x0000, 0x3fff, NULL, ROM);
  AddZ80ARW(0x8000, 0x87ff, NULL, RAM);
  AddZ80ARW(0xa800, 0xabff, NULL, gfx_ram);
  AddZ80ARW(0xb000, 0xb0ff, NULL, attributes);

  AddZ80AWrite(0xb808, 0xb808, NULL, nmi_enable);
  AddZ80AWrite(0xb80c, 0xb80c, NULL, flip_screen_y);
  AddZ80AWrite(0xb810, 0xb810, NULL, flip_screen_x);
  AddZ80AWrite(0xd000, 0xd000, frogger_sound_w, NULL);

  /* I test inputs using the very much simplified method of emudx instead of the
     "emulate everything" method of mame. Hope I won't need anything from mame here. */
  AddZ80ARead(0xe000, 0xe004, NULL, input_buffer);
  AddZ80ARead(0x0000, 0xFFFF, DefBadReadZ80,		NULL);
  AddZ80AWrite(0x0000, 0xFFFF, DefBadWriteZ80,		NULL);

  AddZ80AReadPort(0x00, 0xFF, DefBadReadZ80,			NULL);	// <bad reads>
  AddZ80AReadPort(-1, -1, NULL, NULL);

  AddZ80AWritePort(0xAA, 0xAA, StopZ80Mode2,			NULL);	// Trap Idle Z80
  AddZ80AWritePort(0x00, 0xFF, DefBadWriteZ80,			NULL);	// <bad reads>
  AddZ80AWritePort(-1, -1, NULL, NULL);
  AddZ80AInit();

  // sound z80
  AddZ80BROMBase(rom2, 0x0038, 0x0066); // ???!
  AddZ80BRead(0x0000, 0x1fff, NULL, rom2);
  AddZ80BRW(0x4000, 0x43ff, NULL, ram2);
  AddZ80BRead(0x0000, 0xFFFF, DefBadReadZ80,		NULL);
  AddZ80BWrite(0x0000, 0xFFFF, DefBadWriteZ80,		NULL);

  AddZ80BReadPort(0x40, 0x40, AY8910_read_port_0_r,	NULL);	// <bad reads>
  AddZ80BReadPort(0x00, 0xFF, DefBadReadZ80,		NULL);	// <bad reads>
  AddZ80BReadPort(-1, -1, NULL, NULL);

  AddZ80BWritePort(0x40, 0x40, AY8910_write_port_0_w,	NULL);	// Trap Idle Z80
  AddZ80BWritePort(0x80, 0x80, AY8910_control_port_0_w,	NULL);	// Trap Idle Z80
  AddZ80BWritePort(0x00, 0xFF, DefBadWriteZ80,		NULL);	// <bad reads>
  AddZ80BWritePort(-1, -1, NULL, NULL);
  AddZ80BInit();

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

  Convert the color PROMs into a more useable format.

  Galaxian has one 32 bytes palette PROM, 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

  The output of the background star generator is connected this way:

  bit 5 -- 100 ohm resistor  -- BLUE
        -- 150 ohm resistor  -- BLUE
        -- 100 ohm resistor  -- GREEN
        -- 150 ohm resistor  -- GREEN
        -- 100 ohm resistor  -- RED
  bit 0 -- 150 ohm resistor  -- RED

  The blue background in Scramble and other games goes through a 390 ohm
  resistor.

  The bullet RGB outputs go through 100 ohm resistors.

  The RGB outputs have a 470 ohm pull-down each.

***************************************************************************/
  for (i=0; i<get_region_size(REGION_PROMS); i++) {
    int red = (color_prom[i] & 7);
    int green = (color_prom[i] & 0x38) >> 3;
    int blue = (color_prom[i] & 0xc0) >> 5;
    RAM_PAL[i] = (blue) | (green<<3) | (red<<6);
  }
  RAM_PAL[i] = 0;
  RAM_PAL[i+1] = 2; // background color for half top of the screen
  InitPaletteMap((UINT8*)RAM_PAL, 9, 4, 0x200); // 8 banks of 4 colors each : extreme !!!
  set_colour_mapper(&col_map_xxxxRrrgggbbb);
  layer_id_data[0] = add_layer_info("BG");
  layer_id_data[1] = add_layer_info("SPRITES");

  // The wicked layouts
  load_region[REGION_GFX2] = copy_sprites(load_region[REGION_GFX1]);
  decode1 = decode_gfx(load_region[REGION_GFX1],0x1000,&galaxian_charlayout,&dest_size);
  GFX_SOLID[0] = make_solid_mask_8x8(decode1,dest_size/64);
  decode2 = decode_gfx(load_region[REGION_GFX2],0x1000,&galaxian_spritelayout,&dest_size);
  GFX_SOLID[1] = make_solid_mask_16x16(decode2,dest_size/0x100);

  FreeMem(load_region[REGION_GFX1]);
  FreeMem(load_region[REGION_GFX2]);
  gfx = load_region[REGION_GFX1] = decode1;
  spr = load_region[REGION_GFX2] = decode2;

  ay8910_amplify = 8;
  if (exists_emudx_file("froggerg.dx")) {
#ifndef SDL
    if((raine_alert(raine_translate_text("EmuDX"),NULL,raine_translate_text("EmuDX support?"),NULL,raine_translate_text("&Yes"),raine_translate_text("&No"),'Y','N'))==1)
#endif
      {
      load_emudx("froggerg.dx",1,280,282,351,
		 0,0, // no chars here, they seem to have coloured tiles for the chars
		 448,512,0xf81f,draw_emudx);
      setup_frog_gfx();
      draw_emudx_tile = 0;
    }
  }
}

static void draw_frogger() {
  /* The only difficulty here is the row/col scroll of the layer (since the screen is
     rotated you call it either col or row scroll ! */

  UINT8 code, color;
  SCROLL_REGS;
  UINT8 *map,*solid;
  int coul1, coul2;

  // background color
  MAP_PALETTE_MAPPED_NEW(
			 8,
			 4,
			 map
			 );
  /* The screen is split by 2 bands of colour. These colors are not actually drawn by
     the game, but it was verified on the original hardware (as mentioned in the mame
     driver) */
  switch(display_cfg.bpp) {
  case 8: coul1 = map[0]; coul2 = map[1]; break;
  case 15:
  case 16: coul1 = ReadWord(&map[0]); coul2 = ReadWord(&map[2]); break;
  default: coul1 = ReadLong(&map[0]); coul2 = ReadLong(&map[4]); break;
  }
  rectfill(GameBitmap,BORDER,BORDER,BORDER+224,BORDER+256/2,coul2);
  rectfill(GameBitmap,BORDER,BORDER+256/2,BORDER+224,BORDER+256,coul1);

  if( check_layer_enabled(layer_id_data[0])) {
    solid = GFX_SOLID[0];

    /* No scroll register for this layer (0,0) */
    MAKE_SCROLL_n_8(256,224,1,0, 0);

    /* These complex looking lines are just the unrolling of START_SCROLL_8(BORDER,BORDER,256,224)
       + the line scroll handling between the fors */

    zz=zzzz;
    for(x=(BORDER);(UINT32)x<(256+BORDER);x+=8){
      int coffs = attributes[(x-BORDER)/8*2];
      int xoffs=0;

      /* In fact it's not a true line scroll it would rather be some sort of "character"
	 scroll, which means that the offset is applied to the whole character line (8
	 pixels). As such, we can just change the offset, without calling the ldraw
	 functions which become unnecessary here ! The offset is in pixels though, not in
	 characters, so we compute an intermediate xoffs...
	 It's more like changing the layer scroll offset every 8 pixels or every row */

      if (coffs) {
	coffs = ((coffs << 4) | (coffs >> 4)) & 0xff; // frogger modify
	xoffs = (coffs&7);
	coffs /= 8;
      }

      for(y=(int)(8-xoffs);(int)y<(224+24-xoffs);y+=8){
	zz = ((((y+xoffs)/8)+coffs)&31)*32+(x-BORDER)/8; // direct access (ignores scrollx, scrolly)
	code = gfx_ram[zz];
	color = attributes[((zz & 0x1f) << 1) | 1];
	color = ((color >> 1) & 0x03) | ((color << 2) & 0x04); // frogger modify

	if (solid[code]) {
	  MAP_PALETTE_MAPPED_NEW(
				 color,
				 4,
				 map
				 );
	  if (solid[code] == 1) // transp
	    Draw8x8_Trans_Mapped_Rot(&gfx[code<<6],x,y+BORDER-16,map);
	  else
	    Draw8x8_Mapped_Rot(&gfx[code<<6],x,y+BORDER-16,map);
	}
      }
    }
  }

  if( check_layer_enabled(layer_id_data[1])) {
    solid = GFX_SOLID[1];
    int offs;
    for (offs = 0x20 - 4;offs >= 0;offs -= 4) {
      UINT8 sx,sy,color;
      int flipx,flipy,code;

      sx = spriteram[offs + 3] + 1; /* the existence of +1 is supported by a LOT of games */
      sy = spriteram[offs];			/* Anteater, Mariner, for example */
      flipx = spriteram[offs + 1] & 0x40;
      flipy = spriteram[offs + 1] & 0x80;
      code = spriteram[offs + 1] & 0x3f;
      color = spriteram[offs + 2] & 7;

      color = ((color >> 1) & 0x03) | ((color << 2) & 0x04); // frogger modify
      sy = ((sy << 4) | (sy >> 4)); // frogger modify
      /* Notice : flip_screen_x and flip_screen_y are not yet handled for the layer.
	 Not sure if it's usefull or not */
      if (*flip_screen_x & 1) {
	sx = 240 - sx;
	flipx = !flipx;
      }

      if (*flip_screen_y & 1) {
	flipy = !flipy;
      } else {
	sy = 240 - sy;
      }

      if (solid[code]) {
	MAP_PALETTE_MAPPED_NEW(
			       color,
			       4,
			       map
			       );
	if (solid[code] == 1) // transp
	  Draw16x16_Trans_Mapped_flip_Rot(&spr[code<<8],sx+BORDER,sy+BORDER-16,map,(flipx ? 1 : 0) | (flipy?2:0));
	else // solid
	  Draw16x16_Mapped_flip_Rot(&spr[code<<8],sx+BORDER,sy+BORDER-16,map,(flipx ? 1 : 0) | (flipy?2:0));
      }
    }
  }
}

static struct VIDEO_INFO frogger_video =
{
   draw_frogger,
   256,
   224,
   BORDER,
   VIDEO_ROTATE_90 |
   VIDEO_ROTATABLE,
   NULL, // no automatic region decoding
};

#define frogger_sound frogger_sound

/* #define SLICES 48 */

static void execute_frogger() {
  cpu_execute_cycles(CPU_Z80_0,3072000/60);
  if (*nmi_enable) {
    cpu_int_nmi(CPU_Z80_0);
  }

  // Get an irq by the main cpu for each new sound command
  // so the frequency of the cpu determines music speed. This one is taken from mame
  cpu_execute_cycles(CPU_Z80_1,1789750/60);
}

GME( frogger,
     "Frogger",
     COMPANY_ID_KONAMI,
     1981,
     GAME_MISC);
