unit uWorld;

interface
uses
  Classes, uConst, zglHeader,
  uObj, uLiveObj, uBox, uHero, uEnemy, uLevelEnd, uBomb;

procedure WorldCreate;
procedure WorldInit;
procedure Draw;
procedure Update;

procedure Level_1;

procedure Collision(Obj : TObj; NoTest : TObj = nil);
function noCollision(Rect : zglTRect) : boolean;

var
  StaticObjs : TList;
  DynamicObjs : TList;
  Fishs : TList;
  LevelEnd : TLevelEnd;
  Bomb : TBomb;

implementation

type
  TWall = class(TObj)
    constructor Create(X, Y, W, H : Single; PosX : Integer = 0; PosY : Integer = 0);
    procedure DrawBottom; override;
  end;

procedure WorldCreate;
begin
  Objs := TList.Create;
  Boxs := TList.Create;
  LiveObjs := TList.Create;
  Enemys := TList.Create;
  StaticObjs := TList.Create;
  DynamicObjs := TList.Create;
  Fishs := TList.Create;

  LevelEnd := TLevelEnd.Create;
  Hero := THero.Create;
  Bomb := TBomb.Create();
end;

procedure ClearLevel;
var
  I : Integer;
begin
  DynamicObjs.Clear;
  StaticObjs.Clear;
  for I := 0 to Boxs.Count - 1 do
    TBox(Boxs[I]).Free;
  Boxs.Clear;
  for I := 0 to Enemys.Count - 1 do
    TEnemy(Enemys[I]).Free;
  Enemys.Clear;
  for I := 0 to Fishs.Count - 1 do
    TFish(Fishs[I]).Free;
  Fishs.Clear;
  Objs.Clear;
end;

procedure WorldInit;
var
  I, O, X, Y : Integer;
  Rect : zglTRect;
  Box : TBox;
  Fish : TFish;
  Enemy : TEnemy;
begin
  ClearLevel;
  LevelEnd.Init(50, 300, 100, 100, $2050AA);

  for I := 1 to 30 do
  begin
    repeat
    Rect.X := random(WinW);
    Rect.Y := random(WinH);
    Rect.W := 50 + random(30);
    Rect.H := 30 + random(30);
    until noCollision(Rect);
    TWall.Create(Rect.X, Rect.Y, Rect.W, Rect.H);

  end;

  Rect.W := cBoxSize;
  Rect.H := cBoxSize;
  for I := 1 to 10 do
  begin
    repeat
    Rect.X := random(WinW);
    Rect.Y := random(WinH);
    until noCollision(Rect);
    Box := TBox.Create(Rect.X, Rect.Y);
    {Objs.Add(Box);
    Boxs.Add(Box);
    DynamicObjs.Add(Box);}
  end;

  Rect.W := 64;
  Rect.H := 32;
  for I := 1 to 5 do
  begin
    repeat
    Rect.X := random(WinW);
    Rect.Y := random(WinH);
    until noCollision(Rect);
    TEnemy.Create(Rect.X, Rect.Y, 30, 150, random(180), 180 + random(180)).angle := random(360);
  end;

  Rect.W := cFishSize;
  Rect.H := cFishSize;
  for I := 1 to 5 do
  begin
    repeat
    Rect.X := random(WinW);
    Rect.Y := random(WinH);
    until noCollision(Rect);
    TFish.Create(Rect.X, Rect.Y);
  end;

  Hero.Init(50, 50);

end;



procedure Level_1;
var
  I : Integer;
begin
  ClearLevel;
  LevelEnd.Init(200, 650, 100, 75, $2050AA);
  Hero.Init(200 - 32, 650);
 // for I := 0 to WinW div 70 do
 // TWall.Create(I*70, 16, 64, 64, 1, 1);
  TWall.Create(0, 10, WinW - 100, 50, 1, 1);
  TWall.Create(200, 10 + 50, 50, 100, 1, 1);

  TWall.Create(500, 10 + 50, 200, 50, 1, 1);
  TWall.Create(500, 70 + 50, 50, 100, 1, 1);
  TWall.Create(500 + 150, 70 + 50, 50, 100, 1, 1);

  TWall.Create(90, 480, 260, 50, 1, 1);
  TWall.Create(500, 480, 260, 50, 1, 1);
  TWall.Create(880, 480, 1024-880, 50, 1, 1);

  TWall.Create(90+260-50, 340, 50, 50, 1, 1);
  TWall.Create(500, 320, 50, 50, 1, 1);

  TBox.Create(570, 570);
  TBox.Create(570, 570 + 64);
  TBox.Create(570 + 64, 570);
  TBox.Create(570 + 64, 570 + 64);

  TFish.Create(570 + 32, 570 + 110);
  TFish.Create(145, 115);
  TFish.Create(600, 170);

  TBox.Create(840, 120);
  TBox.Create(350, 300);

  TEnemy.Create(140, 260, 25, 200, -43, 160).angle := 0;
  TEnemy.Create(50, 420, 45, 150, 60, 120).angle := 90;
  TEnemy.Create(800, 420, 45, 150, 60, 120).angle := 90;
  TEnemy.Create(740, 290, 30, 250, -45, 200).angle := 90;
  with TEnemy.Create(310, 470, 25, 200, 180, 380) do
  begin
    angle := 0;
    angle_m := -1;
  end;
  with TEnemy.Create(530, 470, 25, 200, 170, 380) do
  begin
    angle := 180;
    angle_m := 1;
  end;
  //WorldInit;
end;

procedure Update;
var
  I : Integer;
