#include <dos.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


// S T R U C T U R E S //////////////////////////////////////////////////////
char far *MemTexto = (char far *)0xB8000000;

typedef struct worm_typ
	{
	int y;       // current y position of worm
	int color;   // color of worm
	int speed;   // speed of worm
	int counter; // counter

	} worm, *worm_ptr;

worm worms[90]; // used to make the screen melt

unsigned int far *clock = (unsigned int far *)0x0000046C; // pointer to internal
                                                          // 18.2 clicks/sec

//////////////////////////////////////////////////////////////////////////////



char ptr_char[4096];

typedef struct
 {
  int x, y;             // Coordenadas iniciales de muestreo
  char ndigitos;        // n£mero de digitos a mostrar
  char AX, AY;          // factor de espaciado
  char C1, C2, C3;      // colores de fondo, texto, borde

  // Datos privados y uso interno exclusivamente
  unsigned int  Flen;   // longitud de la frase actual
  char BitByte;         // bit del byte por el que va en el recorrido
  char currByte;        // byte actual dentro de la frase



  // Datos no validos para el nuevo formato de frase
  char FraseBit[110][16];
  char Frase1[100];

  char Flen1;

} p_Ampliada;

void LeeFuentes(char *file);
void FuenteAmplia( char *Frase, p_Ampliada far *FA, char ini );
void aFuenteAmplia( char *Frase, p_Ampliada far *FA );

p_Ampliada sPinBall =  { 2,  0, 3, 1, 1, BLACK, BLUE, BLUE };
p_Ampliada sPinBallC = { 12, 1, 7, 1, 1, BLACK, BLUE, BLUE };
p_Ampliada sPinBallB = { 12,12, 7, 1, 1, BLACK, BLUE, BLUE };


#define IZQUIERDO 1
#define DERECHO   0

#define RELAX     0
#define PULSO     1

#define RESET     0
#define OK        1

#define SUBE      1
#define BAJA     -1

struct Petaco
{
 char Petaco[3][10];
};

struct Petaco PetacoI[4] = { {"(\\\\     ",
                              "  \\\\    ",
                              "   \\\\   "},

                             {"(\\\\     ",
                              "  \\\\    ",
                              "   ==   "},

                             {"(\\\\     ",
                              "  ====  ",
                              "        "},

                             {"(====== ",
                              "        ",
                              "        "} };

struct Petaco PetacoD[4]  = {
                      {"     //)",
                       "    //  ",
                       "   //   "},
                      {"     //)",
                       "    //  ",
                       "  ==    "},
                      {"     //)",
                       " ====   ",
                       "        "},
                      {" ======)",
                       "        ",
                       "        "} };


void DibujaPetaco( char CUAL, char PulsoRelax );
void ProcesaLuzTirador( char OkReset );
void DistorsionaFondoInfo( void );
void AccionaTirador( char Como );
void DibujaTablero( void );
void Melt( void );

void main(void)
{
 int ok, key;
 char buffer[4096], y;
 y = (char)wherey();
 gettext(1, 1, 80, 25, buffer);


 Melt();
 _setcursortype(_NOCURSOR);

 LeeFuentes( "PinBall.Fnt" );

 DibujaTablero();

 DibujaPetaco( IZQUIERDO, PULSO );
 DibujaPetaco( DERECHO  , PULSO );
 ProcesaLuzTirador( RESET );

 ok = 0;
 do {
  if ( kbhit() )
   switch( getch() )
   {
    case '1':
         DibujaPetaco( IZQUIERDO, PULSO );
         break;
    case '2':
         DibujaPetaco( DERECHO, PULSO );
         break;
    case 27:
         ok = 1;
         break;


    case 0:
         switch( getch() )
         {
          // Tirador
          case 80:
                 AccionaTirador(1);
                 break;

         }
         break;
   }

  AccionaTirador(0);
  DistorsionaFondoInfo();
  DibujaPetaco( IZQUIERDO, RELAX );
  DibujaPetaco( DERECHO  , RELAX );
  ProcesaLuzTirador( OK );
  aFuenteAmplia( "Jose David Guillen", &sPinBall );
  delay(50);
 } while( !ok );

 _setcursortype(_NORMALCURSOR);
 puttext(1, 1, 80, 25, buffer);
 gotoxy( 1, y ); printf( "\n" );
 printf( "UPAD:\n" );
 printf( "          Un pinBALL algo diferente \n" );
 printf( "         JD Soft. _-ùFuTuRe ViSiOnù-_\n" );

}

