#include "gameinc.h"
#include "decode.h"
#include "dkongm.h"
#include "sasound.h"
#include "emudx.h"
#include "blit.h"
#include "cpuid.h"
#include "profile.h"
#include "emumain.h" // set_reset_function
#include "dxsmp.h"
#include "savegame.h"

#define MASKRED 0xF800
#define MASKGREEN 0x07E0
#define MASKBLUE 0x1F

extern int disp_y_32;

#if 0
// Attempt to emulate the draw_trans_sprite combined with set_screen_blender effect.
// Still not perfect. Using allegro for now...
static void my_draw_alpha(UINT16 *src, int x, int y) {
  UINT32 sred,sgreen,sblue, dred,dgreen,dblue,dx,dy;
  UINT16 *dest;
  dx = disp_y_32 - y;
  y = x;
  x = dx;
  for (dy=0; dy<32; dy++) {
    dest = ((UINT16*)GameBitmap->line[dy+y])+x;
    for (dx=0; dx<32; dx++) {
      UINT32 val = *src++;
      if (val != emudx_transp) {
	// val = *dest;
	sred = (val & MASKRED)>> 8;
	sgreen = (val & MASKGREEN)>>3;
	sblue = (val & MASKBLUE)<<3;
	dred = (*dest & MASKRED)>>8;
	dgreen = (*dest & MASKGREEN)>>3;
	dblue = (*dest & MASKBLUE)<<3;
	sred = 255 - ((255 - sred) * (255 - dred))/256;
	sgreen = 255 - ((255 - sgreen) * (255 - dgreen))/256;
	sblue = 255 - ((255 - sblue) * (255 - dblue))/256;
	*dest++ = ((sred>>3)<<11) | ((sgreen>>2)<<5) | ((sblue>>3));
      } else
	dest++;
    }
  }
}
#endif

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

static struct SOUND_INFO dkong_sound[] =
{
  { SOUND_DXSMP, &dkong_emudx_interface, },
  { 0, NULL },
};

// 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 dkong_roms[] =
{
  { "c_5et_g.bin", 0x1000, 0xba70b88b, REGION_ROM1, 0x0000, LOAD_NORMAL },
  { "c_5ct_g.bin", 0x1000, 0x5ec461ec, REGION_ROM1, 0x1000, LOAD_NORMAL },
  { "c_5bt_g.bin", 0x1000, 0x1c97d324, REGION_ROM1, 0x2000, LOAD_NORMAL },
	/* space for diagnostic ROM */
  { "c_5at_g.bin", 0x1000, 0xb9005ac0, REGION_ROM1, 0x3000, LOAD_NORMAL },
  { "s_3i_b.bin", 0x0800, 0x45a4ed06, REGION_ROM2, 0x0000, LOAD_NORMAL },
  { "s_3j_b.bin", 0x0800, 0x4743fe92, REGION_ROM2, 0x0800, LOAD_NORMAL },
  { "v_5h_b.bin", 0x0800, 0x12c8c95d, REGION_GFX1, 0x0000, LOAD_NORMAL },
  { "v_3pt.bin", 0x0800, 0x15e9c5e9, REGION_GFX1, 0x0800, LOAD_NORMAL },
  { "l_4m_b.bin", 0x0800, 0x59f8054d, REGION_GFX2, 0x0000, LOAD_NORMAL },
  { "l_4n_b.bin", 0x0800, 0x672e4714, REGION_GFX2, 0x0800, LOAD_NORMAL },
  { "l_4r_b.bin", 0x0800, 0xfeaa59ee, REGION_GFX2, 0x1000, LOAD_NORMAL },
  { "l_4s_b.bin", 0x0800, 0x20f2ef7e, REGION_GFX2, 0x1800, LOAD_NORMAL },
  { "c-2k.bpr", 0x0100, 0xe273ede5, REGION_PROMS, 0x0000, LOAD_NORMAL },
  { "c-2j.bpr", 0x0100, 0xd6412358, REGION_PROMS, 0x0100, LOAD_NORMAL },
  { "v-5e.bpr", 0x0100, 0xb869b8f5, REGION_PROMS, 0x0200, LOAD_NORMAL },
  { NULL, 0, 0, 0, 0, 0 }
};

static struct ROM_INFO dkongjp_roms[] =
{
  { "c_5f_b.bin", 0x1000, 0x424f2b11, REGION_ROM1, 0x0000, LOAD_NORMAL },
  { "5g.cpu", 0x1000, 0xd326599b, REGION_ROM1, 0x1000, LOAD_NORMAL },
  { "5h.cpu", 0x1000, 0xff31ac89, REGION_ROM1, 0x2000, LOAD_NORMAL },
  { "c_5k_b.bin", 0x1000, 0x394d6007, REGION_ROM1, 0x3000, LOAD_NORMAL },
  { "v_5h_b.bin", 0x0800, 0x12c8c95d, REGION_GFX1, 0x0000, LOAD_NORMAL },
  { "v_5k_b.bin", 0x0800, 0x3684f914, REGION_GFX1, 0x0800, LOAD_NORMAL },
  { NULL, 0, 0, 0, 0, 0 }
};

