unit uWeapon;

interface

uses uGLobal, VectorTypes, VectorGeometry;

type
  TBulletType = (btBullet);
  TBullet = record
    Position, Direction: array[0..2] of Double;
    Speed, Path, Distance, Power: Double;
    BulletType: TBulletType;
    Model: integer;
    Active: boolean;
    ShotedBy: TObject;

    ShotSound, HitSound: integer;
  end;

  TWeaponType = (wtMachineGun);
  TWeapon = class
  public
    Position: array [0..2] of Double;
    Distance, Speed, Power: Double;
    RotationX, RotationY: Double;
    BulletType: TBulletType;
    Owner: TObject; // Must be TPlayer
    Model: integer;
    FireSound: integer;

    Interval, IntervalElapsed: Double;

    procedure Shot(Step: Double);

    constructor Create(Player: TObject; WeaponType: TWeaponType);
  end;

var
  Weapons: array of TWeapon;
  Bullets: array of TBullet;

  procedure WeaponProcess(Step: Double);

implementation

uses uPlayer, uGame, uObjects;

procedure BulletActivate(Bullet: integer;const Active: boolean = true);
begin
  Bullets[Bullet].Active:=Active;
  call('poavisible', [Bullets[Bullet].Model, Active]);
  if Active then call('alPlay', [call('poaObjectID', [Bullets[Bullet].Model, 0]), true, Bullets[Bullet].ShotSound]);
end;

function BulletGetOrCreate(BulletType: TBulletType): integer;
var
  x: integer;
begin
  Result:=-1;
  for x := 0 to length(Bullets) - 1 do
    if (Bullets[x].Active=false)and(Bullets[x].BulletType=BulletType) then
    begin
      Result:=x;
      break;
    end;
  if Result=-1 then
  begin
    SetLength(Bullets, length(Bullets)+1);
    Bullets[length(Bullets)-1].BulletType:=BulletType;
    case BulletType of
      btBullet: Bullets[length(Bullets)-1].Model:=call('model_bullet',[]);
    end;
    Result:=length(Bullets)-1;

    Bullets[Result].ShotSound:=call('alObjectSound', [call('poaObjectID', [Bullets[Result].Model, 0]), SSMGFire,0]);
    Bullets[Result].HitSound:=call('alObjectSound', [call('poaObjectID', [Bullets[Result].Model, 0]), WoodBullet,1]);
  end;
  Bullets[Result].Path:=0;
end;

procedure WeaponProcess(Step: Double);
var
  x, y: integer;
  BulletPath, d: Double;
begin
  for x := 0 to length(Bullets) - 1 do
  if Bullets[x].Active then
  begin
    call('poaposition', [Bullets[x].Model, Bullets[x].Position[0], Bullets[x].Position[1], Bullets[x].Position[2]]);
    BulletPath:=0;
    while BulletPath<Bullets[x].Speed*Step do
    begin
      BulletPath:=BulletPath+0.01;
      for y := 0 to length(players) - 1 do
      if Players[y]<>Bullets[x].ShotedBy then
      begin
        d:=VectorLength(Bullets[x].Position[0]+Bullets[x].Direction[0]*BulletPath-players[y].Position[0],Bullets[x].Position[1]+Bullets[x].Direction[1]*BulletPath-players[y].Position[1],Bullets[x].Position[2]+Bullets[x].Direction[2]*BulletPath-players[y].Position[2]);
        if d<=Players[y].Radius then
        begin
          BulletActivate(x, false);
          players[y].Health:=Players[y].Health-Bullets[x].Power;
          call('alPlay', [call('poaObjectID', [Bullets[x].Model, 0]), true, Bullets[x].HitSound]);
          BulletPath:=Bullets[x].Speed*Step;
          Break;
        end;
      end;
      for y := 0 to length(objects) - 1 do
      if objects[y].Reflect then
      begin
        d:=VectorLength(Bullets[x].Position[0]+Bullets[x].Direction[0]*BulletPath-objects[y].Position[0],Bullets[x].Position[1]+Bullets[x].Direction[1]*BulletPath-objects[y].Position[1],Bullets[x].Position[2]+Bullets[x].Direction[2]*BulletPath-objects[y].Position[2]);
        if d<=objects[y].Radius then
        begin
          BulletActivate(x, false);
          call('alPlay', [call('poaObjectID', [Bullets[x].Model, 0]), true, Bullets[x].HitSound]);
          BulletPath:=Bullets[x].Speed*Step;
          Break;
        end;
      end;
    end;

    if Bullets[x].Active then
    begin
      for y := 0 to length(Bullets[x].Position) - 1 do
        Bullets[x].Position[y]:=Bullets[x].Position[y]+Bullets[x].Direction[y]*Bullets[x].Speed*Step;

      Bullets[x].Path:=Bullets[x].Path+Bullets[x].Speed*Step;
      If Bullets[x].Path>Bullets[x].Distance then BulletActivate(x, false);
    end;
  end;
end;

constructor TWeapon.Create(Player: TObject; WeaponType: TWeaponType);
begin
  case WeaponType of
    wtMachineGun:
    begin
      Distance:=200;
      Speed:=250;
      BulletType:=btBullet;
      Owner:=Player;
      Model:=call('model_weapon',[(Owner as TPlayer).BodyModel]);
      Interval:=0.1;
      IntervalElapsed:=0;
      Power:=1;
    end;
  end;
end;

procedure TWeapon.Shot(Step: Double);
var
  Bullet: integer;
  V: Tvector4f;
  A: TVector3F;
begin
  IntervalElapsed:=IntervalElapsed+Step;
  if IntervalElapsed<Interval then exit;

  IntervalElapsed:=0;

  MakeVector(V,Position[0],Position[1],Position[2]);
  MakeVector(A,0,1,0);
  RotateVector(v,a, DegToRad(-(Owner as TPlayer).WeaponRotationX+RotationX));

  Bullet:=BulletGetOrCreate(btBullet);
  Bullets[Bullet].Position[0]:=(Owner as TPlayer).Position[0]+V[0];
  Bullets[Bullet].Position[1]:=(Owner as TPlayer).Position[1]+V[1];
  Bullets[Bullet].Position[2]:=(Owner as TPlayer).Position[2]+V[2];

  MakeVector(V,-cos(DegToRad((Owner as TPlayer).WeaponRotationX+RotationX)), sin(DegToRad((Owner as TPlayer).WeaponRotationY-20+RotationY)), sin(DegToRad((Owner as TPlayer).WeaponRotationX+RotationX)) );
  NormalizeVector(V);
  Bullets[Bullet].Direction[0]:=v[0];
  Bullets[Bullet].Direction[1]:=v[1];
  Bullets[Bullet].Direction[2]:=v[2];
  call('glDirection', [call('poaObjectID', [Bullets[Bullet].Model,0]), v[0], v[1], v[2]]);

  Bullets[Bullet].Speed:=Speed;
  Bullets[Bullet].Distance:=Distance;
  Bullets[Bullet].Power:=Power;
  Bullets[Bullet].ShotedBy:=Owner;

  BulletActivate(Bullet);
end;

end.
