/*
*****************************************
* This is Snake 256!                    *
* Author: Tony Wasserka                 *
* Version: 0.0.3                        *
* License: GPL                          *
* See Readme.txt                        *
* Enjoy this!                           *
*****************************************
*/

#include "snake.h"

class NormalSnake
{
public:
 NormalSnake() {};
 NormalSnake(bool doinit) { if(doinit) RandomSnake(); };
 ~NormalSnake() { };

 void RandomSnake()
 {
  x[0] = (float)(rand() % Config::screenw);
  y[0] = (float)(rand() % Config::screenh);
  for(int a = 1;a < 64;a++)
  {
   x[a] = x[a - 1] - 1;
   y[a] = y[a - 1];
  }
  score = rand() % 30 + 25;
 }
 float x[64], y[64];
 int score;
};

NormalSnake normal_snake;
int normal_snake_tx, normal_snake_ty;

int true_snake_playernum;
float true_snake_max_score = 0;

void InitNormalSnake()
{
 normal_snake = NormalSnake(true);

 normal_snake_tx = rand() % Config::screenw;
 normal_snake_ty = rand() % Config::screenh;
}

void PlayNormalSnake(float dtime)
{
 if(ABS(normal_snake_tx - normal_snake.x[0]) <= 10 && ABS(normal_snake_ty - normal_snake.y[0]) <= 10)
 {
  normal_snake.score += 10;
  if(normal_snake.score > 255) normal_snake.score = 255;
  normal_snake_tx = rand() % Config::screenw;
  normal_snake_ty = rand() % Config::screenh;
 }
 for(int b = 63;b > 0;b--)
 {
  normal_snake.x[b] = normal_snake.x[b - 1];
  normal_snake.y[b] = normal_snake.y[b - 1];
 }

 if((normal_snake_tx - (int)normal_snake.x[0]) < -7) normal_snake.x[0] -= dtime * 100;
 else if((normal_snake_tx - (int)normal_snake.x[0]) > 7) normal_snake.x[0] += dtime * 100;
 else if((normal_snake_ty - (int)normal_snake.y[0]) < -7) normal_snake.y[0] -= dtime * 100;
 else if((normal_snake_ty - (int)normal_snake.y[0]) > 7) normal_snake.y[0] += dtime * 100;

 for(int b = 0;b < normal_snake.score - 1;b++)
  line(screenbmp, (int)normal_snake.x[b], (int)normal_snake.y[b], (int)normal_snake.x[b + 1], (int)normal_snake.y[b + 1],
       makecol(255, 255, 255));

 circle(screenbmp, normal_snake_tx, normal_snake_ty, 5, makecol(255, 255, 255));
 circle(screenbmp, normal_snake_tx, normal_snake_ty, 10, makecol(255, 255, 255));
}

void InitTrueSnake(int w, int h)
{
 true_snake_playernum = rand() % 4 + 3;

 for(int a = 0;a < 8;a++)
 {
  float ang = (float)(rand() % 628000) / 100000.;
  snake[a].num = a;

  snake[a].x[0] = rand() % w;
  snake[a].y[0] = rand() % (h - true_snake_playernum * 15 - 5);

  for(int b = 159;b > 0;--b)
  {
   snake[a].x[b] = snake[a].x[b - 1] - cosf(ang);
   snake[a].y[b] = snake[a].y[b - 1] - sinf(ang);
  }
  snake[a].color = makecol(rand() % 256, rand() % 256, rand() % 256);

  snake[a].angle = ang;

  snake[a].state = false;
  snake[a].score = rand() % 100 + 50;
  snake[a].new_score = snake[a].score;
 }
 target.x = (rand() % w);
 target.y = (rand() % (h - true_snake_playernum * 15 - 5));
 target.r = 0.;
}