static struct ROM_INFO dkongjr_roms[] =
{
  { "dkj.5b", 0x2000, 0xdea28158, REGION_ROM1, 0, LOAD_NORMAL },
  { "dkj.5c", 0x2000, 0x6fb5faf6, REGION_ROM1, 0, LOAD_NORMAL },
  { "dkj.5e", 0x2000, 0xd042b6a8, REGION_ROM1, 0, LOAD_NORMAL },
  { "c_3h.bin", 0x1000, 0x715da5f8, REGION_ROM2, 0x0000, LOAD_NORMAL },
  { "dkj.3n", 0x1000, 0x8d51aca9, REGION_GFX1, 0x0000, LOAD_NORMAL },
  { "dkj.3p", 0x1000, 0x4ef64ba5, REGION_GFX1, 0x1000, LOAD_NORMAL },
  { "v_7c.bin", 0x0800, 0xdc7f4164, REGION_GFX2, 0x0000, LOAD_NORMAL },
  { "v_7d.bin", 0x0800, 0x0ce7dcf6, REGION_GFX2, 0x0800, LOAD_NORMAL },
  { "v_7e.bin", 0x0800, 0x24d1ff17, REGION_GFX2, 0x1000, LOAD_NORMAL },
  { "v_7f.bin", 0x0800, 0x0f8c083f, REGION_GFX2, 0x1800, LOAD_NORMAL },
  { "c-2e.bpr", 0x0100, 0x463dc7ad, REGION_PROMS, 0x0000, LOAD_NORMAL },
  { "c-2f.bpr", 0x0100, 0x47ba0042, REGION_PROMS, 0x0100, LOAD_NORMAL },
  { "v-2n.bpr", 0x0100, 0xdbf185bf, REGION_PROMS, 0x0200, LOAD_NORMAL },
  { NULL, 0, 0, 0, 0, 0 }
};

static struct ROM_INFO dkong3_roms[] =
{
  { "dk3c.7b", 0x2000, 0x38d5f38e, REGION_ROM1, 0x0000, LOAD_NORMAL },
  { "dk3c.7c", 0x2000, 0xc9134379, REGION_ROM1, 0x2000, LOAD_NORMAL },
  { "dk3c.7d", 0x2000, 0xd22e2921, REGION_ROM1, 0x4000, LOAD_NORMAL },
  { "dk3c.7e", 0x2000, 0x615f14b7, REGION_ROM1, 0x8000, LOAD_NORMAL },
  { "dk3c.5l", 0x2000, 0x7ff88885, REGION_ROM2, 0xe000, LOAD_NORMAL },
  { "dk3c.6h", 0x2000, 0x36d7200c, REGION_CPU3, 0xe000, LOAD_NORMAL },
  { "dk3v.3n", 0x1000, 0x415a99c7, REGION_GFX1, 0x0000, LOAD_NORMAL },
  { "dk3v.3p", 0x1000, 0x25744ea0, REGION_GFX1, 0x1000, LOAD_NORMAL },
  { "dk3v.7c", 0x1000, 0x8ffa1737, REGION_GFX2, 0x0000, LOAD_NORMAL },
  { "dk3v.7d", 0x1000, 0x9ac84686, REGION_GFX2, 0x1000, LOAD_NORMAL },
  { "dk3v.7e", 0x1000, 0x0c0af3fb, REGION_GFX2, 0x2000, LOAD_NORMAL },
  { "dk3v.7f", 0x1000, 0x55c58662, REGION_GFX2, 0x3000, LOAD_NORMAL },
  { "dkc1-c.1d", 0x0200, 0xdf54befc, REGION_PROMS, 0x0000, LOAD_NORMAL },
  { "dkc1-c.1c", 0x0200, 0x66a77f40, REGION_PROMS, 0x0100, LOAD_NORMAL },
  { "dkc1-v.2n", 0x0100, 0x50e33434, REGION_PROMS, 0x0200, LOAD_NORMAL },
  { NULL, 0, 0, 0, 0, 0 }
};

static struct DSW_DATA dsw_data_dkong_3[] =
{
  { MSG_LIVES, 0x03, 4 },
  { "3", 0x00, 0x00 },
  { "4", 0x01, 0x00 },
  { "5", 0x02, 0x00 },
  { "6", 0x03, 0x00 },
  { MSG_EXTRA_LIFE, 0x0c, 4 },
  { "7000", 0x00, 0x00 },
  { "10000", 0x04, 0x00 },
  { "15000", 0x08, 0x00 },
  { "20000", 0x0c, 0x00 },
  { MSG_COINAGE, 0x70, 8 },
  { MSG_5COIN_1PLAY, 0x70, 0x00 },
  { MSG_4COIN_1PLAY, 0x50, 0x00 },
  { MSG_3COIN_1PLAY, 0x30, 0x00 },
  { MSG_2COIN_1PLAY, 0x10, 0x00 },
  { MSG_1COIN_1PLAY, 0x00, 0x00 },
  { MSG_1COIN_1PLAY, 0x20, 0x00 },
  { MSG_1COIN_3PLAY, 0x40, 0x00 },
  { MSG_1COIN_4PLAY, 0x60, 0x00 },
  { MSG_CABINET, 0x80, 2 },
  { MSG_UPRIGHT, 0x80, 0x00 },
  { MSG_TABLE, 0x00, 0x00 },
  { NULL, 0, 0}
};

