unit u_player;

interface

uses zglHeader, u_const, zglParticleEngine, u_body;

type
  TPlayerBestFriend = class (TBody)
    public
      fLastPosition: zglTRect;
      procedure Draw; override;
      procedure Update(dt: Double); override;
      constructor Create(X, Y: integer);
  end;

  TPlayer = class (TBody)
    public
      fCnt, fPt: integer;
      fParticle: peTPaticleSet;
      fInField: Boolean;
      fBestFriend: TPlayerBestFriend;
      fLastPos: array[0.. PLAYER_UPDATES - 1] of zglTPoint2D;

      property Angle: Single read fAngle;
      procedure Draw; override;
      procedure Update(dt: Double); override;
      constructor Create(X, Y: integer);
  end;

implementation

uses u_map, u_game;

constructor TPlayerBestFriend.Create(X, Y: integer);
begin
  inherited Create(Map, X, Y, CUBE_WIDTH, CUBE_HEIGHT, 0, 0, CUBE_MASS);
  fLastPosition := fPosition;
end;

procedure TPlayerBestFriend.Draw;
var i: integer;
    size: Single;
begin
  inherited;
  ssprite2d_Draw(txCube,
    fPosition.X * BLOCKSIZE - 2,
    fPosition.Y * BLOCKSIZE - 2,
      16, 16, 0);
end;

procedure TPlayerBestFriend.Update;
var i, speed: integer;
    b: boolean;
begin
  inherited;
  if fMap.fData[Round(fPosition.Y),
                  Round(fPosition.X)].Block = blField then begin

    if Self = TPlayer(fMap.fPlayer).fBestFriend then
      TPlayer(fMap.fPlayer).fBestFriend := nil;
    snd_Play(sndField);
    fPosition := fLastPosition;
    fSpeed.X := 0;
    fSpeed.Y := 0;
  end;
end;

constructor TPlayer.Create(X, Y: integer);
begin
  inherited Create(Map, X, Y, PLAYER_WIDTH, PLAYER_HEIGHT, 0, 0, PLAYER_MASS);
  fParticle := peTPaticleSet.Create('mainhero');
  fInField := False;
  fBestFriend := nil;
end;

procedure TPlayer.Draw;
var i: integer;
    size: Single;
    b: TBody;
begin
  inherited;
  for i := 0 to PLAYER_UPDATES - 1 do begin
    size := 6 + (i / PLAYER_UPDATES) * 10;
    asprite2d_Draw(txPlayer,
      fLastPos[i].X * BLOCKSIZE + (16 - size) / 2,
      fLastPos[i].Y * BLOCKSIZE + (16 - size) / 2,
      size, size, 0, 1);
  end;
  for i := 0 to PLAYER_UPDATES - 1 do begin
    size := 4 + (i / PLAYER_UPDATES) * 12;
    asprite2d_Draw(txPlayer,
      fLastPos[i].X * BLOCKSIZE + (16 - size) / 2,
      fLastPos[i].Y * BLOCKSIZE + (16 - size) / 2,
      size, size, 0, 2);
  end;
  if fBestFriend = nil then begin
    for i := 0 to Map.fBodies.Count - 1 do begin
      b := Map.fBodies.Items[i];
      if b <> Self then begin
        if m_Distance(fPosition.X, fPosition.Y,
          b.fPosition.X, b.fPosition.Y) < 2 then begin
            text_Draw(fntMain,
              fPosition.X * BLOCKSIZE , fPosition.Y * BLOCKSIZE  - 24,
            'E');
          end;
      end;
    end;
  end;
end;

procedure TPlayer.Update;
var i, speed: integer;
    d: single;
    b: boolean;
    bd: TBody;
