/****************************************************************************/
/**                                                                        **/
/**                                  main.c                                **/
/**                                                                        **/
/**                    Programmation en C de DACMAN v1.3                   **/
/**                        Par / by Daniel Bienvenu                        **/
/**                      librairies C de Coleco Vision                     **/
/**                         Par / by Marcel DeKogel                        **/
/**                                                                        **/
/**                                  2000                                  **/
/****************************************************************************/

/* THIS SOURCE CODE WAS UPDATED IN 2009 TO BE COMPILED WITH LIB4K AND SDCC */

#include <string.h>
#include <coleco.h>
#include <getput1.h>

/* VDP table addresses */
#define chrtab  0x1800
#define chrgen  0x0000
#define coltab  0x2000
#define sprtab  0x3800 /* sprite_pattern_table */
#define sprgen  0x1b00 /* sprite_attribute_table */

#define lastlinecoltab 0x3700 /* last line color */

extern const sound_t snd_table[];

/* external bonus game */
extern void bonus_game(void);

/* various RLE-encoded tables (in tables.c) */
extern const byte info[];
extern const byte daniel[];
extern const byte title[];

/* EXTERN GRAPHICS */
extern const byte grafx[];
extern const byte numbers[];
extern const byte font[];
extern const byte dieze[];
extern const byte etoile[];
extern const byte medaille[];
extern const byte board1[];
extern const byte board2[];
extern const byte board3[];
extern const byte board4[];
extern const byte board_vide[];
extern const byte again[];

extern const byte mssprites[];

static int score;
static int hiscore;
static int dots;
static int nextlife;

/* VARIABLES AVEC LESQUELS ON PEUT TRICHER */
static byte nbpaclifes;
static byte nolevel;
static byte easymode;
static byte bonusgame;

/* 3 GHOST Direction, coor X and Y, and the undercaracter */
 byte gd[3];
 byte gx[3];
 byte gy[3];
 byte ogx[3];
 byte ogy[3];
 char gc[3];
 byte gt[3];

 byte pacx;
 byte pacy;
 byte paclifes;
 byte pacmedaille;

 byte bonusx;
 byte bonusy;
 int bonus;

 byte level;

 byte speed1;
 byte speed2;

 byte playing;

 byte flashing;

/* COLORS FONT */
 static const byte green_font[8]= { 0xc1,0x21,0x31,0xb1,0x31,0x21,0xc1,0xc1 };
 static const byte red_font[8]= { 0x61,0x81,0x91,0xb1,0x91,0x81,0x61,0x61 };
 static const byte yellow_font[8]= { 0xa1,0xb1,0xe1,0xf1,0xe1,0xb1,0xa1,0xa1};
/* COLORS GHOST */
 static const byte ghost[24] = {
  0x81,0x81,0x8f,0x8f,0x81,0x81,0x81,0x81,
  0x71,0x71,0x7f,0x7f,0x71,0x71,0x71,0x71,
  0x31,0x31,0x3f,0x3f,0x31,0x31,0x31,0x31};
/* COLORS ITEMS */
 static const byte items_color[80] = {
  0x21,0x21,0x21,0x21,0x81,0x81,0x81,0x81,
  0x21,0x21,0x31,0x81,0x81,0x81,0x81,0x81,
  0x21,0x21,0x61,0xa1,0xa1,0xa1,0xa1,0xa1,
  0x21,0x21,0x81,0x81,0x81,0x81,0x81,0x81,
  0x61,0x61,0x31,0x31,0x31,0x31,0x31,0x31,
  0x21,0x21,0x91,0x91,0x91,0x91,0x91,0x91,
  0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,
  0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
  0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,
  0xf1,0x81,0xf1,0x81,0xf1,0x81,0xf1,0x81};

/* COULEURS MEDAILLES */
static const byte med_col[8] = {0x91, 0x81, 0x61, 0xe1, 0xf1, 0xf1, 0xf1, 0xf1};

/* GHOST MOUVEMENTS */
 static const byte g0[]={0,1,2,-3,4,-5,-6,-7,8,-9,-10,-11,-12,-13,-14,-15};
 static const byte g1[]={0,1,2,1,4, 1,2,-3,8,1,-10,  1,8, -9,-10,-11};
 static const byte g2[]={0,1,2,2,4,-5,2, 2,8,1,  2, -3,4, -5, -6, -7};
 static const byte g4[]={0,1,2,2,4, 4,4,-6,8,8,-10,-10,4,-12,  4,-14};
 static const byte g8[]={0,1,2,1,4,-5,4,-5,8,8,  8, -9,8,  8,-12,-13};

/* directions */
 static const byte dx[]={0,1,0,0,-1,0,0,0,0};
 static const byte dy[]={0,0,1,0,0,0,0,0,-1};

/* MUSIC AND SOUND FX - EXTERNAL CALLS */
extern void pacdd (void);
extern void pacgob (void);

/* MUSIC AND SOUND FX */
static void pacman (void)
{
	play_sound(1);
	play_sound(2);
	delay(318);
}

