unit _World;

interface

Uses
  Windows,
  _Geometry,
  OpenGL,
  _png,
  _bass,
  _2d,
  _sysUtils;

const
  map_x = 15;
  map_y = 11;
  max_armies = 15;
  max_warriors = 9;

  max_parts = 500;

  //map types
  mt_none = 0;
  mt_wall = 1;
  mt_snake = 2;//snake body
  mt_food = 3;//friendly armies + len
  mt_enemy = 5;//enemy armies/castles


type

  tmap = record
    tip:byte; //tile tip
    tile:byte;//tile picture
    anim:byte;//for picture animation      
    side:byte;//side of move
    tex:TCoord;//army zdvig
  end;

  TArmy = record
    poz:array [0..max_warriors] of TVect;//army zdvig
    tex:array [0..max_warriors] of TCoord;//army zdvig
    side:byte;//side of move
  end;

  TPart = record
    tip:byte;
    poz,vect:TVect;
    life:byte;
  end;

  TWorld = class
    private
     map:array [-1..map_x+1,-1..map_y+1] of tmap;
     Army:array [0..max_armies] of TArmy;
     Part:array [0..max_parts] of TPart;
     Snake:TCoord;//current coords of snake
     Snake_side:byte;//side of snake move  0-right 1-down 2-left 3-up
     Snake_len,Need_side:byte;//length of snake
     _army,_tiles,_parts:Cardinal;//for army texture
     procedure Find_Tiles;
     procedure add_part(poz,vect:TVect;tip:byte);
     procedure load_level;
    public
     Vis:byte;
     _AAA,_rrr:TSound;
     period,timer:integer;//tact of move
     clev,cwalls,cenemy,cfood:byte;
     game_type:byte;//0-game 1-menu
     constructor create;
     procedure Move;
     procedure Render;
     procedure Control(side:byte);
     procedure Show_Text(Text:String);
  end;

var world:TWorld;

implementation

{$REGION 'find_tiles'}
procedure  TWorld.Find_Tiles;
var i,j:integer;
begin     
  for i:= 0 to map_x do
  for j:= 0 to map_y do
   begin
    case map[i,j].tip of
      mt_none :map[i,j].tex:=Coord(3,0);
      mt_wall :map[i,j].tex:=Coord(Random(4),1);
      mt_snake:map[i,j].tex:=Coord(3,3);
      mt_food :map[i,j].tex:=Coord(1,2);
      mt_enemy:map[i,j].tex:=Coord(2+Random(2),2);

    end;
   end;
end;
{$ENDREGION}

{$REGION 'load lev'}
procedure TWorld.load_level;
var i,j:integer;
begin
 case cLev of
 0,1:begin cWalls:=0;cFood:=5;cEnemy:=0; end;
 2:begin cWalls:=4;cFood:=6;cEnemy:=1; end;
 3:begin cWalls:=7;cFood:=8;cEnemy:=2; end;
 4:begin cWalls:=10;cFood:=11;cEnemy:=3; end;
 5:begin cWalls:=12;cFood:=11;cEnemy:=4; end;
 6:begin cWalls:=15;cFood:=13;cEnemy:=5; end;
 7:begin cWalls:=15;cFood:=12;cEnemy:=5; end;
  else begin cWalls:=23;cFood:=13;cEnemy:=6; end;
 end;
 //level walls
 for i:=-1 to map_x+1 do
 begin
  map[i,-1].tip:=mt_wall;
  map[i,map_y+1].tip:=mt_wall;
 end;
 for i:=-1 to map_y+1 do
 begin
  map[-1,i].tip:=mt_wall;
  map[map_x+1,i].tip:=mt_wall;
 end;
 //armies
 for i:=0 to max_armies do
  for j:=0 to max_warriors do
   begin
    Army[i].poz[j]:=Vector(Random(20)/20-0.5,-(j+1)/(max_warriors+1)+0.5);
    Army[i].tex[j]:=Coord(Random(2),Random(4));
   end;
 //clear
 for i:=0 to map_x do
  for j:=0 to map_y do
   map[i,j].tip:=mt_none;
 //
 for i:=0 to cwalls do
  map[random(map_x-1)+1,random(map_y)].tip:=mt_wall;
 for i:=0 to cenemy do
  map[random(map_x-1)+1,random(map_y)].tip:=mt_enemy;
 for i:=0 to cfood do
  map[random(map_x-1)+1,random(map_y)].tip:=mt_food;
 find_tiles;
