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

#include "snake.h"

float score_size = 1;

Snake snake[8];

SnakeTarget target;

Snake::Snake(int _num) : num(_num)
{
 float ang = (float)(rand() % 628000) / 100000.;

 x[0] = rand() % SCREEN_W;
 y[0] = rand() % (SCREEN_H - Config::num_snakes * 15 - 5);

 for(int a = 1;a < MAX_SCORE;a++)
 {
  x[a] = x[a - 1] - cosf(ang);
  y[a] = y[a - 1] - sinf(ang);
 }
 if(Config::colconfig_method[num] != 3)
  color = makecol(Config::r[num], Config::g[num], Config::b[num]);
 else color = makecol(rand() % 256, rand() % 256, rand() % 256);

 angle = ang;

 state = false;
 score = 0;
 new_score = 50;
}

void Snake::Logic(double d_time)
{
 bool do_fast = false;

 if(x[0] > SCREEN_W) x[0] -= SCREEN_W;
 else if(x[0] < 0) x[0] += SCREEN_W;
 if(y[0] > SCREEN_H - Config::num_snakes * 15 - 5) y[0] -= SCREEN_H - Config::num_snakes * 15 - 5;
 else if(y[0] < 0) y[0] += SCREEN_H - Config::num_snakes * 15 - 5;

 if(ABS(x[0] - target.x) < 7)
  if(ABS(y[0] - target.y) < 7)
  {
   new_score += 10;
   x[(int)new_score + min_length] = x[(int)new_score + min_length - 1];
   y[(int)new_score + min_length] = y[(int)new_score + min_length - 1];
   target.x = rand() % SCREEN_W;
   target.y = rand() % (SCREEN_H - Config::num_snakes * 15 - 5);
   target.r = 0;
  }
  for(int snum = 0;snum < Config::num_snakes;snum++)
   if(num != snum && !snake[snum].state)
    for(int pnum = 0;pnum < snake[snum].score + min_length;pnum++)
     if(ABS(x[0] - snake[snum].x[pnum]) < 10)
      if(ABS(y[0] - snake[snum].y[pnum]) < 10)
      {
       new_score -= d_time;
       break;
      }

 for(int pnum = 20;pnum < new_score + min_length;pnum++)
   if(ABS(x[0] - x[pnum]) < 10)
    if(ABS(y[0] - y[pnum]) < 10)
    {
     new_score -= d_time;
     break;
    }
 if(score < new_score) score += d_time;
 if(score > new_score) score -= d_time;
 if(ABS(score - new_score) < d_time + 0.1) score = new_score;
 if(score < 0) state = true;

 if(!Config::is_cpu[num])
 {
  if(key[Config::keys[num].right]) angle += d_time / 20;

  if(key[Config::keys[num].fast ]) do_fast = true;
  if(key[Config::keys[num].left ]) angle -= d_time / 20;

  x[0] += cosf(angle) * d_time * (1 + do_fast);
  y[0] += sinf(angle) * d_time * (1 + do_fast);
 }
 else
 {
  float new_angle = angle;
  int dx = (int)(target.x - x[0]), dy = (int)(target.y - y[0]);

  if(ABS(dx) > (SCREEN_W >> 1)) dx += SCREEN_W * SGN((SCREEN_W >> 1) - dx);
  if(ABS(dy) > ((SCREEN_H - Config::num_snakes * 15 - 5) >> 1))
   dy += (SCREEN_H - Config::num_snakes * 15 - 5) * SGN(((SCREEN_H - Config::num_snakes * 15 - 5) >> 1) - dy);

  new_angle = atan2f(dy, dx);

  float differ = angle - new_angle;

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

  if(differ < 3.14) angle -= d_time / 20;
  else angle += d_time / 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;

  x[0] += cosf(angle) * d_time * (1 + do_fast);
  y[0] += sinf(angle) * d_time * (1 + do_fast);
 }
 for(int a = 1;a <= (int)score + min_length;a++)
 {
  float angle = atan2f(y[a] - y[a - 1], x[a] - x[a - 1]);

  if(ABS(x[a] - x[a - 1]) > SCREEN_W >> 1) angle = 3.14 + angle;
  if(ABS(y[a] - y[a - 1]) > (SCREEN_H - Config::num_snakes * 15 - 5) >> 1) angle = -angle;

  x[a] = x[a - 1] + cosf(angle);
  y[a] = y[a - 1] + sinf(angle);
  if(x[a] > SCREEN_W) x[a] -= SCREEN_W;
  if(x[a] < 0) x[a] += SCREEN_W;
  if(y[a] > SCREEN_H - Config::num_snakes * 15 - 5) y[a] -= SCREEN_H - Config::num_snakes * 15 - 5;
  if(y[a] < 0) y[a] += SCREEN_H - Config::num_snakes * 15 - 5;
 }
 if(angle > 6.28) angle -= 6.28;
 else if(angle < 0) angle += 6.28;
}

