/*
 * SYSTEM 16 ARCADE EMULATOR SOURCE CODE
 * 
 * Copyright 1996/97 Thierry Lescot
 */

#include "cpudefs.h"
#include "readcpu.h"
#include <allegro.h>

#include "shinobi.h"

#define SPR_PAGE 0xF800
// 0xEC00
#define INT_NUMBER 4
// #define DEBUG_INT
// #define TEST_CPU_SPEED
// #define EMULATE_Z80

#ifdef MAX_MEM_TEST
extern UWORD MaximumR[0x100], MaximumW[0x100];
#endif
ULONG historique[20];
int phist=0;
long frame=2;
long icount=0, temps=0, fcount=0, opcodeb=10000;
char sync=0, joy=0, joystick_support=1, nouvelle_methode=0;
int sx=0, sy=0;
char svga=0;

char TEMP[0x8000];
char sfx_enabled = 1;
char bgm_enabled = 1;
char voice_enabled = 0;
char last_bgm = 0;
#ifdef EMULATE_Z80
char *soundrom[6] = {
   "shinobi.a7", "ab11671.bin", "ga12390.bin", "ts10562.bin", "ns", "ns"};
extern char ComunicationPort;
extern long Ciclos;
extern char Texto[80];
extern unsigned short BaseSb, OPL3, BaseDelay, DelayReg, DelayData;
char sound_enabled = 1, sound_active = 0;
#else
char ComunicationPort;
#endif

#ifdef SEARCH
// int valeur_controle=0x410E80;
int valeur_controle=0xFFFFECFC;
RGB pal_rgb;
PALLETE save_palette;
UWORD s_old_values[0x10000];
UBYTE s_check[0x10000];
UWORD s_count, s_zone;
#endif

char ws[80], DeleteMessage_REQ=0, NO_LFB=0;
int time_countdown=0;

extern UBYTE shinobi_ds1[10], shinobi_ds2[10];

UBYTE *TimerA, *TimerB;
char game_basename[9], game_name[20], game=1;
char game_to_load=0;

int timer_count=0;
unsigned int timer_adrs=0xF01C;

long total_render=0;

UBYTE txt_bank=0x41, vid_bank=0x40, pal_bank=0x84, ext_bank=0x3F, ctr_bank=0xC4;
ULONG total_palette=0, total_new_colors=0, total_palette_reset=0;

char int_request=0, refresh_request=0;
int int_dec=5000, frame_rate=5, frame_number=0;

char background_active=1, mode_video=0;
int pcx_number=-1;

long render_countdown=1;
#ifdef RELEASE_BETA
long render_cd_start=200;
#else
long render_cd_start=20000;
#endif
int int_speed = 200;
int z80cycles = 2000;

/* screen variables */
BITMAP *vscreen, *vscreen_sub;

int sortie=1, strace=0, pause=0;
long i, i2, i3, i4, i5, i6;
CPTR BreakPoint=0, p;

unsigned char sound_buffer[20], sbuf_read = 0, sbuf_write = 0;
long sbuf_ptr = (long)&sound_buffer[0];

void pc_int() {
   int_request++;
}
END_OF_FUNCTION(pc_int);

void Video(int f) {
   int rx=320, ry=240;
   switch (svga) {
    case 1: rx=640; ry=480; break;
    case 2: rx=640; ry=400; break;
    case 3: ry=200; break;
    case 4: rx=400; ry=300; break;
   }
   if (f) {
      mode_video=1;
      if (set_gfx_mode(GFX_VESA2L, rx, ry, 0, 0)||NO_LFB) {
	 mode_video=2;
	 if (set_gfx_mode(GFX_VESA2B, rx, ry, 0, 0)) {
	    if (svga) {
	       mode_video=4;
	       if (set_gfx_mode(GFX_AUTODETECT, rx, ry, 0, 0)) {
		  allegro_exit();
		  printf("Error, i can't switch to %dx%d video mode !\n", rx, ry);
		  exit(1);
	       }
	    } else {
	       mode_video=3;
	       if (set_gfx_mode(GFX_MODEX, rx, ry, 0, 0)) {
		  allegro_exit();
		  printf("Error, i can't switch to %dx%d video mode !\n", rx, ry);
		  exit(1);
	       }
	    }
	 }
      }
   } else {
      set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
   }
   sx=(rx-312)/2;
   sy=(ry-224)/2;
}

