Unit Objs;
                     InterFace
Uses Objects, Graph, TypeLib;
Const

 MAXNAME = 30;
 MAXTYPE = 20;

Type
  vec = record x,y:real; end;
  rect = record A,B,C,D : vec; end;
  Pline = ^TLine;
  Tline = record A,B : vec; end;
  PString = ^String;
  ManMoods = (MOOD_STOP,MOOD_WALK,MOOD_ACCEL,MOOD_BRAKING);

  CObjs = Object
    oType  : string[MAXTYPE];
    Name   : string[MAXNAME];
    Color  : integer;
    Heading: Real;
    POS    : vec;
    Speed  : vec;
    Accel  : vec;
    Bounds : TLine;
    procedure Step;
    procedure Draw;
    procedure Clear;
  End;

  CHouse = Object (COBjs)
    UL, BR : vec;
    Door   : Rect;
    Constructor Init(cx,cy,sTop,sBottom,sLeft,sRight : real;aName : string);
    Procedure SetDoor(dx1,dy1,dx2,dy2 : real);
    Procedure Draw;
  end;


  CMan = Object (COBjs)
    Mood     : MANMOODS;
    MaxAccel : real;
    MaxSpeed : real;
    StepPos  : real;
    Scale    : real;
    NewMove  : byte;
    DefBounds: TLine;
    Model    : array [0..5] of PLine;
    Procedure CreateMan(var Ar:array of PLine;SP:real);
    Constructor Init(cx,cy,ang,aScale:real;aName:string;aCol:integer);
    Procedure Rotate(aAng : real);
    Procedure SetSpeed(aNewSpeed : real);
    Procedure SetAccel(aNewAccel : real);
    Procedure Step;
    Procedure Clear;
    Procedure Draw;
    Destructor Destroy;
  end;

  Procedure DrawRay(aC:vec;Ang,Len:real);
  Procedure SetBounds(Ob : array of Pline;numvert:word;var aB:TLine;DefBounds:TLine);
  Procedure RotateVec(var aV : Vec; Ang:Real);
  Procedure RotateRect(var Ob : rect;Ang:real);
  Procedure RotateLine(var Ob : TLine;Ang:real);
  Procedure RotateArray(var Ob : array of Pline;numvert:word;Ang:real);
  Function  Len(aVec : vec) : real;
  Procedure Neg(var aV : real);

                         IMPLEMENTATION
{-------------------------------}
Procedure Neg(var aV : real);
begin
  aV := -aV;
end;{Neg}
{-------------------}
Procedure SetBounds;
var
 i : word;
begin
  with aB do begin
    Ab := DefBounds;
    for i := 0 to NumVert do
     begin
       if ob[i]^.A.X > A.X then A.X:=ob[i]^.A.X;
       if ob[i]^.B.X > A.X then A.X:=ob[i]^.B.X;
       if ob[i]^.A.Y > A.Y then A.Y:=ob[i]^.A.Y;
       if ob[i]^.B.Y > A.Y then A.Y:=ob[i]^.B.Y;
       if ob[i]^.A.X < B.X then B.X:=ob[i]^.A.X;
       if ob[i]^.B.X < B.X then B.X:=ob[i]^.B.X;
       if ob[i]^.A.Y < B.Y then B.Y:=ob[i]^.A.Y;
       if ob[i]^.B.Y < B.Y then B.Y:=ob[i]^.B.Y;
     end;
  end;
end;{SetBounds}
{--------------------}
Procedure DrawRay;
Begin
  Line(Round(aC.X),Round(aC.Y),
       Round(aC.X+Len*cos(PI*Ang/180)),Round(aC.Y+Len*sin(PI*Ang/180)));
end; {DrawRay}
{--------------------}
Procedure RotateVec;
var ps : vec;
begin
  ps.X := aV.X * cos(PI*Ang/180) - aV.Y * sin(PI*Ang/180);
  ps.Y := aV.X * sin(PI*Ang/180) + aV.Y * cos(PI*Ang/180);
  av := ps;
end;{RotateVec}
{--------------------}
Procedure RotateRect;
begin
  RotateVec(ob.A,Ang);
  RotateVec(ob.B,Ang);
  RotateVec(ob.C,Ang);
  RotateVec(ob.D,Ang);
end;{RotateVec}
{--------------------}
Procedure RotateLine;
begin
  RotateVec(ob.A,Ang);
  RotateVec(ob.B,Ang);
end;{RotateVec}
{--------------------}
Procedure RotateArray;
var u : word;
begin
  for u := 0 to numvert do RotateLine(ob[u]^,Ang);
end;{RotateVec}
{--------------------}
Function Len;
begin
  Len := Sqrt(Sqr(aVec.X)+Sqr(aVec.Y));
end;{Len}
{--------------------}
{COBJ}
  Procedure CObjs.step; begin end;
  Procedure CObjs.Draw; begin end;
  Procedure CObjs.Clear; begin end;
{/COBJ}
{------------}
{CMan}
Procedure CMan.CreateMan;
Begin
with Ar[0]^ do Begin
  A.x:=-3*Scale;A.y:=0;B.x:=-7*Scale;B.y:=0;end;
with Ar[1]^ do Begin
  A.x:=3*Scale;A.y:=0;B.x:=7*Scale;B.y:=0;end;
with Ar[2]^ do Begin
  A.x:=-7*Scale;A.y:=0;B.x:=-7*Scale;B.y:=4*Scale-8*abs(SP)/5;end;