end;
{$ENDREGION}

{$REGION 'create'}
constructor TWorld.create;
begin
 game_type:=1;
 _bass.Load_Sound(_AAA,'snd/aaa.ogg',1,true);
 _bass.Load_Sound(_rrr,'snd/figth.ogg');
// _bass.Play_Sound(_AAA);
 LoadPNGTexture('img/war.png',_army);
 LoadPNGTexture('img/tiles.png',_tiles);
 LoadPNGTexture('img/particles.png',_parts);
 //snake;
 period:=12;
 snake_len:=1;
 snake[0]:=0;
 snake[1]:=0;
 Snake_side:=1;
 Need_side:=1;
 //lev
 cwalls:=20;
 cfood:=20;
 cenemy:=5;
 load_level;
end;
{$ENDREGION}

{$REGION 'show text'}
procedure TWorld.Show_Text(Text:String);
begin
 Vis:=100;
 menu.Panel[0].Text:=text;
end;
{$ENDREGION}

{$REGION 'move'}
procedure TWorld.Move;
var i:integer;j,z:byte;
begin
{$REGION 'snake move'}
 if game_type>0 then exit;
 timer:=timer+1;
 if (period<timer) then timer:=0;
 if (timer = 0) then
 begin
  Snake_side:=Need_side;
  case Snake_side of  //snake move
   0:Snake[0]:=Snake[0]+1;
   1:Snake[1]:=Snake[1]+1;
   2:Snake[0]:=Snake[0]-1;
   3:Snake[1]:=Snake[1]-1;
  end;
  if (Snake[0]>=-1) and //snake move collisions
     (Snake[0]<=map_x+1) and
     (Snake[1]>=-1) and
     (Snake[1]<=map_y+1) then
   case map[snake[0],snake[1]].tip of
    mt_none:begin
       map[snake[0],snake[1]].tip:=mt_snake;//set tail
       map[snake[0],snake[1]].anim:=0;//set tail
       map[snake[0],snake[1]].side:=snake_side;//for army animation
      end;
    mt_wall,mt_snake:begin //dead - to wall
       map[snake[0],snake[1]].tip:=mt_snake;//set tail
       map[snake[0],snake[1]].anim:=0;//set tail
       map[snake[0],snake[1]].side:=snake_side;//for army animation
       map[snake[0],snake[1]].side:=snake_side;//for army animation
       for i:=0 to 20 do
        add_part(Vector(snake[0]+(Random(100)-50)/500,snake[1]+(Random(100)-50)/500),Vector((Random(100)-50)/5000,(Random(100)-50)/5000),1);
       snake_len:=1;
       snake[0]:=0;
       snake[1]:=0;
       Snake_side:=1;
       Need_side:=1;
       load_level;    
       Show_TExt('Заблудились');
      end;
    mt_food:begin //eat - more length
       snake_len:=snake_len+1;
       if (Snake_len>max_armies) then Snake_len:=max_armies;
       map[snake[0],snake[1]].tip:=mt_snake;//set tail
       map[snake[0],snake[1]].anim:=0;//set tail
       map[snake[0],snake[1]].side:=snake_side;//for army animation
       map[snake[0],snake[1]].tex:=Coord(1,3);
       for i:=0 to 20 do
        add_part(Vector(snake[0]+(Random(100)-50)/500,snake[1]+(Random(100)-50)/500),Vector((Random(100)-50)/5000,(Random(100)-50)/5000),1);
       _bass.Play_Sound(_rrr);
      end;
    mt_enemy:begin //enemy - less length
       snake_len:=snake_len-2 ;
       map[snake[0],snake[1]].tip:=mt_snake;//set tail
       map[snake[0],snake[1]].anim:=0;//set tail
       map[snake[0],snake[1]].side:=snake_side;//for army animation
       map[snake[0],snake[1]].tex:=coord(map[snake[0],snake[1]].tex[0],map[snake[0],snake[1]].tex[1]+1);
       _bass.Play_Sound(_rrr); 
       for i:=0 to 20 do
        add_part(Vector(snake[0]+(Random(100)-50)/500,snake[1]+(Random(100)-50)/500),Vector((Random(100)-50)/5000,(Random(100)-50)/5000),1);
       if (snake_len<=0) or (snake_len>=100) then
       begin
        snake_len:=1;
        snake[0]:=0;
        snake[1]:=0;
        Snake_side:=1;
        Need_side:=1;
        load_level;
        Show_TExt('Убили');
       end;
      end;
   end;
{$ENDREGION}
{$REGION 'map animation'}
 z:=0;
  for i:=0 to  map_x do
   for j:=0 to  map_y do
    begin
     if (map[i,j].anim>=snake_len) and (map[i,j].tip=mt_snake) then //snake tail end
      map[i,j].tip:=mt_none;
     if (map[i,j].anim<snake_len) then //animation
      map[i,j].anim:=map[i,j].anim+1;
     if map[i,j].tip=mt_enemy then
      z:=z+1;
    end;
  if z=0 then
   begin
    cLev:=cLev+1;
    snake_len:=1;
    snake[0]:=0;
    snake[1]:=0;
    Snake_side:=1;
    Need_side:=1;
    World.Show_Text('Уровень '+IntToStr(cLev));
    load_Level;
   end;
 end;

