unit units;

interface

uses vfm, variables, constants, path_map, global, OpenGL, respawns, records, files_names;

type
  TUnit = class
    path_pos, num : integer;
    path_pos_f : single;
    respawn_number : integer;
    body1, body2, wings1, wings2 : TObject;
    angle : single;
    hor_s, ver_s : integer;
    depth_s : single;
    cell_s, speed_hor, speed_ver, speed_angle : single;
    params : REnemyParams;
    tx, ty : integer;
    killed : boolean;
  public
    constructor Create(mx, my : integer; par : REnemyParams; big : boolean);
    procedure Kill;
    procedure Move;
    procedure Redraw;
  end;

var
  gEnemys : array[1..max_enemys] of TUnit;
  iEnemys : array[1..max_enemys] of boolean;
  total_enemys : integer;

implementation

constructor TUnit.Create(mx, my : integer; par : REnemyParams; big : boolean);
begin
inherited Create;  
with pathmap.map[mx, my] do
  begin walk := true; build := false; end;  

body1 := TObject.CreateStandart(mx, my, mesh_enemy_body1_id);
body2 := TObject.CreateStandart(mx, my, mesh_enemy_body2_id);
wings1 := TObject.CreateStandart(mx, my, mesh_enemy_wings1_id);
wings2 := TObject.CreateStandart(mx, my, mesh_enemy_wings2_id);

body1.sx := par.scale; body1.sy := body1.sx; body1.sz := body1.sx;
if big then
  begin
    body1.color.r := 0.2;  body1.color.g := 0.2;  body1.color.b := 0.2;
    wings1.color.r := 0; wings1.color.g := 0; wings1.color.b := 0;
    body2.color.g := 0;  body2.color.b := 0;
    wings2.color.g := 0; wings2.color.b := 0;
  end;
body1.z := 0;
body2.Link(body1); wings1.Link(body1); wings2.Link(body1);

params := par;

speed_hor := params.speed * landscape.sx;
speed_ver := params.speed * landscape.sy;
speed_angle := params.speed * 360;

wings1.animation_speed := 1 / 30;
end;

procedure TUnit.Kill;
begin
killed := true;
body1.animation_step := true;
body1.current_frame_f := 0;
with body1.color do begin r := 1; g := 1; b := 1; a := 1; end;
body1.current_mesh := mesh_enemy_death_id;
body1.animation_speed := 1 / 180;
end;

procedure TUnit.Move;
var
old, old_x, old_y : integer;

function EnemyKilled(n : integer) : boolean;
begin
result := true;
if not iEnemys[n] then exit;
if gEnemys[n].killed then exit;
result := false;
end;

begin
if killed and (body1.current_frame_f >= 8) then
  with body1 do 
    begin
      pathmap.map[map_x, map_y].child_enemy_id := 0;
      iEnemys[num] := false;
      gEnemys[num].Free;
    end;
if killed then exit;

life_enemys := life_enemys + 1;
if not gRespawns[respawn_number].path.exists then exit;
cell_s := params.speed * count_time;
path_pos_f := path_pos_f - cell_s;
old := path_pos;
path_pos := round(path_pos_f);
if old <> path_pos then
  begin
    if path_pos <= 1 then
      begin
        missed_enemys := missed_enemys + 1;
        base_health := base_health - params.damage;
        credits := credits - params.get_credits div 3;
        score := score - params.get_score div 3;
        Kill;
        play_enemy_miss := play_enemy_miss + 1;
        exit;
      end;

    with gRespawns[respawn_number] do
      with pathmap.map[path.points[path_pos].x, path.points[path_pos].y] do
      if (child_enemy_id <= 0) or EnemyKilled(child_enemy_id) then
        begin
          pathmap.map[path.points[old].x,
                      path.points[old].y].child_enemy_id := 0;  
          child_enemy_id := num;
        end
      else
        begin
          path_pos := old;
          path_pos_f := path_pos_f + cell_s;
          exit;
        end;

    old_x := body1.map_x; old_y := body1.map_y;

    body1.map_x := gRespawns[respawn_number].path.points[path_pos].x;
    body1.map_y := gRespawns[respawn_number].path.points[path_pos].y;

    if old_x > body1.map_x then
      begin
        if old_y < body1.map_y then angle := 315;
        if old_y = body1.map_y then angle := 0;
        if old_y > body1.map_y then angle := 45;
        hor_s := -1;
      end;
    if old_x = body1.map_x then
      begin
        if old_y < body1.map_y then angle := 270;
        if old_y > body1.map_y then angle := 90;
        hor_s := 0;
      end;
    if old_x < body1.map_x then
      begin
        if old_y < body1.map_y then angle := 225;
        if old_y = body1.map_y then angle := 180;
        if old_y > body1.map_y then angle := 135;
        hor_s := 1;
      end;

    if old_y < body1.map_y then ver_s := 1;
    if old_y = body1.map_y then ver_s := 0;
    if old_y > body1.map_y then ver_s := -1;

    angle := angle - 90;

    depth_s := landscape.map[body1.map_x + hor_s - 1, body1.map_y + ver_s - 1].z - body1.z;
  end;

if body1.rz < angle then body1.rz := body1.rz + speed_angle * count_time;
if body1.rz > angle then body1.rz := body1.rz - speed_angle * count_time;

if hor_s > 0 then body1.x := body1.x + speed_hor * count_time;
if hor_s < 0 then body1.x := body1.x - speed_hor * count_time;
if ver_s > 0 then body1.y := body1.y + speed_ver * count_time;
if ver_s < 0 then body1.y := body1.y - speed_ver * count_time;
body1.z := body1.z + depth_s * cell_s;

body2.Link(body1); wings1.Link(body1); wings2.Link(body1);
end;

procedure TUnit.Redraw;
begin
if not killed then
  begin
    wings1.Animate(count_time);
    wings2.LinkAnimation(wings1);
  end
else body1.Animate(count_time);

body1.Redraw;
if killed then exit;
body2.Redraw;
wings1.Redraw;
wings2.Redraw;
end;

end.