static struct DSW_INFO dkong_dsw[] =
{
  { 0x6, 0x80, dsw_data_dkong_3 },
  { 0, 0, NULL }
};

static struct DSW_DATA dsw_data_dkong3_2[] =
{
  { MSG_COINAGE, 0x07, 8 },
  { MSG_3COIN_1PLAY, 0x02, 0x00 },
  { MSG_2COIN_1PLAY, 0x04, 0x00 },
  { MSG_1COIN_1PLAY, 0x00, 0x00 },
  { MSG_1COIN_1PLAY, 0x06, 0x00 },
  { MSG_1COIN_3PLAY, 0x01, 0x00 },
  { MSG_1COIN_4PLAY, 0x03, 0x00 },
  { MSG_1COIN_5PLAY, 0x05, 0x00 },
  { MSG_1COIN_6PLAY, 0x07, 0x00 },
  { MSG_UNKNOWN, 0x08, 2 },
  { MSG_OFF, 0x00, 0x00 },
  { MSG_ON, 0x08, 0x00 },
  { MSG_UNKNOWN, 0x10, 2 },
  { MSG_OFF, 0x00, 0x00 },
  { MSG_ON, 0x10, 0x00 },
  { MSG_UNKNOWN, 0x20, 2 },
  { MSG_OFF, 0x00, 0x00 },
  { MSG_ON, 0x20, 0x00 },
  { MSG_CABINET, 0x80, 2 },
  { MSG_UPRIGHT, 0x00, 0x00 },
  { MSG_TABLE, 0x80, 0x00 },
  { NULL, 0, 0}
};

static struct DSW_DATA dsw_data_dkong3_3[] =
{
  { MSG_LIVES, 0x03, 4 },
  { "3", 0x00, 0x00 },
  { "4", 0x01, 0x00 },
  { "5", 0x02, 0x00 },
  { "6", 0x03, 0x00 },
  { MSG_EXTRA_LIFE, 0x0c, 4 },
  { "30000", 0x00, 0x00 },
  { "40000", 0x04, 0x00 },
  { "50000", 0x08, 0x00 },
  { MSG_UNKNOWN, 0x0c, 0x00 },
  { "Additional Bonus", 0x30, 4 },
  { "30000", 0x00, 0x00 },
  { "40000", 0x10, 0x00 },
  { "50000", 0x20, 0x00 },
  { MSG_UNKNOWN, 0x30, 0x00 },
  { MSG_DIFFICULTY, 0xc0, 4 },
  { MSG_EASY, 0x00, 0x00 },
  { MSG_MEDIUM, 0x40, 0x00 },
  { MSG_HARD, 0x80, 0x00 },
  { MSG_HARDEST, 0xc0, 0x00 },
  { NULL, 0, 0}
};

static struct DSW_INFO dkong3_dsw[] =
{
  { 0x4, 0x00, dsw_data_dkong3_2 },
  { 0x6, 0x00, dsw_data_dkong3_3 },
  { 0, 0, NULL }
};

static struct INPUT_INFO dkong_inputs[] =
{
  { KB_DEF_P1_RIGHT, MSG_P1_RIGHT, 0x00, 0x01, BIT_ACTIVE_1 },
  { KB_DEF_P1_LEFT, MSG_P1_LEFT, 0x00, 0x02, BIT_ACTIVE_1 },
  { KB_DEF_P1_UP, MSG_P1_UP, 0x00, 0x04, BIT_ACTIVE_1 },
  { KB_DEF_P1_DOWN, MSG_P1_DOWN, 0x00, 0x08, BIT_ACTIVE_1 },
  { KB_DEF_P1_B1, MSG_P1_B1, 0x00, 0x10, BIT_ACTIVE_1 },
#ifdef RAINE_DEBUG
  { KB_DEF_P1_B2, MSG_P1_B2, 0x08, 0x8, BIT_ACTIVE_1 },
#endif

  { KB_DEF_P2_RIGHT, MSG_P2_RIGHT, 0x02, 0x01, BIT_ACTIVE_1 },
  { KB_DEF_P2_LEFT, MSG_P2_LEFT, 0x02, 0x02, BIT_ACTIVE_1 },
  { KB_DEF_P2_UP, MSG_P2_UP, 0x02, 0x04, BIT_ACTIVE_1 },
  { KB_DEF_P2_DOWN, MSG_P2_DOWN, 0x02, 0x08, BIT_ACTIVE_1 },
  { KB_DEF_P2_B1, MSG_P2_B1, 0x02, 0x10, BIT_ACTIVE_1 },