void AccionaTirador( char Como )
{
 static char Posicion = 6, SubeBaja = BAJA;

 // Inicializamos el movimiento
 if ( Como == 1 )
 {
  Posicion = 6;
  SubeBaja = BAJA;
 } else {
  if ( SubeBaja == SUBE && Posicion == 6 )
                                    return;
 }

 if ( Posicion != 0 )
 {
  Posicion+= SubeBaja; if ( Posicion == 0 ) SubeBaja = SUBE;
 }

 textcolor( WHITE );
 switch( (SubeBaja == BAJA ? Posicion : ( 6 - Posicion )) )
 {
  case 6:
  gotoxy( 73, 21 ); cprintf( "~Â~" );
  gotoxy( 73, 22 ); cprintf( " ³ " );
  gotoxy( 73, 23 ); cprintf( "ÄÛÄ" );
  gotoxy( 73, 24 ); cprintf( "   " );
  break;
  case 5:
  gotoxy( 73, 21 ); cprintf( "~^~" );
  gotoxy( 73, 22 ); cprintf( " ³ " );
  gotoxy( 73, 23 ); cprintf( "ÄÛÄ" );
  gotoxy( 73, 24 ); cprintf( "   " );
  break;
  case 4:
  gotoxy( 73, 21 ); cprintf( "~_~" );
  gotoxy( 73, 22 ); cprintf( " ³ " );
  gotoxy( 73, 23 ); cprintf( "ÄÛÄ" );
  gotoxy( 73, 24 ); cprintf( "   " );
  break;
  case 3:
  gotoxy( 73, 21 ); cprintf( "~ ~" );
  gotoxy( 73, 22 ); cprintf( " Â " );
  gotoxy( 73, 23 ); cprintf( "ijÄ" );
  gotoxy( 73, 24 ); cprintf( " Û " );
  break;
  case 2:
  gotoxy( 73, 21 ); cprintf( "~ ~" );
  gotoxy( 73, 22 ); cprintf( " _ " );
  gotoxy( 73, 23 ); cprintf( "ijÄ" );
  gotoxy( 73, 24 ); cprintf( " Û " );
  break;
  case 1:
  gotoxy( 73, 21 ); cprintf( "~ ~" );
  gotoxy( 73, 22 ); cprintf( "   " );
  gotoxy( 73, 23 ); cprintf( "ÄÂÄ" );
  gotoxy( 73, 24 ); cprintf( " Û " );
  break;
 }

}

void DibujaPetaco( char CUAL, char PulsoRelax )
{
 static char PetacoID[2] = { 0,0 };
 static char ActividadID[2]  = { 0,0 };
 int i;

       if ( PulsoRelax == PULSO )               // Actividad del petaco:
                       ActividadID[CUAL] =  1;  //      AVANCE

       if ( ActividadID[CUAL] == 1 )
       {
         PetacoID[CUAL] ++;
         if  ( PetacoID[CUAL] > 2 )             // Maxima extenci¢n del petaco
               ActividadID[CUAL] = -1;          //  empezamos a contraerlo
       } else
       if ( ActividadID[CUAL] == -1 )
       {
         PetacoID[CUAL] --;
         if  ( PetacoID[CUAL] < 0 )             // Llegamos a su origen...
               ActividadID[CUAL] = 0;           //         ...asi que paramos.
       }

 // Iniciamos el dibujo del petaco
 if ( ActividadID[CUAL] != 0 && PetacoID[CUAL] < 4 )
 {
  textbackground(BLACK);
  textcolor(YELLOW);
  for ( i = 0; i < 3; i++ )
  {
   gotoxy( CUAL ? 41 : 49, 19+i );
   cprintf( "%s", CUAL ?
             PetacoI[PetacoID[CUAL]].Petaco[i]
             :
             PetacoD[PetacoID[CUAL]].Petaco[i]
         );
   if ( CUAL == IZQUIERDO )
   {
    gotoxy( 29, 11+i );
    cprintf( "%s", PetacoI[PetacoID[CUAL]].Petaco[i] );
   }

  }
 }

}