void PlayTrueSnake(BITMAP *bmp, float dtime)
{
 for(int a = 0;a <  true_snake_playernum;a++)
  if(!snake[a].state)
  {
   bool do_fast = false;

   if(snake[a].x[0] > bmp->w) snake[a].x[0] -= bmp->w;
   else if(snake[a].x[0] < 0) snake[a].x[0] += bmp->w;
   if(snake[a].y[0] > bmp->h - true_snake_playernum * 15 - 5) snake[a].y[0] -= bmp->h - true_snake_playernum * 15 - 5;
   else if(snake[a].y[0] < 0) snake[a].y[0] += bmp->h - true_snake_playernum * 15 - 5;

   if(ABS(snake[a].x[0] - target.x) < 7)
    if(ABS(snake[a].y[0] - target.y) < 7)
    {
     snake[a].new_score += 10;
     snake[a].x[(int)snake[a].new_score + min_length] = snake[a].x[(int)snake[a].new_score + min_length - 1];
     snake[a].y[(int)snake[a].new_score + min_length] = snake[a].y[(int)snake[a].new_score + min_length - 1];
     target.x = rand() % bmp->w;
     target.y = rand() % (bmp->h - true_snake_playernum * 15 - 5);
     target.r = 0;
    }
    for(int snum = 0;snum < true_snake_playernum;snum++)
     if(a != snum && !snake[snum].state)
      for(int pnum = 0;pnum < snake[snum].score + min_length;pnum++)
       if(ABS(snake[a].x[0] - snake[snum].x[pnum]) < 10)
        if(ABS(snake[a].y[0] - snake[snum].y[pnum]) < 10)
        {
         snake[a].new_score -= dtime;
         break;
        }

    for(int pnum = 20;pnum < snake[a].new_score + min_length;pnum++)
     if(ABS(snake[a].x[0] - snake[a].x[pnum]) < 10)
      if(ABS(snake[a].y[0] - snake[a].y[pnum]) < 10)
      {
       snake[a].new_score -= dtime;
       break;
      }

   if(snake[a].score < snake[a].new_score) snake[a].score += dtime;
   if(snake[a].score > snake[a].new_score) snake[a].score -= dtime;
   if(ABS(snake[a].score - snake[a].new_score) < dtime + 0.1) snake[a].score = snake[a].new_score;
   if(snake[a].score < 0) snake[a].state = true;

   float new_angle = snake[a].angle;
   int dx = (int)(target.x - snake[a].x[0]), dy = (int)(target.y - snake[a].y[0]);

   if(ABS(dx) > (bmp->w >> 1)) dx += bmp->w * SGN((bmp->w >> 1) - dx);
   if(ABS(dy) > ((bmp->h - true_snake_playernum * 15 - 5) >> 1))
    dy += (bmp->h - true_snake_playernum * 15 - 5) * SGN(((bmp->h - true_snake_playernum * 15 - 5) >> 1) - dy);

   new_angle = atan2f(dy, dx);

   float differ = snake[a].angle - new_angle;

   if(differ > 6.28) differ -= 6.28;
   else if(differ < 0) differ += 6.28;

   if(differ < 3.14) snake[a].angle -= dtime / 20;
   else snake[a].angle += dtime / 20;

   if(differ > 3.14) differ = 6.28 - differ;
   else if(differ < 0)
   {
    differ += 6.28;
    if(differ > 3.14) differ = 6.28 - differ;
   }

   if(differ < 0.39) do_fast = true;

   snake[a].x[0] += cosf(snake[a].angle) * dtime * (1 + do_fast);
   snake[a].y[0] += sinf(snake[a].angle) * dtime * (1 + do_fast);

   for(int b = 1;b <= (int)snake[a].score + min_length;b++)
   {
    float angle = atan2f(snake[a].y[b] - snake[a].y[b - 1], snake[a].x[b] - snake[a].x[b - 1]);

    if(ABS(snake[a].x[b] - snake[a].x[b - 1]) > bmp->w >> 1) angle = 3.14 + angle;
    if(ABS(snake[a].y[b] - snake[a].y[b - 1]) > (bmp->h - true_snake_playernum * 15 - 5) >> 1) angle = -angle;

    snake[a].x[b] = snake[a].x[b - 1] + cosf(angle);
    snake[a].y[b] = snake[a].y[b - 1] + sinf(angle);
    if(snake[a].x[b] > bmp->w) snake[a].x[b] -= bmp->w;
    if(snake[a].x[b] < 0) snake[a].x[b] += bmp->w;
    if(snake[a].y[b] > bmp->h - true_snake_playernum * 15 - 5) snake[a].y[b] -= bmp->h - true_snake_playernum * 15 - 5;
    if(snake[a].y[b] < 0) snake[a].y[b] += bmp->h - true_snake_playernum * 15 - 5;
   }
   if(snake[a].angle > 6.28) snake[a].angle -= 6.28;
   else if(snake[a].angle < 0) snake[a].angle += 6.28;
  } // End of logic

 true_snake_max_score = 0;

 for(int a = 0;a < Config::num_snakes;a++)
  if(!snake[a].state)
   if(snake[a].score > true_snake_max_score) true_snake_max_score = snake[a].score;

 if(true_snake_max_score / (int)score_size > ((bmp->w * 5) >> 3))
  score_size += (true_snake_max_score / score_size - ((bmp->w *5) >> 3) ) / 10000.;
 if(score_size > 1)
  if(true_snake_max_score / (int)score_size < (bmp->w >> 1))
  {
   score_size -= ((bmp->w >> 1) - true_snake_max_score / score_size) / 100000.;
   if(score_size < 1) score_size = 1;
  }

 for(int a = 0;a < true_snake_playernum;a++)
  if(!snake[a].state)
   snake[a].Draw(bmp, dtime * 120);

 if(target.r < 100.)
 {
  drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
  set_trans_blender(0, 0, 0, 255 - (int)(target.r * 2.55));
  circle(bmp, target.x, target.y, (int)target.r, makecol(255 - (int)(target.r * 2.55), 255, 255 - (int)(target.r * 2.55)));
  drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
  circlefill(bmp, target.x, target.y, (target.r > 25) ? 3 : (int)(target.r / 25 * 3), makecol(255,255,255));
  target.r += dtime / 120 * 100;
 }
 else circlefill(bmp, target.x, target.y, 3, makecol(255,255,255));

 rectfill(bmp, 0, bmp->h - true_snake_playernum * 15 - 5, bmp->w, bmp->h, makecol(128,128,128));

 for(int a = 0;a < true_snake_playernum;a++)
  if(!snake[a].state)
  {
   rectfill(bmp, 100, bmp->h + (a - true_snake_playernum) * 15,
            100 + (int)(snake[a].score / score_size),
            bmp->h + (a - true_snake_playernum) * 15 + 10, snake[a].color);

   textprintf_ex(bmp, font, 10, bmp->h + (a - true_snake_playernum) * 15, makecol(255, 255, 255), -1,
                 "Player %d: ", a + 1);
   textprintf_ex(bmp, font, 120 + (int)(snake[a].score / score_size),
                 bmp->h + (a - true_snake_playernum) * 15, makecol(255, 255, 255), -1,
                 "%.1f", snake[a].score / 10);
  }
}