static void pacbg (void)
{
	play_sound(3);
}
/*  LENGTH  =  24 */

static void pacbg2 (void)
{
	play_sound(4);
}
/*  LENGTH  =  10  */
	
static void pacbonus (void)
{
	play_sound(7);
}
/*  LENGTH  =  19  */

static void pacgbleu (void)
{
	stop_sound(8);
	delay(1);
	play_sound(8);
}
/*  LENGTH  =  59  */

static void newlife (void)
{
	play_sound(9);
}
	
static void ding (void)
{
	play_sound(10);
}

static void med(void)
{
	play_sound(11);
	play_sound(12);
	play_sound(13);
}
/*  LENGTH  =  1920  */

static void m022 (void)
{
	play_sound(14);
	play_sound(15);
	play_sound(16);
	delay(2000);
}
/*  LENGTH  =  3840  */

/* FLASHING BLUE GHOST AND POWER DOTS */
void flash (void)
{
  byte gt0;
  byte gt1;
  byte gt2;
  byte max = 0;

    flashing++;
    if (flashing==12)
    {
     fill_vram (coltab+(128+33)*8,0xf1,8);
     fill_vram (coltab+(256+128+33)*8,0xf1,8);
     fill_vram (coltab+(512+128+33)*8,0xf1,8);
    }
    if (flashing==24)
    {
     fill_vram (coltab+(128+33)*8,0x11,8);
     fill_vram (coltab+(256+128+33)*8,0x11,8);
     fill_vram (coltab+(512+128+33)*8,0x11,8);
     flashing=0;
    }
    gt0 = gt[0];
    gt1 = gt[1];
    gt2 = gt[2];
    max = 0;
    if (gt0 > max) max = gt0;
    if (gt1 > max) max = gt1;
    if (gt2 > max) max = gt2;
    if (max == 0 || max == 6 || max > 9)
    {
     fill_vram (coltab+(128+34+9+3)*8,0x41,8);
     fill_vram (coltab+(256+128+34+9+3)*8,0x41,8);
     fill_vram (coltab+(512+128+34+9+3)*8,0x41,8);
    }
    if (max == 3 || max == 9)
    {
     fill_vram (coltab+(128+34+9+3)*8,0xf1,8);
     fill_vram (coltab+(256+128+34+9+3)*8,0xf1,8);
     fill_vram (coltab+(512+128+34+9+3)*8,0xf1,8);
    }
}

/* The NMI routine */
void nmi (void)
{
  if (playing) {flash();}
}

static void init_vdp (void)
{
 register byte i;
 /* turn display off */
 screen_off ();
 /* disable NMI */
 disable_nmi ();
 /* clear VRAM */
 fill_vram (0,0,0x4000);
 /* Upload ASCII character patterns */
 upload_ascii (29,128-29,chrgen+29*8,BOLD);
 /* USE MY OWN NUMBERS FONT */
 put_vram (chrgen+'0'*8,numbers,8*10);
 /* USE MY OWN ALPHABET FONT */
 put_vram (chrgen+'A'*8,font,8*26);
 /* USE MY OWN ! AND ? Symbol */
 put_vram (chrgen+'!'*8,font+26*8,8);
 put_vram (chrgen+'?'*8,font+27*8,8);
 /* USE MY OWN # and * Symbol */
 put_vram (chrgen+0x23*8,dieze,8);
 put_vram (chrgen+0x2a*8,etoile,8);
 /* ADD medaille */
 put_vram (chrgen+0xe0*8,medaille,12*8);
 /* Fill colour table */
 /* NUMBERS ARE GREEN, ALL OTHER CARACTERS ARE YELLOW */
 put_vram_pattern (coltab,yellow_font,8,256);
 put_vram_pattern (coltab+48*8,green_font,8,10);

 /* More graphics */
 put_vram (chrgen+8*128,grafx,256);
 put_vram (chrgen+8*128+256,grafx+256,256);
 put_vram (chrgen+8*128+512,grafx+512,160);
 fill_vram (coltab+128*8,0x41,256);
 fill_vram (coltab+(128+32)*8,0xf1,16);
 fill_vram (coltab+(128+32+2)*8,0xb1,5*8);
 fill_vram (coltab+(128+32+7)*8,0x81,16);
 fill_vram (coltab+(128+32+9)*8,0xf1,16);
 put_vram_pattern (coltab+(128+34+9)*8,ghost,24,1);
 fill_vram (coltab+(128+34+9+3)*8,0x41,8);
 fill_vram (coltab+(128+34+9+3+1)*8,0xf1,8);
 put_vram_pattern (coltab+(128+48)*8,items_color,80,1);
 fill_vram (coltab+(128+64)*8,0xb1,256);


 /* Copy first pattern and colour tables to third ones */ 
 for (i=0;i<16;++i)
 {
  get_vram (chrgen+i*128,sprites,128);
  put_vram (chrgen+8*256+i*128,sprites,128);
  put_vram (chrgen+8*512+i*128,sprites,128);
  get_vram (coltab+i*128,sprites,128);
  put_vram (coltab+8*256+i*128,sprites,128);
  put_vram (coltab+8*512+i*128,sprites,128);
 }
 /* LES LETTRES AU MILIEU DE l'ECRAN EN ROUGE */
 put_vram_pattern (coltab+8*256+64*8,red_font,8,32);

 /* LES MEDAILLES */
 /* BRONZE */
 put_vram_pattern (coltab+8*0xe0,med_col,8,3);
 fill_vram (coltab+8*0xe3,0x61,9*8);
 fill_vram (coltab+8*0xe7,0x69,4);
 fill_vram (coltab+8*0xe8+4,0x69,3);
 fill_vram (coltab+8*0xea+5,0x69,2);
 /* ARGENT */
 put_vram_pattern (coltab+8*256+8*0xe0,med_col,8,3);
 fill_vram (coltab+8*256+8*0xe3,0xe1,9*8);
 fill_vram (coltab+8*256+8*0xe7,0xef,4);
 fill_vram (coltab+8*256+8*0xe8+4,0xef,3);
 fill_vram (coltab+8*256+8*0xea+5,0xef,2);
 /* OR */
 put_vram_pattern (coltab+8*512+8*0xe0,med_col,8,3);
 fill_vram (coltab+8*512+8*0xe3,0xb1,9*8);
 fill_vram (coltab+8*512+8*0xe7,0xbf,4);
 fill_vram (coltab+8*512+8*0xe8+4,0xbf,3);
 fill_vram (coltab+8*512+8*0xea+5,0xbf,2);

 /* Black screen border */
 vdp_out (7,0xf1);
 /* turn display on */
 screen_on ();
 /* enable NMI */
 enable_nmi ();
}

