/*
 * SYSTEM 16 ARCADE EMULATOR SOURCE CODE
 * 
 * Copyright 1996/97 Thierry Lescot
 */

#include <allegro.h>
#include "cpudefs.h"

#define FADE_SPEED 16

#define SHINOBI_NUMBER 1
#define EMULATOR_VERSION 0x0051

extern char game_basename[9];
extern char game, joy, joystick_support, ws[80], joydef[4];
extern UBYTE vid_bank, txt_bank, ext_bank, pal_bank;
extern int sx, sy, svga;

PALLETE menu_save_palette;
RGB pal[256];

int int_value, screen_update;
extern BITMAP *vscreen;
extern int keydef[40];
extern UBYTE shinobi_ds1[10], shinobi_ds2[10], reset_palette;
extern UBYTE Palette256[0x1000];
BITMAP *save_screen, *save_screen_2;

char *b1[6]= {"ATTACK","PUNCH","-","LEFT FLIPPER","-","JUMP"};
char *b2[6]= {"JUMP","KICK","-","RIGHT FLIPPER","-","MAGIC"};
char *b3[6]= {"MAGIC","JUMP","-","-","-","ATTACK"};

struct {
   char ok;
   char description[20];
} savegame_list[10];

void Outline_Text(int y, int c, char *str) {
   int dx, dy;
   text_mode(-1);
   for (dx=-1;dx!=2;dx++) 
     for (dy=-1;dy!=2;dy++) textout_centre(screen, font, str, 160+dx, y+dy, 4);
   textout_centre(screen, font, str, 160, y, c);
   text_mode(0);
}

void OutlineXY_Text(int x, int y, int c, char *str) {
   int dx, dy;
   text_mode(-1);
   for (dx=-1;dx!=2;dx++) 
     for (dy=-1;dy!=2;dy++) textout(screen, font, str, x+dx, y+dy, 4);
   textout(screen, font, str, x, y, c);
   text_mode(0);
}

void GetTextGfx(char *caption, char *p, int lm) {
   int pos=0, key;
   int l=strlen(p);
   int px=(300-(lm*10))/2;
   int py=100;
   int w=(10*lm)+20;
   char one_char[2] = {0,0};
   blit(screen, save_screen_2, 0, 0, 0, 0, 320, 240);
   rectfill(screen, px, py, px+w, py+28, 8);
   rect(screen, px, py, px+w, py+28, 4);
   Outline_Text(py+3, 2, caption);
   do {
      if (pos!=lm) 
      	rectfill(screen, px+10+(pos*10), py+15, px+18+(pos*10), py+23, 5);
      key=(readkey()&0x00FF);
      if (pos!=lm) {
	 rectfill(screen, px+10+(pos*10), py+15, px+18+(pos*10), py+23, 8);
	 if ((key>='a')&&(key<='z')) key-=32;
	 if (((key>='A')&&(key<='Z'))||
	     ((key>='0')&&(key<='9'))||(key==' ')) {
		p[pos]=key;
		one_char[0]=key;
		OutlineXY_Text(px+11+(pos*10), py+16, 1, one_char);
		pos++;
		p[pos]=0;
	     }
      }
      if ((key==8)&&(pos)) {
	 pos--;
	 p[pos]=0;
      }
   } while (key!=13);
   blit(save_screen_2, screen, 0, 0, 0, 0, 320, 240);
}

void Message(char *txt, int c, int p) {
   int w=((text_length(font, txt)/2)+20);
   blit(screen, save_screen, 0, 0, 0, 0, 320, 240);
   rectfill(screen, 160-w, 106, 160+w, 134, 7);
   rect(screen, 160-w, 106, 160+w, 134, 4);
   Outline_Text(117, c, txt);
   if (p) {
      clear_keybuf();
      while (!keypressed());
      clear_keybuf();
   } else {
      rest(1500);
   }
   blit(save_screen, screen, 0, 0, 0, 0, 320, 240);
}

void Message_NoPause(char *txt, int c) {
   int w=((text_length(font, txt)/2)+20);
   rectfill(screen, 160-w, 106, 160+w, 134, 7);
   rect(screen, 160-w, 106, 160+w, 134, 4);
   Outline_Text(117, c, txt);
}