with Ar[3]^ do Begin
  A.x:=7*Scale;A.y:=0;B.x:=7*Scale;B.y:=-4*Scale+8*abs(SP)/5;end;
with Ar[4]^ do Begin
  A.x:=-4*Scale;A.y:=0;B.x:=-4*Scale;B.y:=-8*Scale+11*abs(SP)/5;end;
with Ar[5]^ do Begin
  A.x:=4*Scale;A.y:=0;B.x:=4*Scale;B.y:=3*Scale-11*abs(SP)/5;end;
End;{CMan.CreateMan}
{--------------------}
  Constructor CMan.Init;
  var i : byte;
  begin
    Heading := Ang;
    oType := 'Man';
    Name  := aName;
    Color := aCol;
    Scale := aScale;
    POS.X := cx;
    POS.Y := cy;
    Mood := MOOD_STOP;
    MaxSpeed := 10;MaxAccel := 5;
    Speed.X:=0;Speed.Y:=0;Accel.X:=0;Accel.Y:=0;
    for i:=0 to 5 do New(Model[i]);
    CreateMan(Model,0);
    RotateArray(Model,5,Heading);
    with DefBounds do begin A.X:=-3*Scale;A.Y:=-3*Scale;B.X:=3*Scale;b.Y:=3*Scale;end;
    SetBounds(Model,5,Bounds,DefBounds);
    NewMove := 0;
  end; {CMan.Init}
  {---------------}
  Procedure CMan.Rotate;
  Begin
    Heading := Heading + aAng;
    If Heading > 360 then Heading := Heading - 360;
    If Heading < 0 then Heading := Heading + 360;
    RotateVec(Speed,aAng);
    RotateVec(Accel,aAng);
    RotateArray(Model,5,aAng);
{    SetBounds(Model,5,Bounds,DefBounds);}
  End;{CMan.Rotate}
  {-------------------}
  Procedure CMan.SetSpeed;
  begin
    if aNewSpeed <> 0 then if Mood = MOOD_STOP then Mood:=MOOD_WALK;
    if aNewSpeed > MaxSpeed then aNewSpeed := MaxSpeed;
    Speed.X := aNewSpeed * cos(PI*Heading/180+PI/2);
    Speed.Y := aNewSpeed * sin(PI*Heading/180+PI/2);
  end;{CMan.SetSpeed}
  {-------------------}
  Procedure CMan.SetAccel;
  begin
    if aNewAccel > 0 then Mood:=MOOD_ACCEL
    else if aNewAccel < 0 then Mood := MOOD_BRAKING;
    if aNewAccel > MaxAccel then aNewAccel := MaxAccel;
    Accel.X := aNewAccel * cos(PI*Heading/180+PI/2);
    Accel.Y := aNewAccel * sin(PI*Heading/180+PI/2);
  end;{CMan.SetSpeed}
  {-------------------}
  Procedure CMan.Step;
  Begin
    POS.X := POS.X + Speed.X;
    POS.Y := POS.Y + Speed.Y;
    StepPos := StepPos + Len(Speed)*0.4;
    while StepPos > 10*Scale do StepPos:=StepPos-10*Scale;
    If StepPos > 5*Scale then StepPos:=StepPos-10*Scale;
    CreateMan(Model,StepPos);
    RotateArray(Model,5,Heading);
    if NewMove <> 0 then Dec(NewMove);
    if NewMove = 1 then
     begin
       NewMove := random(40)+2;
       Rotate(360*random-180);
       SetAccel(MaxAccel*random - MaxAccel/2);
     end;
    Speed.X := Speed.X + Accel.X;
    Speed.Y := Speed.Y + Accel.Y;
    if Len(Speed) > MaxSpeed then SetSpeed(MaxSpeed*random);
    if Len(Speed) < 0.001 then SetAccel(MaxAccel*random - MaxAccel/2);
    if (Pos.X > 630) and (Speed.X > 0) then Pos.X := 10;
    if (Pos.X < 10) and (Speed.X < 0) then Pos.X := 630;
    if (Pos.Y > 470) and (Speed.Y > 0) then Pos.Y:=10;
    if (Pos.Y < 10) and (Speed.Y < 0) then Pos.Y:=470;
  end; {CMan.Step}
  {-------------------}
  Procedure CMan.Draw;
  var i:byte;
  Begin
    SetColor(Color);
    Circle(ROUND(POS.X),Round(480-POS.Y),Round(3*Scale));
    for i := 0 to 5 do
      begin
        Line(ROUND(POS.X+Model[I]^.A.X), ROUND(480-(POS.Y+Model[I]^.A.Y)),
             ROUND(POS.X+Model[I]^.B.X), ROUND(480-(POS.Y+Model[I]^.B.Y)));
      end;
  End; {CMan.Draw}
  {-------------------}
  Procedure CMan.Clear;
  begin
    Bar(ROUND(POS.X+Bounds.A.X)+1, ROUND(480-(POS.Y+Bounds.A.Y))-1,
        ROUND(POS.X+Bounds.B.X)-1, ROUND(480-(POS.Y+Bounds.B.Y))+1);
  end;{CMAn.Clear}
  {-------------------}
  Destructor CMan.Destroy;
  var i:byte;
  begin
    for i := 0 to 5 do Dispose(Model[i]);
  end;{CMan.Destroy}
  {-------------------}
{/CMan}
{CHouse}
  Constructor Chouse.Init; begin end;
  Procedure CHouse.SetDoor; begin end;
  Procedure CHouse.Draw;begin end;
{/CHouse}

END.