#ifdef SEARCH
void TraceOn() {
   if (!strace) {
      get_palette(save_palette);
      Video(0);
      strace=1;
   }
}

void TraceOff() {
   if (strace) {
      Video(1);
      set_palette(save_palette);
      strace=0;
   }
   if (pause) RenderScreen();
}
#endif

static void initCPU(void)
{
    int i,j;

    for (i = 0 ; i < 256 ; i++) {
      for (j = 0 ; j < 8 ; j++) {
       if (i & (1 << j)) break;
      }
     movem_index1[i] = j;
     movem_index2[i] = 7-j;
     movem_next[i] = i & (~(1 << j));
    }
    for (i = 0; i < 256; i++) {
         intel_flag_lookup[i].flags.c = !!(i & 1);
         intel_flag_lookup[i].flags.z = !!(i & 64);
         intel_flag_lookup[i].flags.n = !!(i & 128);
         intel_flag_lookup[i].flags.v = 0;
    }

}

void inline Exception(int nr, CPTR oldpc)
{
   MakeSR();
   #ifdef DEBUG_INT
   TraceOn();
   printf("Exception %0x, valeur = %0x, pc = %0x\n", nr, oldpc, m68k_getpc());
   printf("Valeur de r‚gistre SR = 0x%0x\n", regs.sr);
   #endif
   if(!regs.s) {
      regs.a[7]=regs.isp;
      regs.s=1;
   }
   
   regs.a[7] -= 4;
   put_long (regs.a[7], m68k_getpc ());
   regs.a[7] -= 2;
   put_word (regs.a[7], regs.sr);
   m68k_setpc(get_long(regs.vbr + 4*nr));
   
   #ifdef DEBUG_INT
   printf("VBR=%08x , NR=%d , I=%04x \n", regs.vbr, nr, regs.vbr+4*nr);
   if (strace) printf("int jump 0x%0x\n", regs.pc);
   #endif
   
   regs.t1 = regs.t0 = regs.m = 0;
}

void inline Interrupt68k(int level)
{
   int ipl=(regs.sr&0xf00)>>8;
   #ifndef RELEASE_BETA
  if (strace) printf("appel Interrupt68k : level=%d , ipl=%d\n", level, ipl);
   #endif
   if(level>=ipl) Exception(24+level,0);
}

void MC68000_reset(void)
{
   if (game==3) {
      put_word(0x3CA2, 0x4E75);
   }
   regs.a[7]=get_long(0);
   m68k_setpc(get_long(4));
#ifndef RELEASE_BETA
   printf("start PC at %08x\n", get_long(4));
   printf("start A7 at %08x\n", get_long(0));
#endif
   regs.s = 1;
   regs.m = 0;
   regs.stopped = 0;
   regs.t1 = 0;
   regs.t0 = 0;
   ZFLG = CFLG = NFLG = VFLG = 0;
   regs.intmask = 7;
   regs.vbr = regs.sfc = regs.dfc = 0;
   regs.fpcr = regs.fpsr = regs.fpiar = 0;
}

UBYTE *allocmem(long size, UBYTE init_value) {
   UBYTE *p;
   p=(UBYTE *)malloc(size);
   if (!p) {
      printf("No enough memory !\n");
   }
   return(p);
}

unsigned short GetSBInfo (void)
{
   char *blaster = getenv("BLASTER");
   unsigned short baseport = 0;

   if (blaster) {
      strupr (blaster);
      while (*blaster) {
	 while (*blaster==' ' || *blaster=='\t')
	   ++blaster;
	 switch (*blaster++)
	   {
	    case 'A': 
	      baseport = (unsigned short)strtol(blaster,NULL,16);
	      break;
	      /*
	    case 'I': SB_Info.irq=(byte)strtol(blaster,NULL,10);
              break;
	    case 'D': SB_Info.dma_low=(byte)strtol(blaster,NULL,10);
              break;
	    case 'H': SB_Info.dma_high=(byte)strtol(blaster,NULL,10);
              break;
	    case 'T': SB_Info.type=(byte)strtol(blaster,NULL,10);
              break;
	    case 'E': SB_Info.emu_baseport=(word)strtol(blaster,NULL,16);
              break;
	    case 'P': SB_Info.mpu_baseport=(word)strtol(blaster,NULL,16);
              break;
	       */
	   }
	 while (*blaster && *blaster!=' ' && *blaster!='\t')
	   ++blaster;
      }
   }
   return(baseport);
}