void Hide_Screen(char *titre) {
   fade_out(FADE_SPEED);
   clear(screen);
   Outline_Text(10, 3, "THE SEGA SYSTEM 16 EMULATOR v0.53");
   Outline_Text(30, 3, titre);
}

void Show_Screen() {
   fade_in(pal, FADE_SPEED);
}

void Draw_Main_Menu() {
   Hide_Screen("SETUP MENU");
   Outline_Text(50, 2, "F1 - SETUP KEYBOARD");
   Outline_Text(90, 2, "F3 - SETUP DIP SWITCHS");
   Outline_Text(110,2, "F5 - SAVE CURRENT GAME TO DISK");
   Outline_Text(130,2, "F6 - LOAD GAME STORED ON DISK");
   Outline_Text(150,2, "F8 - SAVE CURRENT CONFIG");
   Outline_Text(180,2, "F10 - RESET THE GAME");
   Outline_Text(210,1, "ESC - QUIT SETUP MENU");
   Show_Screen();
}

void Get_New_Key(int key_number, char *key_name) {
   int ok=1, scancode, i;
   clear_keybuf();
   rectfill(screen, 0, 115, 319, 132, 0);
   do {
      Outline_Text(124, 5, key_name);
      scancode=0;
      do {
	 if (keypressed()) scancode=(readkey()>>8);
	 if (key[KEY_CONTROL]) scancode=KEY_CONTROL;
	 if (key[KEY_ALT]) scancode=KEY_ALT;
      } while (!scancode);
      if (key_number) {
	 ok=1;
	 for (i=0;i!=key_number;i++) {
	    if (keydef[i]==scancode) {
	       Message("THIS IS ALREADY USED", 6, 0);
	       ok=0;
	       continue;
	    }
	 }
      }
      while (key[keydef[key_number]]);
      clear_keybuf();
   } while (!ok);
   keydef[key_number]=scancode;
}

void Setup_KB(int t, char *texte) {
   Hide_Screen(texte);
   Outline_Text(100, 2, "PRESS THE KEY FOR");
   Show_Screen();
   switch (t) {
    case 0:
      Get_New_Key(0, "1P START");
      Get_New_Key(1, "2P START");
      Get_New_Key(2, "COIN SLOT 1");
      Get_New_Key(3, "COIN SLOT 2");
      Get_New_Key(4, "SERVICE");
      Get_New_Key(5, "TEST");
      break;
    case 6:
    case 20:
      switch (game) {
       case 2:
	 Get_New_Key(t, "PUCH");
	 Get_New_Key(t+1, "KICK");
	 Get_New_Key(t+2, "JUMP");
	 Get_New_Key(t+3, "UP");
	 Get_New_Key(t+4, "DOWN");
	 Get_New_Key(t+5, "LEFT");
	 Get_New_Key(t+6, "RIGHT");
	 break;
       case 4:
	 Get_New_Key(t, "LEFT FLIPPER");
	 Get_New_Key(t+1, "RIGHT FLIPPER");
	 keydef[t+2]=127;
	 Get_New_Key(t+3, "FRONT PUSH SWITCH");
	 keydef[t+4]=127;
	 Get_New_Key(t+5, "LEFT PUSH SWITCH");
	 Get_New_Key(t+6, "RIGHT PUSH SWITCH");
	 break;
       case 6: // Shadow Dancer
	 Get_New_Key(t, "JUMP");
	 Get_New_Key(t+1, "MAGIC");
	 Get_New_Key(t+2, "ATTACK");
	 Get_New_Key(t+3, "UP");
	 Get_New_Key(t+4, "DOWN");
	 Get_New_Key(t+5, "LEFT");
	 Get_New_Key(t+6, "RIGHT");
	 break;
       default :
	 Get_New_Key(t, "ATTACK");
	 Get_New_Key(t+1, "JUMP");
	 Get_New_Key(t+2, "MAGIC");
	 Get_New_Key(t+3, "UP");
	 Get_New_Key(t+4, "DOWN");
	 Get_New_Key(t+5, "LEFT");
	 Get_New_Key(t+6, "RIGHT");
	 break;
      }
      break;
   }
}

