unit uGmArena;

interface

uses
  SysUtils, zglHeader, uGmBackground, uGmCreature, uGmBullet, uGmData;

type
  TElementType = ( EL_CREATURE, EL_DECOR, EL_BULLET );

  TElement = record
    eType : TElementType;
    e     : Pointer;
    Y     : Single;
  end;

  TBlock = record
    X, Y  : integer;
  end;

type
  TArena = class
    Background    : TBackground;
    Creatures     : array of TCreature;
    CreaturesCnt  : integer;
    Decor         : array of TDecor;
    DecorCnt      : integer;
    Elements      : array of TElement;
    ElementsCnt   : integer;
    Blocks        : array of TBlock;
    BlocksCnt     : integer;
    BuyCr         : array of PCrPat;
    BuyCrCnt      : integer;
    Money         : integer;
    Text          : array of string;
    TextCnt       : integer;

    constructor Create;
    destructor Destroy; override;
    procedure Draw;
    procedure Update;
    function SomeAction : boolean;
    function GetNextCr : TCreature;
    procedure DecorCreate( pat : PDecorPat; X, Y : integer );
    procedure LoadLev( FileName : string );
    procedure StartLev;
  end;

var
  Arena   : TArena;
  SelCr   : TCreature;
  Lev     : array of string;
  LevLen  : integer;

implementation

//==============================================================================
constructor TArena.Create;
begin
  Background    := TBackground.Create;
  CreaturesCnt  := 0;
  DecorCnt      := 0;
  ElementsCnt   := 0;
  BlocksCnt     := 0;
  BuyCrCnt      := 0;
  TextCnt       := 0;
end;

//==============================================================================
destructor TArena.Destroy;
var
  i : integer;
begin
  Background.Free;
  for i := 0 to CreaturesCnt - 1 do
    Creatures[ i ].Free;
  SetLength( Creatures, 0 );
  SetLength( Decor, 0 );  
  SetLength( Elements, 0 );
  SetLength( Blocks, 0 );
  SetLength( BuyCr, 0 );
  for i := 0 to TextCnt - 1 do
    Text[ i ] := '';
  SetLength( Text, 0 );
  inherited;
end;

//==============================================================================
procedure TArena.Draw;
var
  i, j  : integer;
  elem  : TElement;
  dec   : PDecor;
begin
  //---- создаем список элементов ----------------------------------------------
  ElementsCnt := CreaturesCnt;
  SetLength( Elements, ElementsCnt );
  for i := 0 to CreaturesCnt - 1 do
  begin
    Elements[ i ].eType := EL_CREATURE;
    Elements[ i ].e     := Creatures[ i ];
    Elements[ i ].Y     := Creatures[ i ].Y + i * 0.01;
    if Creatures[ i ].Bullet <> nil then
    begin
      INC( ElementsCnt );
      SetLength( Elements, ElementsCnt );
      Elements[ ElementsCnt - 1 ].eType := EL_BULLET;
      Elements[ ElementsCnt - 1 ].e     := Creatures[ i ].Bullet;
      Elements[ ElementsCnt - 1 ].Y     := Creatures[ i ].Bullet.Y;
    end;
  end;
  j := ElementsCnt;
  ElementsCnt := ElementsCnt + DecorCnt;
  SetLength( Elements, ElementsCnt );
  for i := 0 to DecorCnt - 1 do
  begin
    Elements[ i + j ].eType := EL_DECOR;
    Elements[ i + j ].e     := @Decor[ i ];
    Elements[ i + j ].Y     := Decor[ i ].Y;
  end;

  //---- сортируем элементы ----------------------------------------------------
  for i := 0 to ElementsCnt - 2 do
    for j := i + 1 to ElementsCnt - 1 do
      if ( Elements[ i ].Y > Elements[ j ].Y ) then
      begin
        elem := Elements[ i ];
        Elements[ i ] := Elements[ j ];
        Elements[ j ] := elem;
      end;

  //---- рисуем элементы -------------------------------------------------------
  for i := 0 to ElementsCnt - 1 do
  begin
    if Elements[ i ].eType  = EL_CREATURE then TCreature( Elements[ i ].e ).Draw;
    if Elements[ i ].eType  = EL_DECOR then
    begin
      dec := PDecor( Elements[ i ].e );
      ssprite2d_Draw( dec.Pat.Tex, dec.X - dec.Pat.OffsetX, dec.Y - dec.Pat.OffsetY, dec.Pat.Tex.Width, dec.Pat.Tex.Height, 0 );
    end;
    if Elements[ i ].eType  = EL_BULLET then TBullet( Elements[ i ].e ).Draw;
  end;
end;

//==============================================================================
procedure TArena.Update;
var
  i : integer;
begin
  Background.Update;
  for i := 0 to CreaturesCnt - 1 do
    Creatures[ i ].Update;
end;

//==============================================================================
function TArena.SomeAction : boolean;
var
  i : integer;
