unit l_spider;

interface

uses
 OpenGL,
 l_gl, l_math, l_sound, l_model;

type
 PSpider = ^TSpider;
 TSpider = object
  Health   : integer;
  Pos      : TVector;
  Angle    : single;
  speed    : single;
  CurTime  : integer;
  CurFrame : integer;
  Reload   : integer;  // время перезарядки челюстей ;) 
  tAngle   : single;   // целевой угол
  m        : TMatrix4;
  Next     : PSpider;
  Prev     : PSpider;
  procedure Init;
  procedure GetAngle;
  procedure Update;
  procedure Render;
 end;

const
 SPIDER_DIFF   = 20;
 SPIDER_RELOAD = 50;
 SPIDER_DAMAGE = 10;

var
 vis_spiders : integer;
 snd__spider_attack : integer;
 snd__spider_die    : integer;

implementation

uses
 l_game, l_map, l_camera;

procedure TSpider.Init;
begin
Health   := 3;
Pos      := Vector(0, 0, 0);
CurTime  := random(Spider_xmd.MaxTime);
CurFrame := 0;
Speed    := 0;
Angle    := 0;
tAngle   := 0;
Next := nil;
Prev := nil;
end;

procedure TSpider.GetAngle;
var
 p : TVector;
begin
p.X := Player.Pos.X - Pos.X;
p.Y := 0;
p.Z := Player.Pos.Z - Pos.Z;
tAngle := V_Angle(Vector(1, 0, 0), p);
tAngle := tAngle + (random*SPIDER_DIFF - SPIDER_DIFF/2) * deg2rad;
// т.к. угол у нас 0 - pi приходится немного попариться... ;)
if p.Z < 0 then tAngle := 2 * pi - tAngle;
if (Angle - tAngle) > pi then tAngle := tAngle + pi * 2;
if (tAngle - Angle) > pi then tAngle := tAngle - pi * 2;
end;

procedure TSpider.Update;
var
 Up, Left, Dir : TVector;
 tmp : single;
begin
// Текущее время анимации
CurTime := (CurTime + 30) mod spider_xmd.MaxTime;
// Текущий кадр
CurFrame := 3 * CurTime div 100;
////////////////////////////
// Вычисление неправляющего угла
if random(SPIDER_DIFF * 5) = 0 then
 GetAngle;
// интерполяция этого угла в угол действительный
Angle := Angle + (tAngle - Angle)/SPIDER_DIFF;
// Передвижение
Dir.X := cos(Angle);
Dir.Y := 0;
Dir.Z := sin(Angle);
Pos.X := Pos.X + Dir.X * Speed;
Pos.Z := Pos.Z + Dir.Z * Speed;
// Коррекция позиции
Map.Collision(Pos, Up);

if (Reload = 0) and (Player.Health > 0) and (V_Distq(Pos, Player.Pos) < sqr(spider_xmd.Radius)) then
 begin
 Player.Hit(trunc(V_Dist(Pos, Player.Pos)/spider_xmd.Radius * SPIDER_DAMAGE));
 snd_Play(snd__spider_attack, false, Pos);
 Reload := SPIDER_RELOAD
 end;
 
if Reload > 0 then
 dec(Reload);
// Вычисление скорости передвижения (для наклонных плоскостей)
Speed := 0.2 * sin(V_Angle(Up, Dir));
// т.к. сама моделька ориентирована по оси Z
tmp   := Dir.X;
Dir.X := Dir.Z;
Dir.Z := -tmp;
//// вычисление ориентации паучка на ландшафте ////
// Находим 3 вектора базиса
Left := V_Cross(Dir, Up);
Dir  := V_Cross(left, Up);
Dir  := V_Normalize(Dir);
Left := V_Normalize(Left);
// Заполняем матрицу
m[0][0] := Dir.X;  m[0][1] := Dir.Y;  m[0][2] := Dir.Z;  m[0][3] := 0;
m[1][0] := Up.X;   m[1][1] := Up.Y;   m[1][2] := Up.Z;   m[1][3] := 0;
m[2][0] := Left.X; m[2][1] := Left.Y; m[2][2] := Left.Z; m[2][3] := 0;
m[3][0] := Pos.X;  m[3][1] := Pos.Y;  m[3][2] := Pos.Z;  m[3][3] := 1;
// Умножаем полученную матрицу на матрицу вида (камеры)
m := M_Mult(m, Camera.m);
end;

procedure TSpider.Render;
begin
// Если включено отсечение по раструбу камеры
if culling and not Camera.inFrustum(Pos, spider_xmd.Radius) then
 Exit;
inc(vis_spiders);
spider_xmd.CurFrame := CurFrame;
glLoadMatrixf(@m);
spider_xmd.Render;
end;

end.
