#include <stdio.h>
#include <math.h>
#include "BaseBmp.h"

#include "palatari.h"
#include "map.hpp"

#include "pixel_tables.inc" //STOLEN FROM ALLEGRO!!! AAAAAAWWWWW!!!!!

#define MUSIC

ALLEGRO_DISPLAY*dsp;
int CICLO,k=0;
ALLEGRO_BITMAP*scr,*fnd,*gspr,*gcmd,*gameover,*gblack,*gtitulo,*gforest;
ALLEGRO_FONT*fnt,*fnt2;
ALLEGRO_TIMER*timer;
ALLEGRO_EVENT_QUEUE*evq;
int tfnt,ciclr=0,ciclr2=0,vblack=0;

char*text[50];

uint32_t score;

#ifdef MUSIC
ALLEGRO_VOICE*voice;
ALLEGRO_MIXER*mixer;
ALLEGRO_AUDIO_STREAM*mscmenu,*mscgame;
ALLEGRO_SAMPLE*sndeat,*snddead,*sndshot;
#endif

const char*rawmap[]={
  "_____|____|____|____",
  "__H____H_|__H____H__",
  "||||_H___  ___H__|__",
  "_H_____|H__H|_____H_",
  "_|__H_____|____H__|_",
  "__H_|_H_|__|_H_|_H__"
};
//TODO: Broken C/D global
Map map;

struct _STR_pers{
  int x,y,ld;
  int grf,tim,tm,hp;
  int clrh,clrs,energy;
  int liftd,liftc,fall;
  float fallg;
}pers;

int bx,by,bz;

//============================================================================//
// FUNCIONES GENERALES                                                        //
//============================================================================//

ALLEGRO_COLOR pal[256];

void SetColorRawRGB(ALLEGRO_COLOR*zp,long zc){
  *zp=al_map_rgba((zc>>16)&255,(zc>>8)&255,zc&255,255);
}

void SetCPal(){
  long LC[16]={
    0x101010, //negro         0
    0xffffff, //blanco        1
    0xe04040, //rojo          2
    0x60ffff, //cian          3
    0xe060e0, //violeta       4
    0x40e040, //verde         5
    0x4040e0, //azul          6
    0xffff40, //amarillo      7
    0xe0a040, //naranja       8
    0x9c7448, //marron        9
    0xffa0a0, //rojo claro    a
    0x545454, //gris oscuro   b
    0x888888, //medio gris    c
    0xa0ffa0, //verde claro   d
    0xa0a0ff, //azul claro    e
    0xc0c0c0}; //gris claro    f
  for(int i=0;i<16;i++)
    SetColorRawRGB(pal+i,LC[i]);
}

