unit u_bullets;

interface

uses Classes, zglHeader, u_const, zglParticleEngine, zglChipmunk, u_player;

procedure AddBullet(bType: byte; X_, Y_, Angle_: Double; pl, fl: TPlayer);
procedure BulletsUpdate(dt: Double);
procedure BulletsDraw;
procedure BulletsInit;

type
  PBullet = ^TBullet;
  TBullet = record
    classOf: byte;
    speed: single;
    pBody: PcpBody;
    pShape: PcpShape;
    Time: single;
    Author, FlyTo: TPlayer;
  end;
  TSup = record
    speed, sspeed, speedp, firespeed: Single;
    r, heal: integer;
    mass: single;
    fly, destroy, sound, sndDstr: string;
    cnt: integer;
    timetolive: integer;
    flyEff, dstrEff: TEffectSet;
    snd: zglPSound;
    sndD: array of zglPSound;
  end;

var
  Bullets: TList;
  txBullet1, txBullet2: zglPtexture;
  ClassData: array[0..bullet_count-1] of TSup = (    
    (speed: 2; sspeed: 400; speedp: 0; firespeed: 100; r: 20; heal: 10; mass: 2;
     fly: ''; destroy: 'ExplosionFly|2'; sound:'BlasterFire.wav'; sndDstr:'Riccochet'; cnt: 4;  timetolive: 2000),
    (speed: 2; sspeed: 0; speedp: 0; firespeed: 1000; r: 10; heal: 100; mass: 10;
     fly: 'Fly'; destroy: 'Explosion,ExplosionFly|16,ExplosionBFly|32'; sound:'RocketFire.wav';
     sndDstr:'Explosion'; cnt: 1; timetolive: 10000)
  );

implementation

uses u_var, u_game;

procedure BulletsUpdate(dt: Double);
var b: PBullet;
    i, j: integer;
    d: single;
    v: zglTPoint2D;
    p: cpVect;
    bl: boolean;
begin
  bl := true;
  for i := Bullets.Count -1 downto 0 do begin
    b := Bullets.Items[i];
    case b^.classOf of
      bullet_easy: begin
      end;                           
      bullet_rocket: begin
        if (b^.Author = Player) and bl then begin    
          RCam.X := b^.pBody.p.x - cam_size/2;
          RCam.Y := b^.pBody.p.y - cam_size/2;

          rtarget_Set(rtarget);
            pr2d_Rect(0, 0, cam_size, cam_size, $000000, 255, PR2D_FILL);
            pr2d_Rect(0, 0, cam_size, cam_size, $FFFFFF, 128);
            asprite2d_Draw(txNoise, 0, 0, 256, 256, 0, rnd, 32);
            DrawAllShit(@RCam);
            for j := 0 to cam_size div 3 do begin
              pr2d_Line(0, j*3, cam_size, j*3, $FFFFFF, 8);
            end;
            text_DrawEx(fntMain, 5, cam_size - 25, 0, 1, u_IntToStr(Random(99999) + 100000));
          rtarget_Set(nil);
          bl := false;
        end;
        if Assigned(b^.FlyTo) then begin
          d := m_Angle(b^.FlyTo.X^, b^.FlyTo.Y^, b^.pBody.p.x, b^.pBody.p.y) * deg2rad;
          p := cpv(Cos(d) * rocket_r * dt, Sin(d) * rocket_r * dt);
          cpBodyApplyImpulse(b^.pBody, p,
            cpv(Cos(b^.pBody.a) * rocket_r * dt, Sin(b^.pBody.a) * rocket_r * dt));
          if b^.FlyTo.Health <= 0 then
            b^.Time := 0;
        end;
      end;
    end;
    with b^ do begin

       p := cpv(Cos(pBody.a) * b^.speed * dt, Sin(pBody.a) * b^.speed * dt);
      cpBodyApplyImpulse(pBody, p, cpv(0, 0));
    end;

    b^.speed := b^.speed +  ClassData[b^.classOf].speedp * dt;
    v.X := b^.pBody.p.X;
    v.Y := b^.pBody.p.Y;
    pe.CreateEffect(@ClassData[b^.classOf].flyEff, v, b^.pBody.a * rad2deg);
    b^.Time := b^.Time - dt;
    if b^.Time <= 0 then begin
      if b.Time < -100 then begin
        snd_Play(ClassData[b^.classOf].sndD[Random(ClassData[b^.classOf].cnt)]);
      end;
      pe.CreateEffect(@ClassData[b^.classOf].dstrEff, v, b^.pBody.a * rad2deg);
      cpSpaceRemoveBody(Space, b^.pBody);
      cpSpaceRemoveShape(Space, b^.pShape);
      cpBodyFree(b^.pBody);
      cpShapeFree(b^.pShape);
      Dispose(b);
      Bullets.Delete(i);
    end;
  end;
  if bl then begin
    rtarget_Set(rtarget);
      asprite2d_Draw(txNoise, 0, 0, 256, 256, 0, rnd);
    rtarget_Set(nil);
  end;