  { KB_DEF_SERVICE,      MSG_SERVICE,             1, 0x04, BIT_ACTIVE_1 },
  { KB_DEF_P1_START, MSG_P1_START, 0x04, 0x04, BIT_ACTIVE_1 },
  { KB_DEF_P2_START, MSG_P2_START, 0x04, 0x08, BIT_ACTIVE_1 },
  { KB_DEF_COIN1, MSG_COIN1, 0x04, 0x80, BIT_ACTIVE_1 },
   { 0, NULL, 0, 0, 0 },
};

static struct INPUT_INFO dkong3_inputs[] =
{
  { KB_DEF_P1_RIGHT, MSG_P1_RIGHT, 0x00, 0x01, BIT_ACTIVE_1 },
  { KB_DEF_P1_LEFT, MSG_P1_LEFT, 0x00, 0x02, BIT_ACTIVE_1 },
  { KB_DEF_P1_UP, MSG_P1_UP, 0x00, 0x04, BIT_ACTIVE_1 },
  { KB_DEF_P1_DOWN, MSG_P1_DOWN, 0x00, 0x08, BIT_ACTIVE_1 },
  { KB_DEF_P1_B1, MSG_P1_B1, 0x00, 0x10, BIT_ACTIVE_1 },
  { KB_DEF_P1_START, MSG_P1_START, 0x00, 0x20, BIT_ACTIVE_1 },
  { KB_DEF_P2_START, MSG_P2_START, 0x00, 0x40, BIT_ACTIVE_1 },
  { KB_DEF_COIN3, MSG_COIN3, 0x00, 0x80, BIT_ACTIVE_1 },

  { KB_DEF_P2_RIGHT, MSG_P2_RIGHT, 0x02, 0x01, BIT_ACTIVE_1 },
  { KB_DEF_P2_LEFT, MSG_P2_LEFT, 0x02, 0x02, BIT_ACTIVE_1 },
  { KB_DEF_P2_UP, MSG_P2_UP, 0x02, 0x04, BIT_ACTIVE_1 },
  { KB_DEF_P2_DOWN, MSG_P2_DOWN, 0x02, 0x08, BIT_ACTIVE_1 },
  { KB_DEF_P2_B1, MSG_P2_B1, 0x02, 0x10, BIT_ACTIVE_1 },
  { KB_DEF_COIN1, MSG_COIN1, 0x02, 0x20, BIT_ACTIVE_1 },
  { KB_DEF_COIN2, MSG_COIN2, 0x02, 0x40, BIT_ACTIVE_1 },
   { 0, NULL, 0, 0, 0 },
};

static struct GfxLayout charlayout =
{
	8,8,	/* 8*8 characters */
	RGN_FRAC(1,2),
	2,	/* 2 bits per pixel */
	{ RGN_FRAC(1,2), RGN_FRAC(0,2) },	/* the two bitplanes are separated */
	{ 0, 1, 2, 3, 4, 5, 6, 7 },	/* pretty straightforward layout */
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
	8*8	/* every char takes 8 consecutive bytes */
};

static struct GfxLayout spritelayout =
{
	16,16,	/* 16*16 sprites */
	RGN_FRAC(1,4),	/* 128 sprites */
	2,	/* 2 bits per pixel */
	{ RGN_FRAC(1,2), RGN_FRAC(0,2) },	/* the two bitplanes are separated */
	{ 0, 1, 2, 3, 4, 5, 6, 7,	/* the two halves of the sprite are separated */
			RGN_FRAC(1,4)+0, RGN_FRAC(1,4)+1, RGN_FRAC(1,4)+2, RGN_FRAC(1,4)+3, RGN_FRAC(1,4)+4, RGN_FRAC(1,4)+5, RGN_FRAC(1,4)+6, RGN_FRAC(1,4)+7 },
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,
			8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
	16*8	/* every sprite takes 16 consecutive bytes */
};

static struct GFX_LIST gfxdecodeinfo[] =
{
	{ REGION_GFX1, &charlayout, },
	{ REGION_GFX2, &spritelayout, },
	{ -1 } /* end of array */
};

static UINT8 *gfx_ram,*spriteram,*interrupt_enable,*palette_bank,*color_codes,*gfx_bg_solid,*gfx_spr_solid,*gfx_bank,*gfx_bg,*gfx_spr;
static UINT16 RAM_PAL[256];

static int sp,mask_bank,spriteram_size,shift_bits;
static int roar_counter,repeat_roar;
extern UINT32 cpu_frame_count;
static UINT8 last_level;

