unit uParticles;

{$mode delphi}

interface

uses
  Classes, SysUtils, uSiluet;

const
  cSiluetProtCount = 750;
  cFig_Fall = 8*3*8;
  cFig_Cen  = 8*8;

type
TVector2 = record
  X, Y : Single;
end;

TProton = record
  Tc, Sz, X, Y : Single;
  V : TVector2;
  Color, T, Alpha : Byte;
  Timer : Integer;
  Visible : Boolean;
end;

{ TFig_Proton }

TFig_Proton = class
  ProtonS : array[1..cSiluetProtCount] of TProton;
  constructor Create;
  procedure Draw;
  procedure Update;
  procedure SetSiluet(pX, pY : Integer; pColor : Byte; Siluet : TSiluet);
  procedure Add(pX, pY : Integer; pColor : Byte);
end;

{ TFig_Fall }

TFall = record
  Angle, FAngle, Tc, Sz, X, Y : Single;
  V, F : TVector2;
  Color, T, Alpha : Byte;
  Timer : Integer;
  Visible : Boolean;
end;

TFig_Fall = class
  Proton : TFig_Proton;
  ProtonS : array[1..cFig_Fall] of TFall;
  constructor Create(PProton : TFig_Proton);
  procedure Draw;
  procedure Update;
  procedure Add(pX, pY : Integer; pColor : Byte);
end;

{ TFig_Cen }
TCen = record
  Angle, FAngle, Sz, FSz, X, Y : Single;
  V, F, D : TVector2;
  Color, Alpha : Byte;
  Timer : Integer;
  Use, Visible : Boolean;
end;

TFig_Cen = class
  Proton : TFig_Proton;
  ProtonS : array[1..cFig_Cen] of TCen;
  constructor Create(PProton : TFig_Proton);
  procedure Draw;
  procedure Update;
  procedure Add(pX, pY : Integer; pTimer, pColor : Byte);
  procedure ToGuiEl_begin(I : Integer);
  procedure toGuiEl_end(I : Integer);
end;

implementation
uses
  uGlobal, zglHeader, uGUI;

{ TFig_Cen }

constructor TFig_Cen.Create(PProton: TFig_Proton);
var
  I : Integer;
begin
  for I := 1 to cFig_Cen do
  begin
    ProtonS[I].Visible := false;
  end;
  Proton := PProton;
end;

procedure TFig_Cen.Draw;
var
  I : Integer;
begin
  for I := 1 to cFig_Cen do
  if ProtonS[I].Visible then
  with ProtonS[I] do
  if (Timer = 0) and (Use) then
    csprite2d_Draw(sFig[Color].Texture, X - D.X, Y - D.Y, Sz, Sz, Angle, sFig[Color].DR[2].R, Alpha)
  else
    csprite2d_Draw(sFig[Color].Texture, X, Y, Sz, Sz, Angle, sFig[Color].DR[2].R, Alpha);

end;

procedure TFig_Cen.Update;
var
  I : Integer;
  OnPlaceX, OnPlaceY : Boolean;
begin
  for I := 1 to cFig_Cen do
  if (ProtonS[I].Visible) then
  begin
    if ProtonS[I].Y > WinH + 50 then
      ProtonS[I].Visible := false
    else
    if ProtonS[I].Timer > 0 then
    begin
      ProtonS[I].Timer := ProtonS[I].Timer - 1;
      ProtonS[I].Y := ProtonS[I].Y - 0.5;
      if ProtonS[I].Timer = 0 then
        ToGuiEl_begin(I);
    end
    else
    begin
      OnPlaceX := (trunc(ProtonS[I].X/20) = trunc(ProtonS[I].F.X/20))
      or (ProtonS[I].X < - 50) or (ProtonS[I].X > WinW + 50);

      OnPlaceY := (trunc(ProtonS[I].Y/20) = trunc(ProtonS[I].F.Y/20))
      or (ProtonS[I].Y < - 50);

      if ProtonS[I].Use and OnPlaceX and OnPlaceY then
      begin
        ToGuiEl_end(I);
        ProtonS[I].Visible:=false;
      end
      else
      begin
        if not OnPlaceX then ProtonS[I].X := ProtonS[I].X + ProtonS[I].V.X;
        if not OnPlaceY then ProtonS[I].Y := ProtonS[I].Y + ProtonS[I].V.Y;
        if ProtonS[I].Use and (ProtonS[I].FSz < ProtonS[I].Sz) then
        begin
          ProtonS[I].Sz := ProtonS[I].Sz - 1;
          ProtonS[I].D.X := ProtonS[I].D.X - 0.5;
          ProtonS[I].D.Y := ProtonS[I].D.Y - 0.5;
        end;
      end;
    end;
  end;