int InitScreen(){int err=1;
  if(!al_init())return err;err++;
  if(!al_install_keyboard())return err;err++;
  if(!al_install_mouse())return err;err++;
  /* TODO: Revisar si para las 'VOICE' necesita ser unico para todas las ventanas */
  #ifdef MUSIC
  if(!al_install_audio())return err;err++;
  if(!al_init_acodec_addon())return err;err++;
  #endif
  if(!al_init_image_addon())return err;err++;
  if(!al_init_primitives_addon())return err;err++;
  al_init_font_addon();
  if(!al_init_ttf_addon())return err;err++;
  evq=al_create_event_queue();
  if(!evq)return err;err++;
  timer=al_create_timer(1.0/60);
  if(!timer)return err;err++;
  #ifdef MUSIC
  voice=al_create_voice(44100,ALLEGRO_AUDIO_DEPTH_INT16,ALLEGRO_CHANNEL_CONF_2);
  if(!voice)return err;err++;
  mixer=al_create_mixer(44100,ALLEGRO_AUDIO_DEPTH_FLOAT32,ALLEGRO_CHANNEL_CONF_2);
  if(!mixer)return err;err++;
  if(!al_attach_mixer_to_voice(mixer, voice))return err;err++;
  mscgame=al_load_audio_stream("./Datos/msc/game.it",4,2048);
  if(!mscgame)return err;err++;
  mscmenu=al_load_audio_stream("./Datos/msc/menu.mod",4,2048);
  if(!mscmenu)return err;err++;
  al_set_audio_stream_playmode(mscgame,ALLEGRO_PLAYMODE_LOOP);
  al_register_event_source(evq,al_get_audio_stream_event_source(mscgame));
  al_set_audio_stream_playmode(mscmenu,ALLEGRO_PLAYMODE_LOOP);
  al_register_event_source(evq,al_get_audio_stream_event_source(mscmenu));
  //sndeat=al_load_sample("./Datos/snd/explosion.wav");
  //if(!sndeat)return err;err++;
  //sndlose=al_load_sample("./Datos/snd/lose.wav");
  //if(!sndlose)return err;err++;
  //sndshot=al_load_sample("./Datos/snd/shot.wav");
  //if(!sndshot)return err;err++;
  #endif
  al_register_event_source(evq,al_get_timer_event_source(timer));
  al_register_event_source(evq,al_get_keyboard_event_source());
  al_register_event_source(evq,al_get_mouse_event_source());
  al_set_new_display_flags(ALLEGRO_FRAMELESS);
  //al_set_new_display_flags(ALLEGRO_RESIZABLE|ALLEGRO_MAXIMIZED);
  dsp=al_create_display(960,720);
  if(!dsp)return err;err++; //9
  al_register_event_source(evq,al_get_display_event_source(dsp));
  al_set_blender(ALLEGRO_ADD,ALLEGRO_ALPHA,ALLEGRO_INVERSE_ALPHA);
  scr=al_create_bitmap(320,240);
  if(!scr)return err;err++;
  fnd=al_load_bitmap("./Datos/img/fondo.jpg");
  if(!fnd)return err;err++;
  gspr=al_load_bitmap("./Datos/img/spr.png");
  if(!gspr)return err;err++;
  gameover=al_load_bitmap("./Datos/img/gameover.png");
  if(!gameover)return err;err++;
  gtitulo=al_load_bitmap("./Datos/img/titulo.png");
  if(!gtitulo)return err;err++;
  gforest=al_load_bitmap("./Datos/img/forest.png");
  if(!gforest)return err;err++;
  gcmd=al_create_bitmap(64,64);
  if(!gcmd)return err;err++;
  gblack=al_create_bitmap(320,240);
  if(!gblack)return err;err++;
  if(map.Init())return err;err++;
  //fnt=al_load_ttf_font("./Datos/fnt/TequilaSunset-Regular.ttf",16,ALLEGRO_TTF_MONOCHROME);
  fnt=al_load_ttf_font("./Datos/fnt/Thalia.ttf",16,ALLEGRO_TTF_MONOCHROME);
  if(!fnt)return err;err++; //16
  fnt2=al_load_ttf_font("./Datos/fnt/Omega.ttf",22,ALLEGRO_TTF_MONOCHROME);
  //fnt2=al_load_ttf_font("./Datos/fnt/OldLettresOmbrees.ttf",22,0);
  if(!fnt2)return err;err++;
  tfnt=al_get_font_line_height(fnt);
  {int fl;
    fl=open("./Datos/pal.dat",O_RDONLY);if(fl==-1)return -1;
    read(fl,pal,sizeof(ALLEGRO_COLOR)*256);
    close(fl);
  }
  for(int i=0;i<128;i++){
    pal[i+128]=al_map_rgb(Atari2600_NTSCPalette[i]&255,
      (Atari2600_NTSCPalette[i]>>8)&255,(Atari2600_NTSCPalette[i]>>16)&255);}
  text[0]=(char*)malloc(1231);if(!text[0])return err;err++;
  int fl=open("./Datos/msg.txt",O_RDONLY);
  read(fl,text[0],1230);
  close(fl);text[0][1230]=0;
  {int p,p2;
    for(p=0,p2=1;text[0][p];p++){
      while(text[0][p]!=10&&text[0][p])p++;
      if(text[0][p]){text[0][p]=0;p++;text[p2]=text[0]+p;p2++;}
    }
  }srand(time(0));
  al_start_timer(timer);
  return 0;
}

void EndScreen(){
  #ifdef MUSIC
  al_destroy_audio_stream(mscgame);
  al_destroy_audio_stream(mscmenu);
  #endif
  al_uninstall_system();
}

/** Entrada de teclado */
void EvKey(ALLEGRO_EVENT&ev){
  switch(ev.type){
  case ALLEGRO_EVENT_KEY_DOWN:
    switch(ev.keyboard.keycode){
    case ALLEGRO_KEY_RIGHT:k|=1;break;
    case ALLEGRO_KEY_UP:k|=2;break;
    case ALLEGRO_KEY_LEFT:k|=4;break;
    case ALLEGRO_KEY_DOWN:k|=8;break;
    case ALLEGRO_KEY_Z:k|=16;break;
    case ALLEGRO_KEY_X:k|=32;break;
    case ALLEGRO_KEY_C:k|=64;break;
    case ALLEGRO_KEY_A:k|=128;break;
    case ALLEGRO_KEY_S:k|=256;break;
    case ALLEGRO_KEY_D:k|=512;break;
    case ALLEGRO_KEY_ENTER:k|=1024;break;
    case ALLEGRO_KEY_RSHIFT:k|=1048;break;
    case ALLEGRO_KEY_F5:k|=0x80000000;break;
    case ALLEGRO_KEY_ESCAPE:CICLO=0;break;
    //case ALLEGRO_KEY_Q:printf("PUTAO\n");break;
    }break;
  case ALLEGRO_EVENT_KEY_UP:
    switch(ev.keyboard.keycode){
    case ALLEGRO_KEY_RIGHT:k&=~1;break;
    case ALLEGRO_KEY_UP:k&=~2;break;
    case ALLEGRO_KEY_LEFT:k&=~4;break;
    case ALLEGRO_KEY_DOWN:k&=~8;break;
    case ALLEGRO_KEY_Z:k&=~16;break;
    case ALLEGRO_KEY_X:k&=~32;break;
    case ALLEGRO_KEY_C:k&=~64;break;
    case ALLEGRO_KEY_A:k&=~128;break;
    case ALLEGRO_KEY_S:k&=~256;break;
    case ALLEGRO_KEY_D:k&=~512;break;
    case ALLEGRO_KEY_ENTER:k&=~1024;break;
    case ALLEGRO_KEY_RSHIFT:k&=~1048;break;
    case ALLEGRO_KEY_F5:k&=~0x80000000;break;
    }break;
  //case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
  //case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
  }
}


