unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, PowerTypes, PowerTiming, PowerD3D, agfunit, c_map, defs, c_mobs, PInput,
  DirectInput8, c_towers, PowerFont, particleengine, MiniFMOD;

type
  TForm1 = class(TForm)
    PowerGraph1: TPowerGraph;
    PowerTimer1: TPowerTimer;
    PowerInput1: TPowerInput;
    PowerFont1: TPowerFont;
    procedure FormCreate(Sender: TObject);
    procedure PowerTimer1RealTime(Sender: TObject; Delta: Double);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PowerTimer1Process(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  spawn : integer;

implementation

uses Math;

{$R *.dfm}
{$R res.res}

procedure TForm1.FormCreate(Sender: TObject);
var
  i : integer;
begin
  map.load('maps\default1.dmg');

  for i:=0 to map.wpCount-1 do
  if map.wp[i].ID = WPEnd then
  begin
    Xt:= map.wp[i].X;
    Yt:= map.wp[i].Y;
  end;

  PowerGraph1.Initialize;
  PowerInput1.Initialize;
  PowerFont1.LoadFromFile('arial.fnt', FMT_A8R8G8B8);

  grass:= TAGFImage.Create;
  grass.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'dirt2.jpg', FMT_R5G6B5);
  build:= TAGFImage.Create;
  build.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'build.tga', FMT_A8R8G8B8);
  nonbuild:= TAGFImage.Create;
  nonbuild.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'nonbuild.tga', FMT_A8R8G8B8);
  aura1:= TAGFImage.Create;
  aura1.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'auras\aura1.tga', FMT_A8R8G8B8);
  aura2:= TAGFImage.Create;
  aura2.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'auras\aura2.tga', FMT_A8R8G8B8);
  tree:= TAGFImage.Create;
  tree.LoadFromFile(PowerGraph1.D3DDevice8, 'tree1.tga', 128, 128, 256, 256, FMT_A1R5G5B5);
  tree.Set1bitAlpha($333333);
  tower1:= TAGFImage.Create;
  tower1.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'tower2.jpg', FMT_R5G6B5);
  bullet:= TAGFImage.Create;
  bullet.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'bullet.tga', FMT_A8R8G8B8);
  explosion:= TAGFImage.Create;
  explosion.LoadFromFile(PowerGraph1.D3DDevice8, 'explosion2.tga', 64, 64, 256, 256, FMT_A8R8G8B8);
  exp_ring:= TAGFImage.Create;
  exp_ring.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'explosion_ring.tga', FMT_A8R8G8B8);
  telep:= TAGFImage.Create;
  telep.LoadFromFileAuto(PowerGraph1.D3DDevice8, 'telep1.jpg', FMT_R5G6B5);

  pEngine:= TParticleEngine.Create(PowerGraph1);

  money:= 100;

  XMLoadFromRes('title', 'music');
  XMPlay;
end;

procedure TForm1.PowerTimer1RealTime(Sender: TObject; Delta: Double);
var
  i, j : Integer;
  m, t, p : array of TPoint;