#ifdef EMULATE_Z80
void Init_Z80SOUND() {
   PACKFILE *f;
   
   printf("Initializing sound.\n");
   
   if ((game == 6)||(game == 3)) {
      printf("No sound emulation for this game yet !\n");
      sound_enabled = 0;
      return;
   }
   
   if (!(BaseSb = GetSBInfo())) {
      printf("BLASTER environment variable not found !\n");
      sound_enabled = 0;
   } else {
      printf("BLASTER environment variable found, SB base port = %03xh\n",
	     BaseSb);
   }
   if (f = pack_fopen(soundrom[game - 1], F_READ)) {
      printf("Loading sound rom %s...\n", soundrom[game - 1]);
      pack_fread(TEMP, 0x8000, f);
      pack_fclose(f);
      printf("Initializing YM2151/Z80 emulator.\n");
      Transfer();
      InitYM();
      Ciclos = z80cycles;
      ComunicationPort = 0;
   } else {
      printf("Error, can't open sound rom %s !\n", soundrom[game - 1]);
      sound_enabled = 0;
   }
   
   OPL3 = 1;
   DelayData = 1;
   DelayReg = 1;
   BaseDelay = 0x61;
   
}
#endif

void Initialisation() {
   int i;
   
   LoadAllROMS();

   printf("Allocating memory...\n");
   RAM[vid_bank]=allocmem(0x10000, 0);
   RAM[txt_bank]=allocmem(0x10000, 0);
   RAM[ext_bank]=allocmem(0x10000, 0);
   RAM[pal_bank]=allocmem(0x10000, 0);
   RAM[ctr_bank]=allocmem(0x10000, 0x0);
   RAM[0x20]=allocmem(0x10000, 0); /* temp */
   RAM[0x44]=allocmem(0x10000, 0);
   RAM[0xFE]=allocmem(0x10000, 0); /* temp */
   RAM[0xFF]=allocmem(0x10000, 0);
   RAM[0x1E]=allocmem(0x10000, 0); /* temp */
   if (game==6) {
      RAM[0x7F]=allocmem(0x10000, 0);
   }
   /* Load SRAM */
   if ((game==6)||(game==2)) {
      printf("Loading SRAM...\n");
      Load_SRAM();
   }
   /* Debug function */
   #ifdef MAX_MEM_TEST
   memset(&MaximumW[0], 0, sizeof(UWORD)*0x100);
   memset(&MaximumR[0], 0, sizeof(UWORD)*0x100);
   #endif
   /* Init 68000 emulator */
   printf("Building 68000 emulator...\n");
   BuildCPU();
   initCPU();
   MC68000_reset();
   /* Joystick detection */
   if ((joystick_support)&&(!initialise_joystick())) {
      printf("Joystick found !\n");
      joy=1;
   } else joystick_support=0;
   #ifdef EMULATE_Z80
   if (sound_enabled) Init_Z80SOUND();
   sound_active = sound_enabled;
   #endif
   /* Load a saved game if -load has been specified */
   if (game_to_load) Load_GameFromDisk(game_to_load-1);
}


static void inline make_sound()
{
#ifdef EMULATE_Z80
   if (sound_active) {
      if (sbuf_write != sbuf_read) {
	 ComunicationPort = sound_buffer[sbuf_read];
	 if ((++sbuf_read) == 20) sbuf_read = 0;
      }
      Z80();
   }
#endif
}

/* new version for Emule() used if -regspeed is specified */
void inline NewEmule() {
   for (i2=0;i2!=opcodeb;i2++) exec_instruction();
   if (!int_request) {
      /* update display if int_request=0 and frame_number=1 */
      if (frame_number) frame_number--;
      if (!frame_number) {
	 RenderScreen();
	 frame_number=frame;
	 fcount++;
      }
   } else {
      /* make an interrupt 60 call/sec by default */
      Interrupt68k(4);
      int_request--;
      make_sound();
   }
}