struct _STR_dlg{
  void Print();
  int px,py,tp,tx,ty,ciclr,ciclr2,ttxt,hp;
  int*orix,*oriy;
  char*txt[4];
}dlg,dlge[5];
/*tp: Tipo Dialogo
 * 0: Desactivado
 * 1: Vivora
 * 2: Intrusos
 */

void _STR_dlg::Print(){int i;
  switch(tp){
  case 1:
    px=*orix-40-bx;py=*oriy-ty/2-by;
    ciclr2++;if(ciclr2>32){ciclr2=0;ciclr+=8;if(ciclr>255)ciclr-=120;}
    al_draw_rounded_rectangle(py-3,px-3,py+ty+5,px+tx+5,7,7,pal[ciclr],2);
    al_draw_filled_rounded_rectangle(py-5,px-5,py+ty+5,px+tx+5,7,7,pal[1]);
    for(i=0;i<ttxt;i++){
      al_draw_text(fnt,pal[ciclr],py-1,px-1+i*tfnt,0,txt[i]);
      al_draw_text(fnt,pal[0],py,px+i*tfnt,0,txt[i]);
    }hp--;if(!hp)tp=0;break;
  case 2:
    px=*orix-40-bx;py=*oriy-ty/2-by;
    al_draw_rounded_rectangle(py-4,px-4,py+ty+5,px+tx+5,7,7,pal[11],4);
    al_draw_filled_rounded_rectangle(py-5,px-5,py+ty+5,px+tx+5,7,7,pal[0]);
    for(i=0;i<ttxt;i++){
      al_draw_text(fnt,pal[15],py,px+i*tfnt,0,txt[i]);
    }hp--;if(!hp)tp=0;break;
  }
}

void PrintTxt(int ztp,int zpx,int zpy,char*ztxt){
  int ztam,ztam2,i,p;
  if(dlg.txt[0])free(dlg.txt[0]);
  dlg.txt[0]=(char*)malloc(strlen(ztxt)+1);if(!dlg.txt[0])return;dlg.tp=ztp;
  strcpy(dlg.txt[0],ztxt);
  for(i=1,p=0;i<4;i++){
    while(dlg.txt[0][p]!='\n'&&dlg.txt[0][p])p++;if(!dlg.txt[0][p])break;
    dlg.txt[0][p]=0;p++;dlg.txt[i]=dlg.txt[0]+p;
  }dlg.ttxt=i;ztam=0;
  for(i=0;i<dlg.ttxt;i++){
    ztam2=al_get_text_width(fnt,dlg.txt[i]);if(ztam<ztam2)ztam=ztam2;
  }dlg.tx=dlg.ttxt*tfnt;dlg.ty=ztam;dlg.ciclr=139;dlg.ciclr2=0;
  dlg.px=zpx;dlg.py=zpy;dlg.hp=300;
}
void PrintTxt(int ztp,int*zpx,int*zpy,char*ztxt){
  dlg.orix=zpx;dlg.oriy=zpy;
  PrintTxt(ztp,*zpx,*zpy,ztxt);
}
void PrintTxt(int ztp,int*zpx,int*zpy,char*ztxt,int zn){
  for(zn=0;zn<5&&dlge[zn].tp;zn++);if(zn>=5)return;
  dlge[zn].orix=zpx;dlge[zn].oriy=zpy;
  int ztam,ztam2,i,p;
  if(dlge[zn].txt[0])free(dlge[zn].txt[0]);
  dlge[zn].txt[0]=(char*)malloc(strlen(ztxt)+1);if(!dlge[zn].txt[0])return;dlge[zn].tp=ztp;
  strcpy(dlge[zn].txt[0],ztxt);
  for(i=1,p=0;i<4;i++){
    while(dlge[zn].txt[0][p]!='\n'&&dlge[zn].txt[0][p])p++;if(!dlge[zn].txt[0][p])break;
    dlge[zn].txt[0][p]=0;p++;dlge[zn].txt[i]=dlge[zn].txt[0]+p;
  }dlge[zn].ttxt=i;ztam=0;
  for(i=0;i<dlge[zn].ttxt;i++){
    ztam2=al_get_text_width(fnt,dlge[zn].txt[i]);if(ztam<ztam2)ztam=ztam2;
  }dlge[zn].tx=dlge[zn].ttxt*tfnt;dlge[zn].ty=ztam;dlge[zn].ciclr=139;dlge[zn].ciclr2=0;
  dlge[zn].px=*zpx;dlge[zn].py=*zpy;dlge[zn].hp=300;
}