begin
  PowerGraph1.BeginScene;

  //land
  for i:= -1 to 800 div 256+1 do
  for j:= -1 to 600 div 256+1 do
  PowerGraph1.RenderEffect(grass, 256*i + round(dX mod 256), 256*j + round(dY mod 256), 0, effectNone);

  //landies
  for i:= 0 to 127 do
  for j:= 0 to 127 do
  begin
    if ((i*32 + dx)<1024) and ((i*32 + dx + 32)>170) and ((j*32 + dy)<768) and ((j*32 + dy + 32)>0) then
    case map.cells[i, j] of
      cLandie : PowerGraph1.RenderEffect(build, i*32 + dx, j*32 + dy, 0, effectSrcAlpha);
      cNB     : PowerGraph1.RenderEffect(nonbuild, i*32 + dx, j*32 + dy, 0, effectSrcAlpha);
    end;
  end;

  // mobs
  for i:=0 to mobcount-1 do
  if ((test[i].X + dx)<1024) and ((test[i].X + dx)>170) and ((test[i].Y + dy)<768) and ((test[i].Y + dy)>0) then
  begin
    PowerGraph1.Rectangle(trunc(test[i].X + dx-32), trunc(test[i].Y + dy-16), round(test[i].Health*64/test[i].maxHealth) , 6, $FFFFFFFF, $FF008800, effectSrcAlpha);
    PowerGraph1.RotateEffect(aura1, trunc(test[i].X + dx), trunc(test[i].Y) + dy, trunc(test[i].X) + trunc(test[i].Y), 256, 0, effectSrcAlpha);
  end;

  //towers
  if length(towers) > 0 then
  for i:=0 to high(towers) do
  if ((towers[i].X + dx)<1024) and ((towers[i].X + dx + 32)>170) and ((towers[i].Y + dy)<768) and ((towers[i].Y + dy + 32)>0) then
  begin
    PowerGraph1.RenderEffectCol(tower1, towers[i].X + dx, towers[i].Y + dy, (towers[i].complete shl 24) or $FFFFFF, 0, effectDiffuseAlpha or effectSrcAlpha);
 //   PowerGraph1.Line(towers[i].X + dx +16, towers[i].Y + dy + 16, towers[i].targetX + dx, towers[i].targetY + dy, $88FFFFFF, effectSrcAlpha);
  end;

  // bullets
  if length(bullets) > 0 then
  for i:=0 to high(bullets) do
  if ((bullets[i].X + dx)<1024) and ((bullets[i].X + dx)>170) and ((bullets[i].Y + dy)<768) and ((bullets[i].Y + dy)>0) then
  PowerGraph1.RotateEffect(aura2, trunc(bullets[i].X + dx), trunc(bullets[i].Y) + dy, trunc(bullets[i].X) + trunc(bullets[i].Y), 256, $FF0000FF, 0, effectSrcAlpha);

  //tree
  if map.treecount > 0 then
  for i:=0 to map.treecount-1 do
  if ((map.tree[i].X + dx - 64)<1024) and ((map.tree[i].X + dx + 64)>170) and ((map.tree[i].Y + dy - 64)<768) and ((map.tree[i].Y + dy + 64)>0) then
  begin
    PowerGraph1.RotateEffectFix(tree, map.tree[i].X + dx, map.tree[i].Y + dy, map.tree[i].angle, map.tree[i].Size, map.treeanim[i].l1,  effectSrcAlpha);
    PowerGraph1.RotateEffectFix(tree, map.tree[i].X + dx, map.tree[i].Y + dy, map.tree[i].angle, map.tree[i].Size, map.treeanim[i].l1,  effectSrcAlpha);
  end;

  // "BASE"
  PowerGraph1.RotateEffect(telep, Xt + dx, Yt + dy, spawn, round(sin(spawn/100)*64+196), 0, effectAdd);
  PowerGraph1.RotateEffect(telep, Xt + dx, Yt + dy, -spawn, round(cos(spawn/100)*64+196), 0, effectAdd);
  PowerGraph1.RotateEffect(aura2, Xt + dx, Yt + dy, 64, 512 + round(sin(spawn/10)*512), 0, effectSrcAlpha);

  pEngine.Render(2);

  //GUI
  PowerGraph1.FillRect(0, 0, 170, 768, $FF666666, effectSrcAlpha);


  //minimap
  PowerGraph1.FillRect(0, 0, 150, 150, $FF000000, effectSrcAlpha);

  SetLength(m, 0);
  SetLength(t, 0);
  SetLength(p, 0);

  if length(towers) > 0 then
  for i:=0 to high(towers) do
  begin
    SetLength(t, length(t)+1);
    t[i].X:= trunc(towers[i].X / 16);
    t[i].Y:= trunc(towers[i].Y / 16);
    if Length(t)=256 then
    begin
      PowerGraph1.PutPixel(t, $FF0000FF, effectSrcAlpha);
      SetLength(t, 0);
    end;
  end;

  for i:=0 to mobcount-1 do
  begin
    SetLength(m, length(m)+1);
    m[i].X:= trunc(test[i].X / 16);
    m[i].Y:= trunc(test[i].Y / 16);
    if Length(m)=256 then
    begin
      PowerGraph1.PutPixel(m, $FFFFFF00, effectSrcAlpha);
      SetLength(m, 0);
    end;
  end;

  //landies
  for i:= 0 to 127 do
  for j:= 0 to 127 do
  begin
    if map.cells[i, j] = cLandie then
    begin
      SetLength(p, length(p)+1);
      p[high(p)].X:= i*2;
      p[high(p)].Y:= j*2;
      if Length(p)=256 then
      begin
        PowerGraph1.PutPixel(p, $FFFFFFFF, effectSrcAlpha);
        SetLength(p, 0);
      end;
    end;
  end;

  PowerGraph1.PutPixel(p, $FFFFFFFF, effectSrcAlpha);
  PowerGraph1.PutPixel(m, $FF0000FF, effectSrcAlpha);
  PowerGraph1.PutPixel(t, $FFFFFF00, effectSrcAlpha);

  //stats
  PowerFont1.TextOut('Кол-во пушек: ' + IntToStr(length(towers)), 5, 160, $88FFFFFF);
  PowerFont1.TextOut('Кол-во мобов: ' + IntToStr(length(test)), 5, 175, $88FFFFFF);
  PowerFont1.TextOut('Кол-во денег: ' + IntToStr(Money) + '$', 5, 190, $88FFFFFF);
  PowerFont1.TextOut('Раунд: ' + IntToStr(game_round), 5, 220, $88FFFFFF);
  PowerFont1.TextOut('След. раунд: ' + IntToStr((3000-spawn) div 60), 5, 235, $88FFFFFF);
  PowerFont1.TextOut('Повреждение: ' + IntToStr(corrupted), 5, 250, $88FFFFFF);

  PowerGraph1.EndScene;
  PowerGraph1.Present;

  Caption:= IntToStr(PowerTimer1.FrameRate)
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Xpos:= X;
  Ypos:= Y;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  tx, ty : Integer;
