unit _Effects;

interface

Uses
  QuadEngine,
  _Scene,
  _Geometry,
  _Camera,
  _Resources;

const
  Max_Particles = 1000;
  Max_Texts = 20;

type
TTextEffect = record
    Position: TVector2;
    Life: Single;
    MaxLife: Single;
    Text: String;
    Color: Cardinal;
  end;

TParticle = record
  Position: TVector2;
  Vector: TVector2;
  Size: Single;
  Life: Single;
  MaxLife: Single;
end;

TEmmiter = class
  Position: TVector2;
  Life: Byte;
  MaxLife: Byte;
end;

TEffects = class(TBasicScene)
  private
    class var intent: TEffects;
  private
    FParticle: Array [0..Max_Particles] of TParticle;
    FCurrentPart: Integer;
    FQuad: IQuadRender;
    FText: array[0..Max_Texts] of TTextEffect;
    FBoomLife: Single;
    constructor CreateEffects(QuadEngine: IQuadRender);
  public
    class function Create(QuadEngine: IQuadRender = nil): TEffects;
    destructor Destroy; override;                 
    procedure Stress(Life: Single);
    procedure Blow(Position: TVector2; Count: Integer; Distance: Single);
    procedure AddTextEffect(Text: String; Position: TVector2; Color: Cardinal; Life: Byte);       
    procedure AddSmokeEffect(Position, Vector: TVector2; Size: Single; Life: Single);
    procedure Render; override;
    procedure Update(dt: single); override;
  end;

var
  Effects: TEffects;

implementation

constructor TEffects.CreateEffects(QuadEngine: IQuadRender);
begin
  Effects:= self;
  if QuadEngine <> nil then
    FQuad:= QuadEngine;
  intent:= self;
end;

class function TEffects.Create(QuadEngine: IQuadRender = nil): TEffects;
begin
  if intent <> nil then
    Result:= intent
  else
    Result:= CreateEffects(QuadEngine);
end;

destructor TEffects.Destroy;
begin
  inherited;
end;

procedure TEffects.AddTextEffect(Text: String; Position: TVector2; Color: Cardinal; Life: Byte);
var
  i: Byte;
begin
  for i:=0 to Max_Texts do
    if FText[i].Life = 0 then
      begin
        FText[i].Position:= Position;
        FText[i].Text := Text;
        FText[i].Color:= Color;
        FText[i].Life := Life;
        FText[i].MaxLife := Life;
        Break;
      end;
end;

procedure TEffects.Stress(Life: Single);
begin
  FBoomLife:= Life;
end;

procedure TEffects.Blow(Position: TVector2; Count: Integer; Distance: Single);
var
  i: Word;
begin
  for i:= 0 to Count do
    AddSmokeEffect(Position, Vector2((Random(1000) - 500) * 0.5, (Random(1000) - 500) * 0.5) * Distance, 1, 0.5 + Random(10) / 10);
end;

procedure TEffects.AddSmokeEffect(Position, Vector: TVector2; Size: Single; Life: Single);
var
  i: Integer;
  Flag: Boolean;
begin
  Flag:= true;
  for i:= FCurrentPart + 1 to Max_Particles do
    if FParticle[i].Life = 0 then
      begin
        FParticle[i].Position:= Position;
        FParticle[i].Vector := Vector;
        FParticle[i].Size:= Size;
        FParticle[i].Life := Life;
        FParticle[i].MaxLife := Life;  
        Flag:= False;
        Break;
      end;
end;

procedure TEffects.Render;
var
  i: Integer;         
  Life: Single;
begin
  for i:= 0 to Max_Texts do
    if FText[i].Life > 0 then
      Resources.Font.TextOutAligned(
        FText[i].Position.X,
        FText[i].Position.Y + (FText[i].Life - FText[i].MaxLife) * 0.5,
        0.6,
        PAnsiChar(FText[i].Text),
        trunc(FText[i].Life / FText[i].MaxLife * $ff) * $1000000 + FText[i].Color,
        qfaCenter);   
  for i:= Max_Particles downto 0 do
    if FParticle[i].Life > 0 then
      begin
        Life:= FParticle[i].Life;
        if FParticle[i].Life > 1 then
          Life:= 1;
        Resources.SmokeTexture.DrawRot(Camera.GetX(FParticle[i].Position.X), Camera.GetY(FParticle[i].Position.Y), 1, FParticle[i].Size * Camera.Scale, trunc(Life * $ff) * $1000000 + $ffffff);
      end;
end;

procedure TEffects.Update(dt: single);
var
  i: Integer;
begin
  if (FBoomLife > 0) then
    begin
      FBoomLife:= FBoomLife - dt;
      Camera.AddShift:= Vector2(Random(1000) - 500, Random(1000) - 500) * 0.030 * FBoomLife;
    end
  else
    Camera.AddShift:= Vector2(0, 0);
  for i:=0 to Max_Texts do
    if FText[i].Life > 0 then
      FText[i].Life:= FText[i].Life - dt;
  for i:= 0 to Max_Particles do
    if FParticle[i].Life > 0 then
      begin
        FParticle[i].Life:= FParticle[i].Life - dt;
        FParticle[i].Position:=  FParticle[i].Position + FParticle[i].Vector * dt;
        FParticle[i].Size:= FParticle[i].Size + 2 * dt;
        if FParticle[i].Life < 0 then
          FParticle[i].Life:= 0;        
      end;
end;

end.
