unit uSnake;

interface

uses zglHeader,
     uVar,
     LightEngine2D,
     uAdd;


procedure Snake_Init;
procedure Snake_update;
procedure Snake_step;
procedure Snake_render;
procedure Snake_LoseMember;

function CheckDotInSnake(dt : TPoint)  :  boolean;
function CheckDotInWall(dt : TPoint) : boolean;

implementation

// проверка что данная точка находится внутри змейки
function CheckDotInSnake(dt : TPoint)  :  boolean;
var i : integer;
begin
  result := false;
  for I := 0 to snake.length - 1 do
    if (snake.members[i].pos.x = dt.x) and
       (snake.members[i].pos.y = dt.y) then result := true;
end;

// проверка что данная точка находится внутри столба
function CheckDotInWall(dt : TPoint) : boolean;
begin
  result := false;
  if (dt.x = 4 ) and (dt.y = 4 ) then result:=true;
  if (dt.x = 4 ) and (dt.y = 8 ) then result:=true;
  if (dt.x = 4 ) and (dt.y = 12) then result:=true;
  if (dt.x = 8 ) and (dt.y = 4 ) then result:=true;
  if (dt.x = 8 ) and (dt.y = 12) then result:=true;
  if (dt.x = 12) and (dt.y = 4 ) then result:=true;
  if (dt.x = 12) and (dt.y = 8 ) then result:=true;
  if (dt.x = 12) and (dt.y = 12) then result:=true;
end;

function CheckNextStep() : boolean;
var i : integer;
    b : integer;
    hd : TMember;
begin
  result := true;
  hd := snake.members[snake.length - 1];
  // мысленно представляем, что змейка делает шаг
  case hd.dir of
           0 : inc(hd.pos.X);
           1 : inc(hd.pos.Y);
           2 : dec(hd.pos.X);
           3 : dec(hd.pos.Y);
  end;
  // проверяем на наличие конфиликтов (края поля, столбы, столкновения с телом)
  if (hd.pos.x < 1)or
     (hd.pos.x >15)or
     (hd.pos.y < 1)or
     (hd.pos.y >15)or
     (checkDotInSnake(hd.pos))or
     (checkDotInWall(hd.pos)) then result := false;

  // проверка на съедание бонуса
  if checkDotInSnake(bon) then
     begin
        case bon_t of
          1 : score := score + snake.length * 10;
          2 : speed := speed - 50;
          3 : interest := interest + 100;
        end;
        if bon_t <> 0 then snd_Play( sndTake, FALSE, CalcX2D( hd.pos.x * 32 + 16 ), CalcY2D( hd.pos.x * 32 + 16 ) );
        if speed < 0 then speed:=0;
        bon_t := 0;
     end;

  // проверяем на съедение точки
  if (hd.pos.x = dot.x) and
     (hd.pos.y = dot.y) then
     begin
       inc(snake.length);
       snake.members[snake.length - 1].pos := dot;
       snake.members[snake.length - 1].m_type := dot_t;
       snake.members[snake.length - 1].dir := hd.dir;

       score    := score    +   1;
       interest := interest +  60;
       inc(membs);

       snd_Play( sndMem, FALSE, CalcX2D( hd.pos.x * 32 + 16 ), CalcY2D( hd.pos.x * 32 + 16 ) );

       // создаём новую точку в пределах поля и не в теле змеи
       repeat
         dot.x := random(14) + 1;
         dot.y := random(14) + 1;
         dot_t := random(5) + 1;
       until (not CheckDotInSnake(dot)) and (not CheckDotInWall(dot));
         l5.position := le_v(dot.x*32 + 16, dot.y*32 + 16);
       // бонус
       b := random(1000);
       if (b < 350) and (bon_t = 0) then
       repeat
         bon.x := random(14) + 1;
         bon.y := random(14) + 1;
         bon_t := random(3)  + 1;
       until (not CheckDotInSnake(bon)) and (not CheckDotInWall(bon));
         l6.position := le_v(bon.x*32 + 16, bon.y*32 + 16);
     end else
       snake.members[snake.length - 1] := hd; // делаем шаг
end;

procedure Snake_init;
begin
  snake.length := 3;
  snake.members[0].pos.x := 7;
  snake.members[0].pos.y := 5;
  snake.members[0].dir   := 2;
  snake.members[0].m_type:= random(5) + 1;

  snake.members[1].pos.x := 6;
  snake.members[1].pos.y := 5;
  snake.members[1].dir   := 2;
  snake.members[1].m_type:= random(5) + 1;

  snake.members[2].pos.x := 5;
  snake.members[2].pos.y := 5;
  snake.members[2].dir   := 2;
  snake.members[2].m_type:= random(5) + 1;

  interest := 100;
  speed    := 0;
  membs    := 0;

  repeat
    dot.x := random(8) + 1;
    dot.y := random(8) + 1;
  until (not CheckDotInSnake(dot)) and (not CheckDotInWall(dot));
    dot_t := random(5) + 1;
  l5.position := le_v(dot.x*32 + 16, dot.y*32 + 16);
end;

procedure Snake_Render;
var i: integer;
    d: integer;
begin
  for I := 0 to snake.length - 1 do
    begin
       case snake.members[i].dir of
         0 : d:=3;
         1 : d:=1;
         2 : d:=2;
         3 : d:=0;
       end;
       ASprite2d_Draw(memTex[snake.members[i].m_type - 1],
                      snake.members[i].pos.x*32 + 4,
                      snake.members[i].pos.y*32,
                      24, 32, 0, d*3 + fr + 1);
    end;

end;

procedure Snake_step;
var   i: integer;
begin
  for I := 0 to snake.length - 1 do
    begin
      if i <> snake.length - 1 then
      begin
         // сдвигаем тело змейки начиная с хвоста для всех клеток кроме головы
         snake.members[i].pos := snake.members[i + 1].pos;
         snake.members[i].dir := snake.members[i + 1].dir;
      end
      else
        // смотрим куда пошла голова. если конфликт, то гама овер
        if not CheckNextStep() then
           if level = 5 then igs := igsSucceed else snake_init;
    end;

end;

procedure Snake_Update;
begin
    // новое направление для головы. запрещаем поворот на 180 градусов
    if key_down(K_UP)    and (snake.members[snake.length - 1].dir <> 1) then snake.members[snake.length - 1].dir := 3;
    if key_down(K_LEFT)  and (snake.members[snake.length - 1].dir <> 0) then snake.members[snake.length - 1].dir := 2;
    if key_down(K_DOWN)  and (snake.members[snake.length - 1].dir <> 3) then snake.members[snake.length - 1].dir := 1;
    if key_down(K_RIGHT) and (snake.members[snake.length - 1].dir <> 2) then snake.members[snake.length - 1].dir := 0;
end;

procedure Snake_LoseMember;
var i: integer;
    n: TSnake;
begin
  for i := 0 to snake.length - 1 do
      n.members[i] := snake.members[i + 1];
  n.length := snake.length - 1;
  snake := n;
  inc(interest, 100);
  dec(speed   ,  10);
  if n.length < 3 then Snake_init;
  snd_Play( sndLost, FALSE, CalcX2D(400 ), CalcY2D( 300 ) );
end;

end.