/* old Emule() function */
void inline Emule() {
#ifndef RELEASE_BETA
   if (strace) MC68000_disasm(m68k_getpc(), &p, 1);
   if (m68k_getpc()==BreakPoint) {
      TraceOn();
      printf("POINT D'ARRET -> ");
      MC68000_disasm(m68k_getpc(), &p, 1);
   }
#endif
   #ifdef RELEASE_BETA
   for (i=100;i;i--)
   #endif
   exec_instruction();
   icount+=100;
   #ifndef RELEASE_BETA
   phist++;
   if (phist==20) phist=0;
   historique[phist]=regs.pc;
   #endif
#ifndef TEST_CPU_SPEED
   if (render_countdown) render_countdown--;
   else {
      /* render screen if not in trace mode */
      if (!strace) RenderScreen();
      render_countdown=render_cd_start;
      fcount++;
   }
#endif
#ifdef RELEASE_BETA
   if (int_request) {
      Interrupt68k(4);
      int_request=0;
      make_sound();
   }
#else
   int_dec--;
   if (!int_dec) {
      Interrupt68k(4);
      int_dec=5000;
   }
#endif
}

/* SavePCX */
void SauvegardePCX() {
   char fn[20];
   BITMAP *pcx;
   PALLETE pal;
   pcx=create_sub_bitmap(screen, 4, 8, 312, 224);
   get_palette(pal);
   do {
      pcx_number++;
      strcpy(fn, game_basename);
      sprintf(&fn[6], "%02x.PCX", pcx_number);
   } while (file_exists(fn, 0, NULL));
   save_pcx(fn, pcx, pal);
   destroy_bitmap(pcx);
   sprintf(ws, "%s SAVED", fn);
   message_emul(0, 2, ws);
}

