unit _Map;

interface

uses
  QuadEngine,
  _Geometry,
  _Forms,
  _Cars,
  _Resources,
  pngImage,
  _SysUtils;

const
  MAP_X = 250;
  MAP_Y = 250;
  TILE_SIZE = 64;
  MAX_BORDERS = 200;

  K_NONE = 0;
  K_SLOW = 1;
  K_FAST = 2;
  K_PULL = 3;

type
TCell = record
  Kind: Byte;
  Tile: Byte;
end;

TStartingPoint = record
  Position: TVector2;
  Angle: Single;
end;

TMap = class
  private
    Quad:IQuadRender;
    Map:Array [0..MAP_X, 0..MAP_Y] of TCell;
    procedure SetTile(x,y: Word; Tile, Kind: Byte);
  public
    Color: Cardinal;     
    Startpoints: Array [0..MAX_CARS] of TStartingPoint;
    constructor Create(QuadRender: IQuadRender);
    procedure Render(Camera: TVector2);
    function Collide(Position: TVector2): Word;
    procedure LoadMap(pngImage: String);
  end;

implementation

//TMap
constructor TMap.Create(QuadRender:IQuadRender);
var i,j: Word;
begin
  Quad:= QuadRender;
  for i:= 0 to MAP_X do
    for j:= 0 to MAP_Y do
      begin
        SetTile(i, j, 15, 0);
      end;
  Color:= $ff00ff00;
end;

procedure TMap.SetTile(X, Y: Word; Tile, Kind: Byte);
begin
  if
    (X > MAP_X) or
    (Y > MAP_Y) then exit;
  Map[X, Y].Kind:= Kind;
  Map[X, Y].Tile:= Tile;
end;

procedure TMap.LoadMap(pngImage: String);
var
  i, j,
  CarCount,
  WayPointCount: Word;
  mapImage: TpngObject;

  procedure ClearWayPoints;
  var i: Word;
  begin
    for i:= 0 to MAX_WAYPOINTS do
      WayPoint[i].Num:= 0;
  end;
  procedure AddWayPoint(Pos: TVector2; Num: Word);
  begin
    if WayPointCount > MAX_WAYPOINTS then
      Exit;
    WayPoint[WayPointCount].Position:= Pos;  
    WayPoint[WayPointCount].Num:= Num;
    Inc(WayPointCount);
  end;   
  procedure SortWayPoints;
  var
    i, j: Word;
    Temp: TWayPoint;
  begin
    for j:= 0 to MAX_WAYPOINTS do
      for i:= 0 to MAX_WAYPOINTS - 1 do
        if (WayPoint[i].Num > WayPoint[i + 1].Num) or
           ((WayPoint[i].Num = 0) and (WayPoint[i + 1].Num <> 0)) then
          begin
            Temp:= WayPoint[i];
            WayPoint[i]:= WayPoint[i + 1];
            WayPoint[i + 1]:= Temp;
          end;
    for i:= 0 to MAX_WAYPOINTS do
      if (WayPoint[i].Num>0) then
        WayPoint[i].Num:= i + 1;
  end;
  