void DibujaTablero( void )
{
  int i;

  textbackground(BLACK);
  textcolor( WHITE );
  gotoxy( 1, 1);

  cprintf( "                           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿   \r\n" );
  cprintf( "          TextoPinBALL !   ³_-----</                              ù ùùù\\   ³   \r\n" );
  cprintf( "             u.p.a.d       ³<   </                                      ù\\ ³   \r\n" );
  cprintf( "                           ³< </                          /               |³   \r\n" );
  cprintf( "          Un               ³</                           /   /             ³   \r\n" );
  cprintf( "           PinBall         ³                                /   /          ³   \r\n" );
  cprintf( "            Algo           ³                       /ùù\\        /   /     _/³   \r\n" );
  cprintf( "             Diferente     ³                      |    |          /     /ù ³   \r\n" );
  cprintf( "                           ³                       \\__/                ³ ^ ³   \r\n" );
  cprintf( "                           ³                                   /ùù\\    ³ ^ ³   \r\n" );
  cprintf( "         Puntos:           ³(*                         /ùù\\   |    |   ³ ^ ³   \r\n" );
  cprintf( "                           ³  *                       |    |   \\__/    ³ ^ ³   \r\n" );
  cprintf( "          Player1: 000.000 ³   *                       \\__/           /³ ^ ³   \r\n" );
  cprintf( "          Player2: 000.000 ³                                         ° ³ ^ ³   \r\n" );
  cprintf( "          Player3: 000.000 ³                                          °³ ^ ³   \r\n" );
  cprintf( "          Player4: 000.000 ³                                           ³ ^ ³   \r\n" );
  cprintf( "                           ³                                           ³ ^ ³   \r\n" );
  cprintf( "         Tabla de Records  ³                                           ³ ^ ³   \r\n" );
  cprintf( "                           ³            (              )   |    \\      ³ ^ ³   \r\n" );
  cprintf( "         1. JDG    150.210 ³                               |     \\_____  ^ ³   \r\n" );
  cprintf( "         2. AGD     20.140 ³                              /^\\_  _/     ³~Â~³   \r\n" );
  cprintf( "         3. JD      19.030 ³                    ~       /     ##         ³ ³   \r\n" );
  cprintf( "         4. JDG        980 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÛÄÙ   \r\n" );

  textbackground( GREEN );
  textcolor( WHITE );
  gotoxy( 53,  7 ); cprintf(  "ùù"  );
  gotoxy( 52,  8 ); cprintf( " 20 " );
  gotoxy( 53,  9 ); cprintf(  "__"  );
  textcolor( WHITE + BLINK );
  gotoxy( 53,  8 ); cprintf( "20" );
  textbackground( CYAN );
  textcolor( WHITE );
    gotoxy( 57, 11 ); cprintf(  "ùù"  );
    gotoxy( 56, 12 ); cprintf( " 10 " );
    gotoxy( 57, 13 ); cprintf(  "__"  );
    textcolor( WHITE + BLINK );
    gotoxy( 57, 12 ); cprintf( "10" );
    textbackground( MAGENTA );
    textcolor( WHITE );
      gotoxy( 65, 10 ); cprintf(  "ùù"  );
      gotoxy( 64, 11 ); cprintf( " 30 " );
      gotoxy( 65, 12 ); cprintf(  "__"  );
      textcolor( WHITE + BLINK );
      gotoxy( 65, 11 ); cprintf( "30" );


  textbackground( BLACK );
  textcolor( CYAN );
  gotoxy( 57, 20 ); cprintf( "   |      \\____" );
  gotoxy( 57, 21 ); cprintf( "  /^\\_  _/" );
  gotoxy( 57, 22 ); cprintf( "/     ##" );

  textbackground( BLUE );
  textcolor( BROWN+BLINK );

  gotoxy( 70, 14 );  cprintf( "±" );
  gotoxy( 71, 15 );  cprintf( "±" );

  // Linea para sacar la bola
  textbackground(BLUE);
  textcolor( WHITE );
  gotoxy( 74, 8 );  cprintf( "  " );
  for( i=9; i<21; i++ )
  {
    gotoxy( 73, i );  cprintf( "   " );
  }
    gotoxy( 73, 21 );  cprintf( "~Â~" );
    gotoxy( 73, 22 );  cprintf( " ³ " );


}