void put_hiscore(void)
{
 byte sc;
 char pointage[7];

 sc = (hiscore / 10000) % 10;
 pointage[0]=48+sc;
 sc = (hiscore / 1000) % 10;
 pointage[1]=48+sc;
 sc = (hiscore / 100) % 10;
 pointage[2]=48+sc;
 sc = (hiscore / 10) % 10;
 pointage[3]=48+sc;
 sc = hiscore % 10;
 pointage[4]=48+sc;
 pointage[5]='0';
 pointage[6]='\0';
 center_string(1,pointage);
} 

void put_paclifes(void)
{
 byte g;
 byte h;
 h = paclifes;
 if (h>6) {h=6;}
 for (g = 0; g < h; g++)
 {
  put_char(7+g,23,0xa4);
 }
 put_char(7+h,23,0x20);
}

void put_score(byte points)
{
 byte sc;
 char pointage[7];

 score = score + points;

 sc = (score / 10000) % 10;
 pointage[0]=48+sc;
 sc = (score / 1000) % 10;
 pointage[1]=48+sc;
 sc = (score / 100) % 10;
 pointage[2]=48+sc;
 sc = (score / 10) % 10;
 pointage[3]=48+sc;
 sc = score % 10;
 pointage[4]=48+sc;
 pointage[5]='0';
 pointage[6]='\0';
 put_vram (chrtab+23*32+1,pointage,6);

 if (hiscore<score) {hiscore = score; put_hiscore();}

 if ((score >= nextlife) && nextlife > 0)
 {
  paclifes++;
  newlife();
  put_paclifes();
  if (nextlife > 8000) { nextlife = 0;}
  nextlife = nextlife * 2;
 }
} 

void gameover(void)
{
	print_at(11,11,"GAME OVER");
}

void board (byte lines[])
{
    delay(1);
    put_vram(chrtab+2*32+6,lines+19*0,19);
    put_vram(chrtab+3*32+6,lines+19*1,19);
    put_vram(chrtab+4*32+6,lines+19*2,19);
    put_vram(chrtab+5*32+6,lines+19*3,19);
    put_vram(chrtab+6*32+6,lines+19*4,19);
    put_vram(chrtab+7*32+6,lines+19*5,19);
    put_vram(chrtab+8*32+6,lines+19*6,19);
    put_vram(chrtab+9*32+6,lines+19*7,19);
    put_vram(chrtab+10*32+6,lines+19*8,19);
    put_vram(chrtab+11*32+6,lines+19*9,19);
    put_vram(chrtab+12*32+6,lines+19*10,19);
    put_vram(chrtab+13*32+6,lines+19*11,19);
    put_vram(chrtab+14*32+6,lines+19*12,19);
    put_vram(chrtab+15*32+6,lines+19*13,19);
    put_vram(chrtab+16*32+6,lines+19*14,19);
    put_vram(chrtab+17*32+6,lines+19*15,19);
    put_vram(chrtab+18*32+6,lines+19*16,19);
    put_vram(chrtab+19*32+6,lines+19*17,19);
    put_vram(chrtab+20*32+6,lines+19*18,19);
    put_vram(chrtab+21*32+6,lines+19*19,19);
    put_vram(chrtab+22*32+6,lines+19*20,19);
}