typedef struct VTX
{
 float x, y, z;
} VTX;

typedef struct QUAD
{
 VTX *vtxlist;
 int v1, v2, v3, v4;
} QUAD;

float cuberot;

VTX points[] = 
{
 { -1, -1, -1 },
 { -1,  1, -1 },
 {  1,  1, -1 },
 {  1, -1, -1 },
 { -1, -1,  1 },
 { -1,  1,  1 },
 {  1,  1,  1 },
 {  1, -1,  1 },
};

QUAD faces[] =
{
 { points, 0, 3, 2, 1 },
 { points, 4, 5, 6, 7 },
 { points, 0, 1, 5, 4 },
 { points, 2, 3, 7, 6 },
 { points, 0, 4, 7, 3 },
 { points, 1, 2, 6, 5 }
};

VTX output_points[8];
QUAD output_faces[6];

BITMAP *textures[6];

void init_shapes()
{
 cuberot = 0;
}

void animate_shapes(float dtime)
{
 cuberot += dtime * 35;
}

void translate_shapes()
{
 int d;
 MATRIX_f matrix;
 VTX *outpoint = output_points;
 QUAD *outface = output_faces;

 if(cuberot > 512 && cuberot < 576)
  get_transformation_matrix_f(&matrix, 1, -cuberot, -cuberot, 0, 0, 0, 3);
 else if(cuberot > 576 && cuberot < 640)
  get_transformation_matrix_f(&matrix, 1, -64, -cuberot, 0, 0, 0, 3);
 else if(cuberot > 640 && cuberot < 896)
  get_transformation_matrix_f(&matrix, 1 + (cuberot - 640) / 512, -64, 128, 0, 0, 0, 3);
 else if(cuberot > 896)
  get_transformation_matrix_f(&matrix, 1.5, -64, 128, 0, 0, 0, 3);
 else
  get_transformation_matrix_f(&matrix, 1, 0, -cuberot, 0, 0, 0, 3);

 for (d = 0; d < 8;d++)
 {
  apply_matrix_f(&matrix, points[d].x, points[d].y, points[d].z, &outpoint[d].x, &outpoint[d].y, &outpoint[d].z);
  persp_project_f(outpoint[d].x, outpoint[d].y, outpoint[d].z, &outpoint[d].x, &outpoint[d].y);
 }
 for (d = 0;d < 6;d++)
 {
  outface[d] = faces[d];
  outface[d].vtxlist = outpoint;
 }
}

