unit uGMPM;

{$mode delphi}

interface
uses
  Classes, uGMPL, uGMPLib, uGMPLE, uGMPObject, ugmpao;

const
  WallCountX = 64;
  WallCountY = 42;

type
  { TMap }
  TMusicBox = record
    X, Y, S : Integer;
  end;

  TMap = class
    ObjRect : array[0..10,0..10] of TList;
    GH : TGMPL;
    Portal : TPortal;
    ListStObj : TList;
    MusicBox : array of TMusicBox;
    cMaxY : Integer;

    Wall : array[0..WallCountX,0..WallCountY] of Boolean;
    constructor Create;
    procedure Clear;
    function AddH(X, Y : Single) : TGMPL;
    function AddE(X, Y : Single) : TGMPL;
    function AddBall(X, Y, W, H : Single) : TGMPObject;
    function AddBox(X, Y, W, H : Single): TGMPObject;

    function AddPortal(X, Y : Single; C : Integer = 0) : TGMPObject;
    function AddPortalKey(X, Y : Single; K : Byte) : TGMPObject;
    function AddDoor(X, Y, W, H : Single; Color : Integer): TGMPObject;
    function AddDoorKey(X, Y : Single; Color : Integer): TGMPObject;
    function AddBonus(X, Y : Single; T : Integer) : TGMPObject;
    function cord2tile(P : ZPos) : TPos;
    procedure Calc;
    function FreeLineToObj(A, B : TGMPObject) : Boolean;
    procedure DrawMusicBox;
  end;

implementation
uses
  uGMP, uGlobal, uGMPPart, zglHeader, GSound;
{ TMap }

constructor TMap.Create;
begin
  ListStObj := TList.Create;
end;

procedure TMap.Clear;
var
  I : Integer;
begin
  for I := 0 to ListStObj.Count - 1 do
    TGMPObject(ListStObj.Items[I]).Free;

  for I := 0 to ListLObj.Count - 1 do
    TGMPObject(ListLObj.Items[I]).Free;

  for I := ListBul.Count - 1 downto 0 do
    TGMPObject(ListBul.Items[I]).Free;

  for I := ListParLine.Count - 1 downto 0 do
    TParLine(ListParLine.Items[I]).Free;

  for I := ListPar.Count - 1 downto 0 do
    TParRect(ListPar.Items[I]).Free;

  for I := 1 to ListParGr.Count - 1 do
    TParRect(ListParGr.Items[I]).Free;

  for I := 1 to ListAct.Count - 1 do
    TGMPObject(ListAct.Items[I]).Free;

  ListMapObj.Clear;
  ListBul.Clear;
  ListParLine.Clear;
  ListPar.Clear;
  ListParGr.Clear;

  ListStObj.Clear;
  ListLObj.Clear;

  ListAct.Clear;

  Portal := nil;

  SetLength(MusicBox, 0);

  ListMapObj.Add(gh);

  cMaxY := 65;
end;

function TMap.AddH(X, Y: Single)  : TGMPL;
begin
  Y := Y + cMaxY;
  GH.Pos.SetValue(X, Y);
  GH.Update;
  result := GH;
end;

function TMap.AddE(X, Y: Single)  : TGMPL;
begin
  Y := Y + cMaxY;
  result := TGMPLE.Create(X, Y);
  ListMapObj.Add(result);
  ListLObj.Add(result);
end;

function TMap.AddBall(X, Y, W, H: Single) : TGMPObject;
begin

end;

function TMap.AddBox(X, Y, W, H: Single) : TGMPObject;
begin
  Y := Y + cMaxY;
  result := TGMPObject.Create;
  result.Color := $FFFFFF;
  result.Size.x := W;
  result.Size.y := H;
  result.Pos.x := X;
  result.Pos.y := Y;
  result.Update;
  ListMapObj.Add(result);
  ListStObj.Add(result);
end;

function TMap.AddPortal(X, Y: Single; C : Integer = 0): TGMPObject;
begin
  Portal := TPortal.Create(X, Y + cMaxY);
  Result := Portal;
  ListAct.Add(Portal);
  AddBox(X, Y - cportal_h / 2 - cportal_h / 10, cportal_w + cportal_h / 2, cportal_h / 5 + 2);
  AddBox(X - cportal_w + cportal_h / 4.5, Y, cportal_h / 5 + 2, cportal_h + 2);
  AddBox(X + cportal_w - cportal_h / 4.5, Y, cportal_h / 5 + 2, cportal_h + 2);
end;

function TMap.AddPortalKey(X, Y: Single; K : Byte): TGMPObject;
begin
  Y := Y + cMaxY;
  Result := TPortalKey.Create(X, Y, K);
  ListAct.Add(Result);
end;