begin
  inherited;
  if mouse_Click(M_BLEFT) then begin
    Map.CreateBullet(
      fPosition.X + fPosition.W / 2,
      fPosition.Y + fPosition.H / 2,
      m_Angle(mouse_X, mouse_Y, sX / 2, sY / 2),
      BULLET_SPEED, bcBluePortal);
    mouse_ClearState;
  end;
  if mouse_Click(M_BRIGHT) then begin
    Map.CreateBullet(
      fPosition.X + fPosition.W / 2,
      fPosition.Y + fPosition.H / 2,
      m_Angle(mouse_X, mouse_Y, sX /2, sY /2),
      BULLET_SPEED, bcOrangePortal);
    mouse_ClearState;
  end;
  if key_Down(K_A) then begin
    ApplyImpulse(-PLAYER_SPEED * dt, 0);
    fCollide := False;
  end else
  if key_Down(K_D) then begin
    ApplyImpulse(PLAYER_SPEED * dt, 0);
    fCollide := False;
  end else begin
    fCollide := true;
  end;
  if key_Down(K_SPACE) and (fGround > 2) then begin
    fGround := 0;
    ApplyImpulse(0, -PLAYER_JUMP);
  end;
  fLastPos[PLAYER_UPDATES - 1].X := fPosition.X;
  fLastPos[PLAYER_UPDATES - 1].Y := fPosition.Y;
  fCnt := fCnt + 1;
  speed := 32 - Round(m_Distance(0, 0, fSpeed.X, fSpeed.Y) * 1000);
  if speed < 1 then
    speed := 1;
  if fCnt > speed then begin

    fParticle.AddEffect((fPosition.X + fPosition.W / 2) * BLOCKSIZE ,
                          (fPosition.Y + fPosition.H / 2) * BLOCKSIZE,
                          0);

    fCnt := 0;
    for i := 0 to PLAYER_UPDATES - 2 do begin
      fLastPos[i] := fLastPos[i+1];
    end;
  end;

  b := fMap.fData[Round(fPosition.Y),
                  Round(fPosition.X)].Block = blField;
  if b and (not fInField) then begin
    snd_Play(sndField);
    if blEffects[bcBluePortal].portal <> nil then begin
      blEffects[bcBluePortal].portal.Free;
      fMap.fPortals.Remove(blEffects[bcBluePortal].portal);
      blEffects[bcBluePortal].portal := nil;
    end;
    if blEffects[bcOrangePortal].portal <> nil then begin
      blEffects[bcOrangePortal].portal.Free;
      fMap.fPortals.Remove(blEffects[bcOrangePortal].portal);
      blEffects[bcOrangePortal].portal := nil;
    end;
    for i := 0 to PLAYER_UPDATES - 1 do begin
      fLastPos[i].X := fPosition.X + m_Cos(i * 30) * (i / PLAYER_UPDATES) * 0.4;
      fLastPos[i].Y := fPosition.Y + m_Sin(i * 30) * (i / PLAYER_UPDATES) * 0.4;
    end;
    //
  end;
  fInField := b;
  if fMap.fData[Round(fPosition.Y),
                  Round(fPosition.X)].Finish then begin
    snd_StopFile(mscMainMenu);
    mscMainMenu := snd_PlayFile('Data/Music/Right Osiris.ogg');
    GameState := gsLevelDone;
  end;
  if fBestFriend = nil then begin
    for i := 0 to Map.fBodies.Count - 1 do begin
      bd := Map.fBodies.Items[i];
      if bd <> Self then begin
        if m_Distance(fPosition.X, fPosition.Y,
          bd.fPosition.X, bd.fPosition.Y) < 2 then begin
            if key_Press(K_E) then begin
              fBestFriend := TPlayerBestFriend(bd);
              key_ClearState;
            end;
          end;
      end;
    end;
  end else begin
    if Random(20) = 0 then begin
      i := Random(360);
      fParticle.AddEffect(
        (fPosition.X + fPosition.W / 2) * BLOCKSIZE + m_Cos(i)*8 ,
        (fPosition.Y + fPosition.H / 2) * BLOCKSIZE + m_Sin(i)*8,
        i);
    end;
    fBestFriend.fPosition.X := fPosition.X + fPosition.W / 2 - fBestFriend.fPosition.W / 2;
    fBestFriend.fPosition.Y := fPosition.Y + fPosition.H / 2 - fBestFriend.fPosition.H / 2;
    i := round(m_Angle(mouse_X, mouse_Y, sX / 2, sY / 2));
    d := m_Distance(0, 0, fSpeed.X, fSpeed.Y) * 2;

    fBestFriend.fSpeed.X := m_Cos(i) * d;
    fBestFriend.fSpeed.Y := m_Sin(i) * d;
    if key_Press(K_E) then begin
      fBestFriend := nil;
      key_ClearState;
    end;
  end;
end;

end.
