unit buildings;

interface

uses vfm, variables, constants, OpenGL, global, towers_params,
     units, records, files_names;

type
  TTree = class
    stem, leaves : TObject;     
    animation_speed, animation_max_offset, animation_offset : single;
  public
    constructor Create(mx, my : integer);
    procedure Redraw;
  end;

  TBase = class
    base1, base2, base3, base4 : TObject;
    default_health, health : single;
    light_radius : integer;
  public
    constructor Create(mx, my : integer);
    procedure Redraw;
  end;

  TTurrel = class
    base, head, process : TObject;
    params : RTowerParamsBlock;
    maded_upgrades : array[1..max_upgrades] of boolean;
    count_shoot : single;
    mode : integer;
    builded : boolean;
    build_process : integer;
  public
    constructor Create(mx, my, md : integer);
    procedure ResetLight(old, new : integer);
    function FindTarget(radius, primary : integer) : integer;
    procedure Shoot;
    procedure Redraw;
  end;

  TBuildPlace = class
    obj : TObject;
  public
    constructor Create(mx, my : integer);
    procedure Redraw;
  end;

var
  gTrees: array[1..max_trees] of TTree;
  total_trees: integer = 0;
  gBase: TBase;
  gTurrels: array[1..max_turrels] of TTurrel;
  total_turrels: integer = 0;
  gBuildPlaces: array[1..max_buildplaces] of TBuildPlace;
  total_buildplaces: integer = 0;

implementation

procedure SetLightRadius(mx, my, old, new : integer; color : RColor);

procedure DrawLightRadius(r, n : integer; c : RColor);
var
i1, i2 : integer;
begin
for i1 := mx - r to mx + r do
  for i2 := my - r to my + r do
    if (i1 > 0) and (i1 < pathmap.width + 1) and
       (i2 > 0) and (i2 < pathmap.height + 1) then
       if sqrt(sqr(mx - i1) + sqr(my - i2)) < r then
          with landscape.map[i1, i2].night_color do
            begin
              r := r + n*c.r;
              g := g + n*c.g;
              b := b + n*c.b;
              a := a + n*c.a;
            end;
end;

begin
DrawLightRadius(old, -1, color);
DrawLightRadius(new,  1, color);
end;

constructor TTree.Create(mx, my : integer);
begin
inherited Create;
with pathmap.map[mx, my] do
  begin walk := false; build := false; child_type := 2; end;

animation_speed := (random(2) + 1)/10000;
animation_max_offset := 1.5;
animation_offset := random(2*100*round(animation_max_offset))/100 - animation_max_offset;

stem := TObject.CreateStandart(mx + 0.5, my + 0.5, mesh_tree_stem_id);
stem.sx := stem.sx*2 - random(20)/100;
stem.sy := stem.sx;
stem.sz := stem.sx + random(20)/100 - 0.1;
stem.rz := random(360);

leaves := TObject.CreateStandart(mx + 0.5, my + 0.5, mesh_tree_leaves_id);
leaves.sx := stem.sx;
leaves.sy := stem.sy;
leaves.sz := stem.sz;
leaves.rx := stem.rx;
leaves.ry := stem.ry;
leaves.rz := random(360);
end;

procedure TTree.Redraw;
begin
animation_offset := animation_offset + animation_speed * count_time;
if (animation_offset >= animation_max_offset) or
   (animation_offset <= -animation_max_offset) then
   animation_speed := -animation_speed;

stem.rx := stem.rx - animation_speed * count_time;
stem.ry := stem.ry + animation_speed * count_time;
leaves.rx := stem.rx;
leaves.ry := stem.ry;   

stem.Redraw;
leaves.Redraw;
end;

constructor TBase.Create(mx, my : integer);
var
i1, i2 : integer;
begin
inherited Create;
with pathmap.map[mx, my] do
  begin walk := true; build := false; child_type := 1; end;
base1 := TObject.CreateStandart(mx, my, mesh_base1_id);
base2 := TObject.CreateStandart(mx, my, mesh_base2_id);
base3 := TObject.CreateStandart(mx, my, mesh_base3_id);
base4 := TObject.CreateStandart(mx, my, mesh_base4_id);

base1.id := 1; base2.id := 1; base3.id := 1; base4.id := 1;
base1.rz := random(360);
base2.rz := base1.rz; base3.rz := base1.rz; base4.rz := base1.rz;

default_health := 100;
health := default_health;
base_health := health;

base_x := base1.map_x;
base_y := base1.map_y;

light_radius := 8;
for i1 := mx - light_radius to mx + light_radius do
  for i2 := my - light_radius to my + light_radius do
    if (i1 > 0) and (i1 < pathmap.width+1) and
       (i2 > 0) and (i2 < pathmap.height+1) then
       if sqrt(sqr(mx - i1) + sqr(my - i2)) < light_radius then
         with landscape.map[i1, i2].night_color do
           begin r := r + 0.5; g := g + 0.35; b := b - 0.2; a := a + 0.5; end;
end;

procedure TBase.Redraw;
var
h, x0 : single;
begin
if select_objects then
  begin
    glLoadName(base1.id);
    base1.Redraw; base2.Redraw; base3.Redraw; base4.Redraw;
    exit;
  end;
  
base1.Redraw;
base2.Redraw;
base3.Redraw;
base4.Redraw;
health := base_health;
h := health / default_health;

glDisable(GL_TEXTURE_2D);
glLineWidth(10);
glBegin(GL_LINES);

glColor4f(1 - h, 0, h, 1);
x0 := health / 2;
with base1 do
  begin
    glVertex3f(x - x0, y, z + 110);
    glVertex3f(x + x0, y, z + 110);
  end;