end;
procedure BulletsDraw;
var b: PBullet;
    i: integer;
begin
  for i := 0 to Bullets.Count -1 do begin
    b := Bullets.Items[i];
    case b^.classOf of
      bullet_easy: begin
        ssprite2d_Draw(txBullet1, b^.pBody.p.x - 16, b^.pBody.p.y - 4, 32, 8, b^.pBody.a * rad2deg);
      end;
      bullet_rocket: begin
        ssprite2d_Draw(txBullet2, b^.pBody.p.X - 8, b^.pBody.p.y - 8, 16, 16, b^.pBody.a * rad2deg);
      end;
    end;
  end;
end;

procedure BulletsInit;
var i, j: integer;
begin
  for i := 0 to bullet_count -1 do begin
    pe.SetEffect(@ClassData[i].flyEff, ClassData[i].fly);
    pe.SetEffect(@ClassData[i].dstrEff, ClassData[i].destroy);
    ClassData[i].snd := snd_LoadFromFile('Data/Sounds/' + ClassData[i].sound, 8);
    SetLength(ClassData[i].sndD, ClassData[i].cnt);
    for j := 0 to ClassData[i].cnt - 1 do
      ClassData[i].sndD[j] := snd_LoadFromFile('Data/Sounds/' + ClassData[i].sndDstr + u_IntToStr(j+1) + '.wav', 8);
  end;
  Bullets := TList.Create;
  Bullets.Capacity := 100;
  txBullet1 := tex_LoadFromFile('Data/Textures/Bullet1.png', $FF000000, TEX_DEFAULT_2D);
  txBullet2 := tex_LoadFromFile('Data/Textures/Bullet2.png', $FF000000, TEX_DEFAULT_2D);
end;

procedure AddBullet(bType: byte; X_, Y_, Angle_: Double; pl, fl: TPlayer);
var b: PBullet;
    p: cpVect;
begin
  new(b);
  b^.classOf := bType;
  b^.speed := ClassData[bType].speed;
  b^.Time := ClassData[bType].timetolive;
  b^.Author := pl;
  b^.FlyTo := fl;
  with b^ do begin
      pBody := cpBodyNew( ClassData[bType].mass, cpMomentForCircle(ClassData[bType].mass, ClassData[bType].r, 0, cpv(0, 0)));



      pShape := cpCircleShapeNew(pBody, ClassData[bType].r, cpv(0, 0));
      pShape.e := 1;
      pShape.u := 1;

      pBody.p.x := X_;
      pBody.p.y := Y_;
      cpBodySetAngle(pBody, Angle_ * deg2rad);  

      p := cpv(Cos(pBody.a) * ClassData[bType].sspeed , Sin(pBody.a) * ClassData[bType].sspeed);
      cpBodyApplyImpulse(pBody, p, cpv(0, 0));

      cpSpaceAddShape(space, pShape);
      cpSpaceAddBody(space, pBody);

      pShape.data := b;
      pShape.collision_type := ct_bullet;
  end;
  snd_Play(ClassData[bType].snd);
  Bullets.Add(b);
end;

end.