void Get_New_Button(int key_number, char *key_name) {
   int ok=1, scancode, i, tmp;
   char bval, *bname;
   clear_keybuf();
   rectfill(screen, 0, 115, 319, 132, 0);
   do {
      Outline_Text(124, 5, key_name);
      do {
	 poll_joystick();
	 bval=(joy_b[1]+joy_b[2]+joy_b[3]+joy_b[4]);
      } while (bval);
      do {
	 poll_joystick();
	 bval=(joy_b[1]+joy_b[2]+joy_b[3]+joy_b[4]);
      } while ((!bval)&&(!key[KEY_ESC]));
      if (bval) {
	 if (bval>1) {
	    Message("?", 5, 0);
	    ok=0;
	 } else {
	    if (joy_b[1]) bval=1; 
	    else if (joy_b[2]) bval=2;
	    else if (joy_b[3]) bval=3;
	    else if (joy_b[4]) bval=4;
	    ok=1;
	    for (i=0;i!=key_number;i++) {
	       if (joydef[i]==bval) {
		  switch (i) {
		   case 0: bname=b1[game-1]; break;
		   case 1: bname=b2[game-1]; break;
		   case 2: bname=b3[game-1]; break;
		  }
		  sprintf(ws, "BUTTON %c ALREADY USED FOR %s", bval+64, bname);
		  Message(ws, 6, 0);
		  ok=0;
		  continue;
	       }
	    }
	 }
      } else (ok=1);
   } while (!ok);
   joydef[key_number]=bval;
}

void Setup_Joy() {
   Hide_Screen("JOYSTICK BUTTON MAPPING");
   Outline_Text(100, 2, "PRESS THE BUTTON FOR");
   Outline_Text(220, 3, "ESC - DON'T MAP THIS BUTTON");
   Show_Screen();
   if (b1[game-1][0]!='-') Get_New_Button(0, b1[game-1]); else joydef[0]=0;
   if (b1[game-1][1]!='-') Get_New_Button(1, b2[game-1]); else joydef[1]=0;
   if (b1[game-1][2]!='-') Get_New_Button(2, b3[game-1]); else joydef[2]=0;
}

void Setup_Keyboard() {
   int touche;
   do {
      Hide_Screen("KEYBOARD SETUP");
      Outline_Text(90, 3, "1 - PLAYER ONE KEYS");
      Outline_Text(110, 3, "2 - PLAYER TWO KEYS");
      Outline_Text(130, 3, "G - GENERAL KEYS");
      if (joy) Outline_Text(170, 3, "B - JOYSTICK BUTTON CONFIGURATION");
      if (joystick_support) {
	 rectfill(screen, 0, 149, 319, 159, 0);
	 switch (joy) {
	  case 0: Outline_Text(150, 3, "J - JOYSTICK = NOT USED"); break;
	  case 1: Outline_Text(150, 3, "J - JOYSTICK = 1ST PLAYER"); break;
	  case 2: Outline_Text(150, 3, "J - JOYSTICK = 2ND PLAYER"); break;
	 }
      }
      Outline_Text(220, 2, "ESC to cancel");
      Show_Screen();
      clear_keybuf();
      touche=(readkey()>>8);
      switch (touche) {
       case 0x4F:
       case KEY_1:
	 Setup_KB(6, "Player one keys");
	 break;
       case 0x50:
       case KEY_2:
	 Setup_KB(20, "Player two keys");
	 break;
       case KEY_G:
	 Setup_KB(0, "General keys");
	 break;
       case KEY_J:
	 if (joystick_support) {
	    joy++;
	    if (joy==3) joy=0;
	 }
	 break;
       case KEY_B:
	 Setup_Joy();
	 break;
      }
   } while (touche!=KEY_ESC);
}

void Save_Config() {
   PACKFILE *f;
   int version=EMULATOR_VERSION;
   
   sprintf(ws, "%s.cfg", game_basename);
   f=pack_fopen(ws, F_WRITE_PACKED);
   if (f!=NULL) {
      pack_iputw(version, f);
      pack_fwrite(&keydef[0], sizeof(keydef[0])*40, f);
      pack_fwrite(shinobi_ds1, 10, f);
      pack_fwrite(shinobi_ds2, 10, f);
      pack_fwrite(joydef, 4, f);
      pack_fclose(f);
      Message("CONFIGURATION SAVED", 5, 0);
   } else {
      Message("DISK WRITE ERROR", 6, 0);
   }
}