void put_board(void)
{
 if (level<5)
 {
  board(board1);
 }
 else
 {
  if (level<9)
  {
   board(board2);
  }
  else
  {
   if (level==10)
   {
    board(board4);
   }
   else
   {
    board(board3);
   }
  }
 }
 if (level < 3)
 {speed1 = 2; speed2 = 2; }
 else
 {
  if (level < 5)
  {speed1 = 2; speed2 = 1; }
  else
  {
   if (level < 8)
   {speed1 = 1; speed2 = 3;}
   else
   {speed1 = 1; speed2 = 2;}
  }
 }
}

void show_bonus(void)
{
    byte b;
    byte c;
    delay(1);
    c = level;
    if (c>10) c=10;
    put_char(bonusx,bonusy,0xb0+c);
    for (b=0;b<c;b++)
    {
        put_char(23-b,23,0xb0+b);
    }
    put_char(23-level,23,0xb0+c);
}

void hide_bonus(void)
{
    delay(1);
    put_char(bonusx,bonusy,0x20);
}

void init(void)
{
 byte c;
 byte x;
 byte y;

 playing = 0;

 for (x=6;x<25;x++)
 {
  for (y=2;y<23;y++)
  {
   c = get_char(x,y);
   /* FIND GHOSTS */
   if (c == 0xab) {gd[0]=0; gx[0]=x; gy[0]=y; ogx[0]=x; ogy[0]=y; gc[0]=0x20; gt[0]=0;}
   if (c == 0xac) {gd[1]=0; gx[1]=x; gy[1]=y; ogx[1]=x; ogy[1]=y; gc[1]=0x20; gt[1]=0;}
   if (c == 0xad) {gd[2]=0; gx[2]=x; gy[2]=y; ogx[2]=x; ogy[2]=y; gc[2]=0x20; gt[2]=0;}
   /* FIND PACMAN */
   if (c == 0xa2 || c == 0xa3 || c == 0xa4 || c == 0xa5 || c == 0xa6) {pacx = x; pacy = y;}
   /* FIND BONUS */
   if ((c & 0xf0) == 0xb0) {bonusx=x; bonusy=y;}
  }
 } 

 playing = 1;

}

byte which_ghost(byte x, byte y)
{
 byte i = 0;
 while ( (!(x==gx[i] && y==gy[i])) && i<2) i++;
 return i;
}

void ghost_home(byte g)
{
 byte i; 
 put_score(bonus); pacgbleu(); bonus = bonus * 2; 
 put_char(gx[g],gy[g],0xaf);
 i = g;
 while (get_char(ogx[i],ogy[i])!=0x20) {i = (i+1)%3;}
 gx[g]=ogx[i]; gy[g]=ogy[i]; gt[g]=0; gc[g]=0x20;
 if (gt[0] == 0 && gt[1] == 0 && gt[2] == 0) pacbg();
}

void gobdot(byte i)
{
 put_score(i); pacgob(); dots--;
}

byte move_ghost(byte ok)
{

 byte wall;
 byte nd=0;
 byte number;

 byte c;
 byte g;

  for(g=0;g<3;g++)
  {
   delay(speed1);
   wall = 0xf;
   c = get_char(gx[g]+1,gy[g]);
   if (((c & 0xf0) == 0x80) || ((c & 0xf8) == 0xa8)) {wall = wall - 1;}
   if (gx[g]+1>24)
   {
    c = get_char(6,gy[g]);
    if ((c & 0xf8) == 0xa8) {wall = wall - 1;}
   }
   c = get_char(gx[g],gy[g]+1);
   if (((c & 0xf0) == 0x80) || ((c & 0xf8) == 0xa8)) {wall = wall - 2;}
   if (gy[g]+1>22)
   {
    c = get_char(gx[g],2);
    if ((c & 0xf8) == 0xa8) {wall = wall - 2;}
   }
   c = get_char(gx[g]-1,gy[g]);
   if (((c & 0xf0) == 0x80) || ((c & 0xf8) == 0xa8)) {wall = wall - 4;}
   if (gx[g]-1<6)
   {
    c = get_char(24,gy[g]);
    if ((c & 0xf8) == 0xa8) {wall = wall - 4;}
   }
   c = get_char(gx[g],gy[g]-1);
   if (((c & 0xf0) == 0x80) || ((c & 0xf8) == 0xa8)) {wall = wall - 8;}
   if (c == 0x80) {wall = wall + 8;}
   if (gy[g]-1<2)
   {
    c = get_char(gx[g],22);
    if ((c & 0xf8) == 0xa8) {wall = wall - 8;}
   }
   if (gd[g] == 0) {nd = g0[wall];}
   if (gd[g] == 1) {nd = g1[wall];}
   if (gd[g] == 2) {nd = g2[wall];}
   if (gd[g] == 4) {nd = g4[wall];}
   if (gd[g] == 8) {nd = g8[wall];}
   while (nd>0x08)
   {
    wall = -nd;
    number = get_random() & 0x03;
    if (number == 0x00) {wall = wall & 0x01;}
    if (number == 0x01) {wall = wall & 0x02;}
    if (number == 0x02) {wall = wall & 0x04;}
    if (number == 0x03) {wall = wall & 0x08;}
    if (!(wall == 0x00)) {nd = wall;}
   }
   put_char(gx[g],gy[g],gc[g]);
   gx[g] = gx[g] + dx[nd];
   /* PASSAGE GAUCHE DROIT */
   if (gx[g]<6) gx[g] = 24;
   if (gx[g]>24) gx[g] = 6;   
   gy[g] = gy[g] + dy[nd];
   /* PASSAGE HAUT BAS */
   if (gy[g]<2) gy[g] = 22;
   if (gy[g]>22) gy[g] = 2;   
   c = get_char(gx[g],gy[g]);
   if ((c > 0xa1) && (c < 0xa7))
   {
    if (gt[g]>0) { c=0x20; ghost_home(g); } else {gc[g] = 0x20; ok = g;}
   }
   gc[g] = c;
   gd[g] = nd;
   if (gt[g]>0) {put_char(gx[g],gy[g],0xae); gt[g]--; if(gt[g]==0) {pacbg();}} else {put_char(gx[g],gy[g],0xab+g);}
  }
 return ok;
}