{$ENDREGION}
{$REGION 'particles '}
 for i:=0 to max_parts do
  if part[i].tip>0 then
  begin
   if part[i].life=0 then part[i].tip:=0;
   part[i].life:=part[i].life-1;
   part[i].poz:=plus(part[i].poz,part[i].vect);
  end;
{$ENDREGION}
{$REGION 'Text'}
 if Vis>0 then Vis:=Vis-1;
 if Vis=0 then menu.Panel[0].Text:='';
{$ENDREGION}
end;
{$ENDREGION}

{$REGION 'add_part'}
procedure TWorld.add_part(poz,vect:TVect;tip:byte);
var i:integer;
begin
  for i:=0 to Max_parts do
   if part[i].tip=0 then
    begin
      part[i].tip:=tip;
      case tip of
       1:part[i].life:=40;//dim
       2:part[i].life:=40;//oskolki
      end;
      part[i].poz:=poz;
      part[i].vect:=vect;
      break;
    end;
end;
{$ENDREGION}

{$REGION 'render'}
procedure TWorld.Render;
Var
 i,j:byte;
 z:integer;
 s,zdv:TVect;
 k,a:Single;
begin
 glLoadIdentity();
 glScalef(1.3,1.3,1.3);
 glEnable(GL_Texture_2d);
 glDisable(GL_Depth_Test);
 {$REGION 'tiles'}
 glBindTexture(GL_TExture_2d,_tiles);
 glbegin(GL_Quads);
  for i:= 0 to map_x do
  for j:= 0 to map_y do
   begin
    glColor4f(5,5,5,5);
    gltexcoord2f(Map[i,j].tex[0]*0.25+0.25,Map[i,j].tex[1]*0.25     );  glvertex2f(i+0-8,j+0-6);
    gltexcoord2f(Map[i,j].tex[0]*0.25+0.25,Map[i,j].tex[1]*0.25+0.25);  glvertex2f(i+0-8,j+1-6);
    gltexcoord2f(Map[i,j].tex[0]*0.25     ,Map[i,j].tex[1]*0.25+0.25);  glvertex2f(i+1-8,j+1-6);
    gltexcoord2f(Map[i,j].tex[0]*0.25     ,Map[i,j].tex[1]*0.25     );  glvertex2f(i+1-8,j+0-6);
   end;
  for i:= 1 to 5 do
  for j:= 0 to map_y do
   begin
    glColor4f(5,5,5,5);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25     );  glvertex2f(i+0-14,j+0-6);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25+0.25);  glvertex2f(i+0-14,j+1-6);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25+0.25);  glvertex2f(i+1-14,j+1-6);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25     );  glvertex2f(i+1-14,j+0-6);
   end;
  for i:= 0 to 4 do
  for j:= 0 to map_y do
   begin
    glColor4f(5,5,5,5);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25     );  glvertex2f(i+0+8,j+0-6);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25+0.25);  glvertex2f(i+0+8,j+1-6);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25+0.25);  glvertex2f(i+1+8,j+1-6);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25     );  glvertex2f(i+1+8,j+0-6);
   end;
  j:=0;
  for i:= 0 to 25 do
   begin
    glColor4f(5,5,5,5);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25     );  glvertex2f(i+0-14,j+0-7);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25+0.25);  glvertex2f(i+0-14,j+1-7);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25+0.25);  glvertex2f(i+1-14,j+1-7);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25     );  glvertex2f(i+1-14,j+0-7);
   end;
  j:=13;
  for i:= 0 to 25 do
   begin
    glColor4f(5,5,5,5);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25     );  glvertex2f(i+0-14,j+0-7);
    gltexcoord2f(((i+j) mod 4)*0.25+0.25,1*0.25+0.25);  glvertex2f(i+0-14,j+1-7);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25+0.25);  glvertex2f(i+1-14,j+1-7);
    gltexcoord2f(((i+j) mod 4)*0.25     ,1*0.25     );  glvertex2f(i+1-14,j+0-7);
   end;
 glend;
 {$ENDREGION}
 {$REGION 'army'}
 glBindTexture(GL_TExture_2d,_army);
 glbegin(GL_Quads);
  for i:= 0 to 15 do
  for j:= 0 to 11 do
   if (map[i,j].tip=mt_snake) then
    begin
     case map[i,j].side of
      0:s:=Vector(-1, 0);
      1:s:=Vector( 0,-1);
      2:s:=Vector( 1, 0);
      3:s:=Vector( 0, 1);
     end;
     k:=1-timer/(period+1);
     for z:= 0 to max_Warriors do
      begin
       zdv:=Vector(0,(sin(k*3.14*2+z))*0.04);
       glColor4f(0,0,1*z/max_Warriors,5);
       gltexcoord2f(Army[Map[i,j].anim].tex[z][0]*0.25+0.25,Army[Map[i,j].anim].tex[z][1]*0.25     );
       glvertex2f(i-0.2-7.5+s[0]*k+Army[Map[i,j].anim].poz[z][0]+zdv[0],j-0.2-5.5+s[1]*k+Army[Map[i,j].anim].poz[z][1]+zdv[1]);
       gltexcoord2f(Army[Map[i,j].anim].tex[z][0]*0.25+0.25,Army[Map[i,j].anim].tex[z][1]*0.25+0.25);
       glvertex2f(i-0.2-7.5+s[0]*k+Army[Map[i,j].anim].poz[z][0]+zdv[0],j+0.2-5.5+s[1]*k+Army[Map[i,j].anim].poz[z][1]+zdv[1]);
       gltexcoord2f(Army[Map[i,j].anim].tex[z][0]*0.25     ,Army[Map[i,j].anim].tex[z][1]*0.25+0.25);
       glvertex2f(i+0.2-7.5+s[0]*k+Army[Map[i,j].anim].poz[z][0]+zdv[0],j+0.2-5.5+s[1]*k+Army[Map[i,j].anim].poz[z][1]+zdv[1]);
       gltexcoord2f(Army[Map[i,j].anim].tex[z][0]*0.25     ,Army[Map[i,j].anim].tex[z][1]*0.25     );
       glvertex2f(i+0.2-7.5+s[0]*k+Army[Map[i,j].anim].poz[z][0]+zdv[0],j-0.2-5.5+s[1]*k+Army[Map[i,j].anim].poz[z][1]+zdv[1]);
      end;
    end;
 glend;
{$ENDREGION}
 {$REGION 'parts'}
 glBindTexture(GL_TExture_2d,_parts);
 glbegin(GL_Quads);
 for z:=0 to Max_Parts do
  if part[z].tip>0 then
   begin
    case part[z].tip of
     1:begin
      k:=0.25;a:=1;
      if part[z].life>20 then
       k:=(40-part[z].life)/80;
      if part[z].life<20 then
       a:=(part[z].life)/20;
      i:=0;
      j:=1;
     end;
     2:;
    end;
    glColor4f(5,5,5,a);
    gltexcoord2f(i*0.5+0.5,j*0.5    );  glvertex2f(part[z].poz[0]+0.5-k-8,part[z].poz[1]+0.5-k-6);
    gltexcoord2f(i*0.5+0.5,j*0.5+0.5);  glvertex2f(part[z].poz[0]+0.5-k-8,part[z].poz[1]+0.5+k-6);
    gltexcoord2f(i*0.5    ,j*0.5+0.5);  glvertex2f(part[z].poz[0]+0.5+k-8,part[z].poz[1]+0.5+k-6);
    gltexcoord2f(i*0.5    ,j*0.5    );  glvertex2f(part[z].poz[0]+0.5+k-8,part[z].poz[1]+0.5-k-6);
   end;
 glend;
 {$ENDREGION}
end;
{$ENDREGION}

{$REGION 'Control'}
procedure TWorld.Control(side:byte);
begin
  if ((Snake_side=0) or (Snake_side=2)) and ((side=1) or (side=3))
   then Need_side:=side;
  if ((Snake_side=1) or (Snake_side=3)) and ((side=0) or (side=2))
   then Need_side:=side;
end;
{$ENDREGION}

end.