end;

procedure TFig_Cen.Add(pX, pY: Integer; pTimer, pColor: Byte);
var
  I : Integer;
begin
  I := 1;
  while (I <= cFig_Fall) and (ProtonS[I].Visible) do
    I := I + 1;

  if I <= cFig_Fall then
  begin
   ProtonS[I].X := pX;
   ProtonS[I].Y := pY;


   ProtonS[I].Visible := true;
   ProtonS[I].Color := pColor;
   ProtonS[I].Angle := 0;
   ProtonS[I].Alpha := 255;
   ProtonS[I].Timer := 7 + pTimer * 9 + random(5);
   ProtonS[I].Sz := 50;
  end;
end;

procedure TFig_Cen.ToGuiEl_begin(I: Integer);
var
  Use : Boolean;

  procedure InVoid;
  begin
    ProtonS[I].F.X := ProtonS[I].X;
    ProtonS[I].F.Y := WinH + 100;
    ProtonS[I].V.X := 0;
    ProtonS[I].V.Y := 9;
    Use := false;
    ProtonS[I].Use := false;
  end;
var
  vX, vY, L : Single;
begin
  Use := true;
  case ProtonS[I].Color of
    1 :
     if hm_live < h_max_live then
     begin
       hm_live := hm_live + 1;
       ProtonS[I].F.X := hm_live * 24 + 12;
       ProtonS[I].F.Y := 8 + 16;
       ProtonS[I].FSz := 40;

       ProtonS[I].D.X := 24;
       ProtonS[I].D.Y := 31;
     end
     else
       InVoid;
    2 :
     if em_live > 0 then
     begin
       em_live := em_live - 1;
       ProtonS[I].F.X := WinW - 10;
       ProtonS[I].F.Y := 8 - 22;
       ProtonS[I].FSz := 42;

       ProtonS[I].D.X := 25;
       ProtonS[I].D.Y := 25;
     end
     else
       InVoid;
    3 :
     if hm_sh < h_max_sh then
     begin
       hm_sh := hm_sh + 1;
       ProtonS[I].F.X := h_max_live * 24 + 12 + hm_sh * 24 + 12;
       ProtonS[I].F.Y := 8 + 16;
       ProtonS[I].FSz := 38;

       ProtonS[I].D.X := 25;
       ProtonS[I].D.Y := 22;
     end
     else
       InVoid;
    4 :
     if hm_mana < h_max_mana then
     begin
       hm_mana := hm_mana + 1;
       ProtonS[I].F.X := 38 + hm_mana*20 + 10;
       ProtonS[I].F.Y := 8 + 32 + 16;
       ProtonS[I].FSz := 22;

       ProtonS[I].D.X := 25;
       ProtonS[I].D.Y := 25;
     end
     else
       InVoid;
    5 :
     if hm_exp < h_max_exp then
     begin
       hm_exp := hm_exp + 1;
       ProtonS[I].F.X := (WinW - 22 * h_max_exp) div 2 + hm_exp * 22 + 11;
       ProtonS[I].F.Y := 15;
       ProtonS[I].FSz := 32;

       ProtonS[I].D.X := 25;
       ProtonS[I].D.Y := 25;
     end
     else
       InVoid;

    6 :
      if hm_sh > 0 then
      begin
        hm_sh := hm_sh - 1;
        ProtonS[I].F.X := h_max_live * 24 + 12 + hm_sh * 24 + 12;
        ProtonS[I].F.Y := 8 + 16;
        ProtonS[I].FSz := 48;

        ProtonS[I].D.X := 25;
        ProtonS[I].D.Y := 25;
      end
      else
      if hm_live > 0 then
      begin
        hm_live := hm_live - 1;
        ProtonS[I].F.X := hm_live * 24 + 12;
        ProtonS[I].F.Y := 8 + 16;
        ProtonS[I].FSz := 48;

        ProtonS[I].D.X := 25;
        ProtonS[I].D.Y := 25;
      end
      else
        InVoid;

    7 :
     if em_heart < e_max_heart then
     begin
       em_heart := em_heart + 1;
       ProtonS[I].F.X := WinW - 36 - e_max_heart * 26 - 12 + em_heart * 26 + 13;
       ProtonS[I].F.Y := 8 + 32 + 16;
       ProtonS[I].FSz := 17;

       ProtonS[I].D.X := 25;
       ProtonS[I].D.Y := 25;
     end
     else
       InVoid;
  end;
  if Use then
  begin
    ProtonS[I].X := ProtonS[I].X + ProtonS[I].D.X;
    ProtonS[I].Y := ProtonS[I].Y + ProtonS[I].D.Y;

    vX := (ProtonS[I].F.X - ProtonS[I].X);
    vY := (ProtonS[I].F.Y - ProtonS[I].Y);
    L := sqrt(vX*vX + vY+vY) / 10;
    ProtonS[I].V.X := vX / L;
    ProtonS[I].V.Y := vY / L;
    ProtonS[I].Use := true;
  end;