begin
  tx:= (xpos - dx) div 32;
  ty:= (ypos - dy) div 32 + 1;

  if (map.cells[tx, ty] = cLandie) and (Money >= 10) then
  begin
    map.cells[tx, ty]:= cFree;
    AddTower(tx*32, ty*32);
    Money:= Money - 10;
  end;
end;

procedure TForm1.PowerTimer1Process(Sender: TObject);
var
  i, q : integer;
begin
  if spawn > 3000 then
  begin
    for i:= 0 to game_round*5 do
    begin
      mobcount:= length(test)+1;
      SetLength(test, mobcount);
      test[mobcount-1].Init(WPStart-random(4));
    end;
    spawn:= 0;
    inc(game_round);
  end else inc(spawn);

  PowerInput1.Update;

  if PowerInput1.Keys[DIK_UP] then accY:= accY + 2;
  if PowerInput1.Keys[DIK_DOWN] then accY:= accY - 2;
  if PowerInput1.Keys[DIK_LEFT] then accX:= accX + 2;
  if PowerInput1.Keys[DIK_RIGHT] then accX:= accX - 2;

  dXs:= dXs + accX;
  dYs:= dYs + accY;

  dX:= trunc(dXs);
  dY:= trunc(dYs);

  accX:= accX/1.15;
  accY:= accY/1.15;


  //dead
  q:=0;
  for i:=0 to length(bullets)-1 do
  if bullets[i].dead then begin
                            inc(q);
                            bullets[i]:= bullets[length(bullets)-q];
                          end;
  SetLength(bullets, length(bullets)-q);  //delete died bullets

  q:=0;
  for i:=0 to mobcount-1 do
  if test[i].dead then begin
                         inc(q);
                         test[i]:= test[mobcount-q];
                       end;
  mobcount:= mobcount-q;
  SetLength(test, mobcount);  //delete died mobs

  // process
  pEngine.Process(30, dX, dY);
  map.process(0.5);

  for i:=0 to mobcount-1 do
  test[i].Process(0.5);

  for i:=0 to high(towers) do
  towers[i].process(1);

  for i:=0 to high(bullets) do
  bullets[i].process(1);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  XMStop;
  XMFree;
end;

end.
