unit uParticle;

interface
uses
  zglHeader, uMaterials, LexUtils;

type
  PParticle = ^TParticle;
  TParticle = record
    X, Y, Sz, pX, pY, pSz, Szd2, fA : single;
    Alpha, A, Gr : Byte;
    pAlpha,
    Angle, pAngle : Integer;
    Next, Prev : PParticle;
  end;

  TParticles = class
    Particle : TParticle;
    Last : PParticle;
    PCamera : PM2DPoint;
    constructor Create(const Camera : PM2DPoint);
    procedure Add(X, Y : Single; Gr : Byte);
    procedure Draw;
    procedure Update;
  end;

implementation
const
  c_minstartsize = 15;
  c_maxstartalpha = 255;

{ TParicles }

procedure TParticles.Add(X, Y: Single; Gr : Byte);
var
  AddParticle : PParticle;
begin
  if Last <> nil then
  begin
    New(Last^.Next);
    AddParticle := Last^.Next;
    AddParticle^.X := X;
    AddParticle^.Y := Y;
    AddParticle^.Gr := Gr;
    with AddParticle^ do
    begin
      Sz := c_minstartsize + random(4);
      Szd2 := Last^.Sz / 2;
      pSz := 0.4 + random(10) / 20;
      Alpha := c_maxstartalpha - random(5);
      pAlpha := -3 - random(2);
      Angle := random(36) * 10;
      pAngle := 1 + random(4);
      pX := (random(11) - 5) / 20;
      pY := (random(11) - 5) / 20;
      Prev := Last;
      Next := nil;
      A := 1;
      fA := 1;
    end;
    Last := AddParticle;
  end;
end;

constructor TParticles.Create(const Camera: PM2DPoint);
begin
  PCamera := Camera;
  Last := @Particle;
end;

procedure TParticles.Draw;
var
  UpdateParticle : PParticle;
begin
  UpdateParticle := Particle.Next;
  while UpdateParticle <> nil do
  begin
    with UpdateParticle^ do
      asprite2d_Draw(mParticle[Gr],
      X - PCamera.X - Szd2, Y - PCamera.Y - Szd2, Sz, Sz, Angle, A, Alpha);
    UpdateParticle := UpdateParticle.Next;
  end;
end;

procedure TParticles.Update;
var
  UpdateParticle, Del : PParticle;
begin
  UpdateParticle := Particle.Next;
  while UpdateParticle <> nil do
  begin
    with UpdateParticle^ do
    if Alpha < 11 then
    begin
      Prev.Next := Next;
      if Next <> nil then
        Next.Prev := Prev
      else
        Last := Prev;
      Del := UpdateParticle;
      UpdateParticle := UpdateParticle.Next;
      Dispose(Del);
    end
    else
    begin
      X := X + pX;
      Y := Y + pY;
      Angle := Angle + pAngle;
      Alpha := Alpha + pAlpha;
      Sz := Sz + pSz;
      Szd2 := Sz / 2;
      UpdateParticle := UpdateParticle.Next;
      if A < 16 then
      begin
        fA := fA + 0.2;
        A := trunc(fA);
      end;
    end;
    
  end;
end;

end.