glColor4f(1, 0, 0, 0.5);
x0 := default_health / 2;
with base1 do
  begin
    glVertex3f(x - x0, y, z + 110);
    glVertex3f(x + x0, y, z + 110);
  end;
glEnd;
end;

constructor TTurrel.Create(mx, my, md : integer);
var
i1, i2 : integer;
q1, q2 : single;
begin
inherited Create;
mode := md;

with pathmap.map[mx, my] do
  begin walk := false; build := false; child_type := 3; end;

if md = 3 then
  begin
    with pathmap.map[mx + 1, my] do
      begin walk := false; build := false; child_type := 0; end;
    with pathmap.map[mx, my + 1] do
      begin walk := false; build := false; child_type := 0; end;
    with pathmap.map[mx + 1, my + 1] do
      begin walk := false; build := false; child_type := 0; end;
  end;

params := towers_params_base[md];

q1 := 0; q2 := 0;
case md of
  1 : begin i1 := mesh_tower_small_base_id;  i2 := mesh_tower_small_head_id; end;
  2 : begin i1 := mesh_tower_middle_base_id; i2 := mesh_tower_middle_head_id; end;
  3 : begin i1 := mesh_tower_big_base_id;    i2 := mesh_tower_big_head_id;
            q1 := 0.5; q2 := 0.5; end;
end;   

base := TObject.CreateStandart(mx + q1, my + q2, i1);
head := TObject.CreateStandart(mx + q1, my + q2, i2);
process := TObject.CreateStandart(mx + q1, my + q2, mesh_building_process_id);
if md = 3 then process.sx := 1.7; process.sy := process.sx; 

base.rz := random(360);
head.rz := base.rz;
process.rz := random(360);

build_process := 0;

ResetLight(0, params.light_radius);
end;

procedure TTurrel.ResetLight(old, new : integer);
begin
SetLightRadius(base.map_x, base.map_y, old, new, params.light_color);
end;

function TTurrel.FindTarget(radius, primary : integer) : integer;
var
i1, i2, id : integer;
param : single;
begin
param := 0; id := 0;
if primary = 0 then param := 10000;
for i1 := base.map_x - radius to base.map_x + radius do
  for i2 := base.map_y - radius to base.map_y + radius do
    if (i1 > 0) and (i1 < pathmap.width+1) and
       (i2 > 0) and (i2 < pathmap.height+1) then
       if sqrt(sqr(base.map_x - i1) + sqr(base.map_y - i2)) < radius then
      with pathmap.map[i1, i2] do
        if (child_enemy_id > 0) and iEnemys[child_enemy_id] then
          with gEnemys[child_enemy_id] do
            case primary of
              0 : if (param > params.health) and not gEnemys[child_enemy_id].killed then
                    begin id := child_enemy_id; param := params.health; end;
              1 : if (param < params.damage) and not gEnemys[child_enemy_id].killed then
                    begin id := child_enemy_id; param := params.damage; end;
              2 : if (param < params.speed) and not gEnemys[child_enemy_id].killed then
                    begin id := child_enemy_id; param := params.speed; end;
            end;
result := id;
end;

procedure TTurrel.Shoot;
var
i : integer;

procedure ShootOneWeapon(n : integer);
var
sp : single;
begin
with params.weapons[n] do
  target := FindTarget(radius, primary);

with params.weapons[n] do
if target > 0 then
  with gEnemys[target] do
    begin
      sp := speed * count_time / 1000;

      count_shoot := count_shoot + sp;
      if count_shoot >= 3 then
        begin
          play_shoot := play_shoot + round(count_shoot / 3);
          count_shoot := 0;
        end;

      params.health := params.health - damage_h * sp;
      params.damage := params.damage - damage_d * sp;
      params.speed := params.speed - damage_s * sp / 15000 / 1.7;
      
      if params.damage < 0 then params.damage := 0;
      if params.speed < 0.00005 then params.speed := 0.00005;

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

      if (params.health <= 0) and (not gEnemys[target].killed) then
        begin
          killed_enemys := killed_enemys + 1;
          credits := credits + params.get_credits;
          score := score + params.get_score;        
          gEnemys[target].kill;
          target := 0;
          play_enemy_kill := play_enemy_kill + 1;
        end;
    end;
end;

begin
if not builded then
  begin
    build_process := build_process + count_time;
    base.z := landscape.map[base.map_x, base.map_y].z *
              build_process / params.build_time;
    head.z := base.z;
    if build_process > params.build_time then builded := true;
    exit;
  end;
  
for i := 1 to params.weapons_aviable do ShootOneWeapon(i);
end;

procedure TTurrel.Redraw;
var
i : integer;

procedure DrawOneWeapon(n : integer);
begin
with params.weapons[n] do
  if target > 0 then
    begin
      if not iEnemys[target] then exit;
      glBegin(GL_LINES);
      with base do glVertex3f(x, y, z + 50);
      with gEnemys[target].body1 do glVertex3f(x, y, z + 20);
      glEnd;
    end;
end;

begin
if select_objects then
  begin
    glLoadName(base.id); head.redraw;
    glLoadName(base.id); base.redraw;
    exit;
  end;

if selected_tower = base.id - id_turrels then
  with base.color do begin r := 1; g := 0.5; b := 0.25; a := 1; end
  else with base.color do begin r := 1; g := 1; b := 1; a := 1; end;
head.color := base.color;

if not builded then process.redraw;
head.redraw;
base.redraw;
end;

constructor TBuildPlace.Create(mx, my : integer);
begin
inherited Create;
with pathmap.map[mx, my] do
  begin walk := false; build := true; child_type := 4; end;

obj := TObject.CreateStandart(mx, my, mesh_buildplace_id);
obj.color.r := 0.6;
end;

procedure TBuildPlace.Redraw;
begin
if select_objects then glLoadName(obj.id);
obj.redraw;
end;

end.
 