void draw_quad(BITMAP *b, VTX *v1, VTX *v2, VTX *v3, VTX *v4, int mode, int num)
{
 V3D_f vtx1;
 V3D_f vtx2;
 V3D_f vtx3;
 V3D_f vtx4;

 vtx1.x = v1->x;   vtx1.y = v1->y;   vtx1.z = v1->z;
 vtx2.x = v2->x;   vtx2.y = v2->y;   vtx2.z = v2->z;
 vtx3.x = v3->x;   vtx3.y = v3->y;   vtx3.z = v3->z;
 vtx4.x = v4->x;   vtx4.y = v4->y;   vtx4.z = v4->z;

 switch(num)
 {
  case 0:
  vtx1.u = 0;  vtx2.u = 512;  vtx3.u = 512;  vtx4.u = 0;
  vtx1.v = 0;  vtx2.v = 0;  vtx3.v = 512;  vtx4.v = 512;
  break;
  case 1:
  vtx1.u = 512;  vtx2.u = 512;  vtx3.u = 0;  vtx4.u = 0;
  vtx1.v = 0;  vtx2.v = 512;  vtx3.v = 512;  vtx4.v = 0;
  break;
  case 2:
  vtx1.u = 512;  vtx2.u = 512;  vtx3.u =0;  vtx4.u = 0;
  vtx1.v = 0;  vtx2.v = 512;  vtx3.v = 512;  vtx4.v = 0;
  break;
  case 3:
  vtx1.u = 0;  vtx2.u = 0;  vtx3.u = 512;  vtx4.u = 512;
  vtx1.v = 512;  vtx2.v = 0;  vtx3.v = 0;  vtx4.v = 512;
  break;
  case 4:
  vtx1.u = 512;  vtx2.u = 512;  vtx3.u = 0;  vtx4.u = 0;
  vtx1.v = 0;  vtx2.v = 512;  vtx3.v = 512;  vtx4.v = 0;
  break;
  case 5:
  vtx1.u = 0;  vtx2.u = 512;  vtx3.u = 512;  vtx4.u = 0;
  vtx1.v = 0;  vtx2.v = 0;  vtx3.v = 512;  vtx4.v = 512;
  break;
 }
 if(polygon_z_normal_f(&vtx1, &vtx2, &vtx3) < 0)
  return;

 quad3d_f(b, mode, textures[num], &vtx1, &vtx2, &vtx3, &vtx4);
}

