int CargaPaleta(char *file );

#include <dos.h>
#include <mem.h>
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
//#include <graphics.h>

#define NUM_MOVES  4    // Numero de movimientos por secuencia

#define IZQUIERDA  0
#define DERECHA    1
#define ARRIBA     2
#define ABAJO      3
#define IZQARR     4
#define IZQABJ     5
#define DERARR     6
#define DERABJ     7

#define OK         0
#define ERROR      1

#define SIZE_PERSONAJE (59*33)

typedef unsigned char DacPalette256[256][3];

void setvgapalette256(DacPalette256 *PalBuf);



unsigned char far *video_buffer = (char far *)0xA0000000L; // vram byte ptr

void putpixel( int x, int y, int color)
{
     video_buffer[((y<<8) + (y<<6)) + x] = color;
};

typedef struct
{
 unsigned char Frame[NUM_MOVES][SIZE_PERSONAJE];
} Pmovim;

/*Pmovim *Personaje;*/

typedef struct pcx_header_typ
        {
        char manufacturer;
        char version;
        char encoding;
        char bits_per_pixel;
        int x,y;
        int width,height;
        int horz_res;
        int vert_res;
        char ega_palette[48];
        char reserved;
        char num_color_planes;
        int bytes_per_line;
        int palette_type;
        char padding[58];

        } PCX_HEADER;

Pmovim far *Jugador;

#define PALETTE_MASK        0x3c6
#define PALETTE_REGISTER_RD 0x3c7
#define PALETTE_REGISTER_WR 0x3c8
#define PALETTE_DATA        0x3c9
// this structure holds a RGB triple in three bytes

typedef struct RGB_color_typ
        {

        unsigned char red;    // red   component of color 0-63
        unsigned char green;  // green component of color 0-63
        unsigned char blue;   // blue  component of color 0-63

        } RGB_color, *RGB_color_ptr;

void Set_Palette_Register(int index, RGB_color_ptr color)
{
// this function sets a single color look up table value indexed by index
// with the value in the color structure

// tell VGA card we are going to update a pallete register

outport(PALETTE_MASK,0xff);

// tell vga card which register we will be updating

outport(PALETTE_REGISTER_WR, index);

// now update the RGB triple, note the same port is used each time

outport(PALETTE_DATA,color->red);
outport(PALETTE_DATA,color->green);
outport(PALETTE_DATA,color->blue);

}; // end Set_Palette_Color


int IniciaJugador( Pmovim far **JUgador, int Direcciones, char *PCX, long PorDonde )
{
 FILE *PCX_ptr;
 PCX_HEADER pcx_header;
 int alto, ancho, movimiento;
 int desplaz, contador;
 unsigned char byte;
 int color = -1;
 int contar = -1;

 //Asignamos memoria para los movimientos del jugador
// if ( ( (*Jugador) = (Pmovim far *)farmalloc( sizeof(Pmovim)*Direcciones ) ) == NULL ) return ERROR;

 // Abrimos el fichero de los movimientos
 if ( ( PCX_ptr = fopen( PCX, "rb" ) ) == NULL ) return ERROR;

 // Nos posicionamos en el lugar de comienzo del PCX
 fseek( PCX_ptr, PorDonde, SEEK_SET );

 // Leemos la cabecera
 fread( &pcx_header, sizeof(PCX_HEADER), 1, PCX_ptr );

 // Comprobamos que sea un PCX
 if ( pcx_header.manufacturer == 10 )
  {
   for(alto=0; alto<pcx_header.height; alto++)
   {
    for(ancho=0; ancho<pcx_header.width; )
    {
      byte=getc(PCX_ptr);
      if(byte<=0xC0)
      {
        for ( movimiento = 0; movimiento < NUM_MOVES; movimiento++ )
                         if ( alto >= (47+82*movimiento) && alto < (106+82*movimiento) )
                         {
                          for ( desplaz = 0; desplaz < Direcciones; desplaz++ )
                              if ( ancho >= (80+71*desplaz) && ancho < (113+71*desplaz) )
                              {
                               Jugador[desplaz]./*->*/ Frame[movimiento][ (ancho-(80+71*desplaz)) + 33 * (alto-(47+82*movimiento)) ] = byte;
                               break;
                              }
                          break;
                         }
	ancho++;
      }
      else
      {
	contador=byte&0x3F; byte=getc(PCX_ptr);
	for(; contador>0; contador--)
	{
        for ( movimiento = 0; movimiento < NUM_MOVES; movimiento++ )
                         if ( alto >= (47+82*movimiento) && alto < (106+82*movimiento) )
                         {
                          for ( desplaz = 0; desplaz < Direcciones; desplaz++ )
                              if ( ancho >= (80+71*desplaz) && ancho < (113+71*desplaz) )
                              {
                               Jugador[desplaz]./*->*/ Frame[movimiento][ (ancho-(80+71*desplaz)) + 33 * (alto-(47+82*movimiento)) ] = byte;
                               break;
                              }
                          break;
                         }
   	  ancho++;
	}
      }
     }
   }
  }
 CargaPaleta( PCX );

 // Cerramos el fichero de movimientos
 fclose( PCX_ptr );

 return OK;
};