void Load_Config() {
   PACKFILE *f;
   int version;

   sprintf(ws, "%s.cfg", game_basename);
   f=pack_fopen(ws, F_READ_PACKED);
   if (f!=NULL) {
      version=pack_igetw(f);
      pack_fread(&keydef[0], sizeof(keydef[0])*((version>=0055)? 40:20), f);
      pack_fread(shinobi_ds1, 10, f);
      pack_fread(shinobi_ds2, 10, f);
      if (version>=0051) pack_fread(joydef, 5, f);
      pack_fclose(f);
   }
}

void FillSavegameList() {
   int i, trash;
   char fn[15], desc[21];
   PACKFILE *f;
   for (i=0;i!=10;i++) {
      sprintf(fn, "%s.sa%d", game_basename, i);
      if (file_exists(fn, 0, NULL)) {
	 f=pack_fopen(fn, F_READ_PACKED);
	 trash=pack_igetw(f);
	 trash=pack_igetw(f);
	 pack_fread(savegame_list[i].description, 21, f);
	 pack_fclose(f);
      }
      else strcpy(savegame_list[i].description, "free slot");
   }
}

char SelectFromSavegameList(char *caption) {
   int i, key;
   rectfill(screen, 70, 45, 250, 180, 8);
   rectfill(screen, 75, 65, 245, 175, 0);
   rect(screen, 70, 45, 250, 180, 4);
   rect(screen, 75, 65, 245, 175, 4);
   Outline_Text(50, 2, caption);
   for (i=0;i!=10;i++) 
     OutlineXY_Text(80, 70+10*i, 5, savegame_list[i].description);
   i=0;
   Outline_Text(190, 2, "UP/DOWN to change");
   Outline_Text(205, 2, "ENTER to select a slot");
   Outline_Text(220, 2, "ESC to cancel");
   Show_Screen();
   do {
      rect(screen, 77, 68+(10*i), 243, 78+(10*i), 5);
      key=(readkey()>>8);
      rect(screen, 77, 68+(10*i), 243, 78+(10*i), 0);
      if ((key==KEY_UP)&&(i)) i--;
      if ((key==KEY_DOWN)&&(i!=9)) i++;
      if (key==KEY_ESC) {
	 key=KEY_ENTER;
	 i=-1;
      }
   } while (key!=KEY_ENTER);
   return(i);
}

void Load_GameFromDisk(char n) {
   char fn[15], desc[21];
   int trash;
   PACKFILE *f;
   sprintf(fn, "%s.sa%d", game_basename, n);
   printf("Loading saved game number %d...\n", n);
   f=pack_fopen(fn, F_READ_PACKED);
   if (f!=NULL) {
      trash=pack_igetw(f);
      trash=pack_igetw(f);
      pack_fread(desc, 21, f);
      printf("Description : %s\n", desc);
      pack_fread(&regs, sizeof(regs), f);
      pack_fread(&lastint_regs, sizeof(regs), f);
      pack_fread(&regflags, sizeof(regflags), f);
      pack_fread(RAM[0x40], 0x10000, f);
      pack_fread(RAM[0x41], 0x1000, f);
      pack_fread(RAM[0x44], 0x2000, f);
      pack_fread(RAM[0x84], 0x1000, f);
      pack_fread(RAM[0xFE], 0x40, f);
      pack_fread(RAM[0xFF], 0x10000, f);
      pack_fclose(f);
      reset_palette=1; /* reset the palette */
      printf("Game loaded !\n");
   } else  {
      printf("Can't open %s !\n", fn);
   }
}