end;

procedure TFig_Cen.toGuiEl_end(I: Integer);
begin
  case ProtonS[I].Color of
     1 :
      //if h_live < h_max_live then
        h_live := h_live + 1;

     2 : begin
           if e_live > 0 then
             e_live := e_live - 1;
           if e_live < 0 then
           begin

           end;
         end;

     3 :
      //if h_sh < h_max_sh then
        h_sh := h_sh + 1;
     4 :
     // if h_mana < h_max_mana then
        h_mana := h_mana + 1;
     5 :
      //if h_exp < h_max_exp then
        h_exp := h_exp + 1;

     6 :  begin
            if h_sh > 0 then
              h_sh := h_sh - 1
            else
              h_live := h_live - 1;

            if h_live < 0 then
            begin
              h_live := 0;
            end;
          end;

     7 :
      //if e_heart < e_max_heart then
        e_heart := e_heart + 1;
   end;
//   ProtonS[I].Visible := false;
end;

{ TFig_Fall }

constructor TFig_Fall.Create(PProton: TFig_Proton);
var
  I : Integer;
begin
  for I := 1 to cFig_Fall do
  begin
    ProtonS[I].Visible := false;
  end;
  Proton := PProton;
end;

procedure TFig_Fall.Draw;
var
  I : Integer;
begin
  for I := 1 to cFig_Fall do
  if ProtonS[I].Visible then
  with ProtonS[I] do
  begin
  //  writeln(Color, ' ', X, ' ', Y, ' ', Sz, ' T', T, ' A', Alpha);
    csprite2d_Draw(sFig_f[Color].Texture, X, Y, 18, 9, Angle, sFig_f[Color].DR[T].R, 255);
  end;

end;

procedure TFig_Fall.Update;
var
  I : Integer;
begin
  for I := 1 to cFig_Fall do
  if ProtonS[I].Visible then
  begin
    if ProtonS[I].Timer > 0 then
      ProtonS[I].Timer := ProtonS[I].Timer - 1
    else
    begin
      ProtonS[I].X := ProtonS[I].X + ProtonS[I].V.X;
      ProtonS[I].Y := ProtonS[I].Y + ProtonS[I].V.Y;
      ProtonS[I].V.X := ProtonS[I].F.X;
      ProtonS[I].V.Y := ProtonS[I].V.Y + ProtonS[I].F.Y;
      ProtonS[I].F.Y := ProtonS[I].F.Y + 0.025;
      ProtonS[I].Angle := ProtonS[I].Angle + ProtonS[I].FAngle;
      ProtonS[I].FAngle := ProtonS[I].FAngle + ProtonS[I].Tc;
      if ProtonS[I].Y > WinH then
        ProtonS[I].Visible := false;
    end;
  end;
end;

procedure TFig_Fall.Add(pX, pY: Integer; pColor: Byte);

  function SetProton(tX, tY, vX, vY : Single; vT : Byte) : Integer;
  var
    I : Integer;
  begin
    I := 1;
    while (I <= cFig_Fall) and (ProtonS[I].Visible) do
      I := I + 1;
    if I <= cFig_Fall then
    begin
     ProtonS[I].X := pX + tX;
     ProtonS[I].Y := pY + tY;
     ProtonS[I].V.X := 0;
     ProtonS[I].V.Y := 0;
     ProtonS[I].F.X := vX * (random(8)+3)/10;
     ProtonS[I].F.Y := vY * (random(8)+3)/10;
     ProtonS[I].Visible := true;
     ProtonS[I].Color := pColor;
     ProtonS[I].T := vT + random(4)*8;
     ProtonS[I].Angle := 0;
     ProtonS[I].FAngle := 0;
     ProtonS[I].Tc := (random - 0.5)/25;
     ProtonS[I].Timer:=11 + random(5);
     //ProtonS[I].Sz := 25;
    end;
  end;