begin
  Result := False;
  for i := 0 to CreaturesCnt - 1 do
    with Creatures[ i ] do
      if ( State = CS_WALK ) or ( State = CS_ATACK ) or ( State = CS_DAMAGE ) or ( Bullet <> nil ) then
      begin
        Result := True;
        Exit;
      end;
end;

//==============================================================================
function TArena.GetNextCr : TCreature;
var
  i : integer;
  MaxSpeed : integer;
begin
  Result := nil;
  MaxSpeed := 0;
  for i := CreaturesCnt - 1 downto 0 do
    if ( Creatures[ i ].State <> CS_DIE ) and ( Creatures[ i ].Pohodil = False ) then
    begin
      if ( Creatures[ i ].Pat.Speed > MaxSpeed ) or ( ( Creatures[ i ].Pat.Speed = MaxSpeed ) and ( Creatures[ i ].PlayerN = 1 ) ) then
      begin
        MaxSpeed := Creatures[ i ].Pat.Speed;
        Result := Creatures[ i ];
      end;
    end;
end;

//==============================================================================
procedure TArena.DecorCreate( pat : PDecorPat; X, Y : integer );
begin
  INC( DecorCnt );
  SetLength( Decor, DecorCnt );
  Decor[ DecorCnt - 1 ].Pat := pat;
  Decor[ DecorCnt - 1 ].X   := X;
  Decor[ DecorCnt - 1 ].Y   := Y;
end;

//==============================================================================
procedure TArena.LoadLev( FileName : string );
var
  F : TextFile;
begin
  AssignFile( F, FileName );
  FileMode := $0000;
  Reset( F );

  LevLen := 0;
  while not EOF( F ) do
  begin
    INC( LevLen );
    SetLength( Lev, LevLen );
    ReadLn( F, Lev[ LevLen - 1 ] );
  end;

  CloseFile( F );
end;

//==============================================================================
procedure TArena.StartLev;
var
  n           : integer;
  pat         : PCrPat;
  decpat      : PDecorPat;
  tx, ty, pn  : integer;
begin
  n := 0;
  while n < LevLen do
  begin
    if Lev[ n ] = '[Creatures]' then
    begin
      INC( n );
      repeat
        Pat := CrPat_Get( Lev[ n ] );
        tx  := StrToInt( Lev[ n + 1 ] );
        ty  := StrToInt( Lev[ n + 2 ] );
        pn  := StrToInt( Lev[ n + 3 ] );
        if Pat <> nil then
        begin
          INC( CreaturesCnt );
          SetLength( Creatures, CreaturesCnt );
          Creatures[ CreaturesCnt - 1 ] := TCreature.Create( tx, ty, pat, pn );
        end;
        n := n + 4;
      until Lev[ n ] = '[/Creatures]';
    end;

    if Lev[ n ] = '[Blocks]' then
    begin
      INC( n );
      repeat
        tx  := StrToInt( Lev[ n ] );
        ty  := StrToInt( Lev[ n + 1 ] );
        INC( BlocksCnt );
        SetLength( Blocks, BlocksCnt );
        Blocks[ BlocksCnt - 1 ].X := tx;
        Blocks[ BlocksCnt - 1 ].Y := ty;
        n := n + 2;
      until Lev[ n ] = '[/Blocks]';
    end;

    if Lev[ n ] = '[BackDecor]' then
    begin
      INC( n );
      repeat
        decpat := DecorPat_Get( Lev[ n ] );
        tx     := StrToInt( Lev[ n + 1 ] );
        ty     := StrToInt( Lev[ n + 2 ] );
        if decpat <> nil then Background.DecorCreate( decpat, tx, ty );
        n := n + 3;
      until Lev[ n ] = '[/BackDecor]';
    end;

    if Lev[ n ] = '[Decor]' then
    begin
      INC( n );
      repeat
        decpat := DecorPat_Get( Lev[ n ] );
        tx     := StrToInt( Lev[ n + 1 ] );
        ty     := StrToInt( Lev[ n + 2 ] );
        if decpat <> nil then DecorCreate( decpat, tx, ty );
        n := n + 3;
      until Lev[ n ] = '[/Decor]';
    end;

    if Lev[ n ] = '[BuyCr]' then
    begin
      BuyCrCnt := 0;
      INC( n );
      repeat
        pat := CrPat_Get( Lev[ n ] );
        if pat <> nil then
        begin
          INC( BuyCrCnt );
          SetLength( BuyCr, BuyCrCnt );
          BuyCr[ BuyCrCnt - 1 ] := pat;
        end;
        n := n + 1;
      until Lev[ n ] = '[/BuyCr]';
    end;

    if Lev[ n ] = '[Money]' then
    begin
      Arena.Money := StrToInt( Lev[ n + 1 ] );
      n := n + 2;
    end;

    if Lev[ n ] = '[Text]' then
    begin
      TextCnt := 0;
      INC( n );
      repeat
        INC( TextCnt );
        SetLength( Text, TextCnt );
        Text[ TextCnt - 1 ] := Lev[ n ];
        n := n + 1;
      until Lev[ n ] = '[/Text]';
    end;

    INC( n );
  end;
end;

end.