void dkongSoundWrite(UINT32 dwAddr, UINT8 bVal)
{

/*
7c00      Background sound/music select:
          00 - nothing
		  01 - Intro tune
		  02 - How High? (intermisson) tune
		  03 - Out of time
		  04 - Hammer
		  05 - Rivet level 2 completed (end tune)
		  06 - Hammer hit
		  07 - Standard level end + gorilla roar
		  08 - Background 1	(first screen)
		  09 - ???
		  0A - Background 3	(springs)
		  0B - Background 2 (rivet)
		  0C - Rivet level 1 completed (end tune)
		  0D - Rivet removed
		  0E - Rivet level completed
		  0F - Gorilla roar

7d00      digital sound trigger - walk
7d01      digital sound trigger - jump
7d02      digital sound trigger - boom (gorilla stomps foot)
7d03      digital sound trigger - coin input/spring
7d04      digital sound trigger	- gorilla fall
7d05      digital sound trigger - barrel jump/prize
7d06      ?
7d07      ?
7d80      digital sound trigger - dead

*/
  // if (bVal) printf("%x,%d\n",dwAddr,bVal);
  if(dwAddr==0x7c00)
    {
      switch(bVal)
	{
	case 1:
	  raine_play_sample(start,200);
	  break;

	case 2:
	  raine_stop_samples();
	  // dkong us changes its level at this place in ram, but it must be read
	  // only between levels or otherwise you can see the next level before having
	  // the how high screen...
	  last_level = RAM[0x227];
	  raine_play_sample(howhigh,100);
	  sp=0;
	  break;

	case 6:
	  raine_play_sample(hammer_hit,200);
	  break;

	case 7:
	  raine_stop_samples();
	  raine_play_sample(levelend,150);
	  roar_counter = 2*fps; // roar in 3.1s !
	  repeat_roar = 1;
	  break;

	case 8:
	case 9:
	case 10:
	case 11:
	  if(!sp)
	    {
	      if (bVal == 9) bVal = 10;
	      raine_loop_sample(level1+bVal-8,80);
	      sp = 1;
	    }
	  break;

	case 0x0d:
	  raine_play_sample(jump_over,160);
	  break;

	case 0x0f:
	  raine_play_sample(roar,200);
	  break;
	}

      if(bVal==5 || bVal==12)
	{
	  raine_stop_samples();
	  raine_play_sample(winner,200);

	}
    }
  if(dwAddr==0x7d80 && bVal) {
    raine_stop_samples();
    raine_play_sample(dead,200);
  }

  if(dwAddr==0x7d00 && bVal) {
    raine_play_sample(walk,180);
  }

  if(dwAddr==0x7d01 && bVal)
    raine_play_sample(jump,160);

  if(dwAddr==0x7d02 && bVal)
    raine_play_sample(stomp,200);

  if(dwAddr==0x7d03 && bVal)
    raine_play_sample(coin,60);

  if(dwAddr==0x7d04 && bVal)
    raine_play_sample(fall,100);

  if(dwAddr==0x7d05 && bVal)
    raine_play_sample(jump_over,160);

}

static int layer_id_data[2];
static int draw_emudx_tile;
static BITMAP *flame_red, *flame_blue;

#define tile_index zz
#define BORDER 16

#ifdef RAINE_DEBUG
static void draw_debug_tile() {
  UINT8 code, color;
  SCROLL_REGS;
  UINT8 *map,*gfx;
  char str[4];

  if (*gfx_bank) {
    gfx = gfx_ram + 0x100;
  } else
    gfx = gfx_ram;

  MAKE_SCROLL_n_16(512,512,1,0, 0);
  START_SCROLL_16(BORDER,BORDER,512,512);

  int sy = y-16*2;
  if (sy < 0 || sy > 224*2+BORDER)
    continue;
  code = gfx[tile_index];
  color = (color_codes[(tile_index & 31) + 32 * (tile_index >> 7)] & 0x0f) + 0x10 * *palette_bank;

  // Draw8x8_Mapped_Rot(&gfx_bg[code<<6],x,sy,map);

  if (gfx_bg_solid[code]) {
    MAP_PALETTE_MAPPED_NEW(
			   color,
			   4,
			   map
			   );
    if (gfx_bg_solid[code] == 1) // transp
      Draw8x8_Trans_Mapped_Rot(&gfx_bg[code<<6],x,sy,map);
    else
      Draw8x8_Mapped_Rot(&gfx_bg[code<<6],x,sy,map);
    sprintf(str,"%02x",code);
    textout_fast(str,448+BORDER*2-8-sy,x+8,get_white_pen());
    sprintf(str,"%x",color);
    textout_fast(str,448+BORDER*2-8-sy+8,x,get_white_pen());
  }
    // }
  END_SCROLL_n_16(512,512,1);
}
#endif

static int dkong_us; // order of the levels different...