void Snake::Draw(BITMAP *bmp, double d_time)
{
 for(int a = 1;a < score + min_length;a++)
  circlefill(bmp, (int)x[a], (int)y[a], 5, color);

 if(x[0] < 75)
 {
  hline(bmp, SCREEN_W - 20, (int)y[0], SCREEN_W - 10,color);
  line(bmp, SCREEN_W - 15, (int)y[0] - 5, SCREEN_W - 10, (int)y[0], color);
  line(bmp, SCREEN_W - 15, (int)y[0] + 5, SCREEN_W - 10, (int)y[0], color);
  textprintf_ex(bmp, font, SCREEN_W - 37 , (int)y[0] - 4, color, -1, "P%d",
                num + 1);
 }
 else if(x[0] > SCREEN_W - 75)
 {
  hline(bmp, 20, (int)y[0], 10,color);
  line(bmp, 15, (int)y[0] - 5, 10, (int)y[0], color);
  line(bmp, 15, (int)y[0] + 5, 10, (int)y[0], color);
  textprintf_ex(bmp, font, 22 , (int)y[0] - 4, color, -1, "P%d", num + 1);
 }
 if(y[0] < 75)
 {
  vline(bmp, (int)x[0], SCREEN_H - Config::num_snakes * 15 - 25, SCREEN_H - Config::num_snakes * 15 - 15,color);
  line(bmp, (int)x[0] - 5, SCREEN_H - Config::num_snakes * 15 - 20, (int)x[0], SCREEN_H - Config::num_snakes * 15 - 15, color);
  line(bmp, (int)x[0] + 5, SCREEN_H - Config::num_snakes * 15 - 20, (int)x[0], SCREEN_H - Config::num_snakes * 15 - 15, color);
  textprintf_ex(bmp, font, (int)x[0] - 4, SCREEN_H - Config::num_snakes * 15 - 33 , color, -1, "P%d",
                num + 1);
 }
 else if(y[0] > SCREEN_H - Config::num_snakes * 15 - 5 - 75)
 {
  vline(bmp, (int)x[0], 20, 10,color);
  line(bmp, (int)x[0] - 5, 15, (int)x[0], 10, color);
  line(bmp, (int)x[0] + 5, 15, (int)x[0], 10, color);
  textprintf_ex(bmp, font, (int)x[0] - 4, 22 , color, -1, "P%d", num + 1);
 }
}

void Snake::DrawScore(BITMAP *bmp, double d_time)
{
 rectfill(bmp, 100, SCREEN_H + (num - Config::num_snakes) * 15,
          100 + (int)(score / score_size),
          SCREEN_H + (num - Config::num_snakes) * 15 + 10,color);

 textprintf_ex(bmp, font, 10, SCREEN_H + (num - Config::num_snakes) * 15, makecol(255, 255, 255), -1,
               "Player %d: ", num + 1);
 textprintf_ex(bmp, font, 120 + (int)(score / score_size),
               SCREEN_H + (num - Config::num_snakes) * 15, makecol(255, 255, 255), -1,
               "%.1f", score / 10);
}