begin

{  for I := 0 to LiveObjs.Count - 1 do
    TLiveObj(LiveObjs[I]).UpdateView;}

  Hero.Update;
  Bomb.Update;
//  Hero.UpdateView;

  for I := 0 to Fishs.Count - 1 do
    TFish(Fishs[I]).Update;

  for I := 0 to Enemys.Count - 1 do
    TEnemy(Enemys[I]).Update;

  for I := 0 to Boxs.Count - 1 do
    TBox(Boxs[I]).Update;

  for I := 0 to DynamicObjs.Count - 1 do
    TObj(DynamicObjs[I]).DrawRectUpdate;
end;

procedure Draw;
var
  I : Integer;
begin
  LevelEnd.Draw;

  //for I := 0 to LiveObjs.Count - 1 do
  //  TLiveObj(LiveObjs[I]).DrawView;
  if Hero.Box <> nil then
    Hero.Box.DrawBottom;
  for I := 0 to Objs.Count - 1 do
    TObj(Objs[I]).DrawBottom;

  for I := 0 to Enemys.Count - 1 do
    TEnemy(Enemys[I]).DrawView;

  Bomb.Draw;

  Hero.DrawView;

  for I := 0 to Objs.Count - 1 do
    TObj(Objs[I]).Draw;

  for I := 0 to Enemys.Count - 1 do
    TEnemy(Enemys[I]).Draw;

  Hero.Draw;

  Bomb.Particle.Draw;
end;

const
  c_tcol  = 1.5;//0.05;
  c_tcol2 = 0.7;//0.025;

procedure Collision(Obj : TObj;  NoTest : TObj = nil);
var
  I, C : Integer;
  aX, aY : Single;
  tempObj : TObj;
begin
  if  Obj.zCircle.cX <  Obj.DrawRect.Wd2 then
      Obj.zCircle.cX := Obj.DrawRect.Wd2;
  if  Obj.zCircle.cX >  WinW - Obj.DrawRect.Wd2 then
      Obj.zCircle.cX := WinW - Obj.DrawRect.Wd2;

  if  Obj.zCircle.cY <  Obj.DrawRect.Hd2 then
      Obj.zCircle.cY := Obj.DrawRect.Hd2;
  if  Obj.zCircle.cY >  WinH - Obj.DrawRect.Hd2 then
      Obj.zCircle.cY := WinH - Obj.DrawRect.Hd2;

  // Static
  for I := 0 to StaticObjs.Count - 1 do
  //if TObj(StaticObjs[I]) <> Obj then
  begin
    tempObj := TObj(StaticObjs[I]);
    if col2d_RectVsCircle(tempObj.zRect, Obj.zCircle) then
    for C := 1 to 5 do
    begin
      aX := (Obj.zCircle.cX - tempObj.zCircle.cX) / tempObj.DrawRect.Wd2;
      aY := (Obj.zCircle.cY - tempObj.zCircle.cY) / tempObj.DrawRect.Hd2;
     { aX := Obj.zCircle.cX - Obj.oldCircle.cX;
      aY := Obj.zCircle.cY - Obj.oldCircle.cY; }
      Obj.zCircle.cX := Obj.zCircle.cX + aX*c_tcol;
      Obj.zCircle.cY := Obj.zCircle.cY + aY*c_tcol;

      if not col2d_RectVsCircle(tempObj.zRect, Obj.zCircle) then
        Break;
    end;
  end;
  // Dynamic
  for I := 0 to DynamicObjs.Count - 1 do
  begin
  tempObj := TObj(DynamicObjs[I]);
  if (tempObj <> Obj) and (tempObj <> NoTest) then
  begin
    if col2d_RectVsCircle(tempObj.zRect, Obj.zCircle) then
    for C := 1 to 5 do
    begin
      //aX := Obj.zCircle.cX - tempObj.zCircle.cX;
      //aY := Obj.zCircle.cY - tempObj.zCircle.cY;
      aX := (Obj.zCircle.cX - tempObj.zCircle.cX) / tempObj.DrawRect.Wd2;
      aY := (Obj.zCircle.cY - tempObj.zCircle.cY) / tempObj.DrawRect.Hd2;

      Obj.zCircle.cX := Obj.zCircle.cX + aX * c_tcol2;
      Obj.zCircle.cY := Obj.zCircle.cY + aY * c_tcol2;
      tempObj.zCircle.cX := tempObj.zCircle.cX - aX * c_tcol2;
      tempObj.zCircle.cY := tempObj.zCircle.cY - aY * c_tcol2;

    //  Collision(tempObj);
      tempObj.RectUpdate;

      if not col2d_RectVsCircle(tempObj.zRect, Obj.zCircle) then
        Break;
    end;
  end;
  end;
end;

function noCollision(Rect : zglTRect) : boolean;
var
  I : Integer;
begin
  for I := 0 to Objs.Count - 1 do
  if col2d_Rect(Rect, TObj(Objs[I]).zRect) then
  begin
    result := false;
    exit;
  end;
  result := true;
end;
{ TWall }

constructor TWall.Create(X, Y, W, H: Single; PosX : Integer = 0; PosY : Integer = 0);
begin
  X := X + PosX * trunc(W / 2);
  Y := Y + PosY * trunc(H / 2);

  Init(X, Y, W, H, $404040);
  Objs.Add(Self);
  StaticObjs.Add(Self);
end;

procedure TWall.DrawBottom;
begin
  with DrawRect do
    pr2d_Rect(X, Y+15, W, H, $202050, $FF, PR2D_FILL);

end;

end.