//============================================================================//
// FUNCIONES JUEGO                                                            //
//============================================================================//

int(*Ejec)()=0;

int IEGame();
int EGame();
int EGameOver();
int IEMenu();
int EMenu();

void PutSpr(int zpx,int zpy,int zgrf){
  al_draw_bitmap_region(gspr,(zgrf&7)<<5,(zgrf<<2)&0xe0,32,32,zpy,zpx,0);
}
void PrintPers(){float zr,zg,zb;int i,j;
  if(pers.hp){
    if(pers.energy){
      al_color_hsv_to_rgb(pers.clrh,pers.clrs/255.0,1,&zr,&zg,&zb);
      al_draw_tinted_bitmap_region(gspr,al_map_rgb_f(zr,zg,zb),
        (pers.grf&7)<<5,(pers.grf<<2)&0xe0,32,32,pers.y-by,pers.x-bx,pers.ld);
    }else{
      al_draw_bitmap_region(gspr,(pers.grf&7)<<5,(pers.grf<<2)&0xe0,32,32,pers.y-by,pers.x-bx,pers.ld);
      pers.hp--;if(pers.hp<=0){printf("Score: %ld\n",score);
        #ifdef MUSIC
        al_detach_audio_stream(mscgame);
        #endif
        Ejec=EGameOver;pers.fallg=-6;pers.liftc=0;pers.fall=rand()%5-2;vblack=0;
      }
    }
    if(pers.liftc&&!pers.fall){
      for(i=0;i<6;i++){j=((pers.y+16)&0xFE0)-by;
        al_draw_line(j+.5,pers.x+i+32.5-bx,j+32.5,pers.x+i+32.5-bx,pal[135-i+((pers.liftc&0x3c)<<1)],0);
      }
    }
  }else{
    al_draw_tinted_scaled_rotated_bitmap_region(gspr,
      (pers.grf&7)<<5,(pers.grf<<2)&0xe0,32,32,al_map_rgb(255,255,255),
      16,16,pers.y-by+16,pers.x-bx+16,1,1,pers.liftc/180.0*ALLEGRO_PI,pers.ld);
  }
}


#include "arc.c"

struct _STR_cake{
  void Init();
  void Print();
  int vaux,zd,tp,hide,show;
}cake;
/** tp - TIPO (byte)
 * 0: Estatico
 * 1: Preparacion
 * 2: Gradual
 * 3: Demo
 */

void _STR_cake::Init(){
  tp=1;zd=0;vaux=0;hide=190;show=0;
}