void count_dots(void)
{
 byte c;
 byte x;
 byte y;

 playing = 0;

 disable_nmi();
 
 dots = 0;

 for (x=6;x<25;x++)
 {
  for (y=2;y<23;y++)
  {
   c = get_char(x,y);
   /* COUNT DOTS */
   if (c == 0xa0 || c == 0xa1) {dots++;}
  }
 } 

 enable_nmi();

 playing = 1;

}

byte pacman_play(void)
{
 byte ok;
 byte c;
 byte g;
 byte cpac;
 byte ncpac;
 byte px;
 byte py;
 byte opx;
 byte opy;
 byte dpx;
 byte dpy;
 byte ndpx;
 byte ndpy;

 byte number;

 px=pacx;
 py=pacy;
 cpac=0xa4;
 dpx=2;
 dpy=0;

 pacbg();

 ok = 4;

 if (dots == 0) ok = 0xf;

 while (ok == 4)
 {
  ok = move_ghost(ok);
  /* PAUSE MODE WITH * */
  if (keypad_1 == 10)
  {
   while (keypad_1 == 10);
   while (keypad_1 != 10);
  }
  delay(speed2);
  if (keypad_1 == 5)
  {
   if (score >= 2000)
   {
    score = score - 2000;
    put_score(0);
    paclifes++;
    newlife();
    put_paclifes();
   }
  }
  if (ok == 4)
  {
   /* IMAGE DU PACMAN (pour regler bogue des yeux de fantome toujours visibles */
   put_char(px,py,cpac);
   /* DEPLACEMENT DU PACMAN */ 
   /* Joypad : 0x80 = fire (right), 0x40 = fire (left), 0x8 = left, 0x4 = down, 0x2 = right, 0x1 = up */
   c = joypad_1 & 0xf;
   ndpx = 0; ndpy = 0;
   if (c & 0x1) ndpy = 2;
   if (c & 0x4) ndpy = 1;
   if (c & 0x2) ndpx = 1;
   if (c & 0x8) ndpx = 2;  
   if (!(ndpx==0 && ndpy==0))
   {
    opx = px;    opy = py;
    if (ndpx == 1) {opx++;}
    if (ndpx == 2) {opx--;}
    if (ndpx != 0)
    {
     /* PASSAGE GAUCHE DROIT*/
     if (opx<6) opx = 24;
     if (opx>24) opx = 6;   
     c = get_char(opx,opy);
     if ((c & 0xf0) == 0x80) {ndpx = 0;}  
    }
    opx = px;    opy = py;
    if (ndpy == 1) {opy++;}
    if (ndpy == 2) {opy--;}
    if (ndpy != 0)
    {
     /* PASSAGE HAUT BAS */
     if (opy<2) opy = 22;
     if (opy>22) opy = 2;  
     c = get_char(opx,opy);
     if ((c & 0xf0) == 0x80) {ndpy = 0;} 
    }
    if ((ndpx == 0 && ndpy!=0) || (ndpx !=0 && ndpy==0))
    {
     dpx=ndpx; dpy=ndpy;
    }
    else
    {
     if (!(ndpx==0 && ndpy==0))
     {
      if (ndpx == dpx)
      {
       dpx = 0; dpy = ndpy;
      }
      else
      {
       if (ndpy == dpy)
       {
        dpx = ndpx; dpy = 0;
       }
       else
       {
        if (dpx == 0 && dpy == 0)
        {
         /* RANDOM BETWEEN 2 DIRECTIONS */
         number = get_random() & 0x01;
         if (number == 0x00) {dpx = ndpx; dpy = 0;} else {dpy = ndpy; dpx = 0;}
        }
        else
        {
        if (dpx!=0) {dpx = 3-dpx;}
        if (dpy!=0) {dpy = 3-dpy;}
        }
       }
      }
     }
    } 
   }  
   ncpac = 0xa6;
   opx = px;
   if (dpx == 1) {opx++; ncpac = 0xa2;}
   if (dpx == 2) {opx--; ncpac = 0xa4;}
   /* PASSAGE GAUCHE DROIT */
   if (opx<6) opx = 24;
   if (opx>24) opx = 6;   
   opy = py;
   if (dpy == 1) {opy++; ncpac = 0xa3;}
   if (dpy == 2) {opy--; ncpac = 0xa5;}
   /* PASSAGE HAUT BAS */
   if (opy<2) opy = 22;
   if (opy>22) opy = 2;   
   c = get_char(opx,opy);
   if ((c & 0xf0) == 0x80) {dpx = 0; dpy = 0;}  
   if (!(dpx==0 && dpy==0))
   {
    put_char(px,py,0x20);
    px = opx; py = opy;
    if (cpac == ncpac) {cpac = 0xa6;} else {cpac = ncpac;}
    put_char(px,py,cpac);
    if (c > 0xaa && c < 0xae) {ok = c-0xab; c = gc[ok];}
    if (c == 0xae) {g=which_ghost(opx,opy); c = gc[g]; ghost_home(g);}
    if (c == 0xa0) {gobdot(1);}
    if (c == 0xa1) {gobdot(5); pacbg2(); g = 64 - level * 5; gt[0] = g; gt[1] = g; gt[2] = g; bonus = 20;}
    if ((c & 0xf0) == 0xb0) {put_score((level+1)*10); pacbonus();}
   }
   if (dots == 0) {ok = 0xf;}
  }
 }

 return ok;
}