static void draw_emudx() {
  UINT8 code, color;
  SCROLL_REGS;
  UINT8 *map,*gfx;
  int offs;
  int curlev = 0;

  if (RAM[0x40]) { // number of lifes > 0 (6228 and 6040 seem to be the same !)
    if (RAM[0x22e]) { // seems to stay at 0 in attract mode...
      curlev = (RAM[0x22e]-1) & 3;
      if (dkong_us) {
	// int displev = RAM[0x229]; // level displayed on top right corner
	// printf("displev %d curlev %d\n",displev,curlev);
	curlev = last_level;
      } else
	if (curlev) curlev++;
    }
  }

  if (draw_emudx_tile) {
    if (!curlev) curlev = 1; // attract mode, draw 1st level...
    blit(emudx_tiles[curlev-1], GameBitmap, 0, 0, BORDER, BORDER, 448, 512);
    draw_emudx_tile = 0;
  } else {
    clear_game_screen(0);
  }

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

  if (*gfx_bank) {
    gfx = gfx_ram + 0x100;
  } else
    gfx = gfx_ram;

  if( check_layer_enabled(layer_id_data[0])) {
    MAKE_SCROLL_n_16(512,512,1,0, 0);
    START_SCROLL_16(BORDER,BORDER,512,512);

    int sy = y-16*2;
    if (sy < 0 || sy > 224*2+BORDER)
      continue;
    code = gfx[tile_index];
    color = (color_codes[(tile_index & 31) + 32 * (tile_index >> 7)] & 0x0f) + 0x10 * *palette_bank;

    // Draw8x8_Mapped_Rot(&gfx_bg[code<<6],x,sy,map);

    if ((code >= 0xf0 && code < 0xfb)) {
      draw_emudx_tile = 1;
    } else {
      // level 4 is something really special we have to combine sprites and bg layer for it
      if (code == 0xb7 && curlev == 4) draw_emudx_tile = 1;

      if (code <= 165-5 && (code < 0x50 || code > 0x67)) { // character
	// between 0x50 and 0x67 it's the big sprite of the gorilla on the how high screen
	// when starting a level
	MAP_PALETTE_MAPPED_NEW(
			       color,
			       4,
			       map
			       );
	map += 2*2; // skip 2 first colors...
	// code -= 5;
	Draw16x16_Trans_Mapped_Rot(&emudx_chars[code<<8],x,sy,map);
      } else {
	if (code != 0xc0 || curlev == 4)
	  // only draw the ladders (c0) in level 4.
	  // The other dx levels have the ladders already drawn.
	  Draw16x16_Trans_16_Rot(&emudx_sprites[code<<9],x,sy,0);
      }
    }
    END_SCROLL_n_16(512,512,1);
  }

  /* Draw the sprites. */
  if( check_layer_enabled(layer_id_data[1])) {
    for (offs = 0;offs < spriteram_size;offs += 4){
      if (spriteram[offs]){
	/* spriteram[offs + 2] & 0x40 is used by Donkey Kong 3 only */
	/* spriteram[offs + 2] & 0x30 don't seem to be used (they are */
	/* probably not part of the color code, since Mario Bros, which */
	/* has similar hardware, uses a memory mapped port to change */
	/* palette bank, so it's limited to 16 color codes) */

	int x,y;

	x = spriteram[offs + 3] - 8;
	y = 240 - spriteram[offs] + 7;
	color = (spriteram[offs + 2] & 0x0f) + 16 * *palette_bank;
	code = (spriteram[offs + 1] & 0x7f) + ((spriteram[offs + 2] & mask_bank) << shift_bits);
	x=x*2+BORDER; y= y*2+BORDER-16*2;
	if (x<256*2+BORDER && y < 224*2+BORDER) {
	  int subcol = color & 0xf;
	  if ((code == 30 || code == 31) && subcol == 0x1) {
	    // hammer ready to run out...
	    code += 98;
	  } else if (code == 68 && subcol == 3) {
	    // improved platform on level 3.... is it really necessary to test the
	    // color ???
	    code++;
	  }
	  if((code>60 && code<63) || code==77 || code==78)
	    {
	      // flame effects
	      // int col = ((color >> 1) & 0x03) | ((color << 2) & 0x04);
	      BITMAP *flame = flame_red;
	      if(subcol==0 && (code==61 || code==62)) {
		code+=28; // Fire that fears (1st level)
		flame = flame_blue;
		printf("blue flame 1\n");
	      }
	      if(subcol==0 && (code==77 || code==78)) {
		code+=14; // Fire bugs that fear (rivets level)
		flame = flame_blue;
		printf("blue flame 2\n");
	      }

	      Draw32x32_Trans_16_flip_Rot(&emudx_sprites32[code<<11],x,y,0,
					  ((spriteram[offs + 2] & 0x80)>>7) | ((spriteram[offs + 1] & 0x80)>>6));
	      draw_trans_sprite(GameBitmap,flame,disp_y_32 - y - 12, x - 8);

	      // my_draw_alpha(&flame->line[0],x-8,y+12);

	    } else {
/* 	      if (code==21 || code==25) */
	      /* Barrels are supposed to rotate, but it would be messy to do and almost
		 unnoticable considering the size of the details of the barrel... */
	      // rotate_sprite(prime_display,sprites[V], x, y-3,itofix(x*2+y*2)); //Our beautiful barrel rolls

	      Draw32x32_Trans_16_flip_Rot(&emudx_sprites32[code<<11],x,y,0,
					  ((spriteram[offs + 2] & 0x80)>>7) | ((spriteram[offs + 1] & 0x80)>>6));
	    }
	  /* consider doing it for x+256,y (warp around probably not necessary here) */
	}
      }
    }
  }
}