void _STR_cake::Print(){float zz,zzz;
  switch(tp){
  case 0:
    vaux=map.dotcolor;
    break;
  case 1:
    vaux+=(zd)?-1000:1000;
    if(vaux>737280){vaux=737280;zd=1;}
    if(vaux<map.dotcolor){vaux=map.dotcolor;zd=0;tp=0;}
    break;
  case 2:
    if(vaux>map.dotcolor){vaux-=1000;if(vaux<=map.dotcolor){vaux=map.dotcolor;tp=0;}}
    if(vaux<map.dotcolor){vaux+=1000;if(vaux>=map.dotcolor){vaux=map.dotcolor;tp=0;}}
    break;
  case 3:
    vaux+=(zd)?-1000:1000;
    if(vaux>737280){vaux=737280;zd=1;}
    if(vaux<0){vaux=0;zd=0;}
    break;
  }
  zz=vaux*ALLEGRO_PI/737280.0;
  //al_draw_line(160.5,120.5,160.5+cosf(ALLEGRO_PI-zz)*140,120.5+sinf(ALLEGRO_PI-zz)*80,pal[1],0);
  //al_draw_line(160.5,120.5,160.5+cosf(ALLEGRO_PI+zz)*140,120.5+sinf(ALLEGRO_PI+zz)*80,pal[1],0);
  al_draw_filled_ellipse(160,130+hide,140,60,pal[12]);
  if(vaux){
    if(vaux<368640){
      al_draw_filled_elliptical_arc(160,130+hide,140,60,ALLEGRO_PI-zz,zz,pal[5]);
      al_draw_filled_rectangle(20,110+hide,160,130+hide,pal[5]);
      //al_draw_line(160.5+cosf(ALLEGRO_PI-zz)*140,110.5+sinf(ALLEGRO_PI-zz)*60,
      //  160.5+cosf(ALLEGRO_PI-zz)*140,130.5+sinf(ALLEGRO_PI-zz)*60,pal[13],0);
      al_draw_line(160+cosf(ALLEGRO_PI-zz)*140,110+sinf(ALLEGRO_PI-zz)*60+hide,
        160+cosf(ALLEGRO_PI-zz)*140,130+sinf(ALLEGRO_PI-zz)*60+hide,pal[13],0);
    }else{
      al_draw_filled_elliptical_arc(160,130+hide,140,60,ALLEGRO_PI-zz,zz*2,pal[5]);
      al_draw_filled_rectangle(20,110+hide,40,130+hide,pal[5]);zzz=160+cosf(ALLEGRO_PI-zz)*140-40;
      if(zzz<160)zzz=160;
      al_draw_filled_rectangle(zzz,110+sinf(ALLEGRO_PI-zz)*60+hide,
        160+cosf(ALLEGRO_PI-zz)*140,130+sinf(ALLEGRO_PI-zz)*60+hide,pal[5]);
      al_draw_filled_rectangle(zzz,110+sinf(ALLEGRO_PI+zz)*60+hide,
        160+cosf(ALLEGRO_PI+zz)*140,130+sinf(ALLEGRO_PI+zz)*60+hide,pal[5]);
    }
    al_draw_filled_elliptical_arc(160,110+hide,140,60,ALLEGRO_PI-zz,zz*2,pal[13]);
  }zz=vaux/737280.0*100.0;
  al_draw_textf(fnt2,pal[0],159,79+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  al_draw_textf(fnt2,pal[0],161,81+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  al_draw_textf(fnt2,pal[0],159,81+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  al_draw_textf(fnt2,pal[0],161,79+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  al_draw_textf(fnt2,pal[0],159,80+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  al_draw_textf(fnt2,pal[0],161,80+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  al_draw_textf(fnt2,pal[1],160,80+hide,ALLEGRO_ALIGN_CENTRE,"%3.1f%%",zz);
  if(show){show--;if(hide>0)hide-=10;}else if(hide<190)hide+=10;
}

struct _STR_energy{
  void Init();
  void Print();
  int bc,zsd1,zsd2;
  int vaux,zd,tp;
  ALLEGRO_COLOR color[360];
}energy;
/** tp - TIPO (byte)
 * 0: Estatico
 * 1: Preparacion
 * 2: Gradual
 * 3: Demo
 */

void _STR_energy::Init(){int i;float zr,zg,zb;
  for(i=0;i<360;i++){
    al_color_hsv_to_rgb(i,1,1,&zr,&zg,&zb);
    color[i]=al_map_rgb_f(zr,zg,zb);
  }bc=0;vaux=0;zd=100;tp=1;zsd2=100;zsd1=50;
}
void _STR_energy::Print(){int zz,i,zmax;float zzz,zzz2;
  switch(tp){
  case 1:
    vaux+=zd;
    if(vaux>10000){vaux=10000;zd=-10;}
    if(vaux<pers.energy){vaux=pers.energy;zd=0;tp=0;}
    break;
  case 2:
    if(vaux>pers.energy){vaux-=100;if(vaux<=pers.energy){vaux=pers.energy;tp=0;}}
    if(vaux<pers.energy){vaux+=100;if(vaux>=pers.energy){vaux=pers.energy;tp=0;}}
    break;
  case 3:
    vaux+=zd;
    if(vaux>10000){vaux=10000;zd=-10;}
    if(vaux<0){vaux=0;zd=10;}
    break;
  }
  zmax=vaux*160.0/10000;
  al_draw_ellipse(zsd1,200,20,10,pal[6],5);
  al_draw_ellipse(zsd1,40,20,10,pal[6],5);
  al_draw_line(zsd1-20,40,zsd1-20,200,pal[6],5);
  al_draw_line(zsd1+20,40,zsd1+20,200,pal[6],5);
  al_draw_line(zsd1+15,35,zsd1+15,195,pal[6],2);
  al_draw_line(zsd1+12,35,zsd1+12,195,pal[6],0);
  /*al_draw_filled_ellipse(50,200,20,10,pal[1]);
  al_draw_filled_rectangle(30,40,70,200,pal[1]);
  al_draw_filled_ellipse(50,40,20,10,pal[1]);*/
  zz=bc;
  for(i=0;i<zmax;i++){
    al_draw_filled_ellipse(zsd1,200-i,20,10,color[zz]);
    zz+=4;if(zz>359)zz=0;
  }
  al_draw_ellipse(zsd1,40,20,10,pal[6],2);
  bc++;if(bc>359)bc=0;
  zzz=vaux/100.0;zzz2=zmax*0.8125;
  if(pers.ld){
    if(zsd2<260)zsd2+=10;
    if(zsd1<270)zsd1+=10;
  }else{
    if(zsd2>100)zsd2-=10;
    if(zsd1>50)zsd1-=10;
  }
  al_draw_textf(fnt2,pal[0],zsd2-1,179-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
  al_draw_textf(fnt2,pal[0],zsd2+1,179-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
  al_draw_textf(fnt2,pal[0],zsd2+1,181-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
  al_draw_textf(fnt2,pal[0],zsd2-1,181-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
  al_draw_textf(fnt2,pal[0],zsd2+1,180-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
  al_draw_textf(fnt2,pal[0],zsd2-1,180-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
  al_draw_textf(fnt2,pal[1],zsd2,180-zzz2,ALLEGRO_ALIGN_RIGHT,"%3.0f%%",zzz);
}

struct _STR_enemy{
  void Init();
  void Print();
  void Hit();
  int x,y,ld,tp,act,hp;
  int grf,tim;
  int fall,liftc;
  float fallg;
}ene[400];
int tene=0;
/* tp - TIPO
 * 0 - FREE
 * 1 - Enemigo
 * 2 - Curado
 */

void _STR_enemy::Init(){
  if(rand()&1){
    x=rand()%6*64+26;y=-32;ld=ALLEGRO_FLIP_HORIZONTAL;
  }else{
    x=rand()%6*64+26;y=1920;ld=0;
  }hp=100;
  tp=1;grf=11;tim=0;act=0;fall=0;
}
void _STR_enemy::Print(){
  switch(tp){
  case 1: // ZORRO SIN COLOR
    switch(act){
    case 0: //Caminar
      tim++;if(tim==8)grf=12;if(tim==16){grf=11;tim=0;}
      if(ld){
        y++;if(y>1920)tp=0;
      }else{
        y--;if(y<0)tp=0;
      }
      if(rand()%2000<5){act=1;tim=0;grf=11;}
      {int zx,zy,zz;
        zx=x>>6;zz=y+16;zy=zz/96;zz%=96;
        if(rawmap[zx][zy]==' '){
          fallg=-4;liftc=32;fall=(zz>48)?-1:1;act=2;grf=11;tim=0;
        }}
      break;
    case 1: //Eliminar color
      tim++;
      if(tim==120){int zx1,zy1,zx2,zy2;
        al_set_target_bitmap(map.bmp);
        map.Drain(x-16+rand()%48,y-16+rand()%48,rand()%16+8,rand()%16+8);
        map.Drain(x-16+rand()%48,y-16+rand()%48,rand()%16+8,rand()%16+8);
        map.Drain(x-16+rand()%48,y-16+rand()%48,rand()%16+8,rand()%16+8);
        cake.tp=2;
        al_set_target_bitmap(scr);
      }
      if(tim==240){tim=0;act=0;}
      break;
    case 2: // Saltar/Caer
      y+=fall;x+=fallg;fallg+=.4;liftc--;
      if(!liftc){fall=0;x&=0xFC0;x+=26;act=0;}
      break;
    }break;
  case 2: // ZORRO
    switch(act){
    case 0: //Caminar
      tim++;if(tim==8)grf=14;if(tim==16){grf=13;tim=0;}
      if(ld){
        y++;if(y>1920)tp=0;
      }else{
        y--;if(y<0)tp=0;
      }
      {int zx,zy,zz;
        zx=x>>6;zz=y+16;zy=zz/96;zz%=96;
        if(rawmap[zx][zy]==' '){
          fallg=-4;liftc=32;fall=(zz>48)?-1:1;act=2;grf=13;tim=0;
        }}
      break;
    case 2: // Saltar/Caer
      y+=fall;x+=fallg;fallg+=.4;liftc--;
      if(!liftc){fall=0;x&=0xFC0;x+=26;act=0;}
      break;
    }break;
  }
  al_draw_bitmap_region(gspr,(grf&7)<<5,(grf<<2)&0xe0,32,32,y-by,x-bx,ld);
}

void _STR_enemy::Hit(){
  switch(tp){
  case 1:
    hp--;if(hp<=0){tp=2;act=0;tim=0;score+=10000;
      if(rand()%200<20)PrintTxt((tp==2)?1:2,&x,&y,text[(tp==2)?rand()%9+40:rand()%10+19],0);}
    break;
  }
}

struct _STR_part{
  void Print();
  void AddSnakeShot();
  void AddAirShot();
  float x,y,rd,sx,sy;
  int tp,hp;
  ALLEGRO_COLOR clr;
}part[2000];
int tpart;

void _STR_part::Print(){
  switch(tp){
  case 1:rd=hp/6.0;
    al_draw_filled_circle(y-by,x-bx,rd,clr);
    x+=sx;y+=sy;
    hp--;if(hp<0)tp=0;
    break;
  case 2:rd=hp/15.0;
    al_draw_filled_circle(y-by,x-bx,rd,clr);
    x+=sx;y+=sy;
    hp--;if(hp<0)tp=0;
    break;
  }
}

void _STR_part::AddSnakeShot(){float zr,zg,zb;
  tp=1;x=pers.x+10;y=pers.y+((!pers.ld)?32:0);rd=5;hp=30;
  sx=(rand()%2000)/1000.0-1.0;
  sy=(rand()%2000)/1000.0+1;if(pers.ld)sy*=-1;
  al_color_hsv_to_rgb(rand()%360,1,1,&zr,&zg,&zb);
  clr=al_map_rgb_f(zr,zg,zb);
}

void _STR_part::AddAirShot(){float zr,zg,zb;
  tp=2;x=pers.x+10;y=pers.y+((!pers.ld)?32:0);rd=3;hp=30;
  sx=(rand()%500)/1000.0-0.25;
  sy=(rand()%500)/1000.0;if(pers.ld)sy*=-1;
  al_color_hsv_to_rgb(rand()%360,.2,1,&zr,&zg,&zb);
  clr=al_map_rgb_f(zr,zg,zb);
}

int IEGame(){int i,j,zx,zy;
  al_stop_timer(timer);
  //Continua la inicializacion
  #ifdef MUSIC
  if(!al_attach_audio_stream_to_mixer(mscgame,mixer))return -1;
  //if(!al_attach_audio_stream_to_voice(stream,voice))return -1;
  #endif
  map.Create();
  pers.x=218;pers.y=900;pers.grf=0;pers.tim=0;pers.ld=0;pers.clrh=0;pers.clrs=255;
  pers.tm=0;pers.liftd=0;pers.liftc=0;pers.fall=0;pers.fallg=0;pers.energy=10000;
  pers.hp=3600;ciclr=0;ciclr2=0;
  cake.Init();energy.Init();
  Ejec=EGame;tpart=0;tene=0;score=0;
  al_set_target_bitmap(gcmd);
  al_clear_to_color(al_map_rgba(0,0,0,0));
  al_draw_filled_circle(32,32,32,pal[6]);
  al_draw_circle(32,32,32,pal[4],2);
  al_set_target_bitmap(scr);
  al_clear_to_color(pal[0]);
  //PrintTxt(1,100,100,"Creado burbuja de texto.");
  //PrintTxt(2,10,10,"Creado burbuja de texto.\nPuede tener hasta 4 lineas.");
  PrintTxt(1,&pers.x,&pers.y,text[1]);
  for(i=0;i<5;i++)dlge[i].tp=0;
  al_resume_timer(timer);
  return 0;
}

void DrawGame(){int i;
  //PANTALLA
  al_set_target_bitmap(scr);
  al_clear_to_color(pal[0]);
  al_draw_bitmap(map.bmp,-by,-bx,0);
  al_draw_bitmap(gcmd,928-by,180-bx,0);
  //Enemigos
  for(i=0;i<tene;i++){ene[i].Print();
    if(!ene[i].tp){tene--;ene[i]=ene[tene];i--;}
  }
  if(rand()%2000<50){
    ene[tene].Init();
    tene++;
  }
  PrintPers();
  dlg.Print();for(i=0;i<5;i++)dlge[i].Print();
  //Particulas
  for(i=0;i<tpart;i++){part[i].Print();
    if(!part[i].tp){tpart--;part[i]=part[tpart];i--;}
  }
  cake.Print();
  energy.Print();
  al_draw_textf(fnt,pal[1],0,240-tfnt,0,"Score:%d",score);
  //al_draw_bitmap(gcmd,0,0,0);
}

void RenderGame(){
  //RENDER
  al_set_target_backbuffer(dsp);
  //al_draw_scaled_bitmap(scr,0,0,320,240,0,0,640,480,0);
  al_draw_scaled_bitmap(scr,0,0,320,240,0,0,960,720,0);
  al_flip_display();
}

int EGame(){int zx,zy,zz;
  if(pers.fall){
    pers.y+=pers.fall;pers.x+=pers.fallg;pers.fallg+=.4;pers.liftc--;
    if(!pers.liftc){pers.fall=0;pers.x&=0xFC0;pers.x+=26;}
  }else if(pers.liftc){
    pers.x+=pers.liftd;pers.liftc--;
  }else if(k&16){if(pers.energy>0){part[tpart].AddSnakeShot();
      pers.energy-=10;energy.tp=2;if(pers.energy<0)pers.energy=0;
      al_set_target_bitmap(map.bmp);
      map.Heal(pers.x+rand()%64-26,pers.y+rand()%64+((pers.ld)?-64:32),8,8);
      for(zz=0;zz<tene;zz++){
        if(pers.x==ene[zz].x){zy=ene[zz].y-pers.y;
          if(pers.ld){if(zy>-80&&zy<-16)ene[zz].Hit();}else{
            if(zy>16&&zy<80)ene[zz].Hit();
          }
        }
      }
    }else{
      part[tpart].AddAirShot();
    }tpart++;pers.grf=2;
  }else if(k&64){
    if(pers.y>928&&pers.y<960&&pers.x==218){
      pers.energy+=pow(map.dotcolor/737280.0,2)*60;if(pers.energy>10000)pers.energy=10000;energy.tp=2;
    }
  }else if(k&512){
    if(pers.y>928&&pers.y<960&&pers.x==218)cake.show=600;
  }else{
    if(k&1&&pers.y<1888){cake.show=0;pers.y+=2;pers.ld=0;pers.tim++;}
    else if(k&4&&pers.y>0){cake.show=0;pers.y-=2;pers.ld=ALLEGRO_FLIP_HORIZONTAL;pers.tim++;}
    else{pers.tim=0;pers.grf=0;}
    if(k&2){
      zx=pers.x>>6;zz=pers.y+16;zy=zz/96;zz%=96;
      if(rawmap[zx][zy]=='H'&&zz>32&&zz<64){
        pers.liftd=-1;pers.liftc=64;
      }
    }else if(k&8){
      zx=pers.x>>6;zz=pers.y+16;zy=zz/96;zz%=96;
      if(zx<6&&rawmap[zx+1][zy]=='H'&&zz>32&&zz<64){
        pers.liftd=1;pers.liftc=64;
      }
    }
    if(pers.tim>6){pers.tim=0;pers.grf++;if(pers.grf>3)pers.grf=0;}
    zx=pers.x>>6;zz=pers.y+16;zy=zz/96;zz%=96;
    if(rawmap[zx][zy]==' '){
      pers.fallg=-4;pers.liftc=32;pers.fall=(zz>48)?-1:1;
    }
    if(k&32&&!dlg.tp){
      PrintTxt(1,&pers.x,&pers.y,text[rand()%6+8]);
    }
  }
  pers.tm++;if(pers.tm>8){pers.tm=0;pers.clrh++;if(pers.clrh>360)pers.clrh=0;}
  if(pers.energy>0){pers.energy--;energy.tp=2;}
  if(map.dotcolor<=184320){printf("Score: %ld\n",score);
    #ifdef MUSIC
    al_detach_audio_stream(mscgame);
    #endif
    Ejec=EGameOver;pers.fallg=-6;pers.liftc=0;pers.fall=rand()%5-2;vblack=0;
  }
  if(tene&&rand()%2000<20){zx=rand()%tene;
    PrintTxt((ene[zx].tp==2)?1:2,&ene[zx].x,&ene[zx].y,text[(ene[zx].tp==2)?rand()%9+40:rand()%10+19],0);
  }
  bx=pers.x-104;by=pers.y-144;
  if(bx<0)bx=0;if(bx>144)bx=144;if(by<0)by=0;if(by>1600)by=1600;
  DrawGame();
  RenderGame();
  return 0;
}

int EGameOver(){
  if(pers.x<400){
    pers.x+=pers.fallg;pers.fallg+=.4;pers.y+=pers.fall;pers.liftc+=20;
  }pers.tim++;
  DrawGame();
  if(pers.tim>300)al_draw_bitmap(gameover,21,94,0);
  if(pers.tim>900){
    al_draw_tinted_bitmap(gblack,al_map_rgba(vblack,vblack,vblack,vblack),0,0,0);
    vblack+=2;if(vblack>255){vblack=255;
      Ejec=IEMenu;
    }
  }
  RenderGame();
  return 0;
}

int IEMenu(){by=0;bx=136;vblack=255;bz=0;ciclr=0;
  al_set_target_bitmap(gblack);
  al_clear_to_color(al_map_rgb(0,0,0));
  #ifdef MUSIC
  if(!al_attach_audio_stream_to_mixer(mscmenu,mixer))return -1;
  #endif
  Ejec=EMenu;
  return EMenu();
}

int EMenu(){
  if(k&1024)ciclr=1;
  al_set_target_bitmap(scr);
  al_draw_bitmap(gforest,by,0,0);
  al_draw_bitmap(gtitulo,14,4,0);
  al_draw_text(fnt2,pal[bx],160,190,ALLEGRO_ALIGN_CENTRE,"START");
  if(ciclr){
    vblack+=4;
    if(vblack>255){vblack=255;
      #ifdef MUSIC
      if(!al_detach_audio_stream(mscmenu))return -1;
      #endif
      Ejec=IEGame;
    }
    al_draw_tinted_bitmap(gblack,al_map_rgba(vblack,vblack,vblack,vblack),0,0,0);
  }else{
    if(vblack){
      al_draw_tinted_bitmap(gblack,al_map_rgba(vblack,vblack,vblack,vblack),0,0,0);
      vblack-=4;if(vblack<0)vblack=0;
    }
  }by--;if(by<-432)by=0;bz++;if(bz>2){bz=0;bx++;if(bx>255)bx=136;}
  RenderGame();
  return 0;
}

//============================================================================//
// CICLO                                                                      //
//============================================================================//

int Bucle(){int VIS=0;
  ALLEGRO_EVENT ev;
  do{
    do{
      al_wait_for_event(evq,&ev);
      switch(ev.type){
      case ALLEGRO_EVENT_DISPLAY_CLOSE:CICLO=0;return 0;
      case ALLEGRO_EVENT_TIMER:VIS=1;break;
      case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:break;
      case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:break;
      case ALLEGRO_EVENT_KEY_CHAR:
      case ALLEGRO_EVENT_KEY_UP:
      case ALLEGRO_EVENT_KEY_DOWN:
      case ALLEGRO_EVENT_MOUSE_AXES:
      case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
      case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
      case ALLEGRO_EVENT_DISPLAY_RESIZE:
        EvKey(ev);break;
      }
    }while(!al_event_queue_is_empty(evq));
    if(VIS){
      if(Ejec())CICLO=0;
      VIS=0;
    }
  }while(CICLO);
  return 0;
}

int main(){int i;
  if(i=InitScreen()){printf("ERROR:%d\n",i);return -1;}
  Ejec=IEMenu;CICLO=1;
  al_start_timer(timer);
  srand(time(0));
  Bucle();
  EndScreen();
  return 0;
}