void pacman_dead(byte ok)
{
 byte c;
 byte d;

 pacdd();
 for (c = 0xc0; c<0xd1; c++)
 {
  put_char(gx[ok],gy[ok],c);
  delay(2);
 }
 for (d = 0; d<2; d++)
 {
  for (c = 0xd1; c<0xd4; c++)
  {
   put_char(gx[ok],gy[ok],c);
   delay(3);
  }
 }
 delay(20);
 put_char(gx[ok],gy[ok],0xab+ok);
}

void aff_medaille(void)
{
 byte x;
 byte x1;
 byte x2;
 byte y;
 byte y1;
 byte y2;
 byte c;

 c = 0xe0;

 pacmedaille++; 

 y1 = (pacmedaille * 8) - 6;
 y2 = y1 + 4;
 x1 = 28;
 x2 = x1 + 3;

med();

 for (y = y1; y < y2; y++)
 {
  for (x = x1; x < x2; x++)
  {
   put_char(x,y,c);
   c++;
  }
 }

delay(230);

}

void clear_medaille(void)
{
 byte x;
 byte x1;
 byte x2;
 byte y;
 byte y1;
 byte y2;

 y1 = 8 - 6;
 y2 = y1 + 4;
 x1 = 28;
 x2 = x1 + 3;

 for (y = y1; y < y2; y++)
 {
  for (x = x1; x < x2; x++)
  {
   put_char(x,y,0x20);
   put_char(x,y+8,0x20);
   put_char(x,y+16,0x20);
  }
 }
}

static sprite_t sprites_init[]=
{
 /* {Y, X, NO*4, COULEUR} */
 { 207,0,0,8 }
};

void initsprites()
{
 put_vram (sprgen,sprites_init,4);
 put_vram (sprtab,mssprites,64);
 memcpy (sprites,sprites_init,4);
}

void put_miss(byte bouche)
{
 sprites[0].x = bonusx * 8;
 sprites[0].y = (bonusy * 8) - 1;
 sprites[0].pattern = bouche * 4;
 sprites[0].colour = 8;
 put_char(bonusx,bonusy,0xa6-2*bouche);
 update_sprites (1,sprgen);
}

void theend(void)
{
 byte i;
 byte j;

 initsprites();

 board(board_vide);
 init();

pacbg();
 
for (i = 0; i < 12; i++ )
{
 j = i & 1;
 put_miss(j);
 put_char(pacx,pacy,0x20);
 pacx++;
 put_char(pacx,pacy,0xa6 - j * 4);
 delay(12);
}

 put_miss(0);
 put_char(pacx,pacy,0xa6);

 put_char(pacx,pacy-1,0xa7);
 put_char(pacx+1,pacy-1,0xa8);

 m022 ();

 pacbg();

 for (i = 6; i<10; i++)
 {
  put_char(i-1,pacy,0x20);
  put_char(i,pacy,0xad);
  delay(5);
 }

 for (i = 6; i<9; i++)
 {
  put_char(i-1,pacy,0x20);
  put_char(i,pacy,0xac);
  delay(5);
 }

 for (i = 6; i<8; i++)
 {
  put_char(i-1,pacy,0x20);
  put_char(i,pacy,0xab);
  delay(5);
 }

 put_char(pacx,pacy-1,0x20);
 put_char(pacx+1,pacy-1,0x20);

 put_miss(1);

 put_char(pacx+1,pacy-1,0xa9);

 for (i = 10; i<17; i++)
 {
  put_char(i-3,pacy,0x20);
  put_char(i-2,pacy,0xab);
  put_char(i-1,pacy,0xac);
  put_char(i,pacy,0xad);
  if (i == 11) put_char(pacx,pacy,0xa4);
  delay(20);
 }

 put_char(pacx+1,pacy-1,0x20);
 print_at(7,pacy,"     THE END?    ");
 sprites[0].y = 207;
 update_sprites (1,sprgen);

 put_char(6,pacy-1,0x8a);
 put_char(6,pacy,0x8a);
 put_char(6,pacy+1,0x8a);

 delay(32);
 mute_all();

}