/* keyboard handler */
void inline Clavier() {
   int code, cont=1;
   if (keypressed()) do {
      if (keypressed()) {
	 code=(readkey()>>8);
	 switch (code) {
	  case KEY_F1:
	    Interface();
	    int_request=0;
	    cont=pause;
	    break;
	  case KEY_F11:
	    background_active=~(background_active&0x01);
	    RenderScreen();
	    cont=pause;
	    break;
#ifdef EMULATE_Z80
	  case KEY_TAB:
	    if (sound_enabled) {
	       sound_active = (1 - sound_active);
	       sprintf(ws, "SOUND IS %s", (sound_active)? "ENABLED":"DISABLED");
	       message_emul(0, 2, ws);
	    }
	    cont = pause;
	    break;
#endif
	  case KEY_S: /* CTRL + PRINT SCREEN */
	    SauvegardePCX();
	    cont=pause;
	    int_request=0;
	    break;
	  case KEY_ESC: sortie=cont=0; break;
#ifndef SEARCH
	  /* cheat keys */
	  case KEY_F2:
	    RAM[0xFF][0xD79E]=0x01;
	    message_emul(0, 2, "CHEAT: POWER UP !");
	    cont=pause;
	    break;
	  case KEY_F3:
	    RAM[0xFF][0xD76A]=RAM[0xFF][0xD76B];
	    message_emul(0,2, "CHEAT: ALL HOSTAGES RESCUED !");
	    cont=pause;
	    break;
	  case KEY_F4:
	    RAM[0xFF][0xF08E]=0;
	    message_emul(0,2, "CHEAT: GET BONUS !");
	    cont=pause;
	    break;
	  case KEY_F5:
	    if (game==1) RAM[0xFF][0xD778]=255;
	    if (game==6) RAM[0xFF][0xC41F]=255;
	    message_emul(0,2, "CHEAT: 255 MAGICS !");
	    cont=pause;
	    break;
	  case KEY_F6:
	  case KEY_F7:
	  case KEY_F8:
	    RAM[0xFF][0xD779]=(code-KEY_F6);
	    message_emul(0,2, "CHEAT: MAGIC CHANGED !");
	    cont=pause;
	    break;
	  case KEY_F9:
	    RAM[0xFF][0xD79A]++;
	    message_emul(0,2, "CHEAT: ONE MINUTE ADDED !");
	    cont=pause;
	    break;
	  case KEY_F10:
	    RAM[0xFF][0xD750]++;
	    message_emul(0,2, "CHEAT: ONE LIVE ADDED !");
	    cont=pause;
	    break;
	    /*
	  case KEY_S:
	    sfx_enabled = (1 - sfx_enabled);
	    sprintf(ws, "FM SFX %s", (sfx_enabled)? "ENABLED":"DISABLED");
	    message_emul(0, 2, ws);
	    cont = pause;
	    break;
	  case KEY_V:
	    voice_enabled = (1 - voice_enabled);
	    sprintf(ws, "VOICES %s", (voice_enabled)? "ENABLED":"DISABLED");
	    message_emul(0, 2, ws);
	    cont = pause;
	    break;
	  case KEY_B:
	    bgm_enabled = (1 - bgm_enabled);
	    sprintf(ws, "FM BGM %s", (bgm_enabled)? "ENABLED":"DISABLED");
	    message_emul(0, 2, ws);
	    ComunicationPort = (bgm_enabled)? last_bgm:0;
	    cont = pause;
	    break;
	     */
	  /* change the screen position with keypad + and - */
	  case KEY_PADADD:
	    sy+=2;
	    cont=pause;
	    clear(screen);
	    if (pause) RenderScreen();
	    break;
	  case KEY_PADSUB:
	    sy-=2;
	    cont=pause;
	    clear(screen);
	    if (pause) RenderScreen();
	    break;
#else
	  case KEY_MENU:
	    i=strace;
	    TraceOn();
	    remove_keyboard();
	    printf("entrez le nouvelle valeur :"); scanf("%s", &ws);
	    install_keyboard();
	    put_word(0xFFD780,hex2int(ws));
	    if (!i) TraceOff();
	    cont=pause;
	    break;
	  case KEY_H:
	    TraceOn();
	    printf("historique PC\n");
	    i2=phist;
	    do {
	       printf("PC=%08x\n", historique[i2]);
	       i2++;
	       if (i2==20) i2=0;
	    } while (i2!=phist);
	    break;
	  case KEY_T: TraceOn(); break;
	  case KEY_G: TraceOff(); cont=0; clear_keybuf(); break;
	  case KEY_R: m68k_dumpstate(); break;
	  /* display FIXED RAM video $41000-$41FFF */
	  case KEY_F4:
	    dump_text_video();
	    cont=pause;
	    break;
	  /* display SCROLL RAM video $40000-$43FFF */
	  case KEY_F5:
	    dump_video(0x0000);
	    cont=pause;
	    break;
	  /* display SCROLL RAM video $44000-$47FFF */
	  case KEY_F6:
	    dump_video(0x4000);
	    cont=pause;
	    break;
	  /* display SCROLL RAM video $48000-$4BFFF */
	  case KEY_F7:
	    dump_video(0x8000);
	    cont=pause;
	    break;
	  /* display SCROLL RAM video $4C000-$4FFFF */
	  case KEY_F8:
	    dump_video(0xC000);
	    cont=pause;
	    break;
	  /* dump memory */
	  case KEY_D:
	    TraceOn();
	    remove_keyboard();
	    printf("Adresse de d‚part : ");
	    scanf("%s", &ws[0]);
	    i2=hex2int(ws);
	    printf("Adresse de fin : ");
	    scanf("%s", &ws[0]);
	    i3=hex2int(ws);
	    install_keyboard();
	    i5=0;
	    do {
	       printf("%08x:", i2);
	       for (i4=0;i4!=16;i4++) printf(" %02x", get_byte(i2++));
	       printf("\n");
	       if ((++i5)==20) {
		  i5=0;
		  printf("\nAppuyez sur une touche pour continuer\n");
		  clear_keybuf(); 
		  i6=(readkey()>>8);
		  while (key[i6]);
		  clear_keybuf();
	       }
	    } while (i2<i3);
	    break;
	  /* change the PC value */
	  case KEY_O:
	    if (!strace) TraceOn();
	    remove_keyboard();
	    printf("nouvelle valeur de PC (%08x) : ", regs.pc);
	    scanf("%s", &ws[0]);
	    regs.pc=hex2int(ws);
	    install_keyboard();
	    break;
	  case KEY_B:
	    if (!strace) TraceOn();
	    remove_keyboard();
	    printf("nouveau point d'arret (%08x) : ", BreakPoint);
	    scanf("%s", &ws[0]);
	    BreakPoint=hex2int(ws);
	    install_keyboard();
	    break;
	  /* show the next 68000 instructions to be executed */
	  case KEY_N:
	    if (strace) {
	       printf("-- Instructions suivantes --\n");
	       MC68000_disasm(m68k_getpc(), &p, 10);
	       printf("-- fin ---------------------\n");
	    }
	    break;
	  case KEY_INSERT:
	    valeur_controle+=2;
	    if (pause) RenderScreen();
	    cont=pause;
	    break;
	  case KEY_DEL:
	    valeur_controle-=2;
	    if (pause) RenderScreen();
	    cont=pause;
	    break;
	  case KEY_END:
	    case KEY_HOME: {
	       int page=(code==KEY_END)? 0x44:0xFF;
	       int offs=(code==KEY_END)? 0x0000:0xF800;
	       TraceOn();
	       remove_keyboard();
	       printf("page de sprite (0-3) = "); scanf("%d", &i3);
	       install_keyboard();
	       printf("Donn‚es des sprites (PAGE=0x%02x) :\n\n", i3);
	       for (i=0;i!=16;i++) {
	       printf("SPR %01x: ", i);
		  for (i2=0;i2!=16;i2++)
		    printf("%02x ", RAM[page][offs+(0x100*i3)+(i<<4)+i2]);
		  printf("\n");
	       }
	    }
	    break;
	  case KEY_PADMUL:
	    TraceOn();
	    for (i=0;i!=0x10000;i++) {
	       s_old_values[i]=RAM[0xFF][i];
	       s_check[i]=1;
	    }
	    printf("Moteur de recherche initialis‚.\n");
	    break;
	  case KEY_PADSUB:
	    TraceOn();
	    s_count=0;
	    for (i=0;i!=0x10000;i++) {
	       if (s_check[i]) {
		  if (RAM[0xFF][i]<s_old_values[i]) s_count++;
		  else s_check[i]=0;
		  s_old_values[i]=RAM[0xFF][i];
	       }
	    }
	    printf("Nombre de valeurs ayant diminu‚ : %d\n", s_count);
	    break;
	  case KEY_PADADD:
	    TraceOn();
	    s_count=0;
	    for (i=0;i!=0x10000;i++) {
	       if (s_check[i]) {
		  if (RAM[0xFF][i]>s_old_values[i]) s_count++;
		  else s_check[i]=0x00;
		  s_old_values[i]=RAM[0xFF][i];
	       }
	    }
	    printf("Nombre de valeurs ayant augment‚ : %d\n", s_count);
	    break;
	  case KEY_ENTER:
	    TraceOn();
	    s_count=0;
	    remove_keyboard();
	    printf("valeur … recherche : "); scanf("%d", &i2);
	    install_keyboard();
	    for (i=0;i!=0x10000;i++) {
	       if (s_check[i]) {
		  if (RAM[0xFF][i]==i2) s_count++;
		  else s_check[i]=0x00;
		  s_old_values[i]=RAM[0xFF][i];
	       }
	    }
	    printf("Nombre de valeurs correspondantes : %d\n", s_count);
	    break;
	  case KEY_PADDIV:
	    TraceOn();
	    printf("Liste des zones retenues.\n");
	    for (i=0;i!=0x10000;i++)
	      if (s_check[i]) 
	      printf("0x%04x (0x%02x)\n", i, RAM[0xFF][i]);
	    printf("\n");
	    break;
#endif
       case KEY_P:
	    pause=~pause;
	    cont=pause;
	    int_request=0;
	    if (pause) message_emul(0, 2, "Game paused !");
	 break;
       default: cont=0;
	 }
      }
   } while (cont);
}