function TMap.AddDoor(X, Y, W, H: Single; Color: Integer): TGMPObject;
begin
  Y := Y + cMaxY;
  Result := TDoor.Create(X, Y, W, H, Color);
  ListAct.Add(Result);
  ListMapObj.Add(TDoor(Result).Obj);
end;

function TMap.AddDoorKey(X, Y: Single; Color: Integer): TGMPObject;
begin
  Y := Y + cMaxY;
  Result := TDoorKey.Create(X, Y, Color);
  ListAct.Add(Result);
end;

function TMap.AddBonus(X, Y: Single; T: Integer): TGMPObject;
begin
  Y := Y + cMaxY;
  Result := TBonus.Create(X, Y, T);
  ListAct.Add(Result);
end;

function TMap.cord2tile(P: ZPos): TPos;
  function norm_m(m, m_max : Integer) : Integer;
  begin
    result := m div cwallsize;
    if result < 0 then result := 0
    else
    if result > m_max then result := m_max;
  end;
begin
  Result.x := norm_m(trunc(P.x), WallCountX);
  Result.y := norm_m(trunc(P.y), WallCountY);
end;

procedure TMap.Calc;
var
  I, X, Y : Integer;
  A, B : TPos;
  Pos, SizeD2, Size : ZPos;
  IMX, IMY, MS, MBS, MX, MY, MW, MH : Integer;
begin
  for X := 0 to WallCountX do
  for Y := 0 to WallCountY do
    Wall[X, Y] := false;

  for I := 0 to ListStObj.Count - 1 do
  begin
    Pos    := TGMPObject(ListStObj.Items[I]).Pos;
    SizeD2 := TGMPObject(ListStObj.Items[I]).Size / 2;
    A := cord2tile(Pos - SizeD2);
    B := cord2tile(Pos + SizeD2);
    for X := A.x to B.x do
    for Y := A.y to B.y do
      Wall[X, Y] := true;
  end;

  for I := 0 to ListAct.Count - 1 do
  if TDoorKey(ListAct.Items[I]) is TDoorKey then
  for X := 0 to ListAct.Count - 1 do
  if (X <> I)
  and (TDoor(ListAct.Items[X]) is TDoor)
  and (TDoor(ListAct.Items[X]).ColorN = TDoorKey(ListAct.Items[I]).ColorN) then
    TDoorKey(ListAct.Items[I]).Door := ListAct.Items[X];


  for I := 0 to ListStObj.Count - 1 do
  begin
    Size := TGMPObject(ListStObj.Items[I]).Size;
    if  (Size.X >= c_music_box_min)
    and (Size.Y >= c_music_box_min) then
    begin
      if Size.X < Size.Y then
        MBS := trunc(Size.X)
      else
        MBS := trunc(Size.Y);

      if MBS > c_music_box_max then
        MBS := c_music_box_max;

      Pos := TGMPObject(ListStObj.Items[I]).Pos;
      MW := trunc(Size.X / MBS);
      MH := trunc(Size.Y / MBS);
      MX := trunc(Pos.X - (MW /2 ) * MBS + 2 );
      MY := trunc(Pos.Y - (MH /2 ) * MBS + 2);
      MS := Length(MusicBox);
      SetLength(MusicBox, MS + MW * MH + 1);
      MW := MW - 1;
      MH := MH - 1;

      for IMX := 0 to MW do
      for IMY := 0 to MH do
      begin
        MusicBox[MS].x := MX + IMX * MBS;
        MusicBox[MS].y := MY + IMY * MBS;
        MusicBox[MS].s := MBS - 4;
        MS := MS + 1;
      end;

    end;

  end;
  cMaxY := 0;
end;

function TMap.FreeLineToObj(A, B: TGMPObject): Boolean;
var
  I : Integer;
  vL : zglTLine;
  vP : zglTPoint2D;
begin
  vL.x0 := A.Pos.x;
  vL.y0 := A.Pos.y;
  vL.x1 := B.Pos.x;
  vL.y1 := B.Pos.y;

  result := true;

  for I := 0 to ListMapObj.Count - 1 do
  if  (ListMapObj.Items[I] <> A)
  and (ListMapObj.Items[I] <> B)
  and col2d_LineVsRect(vL, TGMPObject(ListMapObj.Items[I]).Rect, @vP) then
  begin
    result := false;
    Break;
  end;
end;

procedure TMap.DrawMusicBox;
var
  I : Integer;
  Alpha : Integer;
begin
  Alpha := trunc(GSound.Sd_Level * 275);
  if Alpha > 255 then
  Alpha := 255;
  for I := 0 to Length(MusicBox) - 1 do
    pr2d_Rect(MusicBox[I].X, MusicBox[I].Y, MusicBox[I].S, MusicBox[I].S, $FF2F25, Alpha, PR2D_FILL);
end;

end.