void draw_shapes(BITMAP *b)
{
 QUAD *face = output_faces;
 VTX *v1, *v2, *v3, *v4;

 for(int c = 0; c < 6; c++)
 {
  v1 = face->vtxlist + face->v1;
  v2 = face->vtxlist + face->v2;
  v3 = face->vtxlist + face->v3;
  v4 = face->vtxlist + face->v4;

  draw_quad(b, v1, v2, v3, v4, POLYTYPE_PTEX, c);

  face++;
 }
}

void Intro()
{
 ALFONT_FONT *introfont[2];
 double all_time = 0;
 dtime = 0.25;

 for(int a = 0;a < 6;a++)
  textures[a] = create_bitmap(512,512);

 rest(1000);

 set_projection_viewport(0, 0, SCREEN_W, SCREEN_H);

 init_shapes();

 {
  char strbuf[256];

  get_executable_name(strbuf, sizeof(strbuf));
  replace_filename(strbuf, strbuf, "suigener.ttf", sizeof(strbuf));

  introfont[0] = alfont_load_font(strbuf);
  introfont[1] = alfont_load_font(strbuf);
  alfont_set_font_size(introfont[0], 80);
  alfont_set_font_size(introfont[1], 16);
 }
 while(!key[KEY_ESC] || Config::first_start)
 {
  if(dtime)
#ifdef ALLEGRO_WINDOWS
   QueryPerformanceCounter((LARGE_INTEGER*)(&start_t));
#else
   gettimeofday(&start_t, NULL);
#endif

  if(all_time == 0) InitNormalSnake();
  else if(all_time < 7) PlayNormalSnake(dtime);

  if(all_time < 1)
  {
   drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
   set_trans_blender(0, 0, 0, 255 - (int)(all_time * 255));
   rectfill(screenbmp, 0, 0, SCREEN_W, SCREEN_H, 0);
   drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
  }
  else if(all_time > 2 && all_time < 3)
  {
   alfont_textprintf_centre_ex(screenbmp, myfont[FONT_NORMAL], Config::screenw / 2,
                               Config::screenh - alfont_get_font_height(myfont[FONT_NORMAL]) * 2,
                               makecol((int)((all_time-2) * 255),(int)((all_time-2) * 255),
                                       (int)((all_time-2) * 255)),-1,
                               "This stuff is under your dignity!");
  }
  else if(all_time > 3 && all_time < 7)
  {
   alfont_textprintf_centre_ex(screenbmp, myfont[FONT_NORMAL], Config::screenw / 2,
                               Config::screenh - alfont_get_font_height(myfont[FONT_NORMAL]) * 2,
                               makecol(255, 255, 255),-1, "This stuff is under your dignity!");
  }
  if(all_time > 5 && all_time < 7)
  {
   drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
   set_trans_blender(0, 0, 0, (int)((all_time - 5) * 255 / 2));
   rectfill(screenbmp, 0, 0, SCREEN_W, SCREEN_H, 0);
   drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
  }
  else if(all_time > 8 && all_time < 17.5)
  {
   switch((int)((all_time - 8)) / 2)
   {
    case 0:
         clear_to_color(screenbmp, makecol(255,255,255));
         triangle(screenbmp,  (int)(SCREEN_W * (1 - (all_time - 8))), SCREEN_H, SCREEN_W, SCREEN_H, SCREEN_W, (int)(SCREEN_H * (1 - (all_time - 8))), 0);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_GETREADY], "Get ready...", SCREEN_W / 2, SCREEN_H / 2 - Config::screenw / 50, 0, -1);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_GETREADY], "THIS", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 255, 255), -1); break;
    case 1:
         clear_to_color(screenbmp, makecol(255,255,255));
         triangle(screenbmp,  (int)(SCREEN_W * (1 - (all_time - 10))), SCREEN_H, SCREEN_W, SCREEN_H, SCREEN_W, (int)(SCREEN_H * (1 - (all_time - 10))), 0);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_3], "3...", SCREEN_W / 2, SCREEN_H / 2 - Config::screenw / 25, 0, -1);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_3], "IS", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 255, 255), -1); break;
    case 2:
         clear_to_color(screenbmp, makecol(255,255,255));
         triangle(screenbmp,  (int)(SCREEN_W * (1 - (all_time - 12))), SCREEN_H, SCREEN_W, SCREEN_H, SCREEN_W, (int)(SCREEN_H * (1 - (all_time - 12))), 0);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_2], "2...", SCREEN_W / 2, SCREEN_H / 2 - Config::screenw * 2 / 25, 0, -1);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_2], "THE", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 255, 255), -1); break;
    case 3:
         clear_to_color(screenbmp, makecol(255,255,255));
         triangle(screenbmp,  (int)(SCREEN_W * (1 - (all_time - 14))), SCREEN_H, SCREEN_W, SCREEN_H, SCREEN_W, (int)(SCREEN_H * (1 - (all_time - 14))), 0);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_1], "1...", SCREEN_W / 2, SCREEN_H / 2 - Config::screenw * 4 / 25, 0, -1);
         alfont_textout_centre_ex(screenbmp, myfont[FONT_1], "BEST!", SCREEN_W / 2, SCREEN_H / 2, makecol(255, 255, 255), -1); break;
    case 4:
    case 5:
         clear_to_color(screenbmp, makecol(255,255,255));
         if((all_time > 16.25 && all_time < 16.50) || (all_time > 16.75 && all_time < 17) || (all_time > 17.25))
          alfont_textout_centre_ex(screenbmp, myfont[FONT_GO], "GO!!!", SCREEN_W / 2, SCREEN_H / 2 - Config::screenw * 4 / 25, 0, -1); break;
   }
  }
  for(float step = 17.5;step < 26;step += 0.85)
   if(all_time - dtime < step && all_time > step)
    InitTrueSnake(SCREEN_W, SCREEN_H);

  if(all_time > 17.5 && all_time < 26) PlayTrueSnake(screenbmp, dtime * 120);

  if(all_time > 26 && all_time - dtime < 26) InitTrueSnake(512, 512);
  if(cuberot > 0 && cuberot - dtime * 25 < 0) InitTrueSnake(512, 512);
  else if(cuberot > 64 && cuberot - dtime * 25 < 64) InitTrueSnake(512, 512);
  else if(cuberot > 192 && cuberot - dtime * 25 < 192) InitTrueSnake(512, 512);

  if(all_time > 26)
  {
   if(cuberot > 0 && cuberot < 64)
   {
    PlayTrueSnake(textures[0], dtime * 120);
   }
   if(cuberot > 0 && cuberot < 128)
    alfont_textprintf_centre_ex(textures[3], introfont[0], 256, 256 - alfont_get_font_height(introfont[0]) / 2, makecol(255,255,255),-1,
                                "This");

   if(cuberot > 64 && cuberot < 192)
    PlayTrueSnake(textures[1], dtime * 120);

   if(cuberot > 128 && cuberot < 256)
    alfont_textprintf_centre_ex(textures[2], introfont[0], 256, 256 - alfont_get_font_height(introfont[0]) / 2, makecol(255,255,255),-1,
                                "is");

   if(cuberot > 192 && cuberot < 320)
    PlayTrueSnake(textures[0], dtime * 120);

   if(cuberot > 256 && cuberot < 384)
    alfont_textprintf_centre_ex(textures[3], introfont[0], 256, 256 - alfont_get_font_height(introfont[0]) / 2, makecol(255,255,255),-1,
                                "Snake 256!");

   else if(cuberot > 384 && cuberot < 512)
   {
    for(int a = 0;a < 6;a++)
     clear_to_color(textures[a], makecol((int)(cuberot - 384) * 2, (int)(cuberot - 384) * 2, (int)(cuberot - 384) * 2));
   }
   else if(cuberot > 512 && cuberot < 960)
   {
    for(int a = 0;a < 6;a++)
     clear_to_color(textures[a], makecol(255, 255, 255));

    if(cuberot > 544)
     for(int a = 0;a < 6;a++)
      alfont_textprintf_centre_ex(textures[a], introfont[0], 256, 256 - alfont_get_font_height(introfont[0]) / 2, 0, -1,
                                  "Snake 256");
    else
     for(int a = 0;a < 6;a++)
      alfont_textprintf_centre_ex(textures[a], introfont[0], 256, 256 - alfont_get_font_height(introfont[0]) / 2,
                                  makecol(255 - (int)(cuberot - 512) * 8, 255 - (int)(cuberot - 512) * 8,
                                          255 - (int)(cuberot - 512) * 8), -1, "Snake 256");
   }
   else if(cuberot > 960 && cuberot < 1024)
   {
    clear_to_color(textures[4], makecol(255,255,255));
    alfont_textprintf_centre_ex(textures[4], introfont[0], 256, 256 - alfont_get_font_height(introfont[0]) / 2, 0, -1,
                                "Snake 256");
    drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
    set_trans_blender(0, 0, 0, (int)((cuberot - 960)) * 4);
    rectfill(textures[4], 0, 0, SCREEN_W, SCREEN_H, makecol(255, 255, 255));
    drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
   }
   else if(cuberot > 1024 && cuberot < 1088)
   {
    clear_to_color(textures[4], makecol(255, 255, 255));
   }
   else if(cuberot > 1088)
   {
    clear_to_color(textures[4], makecol(255, 255, 255));

    alfont_textprintf_centre_ex(textures[4], introfont[1], 256, 184, makecol(255, 0, 0), -1, "This game was made by Tony Wasserka.");
    alfont_textprintf_centre_ex(textures[4], introfont[1], 256, 184+32, makecol(204, 0, 51), -1, "Thanks to everybody who likes it!");
    alfont_textprintf_centre_ex(textures[4], introfont[1], 256, 184+64, makecol(153, 0, 102), -1, "Also have a look at my other games");
    alfont_textprintf_centre_ex(textures[4], introfont[1], 256, 184+80, makecol(102, 0, 153), -1, "which you can get from");
    alfont_textprintf_centre_ex(textures[4], introfont[1], 256, 184+96, makecol(51, 0, 204), -1, "http://tonwas.freefronthost.com.");
    alfont_textprintf_centre_ex(textures[4], introfont[1], 256, 184+128, makecol(0, 0, 255), -1, "Press Escape to continue.");

    if(cuberot < 1152)
    {
     drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
     set_trans_blender(0, 0, 0, (int)((1152 - cuberot)) * 4);
     rectfill(textures[4], 0, 0, SCREEN_W, SCREEN_H, makecol(255, 255, 255));
     drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
    }
    else Config::first_start = false;
   }
  }
  if(all_time > 26)
  {
   clear_to_color(screenbmp,makecol(64,64,64));
   animate_shapes(dtime);
   translate_shapes();
   draw_shapes(screenbmp);
   for(int a = 0;a < 6;a++)
    clear_bitmap(textures[a]);
  }
  if(key[KEY_F12]) Screenshot();

  switch(Config::bpp)
  {
   case 32: switch_antialias(32); break;
   case 16: switch_antialias(16); break;
   case 15: switch_antialias(15); break;
   default: blit(screenbmp, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
  }
  clear_bitmap(screenbmp);
  if(Config::do_vsync) vsync();

#ifdef ALLEGRO_WINDOWS
  QueryPerformanceCounter((LARGE_INTEGER*)(&end_t));
  dtime = (float)(end_t - start_t) / frequency;
#else
  gettimeofday(&end_t, NULL);
  dtime = (end_t.tv_usec - start_t.tv_usec) / 1000000. + (end_t.tv_sec - start_t.tv_sec);
#endif
  all_time += dtime;
 }
}