void pc_int2() {
   if (time_countdown) {
      time_countdown--;
      if (!time_countdown) {
	 DeleteMessage_REQ=1;
      }
   } 
   temps++;
}
END_OF_FUNCTION(pc_int2);

void Init_Game() {
   char *longname[] = {
      "Shinobi", "Altered Beast", "Golden Axe", "Time Scanner",
      "Quartet (not working)", "Shadow Dancer" 
   };
   char *shortname[] = {
      "SHINOBI", "ALTBEAST", "GOLDNAXE", "TIMSCANR", "QUARTET", "SHDANCER" 
   };
      
   /* change memory mapping for some games */
   switch (game) {
    case 3: /* Golden Axe */
      txt_bank=0x11;
      vid_bank=0x10;
      pal_bank=0x14;
      ext_bank=0x1F;
      break;
    case 6: /* Shadow Dancer */
      ctr_bank=0xE4;
      ext_bank=0xC0;
      break;
   }

   strcpy(game_basename, shortname[game-1]);
   strcpy(game_name, longname[game-1]);

   printf("\nSelected game : %s\n", game_name);
}

int CheckArguments(int argc, char **argv) {
   int i;
   for (i=1;i!=argc;i++) {
      if (argv[i][0]=='-') {
	 if (!strcmp(argv[i], "-frame")) {
	    frame=atoi(argv[++i]);
	    if ((frame<1)||(frame>50)) {
	       printf("Bad frame value, only 1 to 10 are allowed!");
	       return(1);
	    } else {
	       printf("Frame skip value = %d \n", frame);
	       #ifdef RELEASE_BETA
	       render_cd_start=50*frame;
	       #else
	       render_cd_start=5000*frame;
	       #endif
	    }
	 }
	 else if (!strcmp(argv[i], "-int")) {
	    int_speed=atoi(argv[++i]);
	    if ((int_speed<1)||(int_speed>200)) {
	       printf("Bad int value, only 1 to 200 are allowed!");
	       return(1);
	    } else {
	       printf("Interrupt speed = %d call/second \n", int_speed);
	    }
	 }
	 else if (!strcmp(argv[i], "-game")) {
	    game=atoi(argv[++i]);
	    if ((game<1)||(game>LAST_GAME)) {
	       printf("Bad game number, only 1 to %d are allowed!", LAST_GAME);
	       return(1);
	    }
	 }
	 else if (!strcmp(argv[i], "-load")) {
	    game_to_load=atoi(argv[++i]);
	    if ((game<1)||(game>10)) {
	       printf("Bad save game number, only 1 to 10 are allowed!");
	       return(1);
	    }
	 }
	 else if (!strcmp(argv[i], "-nolfb")) {
	    NO_LFB=1;
	 }
	 else if (!strcmp(argv[i], "-svga")) {
	    svga=1;
	 }
	 else if (!strcmp(argv[i], "-svga400")) {
	    svga=2;
	 }
	 else if (!strcmp(argv[i], "-vga")) {
	    svga=3;
	 }
	 else if (!strcmp(argv[i], "-special")) {
	    svga=4;
	 }
	 else if (!strcmp(argv[i], "-vsync")) {
	    sync=1;
	 }
	 else if (!strcmp(argv[i], "-nojoy")) {
	    joystick_support=0;
	 }
	 #ifdef EMULATE_Z80
	 else if (!strcmp(argv[i], "-nosound")) {
	    sound_enabled = 0;
	 }
	 #endif
	 else if (!strcmp(argv[i], "-regspeed")) {
	    nouvelle_methode=1;
	    int_speed=60;
	    if (i!=(argc-1)) {
	       if (argv[i+1][0]!='-') {
		  opcodeb=atoi(argv[i+1]);
		  if (opcodeb<1) {
		     printf("Error, minimum value for -regspeed is 100 !\n");
		     return(1);
		  }
	       }
	    }
	 }
	 else if (!strcmp(argv[i], "-z80")) {
	    if (i!=(argc-1)) {
	       if (argv[i+1][0]!='-') {
		  z80cycles=atoi(argv[i+1]);
		  if ((z80cycles < 100) || (z80cycles > 2500)) {
		     printf("Error, values range for -z80 is 100-2500 !\n");
		     return(1);
		  }
	       }
	    }
	 }
	 else {
	    printf("Bad option name : %s !\n", argv[i]);
	    return(1);
	 }
      }
   }
   return(0);
}