var
  C : Integer;
begin
 { SetProton( 7,  6, -1, -0.29, 0);
  SetProton(18,  6, +1, -0.29, 1);
  SetProton( 7, 19, -1, -0.1, 2);
  SetProton(18, 19, +1, -0.1, 3); }
   C := 25 - 18;
   SetProton( C,  C,     -0.9, -0.32, 0);
   SetProton(25,  C,     +0.9, -0.32, 1);
   SetProton( C,  C + 9, -1.2, -0.29, 2);
   SetProton(25,  C + 9, +1.2, -0.29, 3);

   SetProton( C, 25,     -1.3, -0.17, 4);
   SetProton(25, 25,     +1.3, -0.17, 5);
   SetProton( C, 25 + 9, -1.1, -0.11, 6);
   SetProton(25, 25 + 9, +1.1, -0.11, 7);
end;

{ TFig_Proton }

constructor TFig_Proton.Create;
var
  I : Integer;
begin
  for I := 1 to cSiluetProtCount do
  begin
    ProtonS[I].Tc := random*pi*2;
    ProtonS[I].Visible := false;
  end;
end;

procedure TFig_Proton.Draw;
var
  I : Integer;
begin
  for I := 1 to cSiluetProtCount do
  if ProtonS[I].Visible then
  with ProtonS[I] do
  begin
    //writeln(Color, ' ', X, ' ', Y, ' ', Sz, ' T', T, ' A', Alpha);
    csprite2d_Draw(sFig_p[Color].Texture, X, Y, Sz, Sz, 0, sFig_p[Color].DR[T].R, Alpha);
  end;


end;

procedure TFig_Proton.Update;
var
  I : Integer;
begin
  for I := 1 to cSiluetProtCount do
  if ProtonS[I].Visible then
  begin
    ProtonS[I].Tc := ProtonS[I].Tc + 0.07 + random/150;
    ProtonS[I].Sz := 20 - ProtonS[I].Tc*2;
    ProtonS[I].Alpha := trunc((1 - cos(ProtonS[I].Tc)) * 120) + random(10);
    ProtonS[I].X := ProtonS[I].V.X - ProtonS[I].Sz/2;
    ProtonS[I].Y := ProtonS[I].V.Y - ProtonS[I].Sz/2;

    if ProtonS[I].Tc >= 2*Pi then
   //   ProtonS[I].Tc := 0;
      ProtonS[I].Visible := false;
  end;
end;

procedure TFig_Proton.SetSiluet(pX, pY : Integer; pColor : Byte; Siluet: TSiluet);
var
  I, C, nC, vX, vY  : Integer;

begin
  I := 1;
  C := 0;
  nC := random(3) + 4;
  while (I <= cSiluetProtCount) and (C < nC) do
  if (ProtonS[I].Visible = false) then
  begin
    vX := trunc(random*Siluet.W);
    vY := trunc(random*Siluet.H);

    if Siluet.Mask[vX][vY] then
    begin
      ProtonS[I].V.X := vX + pX;
      ProtonS[I].V.Y := vY + pY;


      ProtonS[I].Visible := true;
      ProtonS[I].Tc := random;
      ProtonS[I].Color := pColor;
      ProtonS[I].T := random(3);
      C := C + 1;
     end;
  end
  else
    I := I + 1;
end;

procedure TFig_Proton.Add(pX, pY: Integer; pColor: Byte);
var
  I, C : Integer;
begin
  I := 1;
  C := 0;
  while (I <= cSiluetProtCount) and (C < 1) do
  if (ProtonS[I].Visible = false) then
  begin
    ProtonS[I].V.X := pX;
    ProtonS[I].V.Y := pY;
    ProtonS[I].Visible := true;
    ProtonS[I].Tc := random;
    ProtonS[I].Color := pColor;
    ProtonS[I].T := random(3);
    C := C + 1;
  end
  else
    I := I + 1;
end;

end.