/* THE GAME */
void game (void)
{
 
 int i;

 byte ghost_number;
 byte g;
 byte c;

/* choix: */

 cls(); 

 /* Debut du jeu */

debut:

 cls();
 score = 0;

 pacmedaille = 0;
 clear_medaille();

 level=nolevel;
 if (easymode)
 {
  paclifes = 29;
 }
 else
 {
  paclifes = nbpaclifes;
 }
 nextlife = 1000;

 center_string(0,"HIGH SCORE");
 put_vram (chrtab+22*32+1,"SCORE",5);
 put_hiscore();
 put_score(0);
 put_paclifes();

new_board:

 put_board();
 init();
 hide_bonus();
 show_bonus();

cont:

 count_dots();

/* PLAY PACMAN MUSIC*/
 pacman();

/* PLAY PACMAN GAME*/
 ghost_number = pacman_play();
 
/* STOP BG MUSIC */
 stop_sound(3);
 stop_sound(4);

 if (ghost_number == 0xf)
 {

  put_vram (chrgen+8*128,grafx+128,128);
  put_vram (chrgen+8*256+8*128,grafx+128,128);
  put_vram (chrgen+8*512+8*128,grafx+128,128);
  delay(24);
  put_vram (chrgen+8*128,grafx,128);
  put_vram (chrgen+8*256+8*128,grafx,128);
  put_vram (chrgen+8*512+8*128,grafx,128);
  delay(24);
  put_vram (chrgen+8*128,grafx+128,128);
  put_vram (chrgen+8*256+8*128,grafx+128,128);
  put_vram (chrgen+8*512+8*128,grafx+128,128);
  delay(24);
  put_vram (chrgen+8*128,grafx,128);
  put_vram (chrgen+8*256+8*128,grafx,128);
  put_vram (chrgen+8*512+8*128,grafx,128);

  level++;
  if (level == 10)
  {
   if ( nolevel == 0 && nbpaclifes == 2)
   {
    aff_medaille();
    if ( pacmedaille < 3 )
    {
     level=0;
     for (g=0;g<10;g++)
     {
      put_char(23-g,23,0x20);
     }
    }
   }
  } 
  if (level == 5)
  {
   if (pacmedaille == 1) {aff_medaille();}
  } 
  if (level<10) {goto new_board;}
  if (level==10 && pacmedaille==3) {goto new_board;}
 }
 else
 {
  /* PLAY PACMAN DEAD */
  pacman_dead( ghost_number );
  if (paclifes>0)
  {
   delay(16);
   paclifes--;
   put_paclifes();
   for (g=0;g<3;g++)
   {
    c = gc[g];
    if ( (c == 0xa0) || (c == 0xa1) || ((c & 0xf0) == 0xb0) || (c == 0x80) ) {put_char(gx[g],gy[g],c);} else {put_char(gx[g],gy[g],0x20);}
    gx[g]=ogx[g];
    gy[g]=ogy[g];
    gc[g]=0x20;
    gt[g]=0;
   }
   for (g=0;g<3;g++)
   {
    put_char(gx[g],gy[g],0xab+g);
   }
   put_char(pacx,pacy,0xa4);
   goto cont;
  }
 }

/* GAME OVER */
 if (pacmedaille<3) {gameover();} else {theend();}

 /*remise a zero du pointage*/
 score=0;
 i = 0;

 /* # = menu choice, * = play again */
 while ((!(keypad_1==10 || keypad_1==11)) && i<450) {delay(1); i++;}

 if (i == 450)
 {
  board(again);
  i = 0;
  /* # = menu choice, * = play again */
  while (!(keypad_1==10 || keypad_1==11))
  {
   i++;
   if (i == 12) {put_char(9,16,0xa6);}
   if (i == 24) {put_char(9,16,0xa2);i=0;}
   delay(2);
  }
 }

 if (keypad_1==10) {goto debut;}

}