void ProcesaLuzTirador( char OkReset )
{
 static char SecActual, Estado;
 char i;

 // Todas a cero
 if ( OkReset == RESET )
 {
  textbackground(BLUE);
  textcolor( LIGHTRED );
  for ( i=0; i<12; i++ )
  {
   gotoxy( 74, 9 +i ); cprintf( "^" );
  }
  SecActual = 0; Estado = 1;
 } else {
  textbackground(BLUE);
  textcolor( LIGHTRED );
  gotoxy( 74, 9 +SecActual ); cprintf( "^" );

  SecActual+= Estado;
  if ( SecActual == 11) Estado = -1;
  else
  if ( SecActual == 0 ) Estado =  1;

  textbackground(LIGHTBLUE);
  textcolor( BLACK );
  gotoxy( 74, 9 +SecActual ); cprintf( "^" );

 }

}


void DistorsionaFondoInfo( void )
{
 int i, j, k;
 static char COLOR=0, COLOR1 = 0;
 // Cuidadin que estamos jugando con algo que nos puede
 // dar problemas en otras partes con los que pretendo hacer
 // ( movimientos de segundo plano en modo texto )

 // Bien, esto no es mas que un barrido de memoria, en las coordenadas
 // f¡sicas de pantalla (9,1) -> (30,23)

 // NOTA: La coordenada inicial de la memoria de video no monocroma es B800

 // Barrido vertical
 for ( i = 0; i < 24; i++ )
 {
  k = i*80*2;
  // Barrido horizontal
  for ( j = 9; j < 27; j++ )
  {
    COLOR1 = (j-9+COLOR)%7;
    // Creo que primero va el texto asi que por eso lo del +1
    MemTexto[ k + j*2 +1] &= 0xE0;
    MemTexto[ k + j*2 +1] |= (COLOR1&0x0F);
  }
 }

 COLOR ++;

}



////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