void main(int argc, char **argv) {
   printf("The System 16 Arcade Emulator v0.53 (Public BETA)\n");
   printf("Copyright Thierry Lescot, 1996/1997.\n\n");
#ifdef EMULATE_Z80
   printf("%s\n", Texto);
#endif
   if (windows_version) {
      printf("Windows %d.%d detected ! %s run slower under Windows !\n",
	     windows_version, windows_sub_version, game_name);
   }
   if (CheckArguments(argc, argv)) {
      exit(0);
   }
   allegro_init();
   install_timer();
   install_keyboard();

   Init_Game();
   #ifdef SON_SIMULE
   if (install_sound(DIGI_AUTODETECT, MIDI_NONE, argv[0])!=0) {
      printf("Pas de son (%s) !\n", allegro_error);
      while (!keypressed()); clear_keybuf();
   } else Load_Samples();
   #endif;
   
   Initialisation();
   
   printf("\nPress any key to continue ...\n");
#ifdef RELEASE_BETA
#ifndef TEST_CPU_SPEED
   while (!keypressed());
   clear_keybuf();
   printf("\n");
   strace=0;
   for (i = 0; i!=25; i++) printf("\n");
   printf("Please, read this !!!\n\n");
   printf("READ SYSTEM16.DOC **BEFORE** E-MAILING ME !!!\n\n");
   printf("AND DON'T ASK ME FOR ROMS !!!\n\n\nPress a key to continue.\n");
   while (keypressed());
   clear_keybuf();
   while (!keypressed());
   clear_keybuf();
   #endif
#else
   strace=1;
#endif
   
//   put_word(0x1DE5C,0x4E71);
   
#ifdef RELEASE_BETA   
   Video(1);
#endif
   
   vscreen=create_bitmap(512, 400);
   vscreen_sub=create_sub_bitmap(vscreen, 88, 88, 336, 224);

   Load_Config();
   clear(vscreen_sub);
   Setup_Asm();
   
   Create_Palette();
   
   LOCK_VARIABLE(int_request);
   LOCK_VARIABLE(time_countdown);
   LOCK_VARIABLE(DeleteMessage_REQ);
   LOCK_VARIABLE(temps);
   LOCK_FUNCTION(pc_int);
   LOCK_FUNCTION(pc_int2);
   install_int_ex(pc_int, 1193181/int_speed);
   install_int_ex(pc_int2, 1193181);

   message_emul(0, 5, " Welcome to The System 16 Emulator v0.53");
//   message_emul(0, 5, " PRIVATE PRE-RELEASE BETA 0.5");

#ifdef TEST_CPU_SPEED
   do {
      Emule();
   } while (temps<=30);
#else
   do {
      if (nouvelle_methode) NewEmule();
      else Emule();
      if (strace) {
	 clear_keybuf();
	 while (!keypressed());
      }
      if (DeleteMessage_REQ) DeleteMessage();
      Clavier();
   } while (!key[KEY_ESC]);
#endif
   
   #ifdef EMULATE_Z80
   ResetYM();
   #endif
   
   allegro_exit();
   if ((game==2)||(game==6)) {
      printf("Saving SRAM...\n");
      Save_SRAM();
   }
   printf("\nVideo mode used = %d (1=LINEAR,2=BANKED,3=XMODE,4=VGA/SVGA)\n", mode_video);
   if (mode_video==3) {
      printf("\nFor beter results you can install the SciTech UniVBE 5.3 drivers.\n");
   }
   /*
   printf("\nValeur de PC=%08x\n", regs.pc);
   printf("\nAcc‚s … la palette = %d\nTotal new colors = %d\n", total_palette, total_new_colors);
   printf("\nNombre de Palette Init = %d\n", total_palette_reset);
   printf("Total render = %d \n", total_render);
    */
   #ifdef MAX_MEM_TEST
   printf("\nMax mem results :\n");
   for (i=0;i!=256;i++) 
     if (MaximumW[i]||MaximumR[i]) 
     printf("bank[%02x] R=%04x W=%04x\n", i, MaximumR[i], MaximumW[i]);
   #endif
   #ifdef TEST_CPU_SPEED
   printf("nombre d'instruction … la seconde = %d\n", icount/30);
   printf("speed = %d procents\n", (icount/300)/2597);
   #endif
   if (temps) printf("Average frame rate = %d FPS\n", fcount/temps);
}