/* SHOW TITLE SCREEN AND WAIT FOR FIRE BUTTON */
void showtitle (void)
{
 unsigned int i;
 byte j;
 screen_mode_2_bitmap();
recomm:
 /* show titre */
 show_picture (daniel);
 delay(20);
 ding();
 enable_nmi();
 delay(300);

 /* DACMAN TITLE SCREEN */
 show_picture (title);
 /* attente FIRE BUTTON */
 pause_delay(700);
	
 if (((joypad_1 | joypad_2)&0xf0)==0)
 {
  /* DACMAN INFORMATIONS SCREEN */
  show_picture (info);
  /* attente FIRE BUTTON */
  while ((joypad_1 | joypad_2)&0xf0);
  i = 0; j = 0;
  while (((joypad_1 | joypad_2)&0xf0)==0 && i<800)
  {/* Keypad : 0,1,2,3...9  10=# et 11=* */
   /* EASY MODE : *3279# (*EASY#) */
   if (keypad_1 == 10) { if ((j == 0) || (j==10)) {j = 10;} else {j = 0;} }
   if (keypad_1 == 3) { if ((j == 10) || (j==3)) {j = 3;} else {j = 0;} }
   if (keypad_1 == 2) { if ((j == 3) || (j==2)) {j = 2;} else {j = 0;} }
   if (keypad_1 == 7) { if ((j == 2) || (j==7)) {j = 7;} else {j = 0;} }
   if (keypad_1 == 9) { if ((j == 7) || (j==9)) {j = 9;} else {j = 0;} }
   if (keypad_1 == 11) { if (j == 9) {easymode = 1; newlife(); j=0;} else {j = 0;} }
   /* BONUS GAME : *1 */
   if (keypad_1 == 1) { if (j == 10) {bonusgame = 1; pacbonus(); j=0;} else {j = 0;} }
   i++;
   delay(1);
  } 
  if (i==800) 
  {
   goto recomm;
  }
 }
}

void main (void)
{

 byte b;
 byte c;
 byte ok;
    
 set_snd_table(snd_table);

 hiscore = 0;


restart:
 /* Show "Daniel Bienvenu" and title Screens */
 flashing = 0;
 playing = 0;
 easymode = 0;
 bonusgame = 0;
 nbpaclifes = 2;
 nolevel = 0;

 showtitle();

 delay(1);

 if (keypad_1==11)
 {
	init_vdp();
	delay(1);
	b=0;
loop_check0:
	put_vram(chrtab+b,&b,1);
	if (b!=0xff)
	{
		b++;
		goto loop_check0;
	}
	center_string(11,"SCREEN TEST");

	ok = 1;
	b=0;
loop_check1:
	delay(1);
	c = get_char(b,0);
	if (c != b)
	{
		ok = 0;
	}
	else
	{
		put_char(b,0,32);
	}
	if (b!=0x7f)
	{
		b++;
		goto loop_check1;
	}
	
	b=0;
loop_check2:
	delay(1);
	c = get_char(b,4) - 128;
	if (c != b)
	{
		ok = 0;
	}
	else
	{
		put_char(b,4,32);
	}
	if (b!=0x7f)
	{
		b++;
		goto loop_check2;
	}
  
	if (ok == 0)
	{
		center_string(11,"BAD SCREEN TEST");
	}
	else
	{
		center_string(11,"SCREEN TEST OK");
	}
	center_string(19,"PRESS FIRE TO CONTINUE");

	pause();

	cls();

  center_string(11,"SOUND TEST");
  center_string(14,"USE NUMERIC KEYPAD");
  center_string(19,"PRESS FIRE TO CONTINUE");

  while ((joypad_1 | joypad_2)&0xf0);
  while (((joypad_1 | joypad_2)&0xf0)==0)
  {
   if (keypad_1 == 1) {ding(); delay(98);}
   if (keypad_1 == 2) {pacman(); delay(4);}
   if (keypad_1 == 3) {pacgob(); delay(6);}
   if (keypad_1 == 4) {pacbonus(); delay(19);}
   if (keypad_1 == 5) {pacgbleu(); delay(59);}
   if (keypad_1 == 6) {newlife(); delay(42);}
   if (keypad_1 == 7) {pacdd(); delay(52);}
  }

  cls();

  goto restart;
 }

 if (keypad_1==10)
 {
  nolevel = 5;
  init_vdp();
  center_string(11,"CHEAT CODE #1");
  center_string(14,"START AT LEVEL 6");
  center_string(19,"PRESS FIRE TO PLAY");
  pacbonus();
  pause();
 }

 if (keypad_1==0)
 {
  nbpaclifes = 9;
  init_vdp();
  center_string(11,"CHEAT CODE #2");
  center_string(14,"START WITH 10 DACMANS");
  center_string(19,"PRESS FIRE TO PLAY");
  pacbonus();
  pause();
 }

 init_vdp();

 if (bonusgame==1) {bonus_game();} else {game();}
 
 goto restart;

}

/* Keypad : 0,1,2,3...9  10=* et 11=#  */
/* Joypad : 0x80 = fire (right), 0x40 = fire (left), 0x8 = left, 0x4 = down, 0x2 = right, 0x1 = up */
/* SPRITES COOR XY SCREEN */
/* 0 ................. 255
 -1
  .
  .
  .   Sprites - CoorXY
  .
  .
 191 */
/* GRAFX SCREEN COOR XY */
/* 0 ................. 255
  0
  .
  .
  .
  .
  .
 191 */
/* TEXT SCREEN COOR XY */
/* 0 ................. 31
  0
  .
  .
  .
  .
  .
  23 */