void MuestraJugador( unsigned char *BitMap_Ptr, int Px, int Py, char FILL )
{
 int x, y;
 static color = -1;

 if ( color == -1 ) color = *(BitMap_Ptr);

 for ( x = 0; x < 33; x++ )
   for ( y = 0; y < 59; y++ )
    if ( 1 || *(BitMap_Ptr + x + y*33) != color )
        if ( FILL==1 )
               putpixel( x+Px, y+Py, 0                        );
        else
               putpixel( x+Px, y+Py, *(BitMap_Ptr + x + y*33) );
    else
       putpixel( x+Px, y+Py, 0 );
}
void asigna_modo_video(char modo)   /* asigna el modo de v�deo indicado      */
{                                   /* en la variable "modo"                 */
  union REGS ent, sal;

  ent.h.al = modo;
  ent.h.ah = 0;
  int86(16, &ent, &sal);	    /* funci�n para asignar el modo de video */
};

void main(void)
{
 Pmovim far *Figuras;
 int  Direccion, O_K = 0;
 float MovAct;

 float x, y;
 // Inicializamos la Pantalla
 asigna_modo_video(0x13);



 if ( ( (Jugador) = (Pmovim far *)farmalloc( sizeof(Pmovim)*8 ) ) == NULL ) return ;

 if ( ( (Figuras) = (Pmovim far *)farcalloc( 8, sizeof(Pmovim) ) ) == NULL ) return ;

 if ( IniciaJugador( &Figuras, 8, "moves.pcx", 0 ) != OK ) return;

 // Mostramos los personajes en la pantalla

 Direccion = 0;
 MovAct = 0;
 float Incx=0, Incy=0;
 x = 0; y = 0;
 do
 {
  if ( kbhit() )
   if ( getch() == 0 )
  {
  switch( getch() )
  {
   case 72: //ARRIBA
           Direccion = 4;
           Incx = 0;
           Incy = -8;
           break;
   case 80: //ABAJO
           Direccion = 0;
           Incx = 0;
           Incy = 8;
           break;
   case 75: //IZQ
           Direccion = 2;
           Incx = -8;
           Incy = 0;
           break;
   case 77: //DER
           Direccion = 6;
           Incx = 8;
           Incy = 0;
           break;
   case 71:
           Direccion = 3;
           Incx = -5;
           Incy = -5;
           break;
   case 73:
           Direccion = 5;
           Incx = 2;
           Incy = -2;
           break;
   case 81:
           Direccion = 7;
           Incx = 2;
           Incy = 2;
           break;
   case 79:
           Direccion = 2;
           Incx = -2;
           Incy = 2;
           break;

   default:
           O_K = 1;
           break;
  }

  }
//     memset( video_buffer, 254, 320*200 );

  MuestraJugador( Jugador[Direccion].Frame[(int)MovAct], x, y, 1 );
  x += Incx; y += Incy; MovAct = (MovAct+=1); if ( MovAct >= 4 ) MovAct = 0;
  if ( x > 320-33 ) x = 320-33; if ( x < 0 ) x = 0;
  if ( y > 200-59 ) y = 200-59; if ( y < 0 ) y = 0;
  MuestraJugador( Jugador[Direccion].Frame[(int)MovAct], x, y, 0 );
  delay(100);
 } while( !O_K );

 farfree( Figuras );
 // Volvemos la pantalla a su estado normal
 asigna_modo_video(0x3);

}



 /**************************************************************************\
|*                                                                          *|
|*  CargaPaleta                                                             *|
|*                                                                          *|
|*  Descripci�n:                                                            *|
|*              Carga la paleta con los colores por defecto                 *|
|*                                                                          *|
|*                                                                          *|
|*  Entradas: achivo PCX de donde cargar la paleta                          *|
|*                                                                          *|
|*  Salidas:  OK    Todo ha ido bien                                        *|
|*            ERROR Algo va mal                                             *|
|*                                                                          *|
 \**************************************************************************/
int CargaPaleta(char *file )
{
 DacPalette256 Palette256;
 int index;
 FILE *fp;

 if ( (fp=fopen( file, "rb" ) ) == NULL )
                                                  return ERROR;

 if ( fseek( fp, -768L, SEEK_END ) == 0 )
 {
    for (index=0; index<256; index++)
    {
    // get the red component
    // get the green component
    // get the blue component
    // set components
    Palette256[index][0] = getc(fp) >> 2;
    Palette256[index][1] = getc(fp) >> 2;
    Palette256[index][2] = getc(fp) >> 2;
    } // end for index

 }
 setvgapalette256( &Palette256 );


 fclose( fp );
 return OK;
}

/* Setvgapalette256 sets the entire 256 color palette */
/* PalBuf contains RGB values for all 256 colors      */
/* R,G,B values range from 0 to 63	              */
/* Usage:					      */
/*  DacPalette256 dac256;			      */
/*						      */
/* setvgapalette256(&dac256);			      */
void setvgapalette256(DacPalette256 *PalBuf)
{
  struct REGPACK reg;

  reg.r_ax = 0x1012;
  reg.r_bx = 0;
  reg.r_cx = 256;
  reg.r_es = FP_SEG(PalBuf);
  reg.r_dx = FP_OFF(PalBuf);
  intr(0x10,&reg);
}