void Load_Game() {
   PACKFILE *f;
   char desc[21], i, fn[15];
   int version, game_number;
   Hide_Screen("Load a game from disk");
   FillSavegameList();
   i=SelectFromSavegameList("SELECT A SAVED GAME");
   
   if (i!=-1) {
      sprintf(fn, "%s.sa%d", game_basename, i);
      f=pack_fopen(fn, F_READ_PACKED);
      if (f!=NULL) {
	 Message_NoPause("Loading...", 5);
	 version=pack_igetw(f);
	 game_number=pack_igetw(f);
	 pack_fread(desc, 21, f);
	 pack_fread(&regs, sizeof(regs), f);
	 pack_fread(&lastint_regs, sizeof(regs), f);
	 pack_fread(&regflags, sizeof(regflags), f);
	 pack_fread(RAM[vid_bank], 0x10000, f);
	 pack_fread(RAM[txt_bank], 0x1000, f);
	 pack_fread(RAM[ext_bank], 0x2000, f);
	 pack_fread(RAM[pal_bank], 0x1000, f);
	 pack_fread(RAM[0xFE], 0x40, f);
	 pack_fread(RAM[0xFF], 0x10000, f);
	 pack_fclose(f);
	 reset_palette=1; /* reset the palette */
	 Message("GAME LOADED", 5, 0);
      } else {
	 Message("DISK READ ERROR", 6, 0);
      }
   }
}
   
void Save_Game() {
   char desc[21], i, fn[15];
   PACKFILE *f;
   int version=EMULATOR_VERSION;
   int game_number=game;

   Hide_Screen("Save the current game");
   FillSavegameList();
   i=SelectFromSavegameList("SELECT A SLOT");
   
   if (i!=-1) {
      GetTextGfx("ENTER THE DESCRIPTION", desc, 20);
      sprintf(fn, "%s.sa%d", game_basename, i);
      f=pack_fopen(fn, F_WRITE_PACKED);
      if (f!=NULL) {
	 Message_NoPause("Saving...", 5);
	 pack_iputw(version, f);
	 pack_iputw(game_number, f);
	 pack_fwrite(desc, 21, f);
	 pack_fwrite(&regs, sizeof(regs), f);
	 pack_fwrite(&lastint_regs, sizeof(regs), f);
	 pack_fwrite(&regflags, sizeof(regflags), f);
	 pack_fwrite(RAM[vid_bank], 0x10000, f);
	 pack_fwrite(RAM[txt_bank], 0x1000, f);
	 pack_fwrite(RAM[ext_bank], 0x2000, f);
	 pack_fwrite(RAM[pal_bank], 0x1000, f);
	 pack_fwrite(RAM[0xFE], 0x40, f);
	 pack_fwrite(RAM[0xFF], 0x10000, f);
	 pack_fclose(f);
	 Message("GAME SAVED", 5, 0);
      } else {
	 Message("DISK WRITE ERROR", 6, 1);
      }
   }
}
   
void Interface() {
   int touche;
   get_palette(menu_save_palette);
   pal[1].r=pal[1].g=pal[1].b=63;
   pal[0].r=pal[0].g=pal[0].b=32;
   pal[2].b=0; pal[2].g=pal[2].r=63;
   pal[3].r=0; pal[3].g=pal[3].b=63;
   pal[4].r=pal[4].g=pal[4].b=0;
   pal[5].r=pal[5].b=0;pal[5].g=63;
   pal[6].g=pal[6].b=0;pal[6].r=63;
   pal[7].r=pal[7].g=pal[7].b=16;
   pal[8].r=pal[8].g=16;pal[8].b=32;
   Draw_Main_Menu();
   save_screen=create_bitmap(320, 240);
   save_screen_2=create_bitmap(320, 240);
   do {
      clear_keybuf();
      touche=(readkey()>>8);
      switch (touche) {
       case KEY_F1:
	 Setup_Keyboard();
	 Draw_Main_Menu();
	 break;
       case KEY_F3:
	 Setup_Dip_Swicths();
	 Draw_Main_Menu();
	 break;
       case KEY_F5:
	 Save_Game();
	 Draw_Main_Menu();
	 break;
       case KEY_F6:
	 Load_Game();
	 Draw_Main_Menu();
	 break;
       case KEY_F8:
	 Save_Config();
	 break;
       case KEY_F10:
	 MC68000_reset();
	 touche=KEY_ESC;
	 break;
      }
   } while (touche!=KEY_ESC);
   while (key[KEY_ESC]);
   clear_keybuf();
   fade_out(FADE_SPEED);
   clear(screen);
   blit(vscreen, screen, 104, 88, sx, sy, 312, 224);
   fade_in(menu_save_palette, FADE_SPEED);
   destroy_bitmap(save_screen);
   destroy_bitmap(save_screen_2);
}