begin
  ClearWayPoints;
  CarCount:= 0;
  WayPointCount:= 0;
  for i:=0 to MAX_CARS do
    begin
      StartPoints[i].Position:= Vector2(0, 0);
      StartPoints[i].Angle:= 0;
    end;
  mapImage:=TpngObject.Create;
  mapImage.LoadFromFile(pngImage);
  for i:= 0 to Map_X do
    for j:= 0 to Map_Y do
    case mapImage.Pixels[i,j] of
      $cccccc: SetTile(i,j,0,CELL_FREE);//clear
      $ffffff: SetTile(i,j,15,CELL_FREE);//road
      $000000: SetTile(i,j,1,CELL_WALL);//wall
      $333333: SetTile(i,j,14,CELL_WALL);//grass
      $666666: SetTile(i,j,2,CELL_FREE);//to paint
      //stripes
      $006600: SetTile(i,j,13,CELL_FREE);//Horizontal
      $005500: SetTile(i,j,12,CELL_FREE);//Vertical
      //Checkouts - road
      $aa0000: SetTile(i,j,15,CELL_CHECKOUT_A);
      $bb0000: SetTile(i,j,15,CELL_CHECKOUT_B);
      $cc0000: SetTile(i,j,15,CELL_CHECKOUT_C);
      $dd0000: SetTile(i,j,15,CELL_CHECKOUT_D);
      //Checkouts - wall
      $aaff00: SetTile(i,j,1,CELL_CHECKOUT_A);
      $bbff00: SetTile(i,j,1,CELL_CHECKOUT_B);
      $ccff00: SetTile(i,j,1,CELL_CHECKOUT_C);
      $ddff00: SetTile(i,j,1,CELL_CHECKOUT_D);
      //Checkouts - grass
      $aaaa00: SetTile(i,j,14,CELL_CHECKOUT_A);
      $bbaa00: SetTile(i,j,14,CELL_CHECKOUT_B);
      $ccaa00: SetTile(i,j,14,CELL_CHECKOUT_C);
      $ddaa00: SetTile(i,j,14,CELL_CHECKOUT_D);
      //Checkouts - none
      $aa7700: SetTile(i,j,0,CELL_CHECKOUT_A);
      $bb7700: SetTile(i,j,0,CELL_CHECKOUT_B);
      $cc7700: SetTile(i,j,0,CELL_CHECKOUT_C);
      $dd7700: SetTile(i,j,0,CELL_CHECKOUT_D);
      // Arrows
      //down
      $00ffff:SetTile(i,j,6,CELL_DOWN);
      //up
      $00ff00:SetTile(i,j,4,CELL_UP);
      //right
      $008888:SetTile(i,j,5,CELL_RIGHT);
      //left
      $008800:SetTile(i,j,7,CELL_LEFT);
      // Stops
      //down
      $ffff00:SetTile(i,j,10,CELL_STOP);//As Wall
      //up
      $ff00ff:SetTile(i,j,8,CELL_STOP);//As Wall
      //right
      $888800:SetTile(i,j,9,CELL_STOP);//As Wall
      //left
      $880088:SetTile(i,j,11,CELL_STOP);//As Wall
      //Way points - variants of red
      $000001..$0000ff:
      begin
        SetTile(i,j,15,CELL_FREE);
        AddWayPoint(
            Vector2(
                i * TILE_SIZE + TILE_SIZE / 2,
                j * TILE_SIZE + TILE_SIZE / 2),
            mapImage.Pixels[i,j]);
      end;
      $ff0000: //start point
      begin
        if (CarCount >= 0) and (CarCount <= MAX_CARS) then
          begin
            StartPoints[CarCount].Position:= Vector2(
                i * TILE_SIZE + TILE_SIZE / 2,
                j * TILE_SIZE + TILE_SIZE / 2);
            StartPoints[CarCount].Angle:= 90;
          end;
        Inc(CarCount);
        SetTile(i,j,15,CELL_FREE);
      end;
     // $00ffff: SetTile(i,j,15,CELL_FREE);
      else SetTile(i,j,0,CELL_FREE);
    end;
  SortWayPoints;
end;

procedure TMap.Render(Camera:TVector2);
var
  ViewLeft,ViewTop:single;
  MapXB,MapYB,
  MapXE,MapYE:integer;
  i,j:word;
begin
  MapXB:= trunc(Camera.X / TILE_SIZE);
  MapYB:= trunc(Camera.Y / TILE_SIZE);
  MapXE:= MapXB + trunc(Window.Width / TILE_SIZE) + 1;
  MapYE:= MapYB + trunc(Window.Height/ TILE_SIZE) + 1;
  if MapXB < 0 then MapXB:= 0;
  if MapYB < 0 then MapYB:= 0;
  if MapXE > MAP_X then MapXE:= MAP_X;
  if MapYE > MAP_Y then MapYE:= MAP_Y;
  ViewLeft:= -Camera.X;
  ViewTop := -Camera.Y;
  for i:= MapXB to MapXE do
    for j:= MapYB to MapYE do
      begin
        Resources.TileTexture.Draw(ViewLeft + i * 64, ViewTop + j * 64, Color, Map[i,j].Tile);
      end;
  //todo debug    
 { for i:= 0 to MAX_WAYPOINTS do
    if WayPoint[i].Num>0 then
      Resources.Font.TextOut(
        ViewLeft + WayPoint[i].Position.X,
        ViewTop  + WayPoint[i].Position.Y,
        1,
        PAnsiChar(IntToStr(WayPoint[i].Num)),
        $ffffffff);      }
end;

function TMap.Collide(Position: TVector2): Word;
var
  X, Y: Integer;
  Res:Word;
begin
  Res:= CELL_FREE;
  X:= Trunc(Position.X / TILE_SIZE);
  Y:= Trunc(Position.Y / TILE_SIZE);
  if X < 0 then X:= 0;
  if Y < 0 then Y:= 0;
  if X > MAP_X then X:= MAP_X;
  if Y > MAP_Y then Y:= MAP_Y;
 { case Map[X, Y].Kind of
    CELL_WALL: Res:= CELL_WALL;
    CELL_STOP: Res:= CELL_STOP;

    CELL_UP   : Res:= CELL_UP;
    CELL_DOWN : Res:= CELL_DOWN;
    CELL_LEFT : Res:= CELL_LEFT;
    CELL_RIGHT: Res:= CELL_RIGHT;

    CELL_Checkout_A: Res:= CELL_Checkout_A;
    CELL_Checkout_B: Res:= CELL_Checkout_B;
    CELL_Checkout_C: Res:= CELL_Checkout_C;
    CELL_Checkout_D: Res:= CELL_Checkout_D;
  end;
  Result:= Res;   }
  Result:= Map[X, Y].Kind;
end;

end.