void aFuenteAmplia( char *Frase, p_Ampliada far *FA )
{
  int i;
  char j, j1;

  char c_elec;
  char bit_s;
  char far *Frase_seg;

  // Rotamos la frase
  int i1;
  char cont;

  char FrBit_tmp[16];
// C A R T E L    D I G I T A L
//*// ( 27 ) - 2 ===> 25  [ Fuente de 8x8 ]
//*   ^___ El tama¤o ha sido reoptimizado para que sea variable seg£n las
//*	   necesidades de cada programador. ( cuando AX = AY = 1 --> T^ )
//* ........ . . . o . . . . o o o o o o . .
//* ........ . . o . o . . . . o . . . . o .
//* ........ . o . . . o . . . o . . . . o .
//* ........ o . . . . . o . . o o o o o . .
//* ........ o o o o o o o . . o . . . . o .
//* ........ o . . . . . o . . o . . . . o .
//* ........ o . . . . . o . . o . . . o . .
//* ........ o . . . . . o . o o o o o . . .
//*
     textbackground(BLACK);

     Frase_seg = FA -> Frase1;

if ( _fstrcmp( FA -> Frase1, Frase ) != 0 )
 {
  _fstrncpy( FA -> Frase1, Frase, 99 );
  FA -> Frase1[99] = '\0';
  j = i = _fstrlen( Frase );
  FA -> Flen =  i * 8;
  cont = 0;

  if ( i < FA -> ndigitos )
           i += FA -> ndigitos - i;
  else
           i += 5;

  FA -> Flen1 = i;

  //strcat( FA->Frase_seg, "    " );

  // Almacenamos en la Frase a Bit's la FRASE A BIT'S
  while( cont <= i )
  {

   // Descomponemos cada caracter en un patron de BIT's
   if ( (cont - j) >= 0 )
    {
	 for( j1=0; j1<16; j1++)
	     FA -> FraseBit[cont][j1]= 0;
    } else

	 for( j1=0;j1<16; j1++)
	     FA -> FraseBit[cont][j1]= ptr_char[ ( *(Frase_seg) ) * 16 + j1 ];

   cont++;
   Frase_seg++;
  }
 } else {
  // Almacenamos el 1er bit que vamos a perder...
  for (  j1=0; j1<16; j1++ )
      FrBit_tmp[j1] = 0x01 & ( FA -> FraseBit[0][j1] >> 7 );

  for ( j=0; j<FA -> Flen1; j++ )
  {
     for (  j1=0;  j1<16; j1++ )
       FA -> FraseBit[ j][j1] = FA -> FraseBit[ j][ j1] << 1;
   for ( j1=0; j1<16; j1++ )
      FA -> FraseBit[j][j1] = ( FA -> FraseBit[j][j1] & 0xFE ) | (0x01 & (FA -> FraseBit[j+1][j1] >> 7 ) );
  }
  for ( j1=0; j1<16; j1++ )
     FA -> FraseBit[FA -> Flen1-1][j1] = ( FA -> FraseBit[FA -> Flen1-1][j1] & 0xFE ) | FrBit_tmp[j1];
 }

//                  . .                      . .                    . .
//               .ï     ï.                .ï     ï.              .ï     ï.
//              .         .              .         .            .
//   __________.________________________.______________________.______________
//   .        .             .          .             .        .
//    .      .               .       .                .      .
//     ' .. '                  ' .. '                  ' .. '
//
//                                  .  .
//                            .  ï       ï .
//                         .                 .
//   ____________________._____________________.______________________________
//   .                 .                        `                         ï
//     .             .                            `                     ï
//       .         .                                `                 ï
//          . . .                                      `            ï
//                                                        `  .  . ï
// ndigitos --> m x. = 40
 //float i1;

 for ( i=0, i1=2; i < FA->ndigitos; (i) ++ )
 {
	for ( j=0, j1=0; j1<8; /*j+=2*FA->AX*/j++, j1++ )
	 {
	   // Analizamos el patron de BIT's y lo imprimimos
	   // FraseBit[cont][0]
	   //          ^   ^----- N£mero de byte del digito ( 8x8 )
	   //          |_________ N£mero de digito alfa-numerico
	   for ( bit_s = 0; bit_s < 8; bit_s++, i1++/*+=.02*/ )
	    {
	     if ( FA -> FraseBit[i][bit_s] & ( (char)0x01 << (7- j1) ) ) c_elec = FA->C2; else c_elec = FA->C1;
	     //putpixel ( FA->x + j + bit_s*2 + i*8*2*FA->AX, FA->y + sin( i1 )*20 + 2*bit_s*FA->AY, c_elec );

             textcolor( c_elec );
 //PutPixel ( FA->x +j +  i*8*2*FA->AX, FA->y + 2* bit_s*FA->AY, c_elec );
//   gotoxy   ( FA->x +j +  i*8/**2*FA->AX*/, FA->y + bit_s/**2*FA->AY*/ );
        gotoxy   (  ( FA->x + bit_s),  8*FA->ndigitos -( FA->y +j +  i*8 ) );
             if ( (j + i*8) < 8  )
             {
                          cprintf( "³" );
             } else
             if ( (j + i*8) > 16 )
             {
                          cprintf( "Û" );
             } else
                          cprintf( "±" );
            }

//y--> TabS[(i+j+bit_s) MOD FLen1]
//x-->

	 }
 }
}