static void dkong_palette_bank_w(UINT32 offset, UINT8 data) {
  offset &= 1;

  if (data & 1)
    *palette_bank |= 1 << offset;
  else
    *palette_bank &= ~(1 << offset);
}

static void reset_roar() {
  roar_counter = 1;
  repeat_roar = 1;
  memset(RAM,0,RAMSize);
  // There is a bit somewhere in these input ports which absolutely needs to be
  // cleared before the game starts, but I didn't try to find which one.
  memset(input_buffer,0,5);
}

static void reset_level() {
  last_level = RAM[0x227]; // for dkong us
}

static void load_dkong() {
  UINT8 *color_prom = load_region[REGION_PROMS];
  int i;
  // RAMSize = 0x1000 + 0x400 + 4;
  RAMSize = 0x1800 + 4;

  dkong_us = is_current_game("dkong");

  if (!(RAM = AllocateMem(0xffff))) return;
  memcpy(RAM,ROM,get_region_size(REGION_CPU1));
  ROM = RAM;
  RAM = RAM + 0x6000;
  gfx_ram = RAM + 0x1400;

  // sprite parameters
  spriteram = RAM +0x900;
  spriteram_size = 0x17f;
  mask_bank = 64;
  shift_bits = 1;

  interrupt_enable = RAM + 0x1800;
  palette_bank = interrupt_enable + 1;
  gfx_bank = palette_bank+1;
  *palette_bank = *gfx_bank = 0;

  AddZ80AROMBase(ROM, 0x0038, 0x0066);
  AddZ80ARead(0x0000, get_region_size(REGION_ROM1)-1, NULL, ROM);
  AddZ80ARW(0x6000, 0x6fff, NULL, RAM);
  AddZ80ARW(0x7400, 0x77ff, NULL, gfx_ram);
  AddZ80ARead(0x7c00, 0x7c00, NULL, &input_buffer[0]);
  AddZ80ARead(0x7c80, 0x7c80, NULL, &input_buffer[2]);
  AddZ80ARead(0x7d00, 0x7d00, NULL, &input_buffer[4]);
  AddZ80ARead(0x7d80, 0x7d80, NULL, &input_buffer[6]);

  AddZ80ARead(0x8000,0xdfff, NULL, ROM + 0x8000);

  AddZ80AWrite(0x7c00, 0x7d80, dkongSoundWrite, NULL);
  AddZ80AWrite(0x7d84, 0x7d84, NULL, interrupt_enable);
  AddZ80AWrite(0x7d86, 0x7d87, dkong_palette_bank_w, NULL);

  AddZ80ARead(0x0000, 0xFFFF, DefBadReadZ80,		NULL);
  AddZ80AWrite(0x0000, 0xFFFF, DefBadWriteZ80,		NULL);

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

  AddZ80AWritePort(0x00, 0xFF, DefBadWriteZ80,			NULL);	// <bad reads>
  AddZ80AWritePort(-1, -1, NULL, NULL);
  AddZ80ARW(-1,-1,NULL,NULL);
  AddZ80AInit();

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

  Convert the color PROMs into a more useable format.

  Donkey Kong has two 256x4 palette PROMs and one 256x4 PROM which contains
  the color codes to use for characters on a per row/column basis (groups of
  of 4 characters in the same column - actually row, since the display is
  rotated)
  The palette PROMs are connected to the RGB output this way:

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

***************************************************************************/
  /* As always for the color prom, great thanks go to mame for their decoding work */
  for (i=0; i<256; i++) {
    UINT8 bit0, bit1, bit2;
    /* red component */
    bit0 = (color_prom[256] >> 1) & 1;
    bit1 = (color_prom[256] >> 2) & 1;
    bit2 = (color_prom[256] >> 3) & 1;
    int r = 7 - (bit0 | (bit1<<1) | (bit2 << 2));
    /* green component */
    bit0 = (color_prom[0] >> 2) & 1;
    bit1 = (color_prom[0] >> 3) & 1;
    bit2 = (color_prom[256] >> 0) & 1;
    int g = 7 - (bit0 | (bit1<<1) | (bit2 << 2));
    /* blue component */
    bit0 = (color_prom[0] >> 0) & 1;
    bit1 = (color_prom[0] >> 1) & 1;
    int b = 7 - ((bit0<<1) | (bit1 << 2));
    RAM_PAL[i] = (b) | (g<<3) | (r<<6);
    color_prom++;
  }
  color_prom += 256;
  /* color_prom now points to the beginning of the character color codes */
  color_codes = color_prom;	/* we'll need it later */

  InitPaletteMap((UINT8*)RAM_PAL, 64, 4, 0x200); // 64 banks of 4 colors
  set_colour_mapper(&col_map_xxxxRrrgggbbb);

  gfx_bg_solid = make_solid_region_8x8(REGION_GFX1);
  gfx_spr_solid = make_solid_region_16x16(REGION_GFX2);
  gfx_bg = load_region[REGION_GFX1];
  gfx_spr = load_region[REGION_GFX2];

  sp = 0; // no sample playing

  layer_id_data[0] = add_layer_info("BG");
  layer_id_data[1] = add_layer_info("SPRITES");

  if (exists_emudx_file("dkongg.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
      {
	DATAFILE *dat;
	load_emudx("dkongg.dx",4,262-5,262,419,
		   5,164,
		   448,512,0xf81f,draw_emudx);
	draw_emudx_tile = 0;

	/* There is a special effect for flames in dkong : the flames are drawn as normal
	   solid sprites, and then a flame "halo" is applied with alpha blending on top
	   of them. The size of the halo is of course different from the size of a normal
	   sprite, so I must load it directly here, it can't be handled in the emudx
	   module... */
	set_screen_blender(140, 140, 140, 140);
	if (!flame_red) {
	  dat = open_emudx_file("dkongg.dx");
	  flame_red = create_bitmap_ex(16,56,49);
	  flame_blue = create_bitmap_ex(16,56,49);
	  stretch_blit(dat[418].dat,flame_red,0,0,84,74,0,0,56,49);
	  stretch_blit(dat[419].dat,flame_blue,0,0,84,74,0,0,56,49);
	  unload_datafile(dat);
	}
      }
  }
  set_reset_function(reset_roar);
  AddLoadCallback(reset_level);
}

static void execute_dkong() {
  if (roar_counter) {
    roar_counter--;
    if (!roar_counter) {
      raine_play_sample(roar,200);
      if (repeat_roar) {
	repeat_roar--;
	roar_counter = fps;
      }
    }
  }
  cpu_execute_cycles(CPU_Z80_0,3072000/60);
  if (*interrupt_enable) {
    cpu_int_nmi(CPU_Z80_0);
  }
}

static void draw_dkong() {
  UINT8 code, color;
  SCROLL_REGS;
  UINT8 *map,*gfx;
  int offs;

  if (*gfx_bank) {
    gfx = gfx_ram + 0x100;
  } else
    gfx = gfx_ram;

  if( check_layer_enabled(layer_id_data[0])) {
    MAKE_SCROLL_n_8(256,256,1,0, 0);
    START_SCROLL_8(BORDER,BORDER,256,256);

    int sy = y-16;
    if (sy < 0 || sy > 224+BORDER)
      continue;
    code = gfx[tile_index];
    color = (color_codes[(tile_index & 31) + 32 * (tile_index >> 7)] & 0x0f) + 0x10 * *palette_bank;
    MAP_PALETTE_MAPPED_NEW(
			   color,
			   4,
			   map
			   );

    Draw8x8_Mapped_Rot(&gfx_bg[code<<6],x,sy,map);
    END_SCROLL_n_8(256,256,1);
  } else
    clear_game_screen(0);

  /* Draw the sprites. */
  if( check_layer_enabled(layer_id_data[1])) {
    for (offs = 0;offs < spriteram_size;offs += 4){
      if (spriteram[offs]){
	/* spriteram[offs + 2] & 0x40 is used by Donkey Kong 3 only */
	/* spriteram[offs + 2] & 0x30 don't seem to be used (they are */
	/* probably not part of the color code, since Mario Bros, which */
	/* has similar hardware, uses a memory mapped port to change */
	/* palette bank, so it's limited to 16 color codes) */

	int x,y;

	x = spriteram[offs + 3] - 8;
	y = 240 - spriteram[offs] + 7;
	color = (spriteram[offs + 2] & 0x0f) + 16 * *palette_bank;
	code = (spriteram[offs + 1] & 0x7f) + ((spriteram[offs + 2] & mask_bank) << shift_bits);
	x+=BORDER; y+=BORDER-16;
	if (x<256+BORDER && y < 224+BORDER && gfx_spr_solid[code]) {
	  MAP_PALETTE_MAPPED_NEW(
				 color,
				 4,
				 map
				 );
	  if (gfx_spr_solid[code] == 1)
	    Draw16x16_Trans_Mapped_flip_Rot(&gfx_spr[code<<8],x,y,map,
					    ((spriteram[offs + 2] & 0x80)>>7) | ((spriteram[offs + 1] & 0x80)>>6));
	  else
	    Draw16x16_Mapped_flip_Rot(&gfx_spr[code<<8],x,y,map,
				      ((spriteram[offs + 2] & 0x80)>>7) | ((spriteram[offs + 1] & 0x80)>>6));
	  /* consider doing it for x+256,y (warp around probably not necessary here) */
	}
      }
    }
  }
}

static struct VIDEO_INFO dkong_video =
{
   draw_dkong,
   256,
   224,
   BORDER,
   VIDEO_ROTATE_90 |
   VIDEO_ROTATABLE,
   gfxdecodeinfo
};

GME( dkong,
     "Donkey Kong",
     COMPANY_ID_NINTENDO,
     1981,
     GAME_PLATFORM);

CLONE( dkongjp, dkong, "Donkey Kong (Japan)", COMPANY_ID_NINTENDO, 1981, GAME_PLATFORM);