void LeeFuentes(char *file)
{
FILE *fich;
	/* Reservamos 4 Kb. para cargar la fuente en memoria */

	/* Abrimos el fichero de la fuente */

        if ((fich=fopen(file,"rb"))==NULL) {
                printf("\a\nArchivo %s no encontrado.\n",file);
                return;
	}

	fseek(fich, SEEK_SET, 0);	/* Nos colocamos al principio del fichero     */
        fread(ptr_char,1,4096,fich);      /* Cargamos en memoria 4096 bytes del fichero */
	fclose(fich);					/* Cerramos el fichero 								 */
}




////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
#define TAMx 8
#define TAMy 8
void FuenteAmplia( char *Frase, p_Ampliada far *FA, char ini )
{
 int  i, j, k;           // Variables de avance
 int  c_elec;            // Color en el momento de imprimir
 int  PosX, PosY;        // Posicion fisica final
 char LCaract;           // Caracter de linea a tratar

 if ( ini )              // Reseteamos las variables de control interno
 {
  // Obtenemos la longitud de la frase. ( En d¡gitos )
  FA -> Flen = _fstrlen( Frase );
  // Contador de digito actual a cero
  FA -> BitByte  = 0;
  // Posicion dentro de la frase
  FA -> currByte = 0;
  return;
 }

 // Avance horizontal de bit's ( avance de digitos )
 for ( i = 0; i < ( TAMx * (FA -> ndigitos) ); i++ )
 {
  k = ( Frase[ ( (i+FA->BitByte)/TAMx + FA -> currByte ) % FA->Flen ] ) << 4;
  LCaract = ( (char)0x01 << (7 - (i+FA->BitByte)%TAMx) );
  PosX = FA -> x + FA->AX   * i;         // Posicion f¡sica horizontal
  // Avance vertical de bit's
  for ( j = 0; j < TAMy; j ++ )
  {
    PosY = FA -> y + FA->AY * j;         // Posicion f¡sica vertical

    if ( ptr_char[ k + j ] & LCaract )
      c_elec = FA->C2;
    else
      c_elec = FA->C1;

    textbackground(BLACK);
    textcolor( c_elec );
    gotoxy   ( PosX, PosY ); cprintf( "±" );
  }
 }
 // Tenemos en cuenta el avance dentro de la frase
 if ( ( FA -> BitByte ++ ) >= 7 )
 {
  FA -> BitByte = 0; FA -> currByte ++;
  if ( FA -> currByte >= FA -> Flen )
     FA -> currByte = 0;
 }

}
#undef TAMy
#undef TAMx




void Melt( void )
{

int index,ticks=0;

textbackground( BLACK );
textcolor( MAGENTA );


for (index=1; index< 81; index++)
    {
        worms[index].speed   = 3 + rand()%9;
            worms[index].y       = 0;
                worms[index].counter = 0;
    gotoxy( index, 1 );
    cprintf(" ");
    }

while(++ticks<290)
     {
      delay(10);

     for (index=1; index<81; index++)
	 {
	 if (++worms[index].counter == worms[index].speed)
	    {
	    worms[index].counter = 0;
	    if (worms[index].y < 25)
	       {
                   gotoxy( index, worms[index].y );
                       cprintf("þ");
                           gotoxy( index, worms[index].y-1 );
                               cprintf(" ");
	       worms[index].y++;
	       } else {
		     gotoxy( index, 24 );
		     cprintf(" ");
               }
	    }
	 }
     if (!(ticks % 500))
	{
	for (index=1; index<81; index++)
	    worms[index].speed--;
	}
     }
}