unit Unit1;

interface
Uses
  Windows,Math,Types;

Const
  MaxLines = 2000;

Type

  CLine=class
   private
    { line index }
    _LineIndex:Integer;
    { Line Coordinates}
    _XY1:TPoint;
    _XY2:TPoint;
    _Alpha:Extended;
    _AlphaRad:Extended;
    _AlphaDeg:Extended;
    _Fddx:Double;
    _Fddy:Double;
    _StepX:Integer;
    _StepY:Integer;
    { Line Properties }
    _Horisontal:Boolean;
    _Vertical:Boolean;
    _Well_Left:Integer;
    _Well_Right:Integer;
    _Slope_Left:Integer;
    _Slope_Right:Integer;
   // _Ceiling:Boolean;
   // _Floor:Boolean;
   // _NumObj:Integer;
    _XSpr:Integer;
    _YSpr:Integer;
    _IndexSpr:Integer;
    _NoClip:Boolean;
    { ... }
    procedure _X1(X1:Integer);virtual;
    procedure _Y1(Y1:Integer);virtual;
    procedure _X2(X2:Integer);virtual;
    procedure _Y2(Y2:Integer);virtual;
    procedure _GetAlpha(XY1:TPoint;XY2:TPoint);virtual;
   public
    constructor Create;
    property X1:Integer read _XY1.X write _X1;
    property Y1:Integer read _XY1.Y write _Y1;
    property X2:Integer read _XY2.X write _X2;
    property Y2:Integer read _XY2.Y write _Y2;
    property Alpha:Extended read _Alpha;
    property AlphaRad:Extended read _AlphaRad;
    property AlphaDeg:Extended read _AlphaDeg;
    property WLeft:Integer read _Well_Left;
    property WRight:Integer read _Well_Right;
    property SLeft:Integer read _Slope_Left;
    property SRight:Integer read _Slope_Right;
    property vert:Boolean read _Vertical;
    property LineIndex:Integer read _LineIndex;
    property xSpr:Integer read _xSpr write _xSpr;
    property ySpr:Integer read _ySpr write _ySpr;
    property IndexSpr:Integer read _IndexSpr write _IndexSpr;
    property StepX:Integer read _StepX write _StepX default 8;
    property StepY:Integer read _StepY write _StepY default 8;
  end;

  PListLines = ^TListLines;
  TListLines = array [0..MaxLines] of CLine;

  CLines=class
   private
    _ListLines:TListLines;
    _LinesCount:Integer;
    _File:File;
    _IndexMask:Integer;
    _Rect:TRect;
    _Pt1,_Pt2:TPoint;
    _Cleared:Boolean;
    function  _GetLine(index:Integer):CLine ;virtual;
    procedure _FindProperty(index:Integer);virtual;
    procedure _GetIndexMask(Var IndexMask:Integer);virtual;
   public
    constructor Create;
    property  Lines[index:Integer]:CLine read _GetLine;
    property  LinesCount:Integer read _LinesCount;
    property  IndexMask:Integer read _IndexMask;
    procedure AddLine(XY1,XY2:Tpoint); virtual;
    procedure SetProperties; virtual;
    procedure Delete(Index:Integer);virtual;
    procedure SaveToFile(FileName:String); virtual;
    procedure LoadFromFile(FileName:String); virtual;
    procedure Clear;virtual;
    procedure InRect(Rect:TRect);virtual;
  end;

  TSides=(toUp,toDown,toLeft,toRight,none);
  TActions=(MoveOnStay,AlwaysMove);
  TSMove=(StartedMoveUp,StartedMoveDown);
  
  CMovingObjects=class
  private
    _idObj:Integer;
    _Dx:Integer;
    _Dy:Integer;
    _DistX:Integer;
    _DistY:Integer;
    _MoveCountY:Integer;
    _MoveCountX:Integer;
    _Action:TActions;
    _Move:Boolean;
    _StartedMoved:TSMove;
  public
    constructor Create;virtual;
    property idObject:Integer read _IdObj;
    property Dx:Integer read _Dx write _Dx;
    property Dy:Integer read _Dy write _Dy;
    property DistX:Integer read _DistX write _DistX;
    property DistY:Integer read _DistY write _DistY;
  end;

  PListMObj=array[0..MaxLines] of CMovingObjects;
  TListMObj=array[0..MaxLines] of CMovingObjects;

  CEngine=class(CLines)
    private
     _XObj:Integer;
     _YObj:Integer;
     _XobjNew:Integer;
     _YobjNew:Integer;
     _IndexLine:Integer;
     _LineStayIndex:Integer;
     _StayOnObj:Integer;
     _IdInClass:Integer;
     _lSecX:Integer;
     _lSecY:Integer;

     _C_L1:Boolean;
     _C_R1:Boolean;
     _C_L2:Boolean;
     _C_R2:Boolean;
     _Can_Left:Boolean;
     _Can_Right:Boolean;
     _Can_Up:Boolean;
     _Can_Down:Boolean;
     _Height:Integer;
     _ScrollMapX:Integer;
     _ScrollMapY:Integer;
     _ScreenSizeX:Integer;
     _ScreenSizeY:Integer;
     _Sides:TSides;
     _LRight:Integer;
     _LLeft:Integer;
     _LBottomSecX:Integer;
     _LBottomSecY:Integer;
     _LBDist:Integer;
     _Stay:Boolean;

     _KeyUp:Boolean;
     _KeyDown:Boolean;
     _KeyLeft:Boolean;
     _KeyRight:Boolean;

     _StepX:Integer;
     _StepY:Integer;
     _Jump:Boolean;
     _CountJump:Integer;
     _IdLeft:Integer;
     _IdRight:Integer;
     _xMap:Integer;
     _yMap:Integer;

     _CountObj:Integer;
     _ListObj:PListMObj;
     _tdx:Integer;
     _tdy:Integer;
     _XEnd:Integer;
     _YEnd:Integer;
     _Teleport:Boolean;
     
     function  _Visible(Index:Integer):Boolean;virtual;
     procedure _LSec(xx1,yy1,xx2,yy2:Integer;x1,y1,x2,y2:Integer;Var Xs:Integer;Var Ys:Integer);virtual;
     procedure LLine(Xpos,Ypos:Integer;x1,y1,x2,y2:Integer;Var DLine:Integer);virtual;
     procedure TestXY(_X,_Y:Integer);virtual;
     function  _GetObjM(Index:Integer):CMovingObjects;virtual;
    public
     constructor Create ; Overload;
     property Can_Left:Boolean read _Can_Left;
     property Can_Right:Boolean read _Can_Right;
     property Can_Up:Boolean read _Can_Up;
     property Can_Down:Boolean read _Can_Down;
     property Xobject:Integer read _Xobj write _Xobj;
     property Yobject:Integer read _Yobj write _Yobj;
     property XobjectNew:Integer read _XobjNew;
     property YobjectNew:Integer read _YobjNew;
     property IndexLine:Integer read _IndexLine;
     property IndexStayLine:Integer read _LineStayIndex;
     property Height:Integer read _Height write _Height default 20;
     property ScrollMapX:Integer read _ScrollMapX write _ScrollMapX default 0;
     property ScrollMapY:Integer read _ScrollMapY write _ScrollMapY default 0;
     property ScreenSizeX:Integer read _ScreenSizeX write _ScreenSizeX default 640;
     property ScreenSizeY:Integer read _ScreenSizeY write _ScreenSizeY default 480;
     property Sides:TSides read _Sides write _Sides;
     property Xsec:Integer read _LSecX;
     property Ysec:Integer read _LSecY;
     property XBsec:Integer read _LBottomSecX;
     property YBsec:Integer read _LBottomSecY;
     property LeftDistance:Integer read _LLeft;
     property RightDistance:Integer read _LRight;
     property BtmDistance:Integer read _LBDist;
     property kUp:Boolean read _KeyUp write _KeyUp default False;
     property kDown:Boolean read _KeyDown  write _KeyDown default False;
     property kLeft:Boolean read _KeyLeft write _KeyLeft default False;
     property kRight:Boolean read _KeyRight write _KeyRight default False;
     procedure ResetKeys;virtual;
     procedure Move;virtual;
     property StepX:Integer read _StepX write _StepX default 8;
     property StepY:Integer read _StepY write _StepY default 8;
     property Stay:Boolean read _Stay;
     property IdLeft:Integer read _IdLeft;
     property IdRight:Integer read _IdRight;
     property xMap:Integer read _xMap;
     property yMap:Integer read _yMap;
     procedure GetXYMap;virtual;
     procedure SetScroll(Var ScrX:Integer; Var ScrY:Integer);virtual;
     property Visible[index:Integer]:Boolean read _Visible;
     property MoveObjProp[index:Integer]:CMovingObjects read _GetObjM;
     procedure AddMovedObj(idObj, Dx, Dy, DistX, DistY: Integer; Act:TActions;StartedAct:TSmove);
     procedure MoveObj; virtual;
     procedure Teleport(Xen,Yen:Integer);
     property Xend:Integer read _Xend write _XEnd;
     property Yend:Integer read _Yend write _YEnd;
     property tdX:Integer read _tdX write _tdX;
     property tdY:Integer read _tdY write _tdY;
     property Teleporting:Boolean read _Teleport write _Teleport;
  end;

implementation

{ CLines }

procedure CLines.AddLine(XY1, XY2: Tpoint);
begin
  { Add Line }
  Inc(_LinesCount);
  _ListLines[_LinesCount-1]:=CLine.Create;
  _ListLines[_LinesCount-1]._LineIndex:=_LinesCount-1;
  _ListLines[_LinesCount-1]._XY1:=XY1;
  _ListLines[_LinesCount-1]._XY2:=XY2;
  _ListLines[_LinesCount-1]._Vertical:=False;
  _ListLines[_LinesCount-1]._GetAlpha(XY1,XY2);
  _ListLines[_LinesCount-1]._noClip:=False;
  _Cleared:=False;
  _FindProperty(_LinesCount-1);
end;

procedure CLines.Clear;
Var
  i:Integer;
begin
  If _Cleared then Exit;
  for i:=0 to _LinesCount-1 do
   _ListLines[i].Free;
  _Cleared:=True;
  _LinesCount:=0;
end;

constructor CLines.Create;
begin
  inherited
  Create;
  _LinesCount:=0;
  _IndexMask:=0;
end;

procedure CLines.Delete(Index: Integer);
Var
  i:Integer;
begin
  If (Index<0)or(Index>LinesCount-1) Then Exit;
  If (Index<_LinesCount-1) Then
   begin
     For i:=(Index+1) to _LinesCount-1 Do
      begin
         _ListLines[i-1]._XY1:=_ListLines[i]._XY1;
         _ListLines[i-1]._XY2:=_ListLines[i]._XY2;
         _ListLines[i-1]._AlphaRad:=_ListLines[i]._AlphaRad;
         _ListLines[i-1]._xSpr:=_ListLines[i]._xSpr;
         _ListLines[i-1]._ySpr:=_ListLines[i]._ySpr;
         _ListLines[i-1]._IndexSpr:=_ListLines[i]._IndexSpr;
         _ListLines[i-1]._Horisontal:=_ListLines[i]._Horisontal;
         _ListLines[i-1]._Vertical:=_ListLines[i]._Vertical;
         _ListLines[i-1]._Well_Left:=_ListLines[i]._Well_Left;
         _ListLines[i-1]._Well_Right:=_ListLines[i]._Well_Right;
         _ListLines[i-1]._Slope_Left:=_ListLines[i]._Slope_Left;
         _ListLines[i-1]._Slope_Right:=_ListLines[i]._Slope_Right;
      end;
   end;
  _ListLines[_LinesCount-1].Free;
  Dec(_LinesCount);
end;

procedure CLines.InRect(Rect:TRect);
begin
  _Rect:=Rect;
  _GetIndexMask(_IndexMask);
end;

procedure CLines.LoadFromFile(FileName: String);
Var
  i,numRead:Integer;
  a,b:TPoint;
begin
  // Load from File
  Clear;
  {$R+}
  AssignFile(_File,FileName);
  Reset(_File,1);
  i:=0;
  numRead:=0;
  While (not Eof(_File)) do
    begin
     BlockRead(_File,a,SizeOf(a),numRead);
     BlockRead(_File,b,SizeOf(b),numRead);
     AddLine(a,b);
     BlockRead(_File,_ListLines[i]._xSpr,SizeOf(_ListLines[i]._xSpr),numRead);
     BlockRead(_File,_ListLines[i]._ySpr,SizeOf(_ListLines[i]._ySpr),numRead);
     BlockRead(_File,_ListLines[i]._IndexSpr,SizeOf(_ListLines[i]._IndexSpr),numRead);
     inc(i);
    end;
  CloseFile(_File);
 {$R-}
end;

Procedure CLines.SaveToFile(FileName: String);
Var
  i:Integer;
  numWrite:Integer;
begin
  // Save to File
  AssignFile(_File,FileName);
  ReWrite(_File,1);
  For i:=0 to _LinesCount-1 Do
   begin
     BlockWrite(_File,_ListLines[i]._XY1,SizeOf(_ListLines[i]._XY1),numWrite);
     BlockWrite(_File,_ListLines[i]._XY2,SizeOf(_ListLines[i]._XY2),numWrite);
     BlockWrite(_File,_ListLines[i]._xSpr,SizeOf(_ListLines[i]._xSpr),numWrite);
     BlockWrite(_File,_ListLines[i]._ySpr,SizeOf(_ListLines[i]._ySpr),numWrite);
     BlockWrite(_File,_ListLines[i]._IndexSpr,SizeOf(_ListLines[i]._IndexSpr),numWrite);
   end;
  CloseFile(_File);
end;

procedure CLines.SetProperties;
Var
  i:Integer;
begin
  If _LinesCount>0 Then
    For i:=0 to _LinesCount-1 do
     begin
       _FindProperty(i);
     end;
end;

procedure CLines._FindProperty(index:Integer);
Var
  i:Integer;
begin
   If Index<=0 Then Exit;
   If Index>_LinesCount-1 Then Exit;
   For i:=0 to Index-1 do
    begin
      If _ListLines[i]._Vertical Then
        If (_ListLines[index]._XY1.X=_ListLines[i]._XY2.X) Then
        begin
         If _ListLines[index]._XY1.Y=_ListLines[i]._XY2.Y Then
            begin
              _ListLines[index]._Slope_Left:=-1;
              _ListLines[index]._Well_Left:=i;
            end;
         If _ListLines[index]._XY1.Y<_ListLines[i]._XY2.Y Then
            begin
              _ListLines[index]._Slope_Left:=i;
              _ListLines[index]._Well_Left:=-1;
            end;
        end;
    end;
end;

procedure CLines._GetIndexMask(Var IndexMask: Integer);
Var
  i:Integer;
begin
  IndexMask:=-1;
  For i:=0 to _LinesCount-1 do
   begin
    _Pt1:=_ListLines[i]._XY1;
    _Pt2:=_ListLines[i]._XY2;
    If PtInRect(_Rect,_pt1) or PtInRect(_Rect,_pt2) Then IndexMask:=i;
   end;
end;

function CLines._GetLine(index: Integer): CLine;
begin
  //_FindProperty(index);
  result:=_ListLines[index];
end;

{ CLine }

constructor CLine.Create;
begin
  inherited
  Create;
  _LineIndex:=-1;
  _Horisontal:=False;
  _Vertical:=False;
  _Well_Left:=-1;
  _Well_Right:=-1;
  _Slope_Left:=-1;
  _Slope_Right:=-1;
  _XY1.X:=-1;
  _XY1.Y:=-1;
  _XY2.X:=-1;
  _XY2.Y:=-1;
end;

procedure CLine._GetAlpha;
Var
  x1,x2,y1,y2:Integer;
  xx1,yy1,xx2,yy2:Integer;
  A1,B1,A2,B2:Integer;
begin
  _Vertical:=False;
  x1:=XY1.X;
  y1:=XY1.Y;
  x2:=XY2.X;
  y2:=XY2.Y;
  xx1:=x1;
  yy1:=y1;
  xx2:=x2;
  yy2:=y1;
  A2:=-yy2+yy1;
  B2:=xx2-xx1;
  A1:=-y2+y1;
  B1:=x2-x1;

  If (A1*B2-A2*B1<>0) and (A1*A2+B1*B2<>0) Then
   _Alpha :=(A1*B2-A2*B1)/(A1*A2+B1*B2)
  else
   _Alpha:=0;

  _AlphaRad := ArcTan(_Alpha);
  _AlphaDeg := RadToDeg(ArcTan(_Alpha));
  _Fddx:=Sin(_AlphaRad)*_StepX;
  _Fddy:=Cos(_AlphaRad)*_StepY;

  If _AlphaRad<0 Then _Fddx:=-_Fddx;
  If _AlphaRad<0 Then _Fddy:=-_Fddy;
  If y1=y2 then _Fddy:=0;
  If (_XY1.X = _XY2.X)and(_XY1.Y<>_XY2.Y) Then _Vertical:=True;
end;

procedure CLine._X1(X1: Integer);
begin
  _XY1.X:=x1;
  _GetAlpha(_XY1,_XY2);
end;

procedure CLine._X2(X2: Integer);
begin
  _XY2.X:=x2;
  _GetAlpha(_XY1,_XY2);
end;

procedure CLine._Y1(Y1: Integer);
begin
  _XY1.Y:=y1;
  _GetAlpha(_XY1,_XY2);
end;

procedure CLine._Y2(Y2: Integer);
begin
  _XY2.Y:=y2;
  _GetAlpha(_XY1,_XY2);
end;

{ CMoveInLines }

constructor CEngine.Create;
begin
  inherited
  Create;
  _CountJump:=0;
  _tdx:=1;
  _tdy:=1;
end;

function YinRangeLine(YSec,Y1,Y2:Integer):Boolean;
begin
  YinRangeLine:=False;
  If y1<y2 Then If (YSec>=y1)and(YSec<=y2) Then  result:=True else YinRangeLine:=False;
  If y1>y2 Then If (YSec>=y2)and(YSec<=y1) Then  result:=True else YinRangeLine:=False;
end;

function XinRangeLine(XSec,X1,X2:Integer):Boolean;
begin
{ If x1<x2 Then
  begin}
  If (XSec>=x1)and(XSec<=x2) Then
    result:=True
   else
    result:=False;
{  end;
 If x1>x2 Then
  begin
  If (XSec>=x2)and(XSec<=x1) Then
    result:=True
   else
    result:=False;
  end;            }
end;

Procedure CEngine.LLine(Xpos,Ypos:Integer; x1,y1,x2,y2:Integer; Var DLine:Integer);
Var
  A,B,C:Integer;
begin
  A:=-Y2+Y1;
  B:=X2-X1;
  C:=-X2*Y1+Y2*X1;
  If (x1<x2)Then
   begin
    DLine:=-Round((A*Xpos+B*Ypos+C)/(Sqrt(Sqr(A)+Sqr(B))));
    If (XPos<X1)or(XPos>X2) Then
     begin
      If Dline>0 Then Dline:=100;
      If Dline<0 Then Dline:=-100;
      If Dline=0 Then Dline:=200;
     end;
   end;
  If x2<x1 Then
   begin
    DLine:=Round((A*Xpos+B*Ypos+C)/(Sqrt(Sqr(A)+Sqr(B))));
    If (XPos<X2)or(XPos>X1) Then
     begin
      If Dline>0 Then Dline:=100;
      If Dline<0 Then Dline:=-100;
      If Dline=0 Then Dline:=200;
     end;
   end;
end;

procedure CEngine.Move;
Var
  TestX,TestY:Integer;
begin
 { If _Teleport Then
   begin
    Teleport(_Xend,_YEnd);
    Exit;
   end;}

  TestX:=_XObj;
  TestY:=_YObj;
  If _KeyRight Then _Sides:=toRight;
  If _KeyLeft Then _Sides:=toLeft;
  If _KeyUp Then
    begin
     If _Stay Then
      begin
       _StayOnObj:=-1;
        _Jump:=True;
        _StepY:=8;
      end;
    end;
  If _Jump and ( _CountJump<5)Then _Sides:=none;
  If _Sides=toRight Then
   begin
      TestX:=_Xobj+_StepX;
      If _Stay Then TestY:=Round(_Yobj+_ListLines[_LineStayIndex]._Fddy);
   end;

  If _Sides=toLeft Then
   begin
      TestX:=_Xobj-_StepX;
      If _Stay Then TestY:=Round(_Yobj-_ListLines[_LineStayIndex]._Fddy);
   end;

  If not _Stay and not _Jump Then
   begin
     TestY:=_YObj+_StepY;
     _StayOnObj:=-1;
   end
  else
   If _Stay Then
    begin
     TestY:=_LBottomSecY;
    end;

  If _Stay and _Jump Then
   begin
     TestY:=_yObj-_StepY;
     _Stay:=False;
   end;

  If _Jump Then
   begin
     If _CountJump<16 Then
      Begin
       TestY:=_yObj-_StepY;
       Inc(_CountJump);
      end
     else
      begin
       _CountJump:=0;
       _Jump:=False;
       _StepY:=4;
      end;
   end;
  TestXY(TestX,TestY);
  If _Can_Right and (_Sides=toRight) Then _XObj:=TestX;
  If _Can_Left and (_Sides=toLeft) Then _XObj:=TestX;
  _Yobj:=TestY;
  If _StayOnObj>-1 Then _XObj:=_XObj+_ListObj[_IdInClass]._Dx;
end;

procedure CEngine.TestXY(_X,_Y:Integer);
Var
  i:Integer;
begin
  _C_L1:=True;
  _C_R1:=True;
  _C_L2:=True;
  _C_R2:=True;
  _LineStayIndex:=-1;
  _IndexLine:=-1;
  _IdLeft:=-1;
  _IdRight:=-1;
  _LbDist:=100;
  _Stay:=False;

  If _Sides=toRight Then
    begin
     For i:=0 to _LinesCount-1 do
      begin
        If _ListLines[i].vert and _Visible(i) Then
         begin
          _LSec(_ListLines[i]._XY1.X,_ListLines[i]._XY1.Y,_ListLines[i]._XY2.X,_ListLines[i]._XY2.Y, _X,_Y-_Height,_X+50,_Y-_Height,_LSecX,_LSecY);
          _LRight:=_LSecX-_X;
          If YinRangeLine(_Y-_Height,_ListLines[i]._XY1.Y,_ListLines[i]._XY2.Y) Then
            If (_LRight<=8)and(_LRight>-2) Then
              begin
                _C_R1:=False;
                _IdRight:=i;
               Break;
              end;
          end;
      end;
   end;

  If _Sides=toLeft Then
   begin
    For i:=0 to _LinesCount-1 do
      begin
        If (_ListLines[i].vert) and _Visible(i) Then
         begin
          _LSec(_ListLines[i]._XY1.X,_ListLines[i]._XY1.Y,_ListLines[i]._XY2.X,_ListLines[i]._XY2.Y,_X,_Y-_Height,_X-50,_Y-_Height,_LSecX,_LSecY);
          _LLeft:=_X-_LSecX;
          If YinRangeLine(_Y-_Height,_ListLines[i]._XY1.Y,_ListLines[i]._XY2.Y) Then
            If (_LLeft<=8)and(_LLeft>-2) Then
             begin
              _C_L1:=False;
              _IdLeft:=i;
              Break;
             end;
         end;
      end;
   end;

  For i:=0 to _LinesCount-1 do
   begin
    If not _ListLines[i].vert and _Visible(i) Then
      begin
        LLine(_X,_Y,_ListLines[i]._XY1.X,_ListLines[i]._XY1.Y,_ListLines[i]._XY2.X,_ListLines[i]._XY2.Y,_LBDist);
        If (_LBDist<=8)and(_LBDist>-8) Then
         begin
           _LSec(_X,_Y-100,_X,_Y+32,_ListLines[i]._XY1.X,_ListLines[i]._XY1.Y,
           _ListLines[i]._XY2.X,_ListLines[i]._XY2.Y,_LBottomSecX,_LBottomSecY);
           _LineStayIndex:=i;
           _Stay:=True;
           _Jump:=False;
         end;
      end;
   end;

   if _ListLines[_LineStayIndex]._Slope_Left=_IdLeft Then _C_l1:=True;
   if _ListLines[_LineStayIndex]._Slope_Right=_IdRight Then _C_R1:=True;
  _Can_Right := _C_R1 and _C_R2;
  _Can_Left :=  _C_L1 and _C_L2;
end;

function CEngine._Visible(Index:Integer): Boolean;
begin
  // Visible or not visible line ;
  _Visible:=True;
  If ((_ListLines[Index]._XY1.X-_ScrollMapX)<0)and((_ListLines[Index]._XY2.X-_ScrollMapX)<0) Then
    _Visible:=False;
  If ((_ListLines[Index]._XY1.X-_ScrollMapX)>_ScreenSizeX+32)and ((_ListLines[Index]._XY2.X-_ScrollMapX)>_ScreenSizeX+32) Then
    _Visible:=False;
  If ((_ListLines[Index]._XY1.Y-_ScrollMapY)>_ScreenSizeY)and ((_ListLines[Index]._XY2.Y-_ScrollMapY)>_ScreenSizeY) Then
    _Visible:=False;
  If ((_ListLines[Index]._XY1.Y-_ScrollMapY)<-64)and((_ListLines[Index]._XY2.Y-_ScrollMapY)<-64) Then
    _Visible:=False;
end;

procedure CEngine._LSec(xx1, yy1, xx2, yy2, x1, y1, x2, y2: Integer;
  var Xs, Ys: Integer);
Var
  A1,B1,C1:Integer;
  A2,B2,C2:Integer;
begin
  A2:=-Y2+Y1;
  B2:=X2-X1;
  C2:=-X2*Y1+Y2*X1;
  A1:=-YY2+Yy1;
  B1:=Xx2-Xx1;
  C1:=-Xx2*Yy1+Yy2*Xx1;
  Xs:=Round((B1*C2-C1*B2)/(B2*A1-B1*A2));
  Ys:=Round(((-A2*Xs-C2)/B2));
end;

procedure CEngine.ResetKeys;
begin
  _KeyDown:=False;
  _KeyUp:=False;
  _KeyLeft:=False;
  _KeyRight:=False;
  _Sides:=none;
end;

procedure CEngine.GetXYMap;
Var
  i:Integer;
  maxX:Integer;
  maxY1,MaxY2:Integer;
begin
  _xMap:=0;
  _yMap:=0;
  MaxX:=0;
  maxY1:=0;
  maxY2:=0;
  For i:=0 to _LinesCount-1 do
   begin
     if _ListLines[i].X2>=maxX Then
      maxX:=_ListLines[i].X2;
     if _ListLines[i].Y1>=maxY1 Then
      maxY1:=_ListLines[i].Y1;
     if _ListLines[i].Y2>=maxY2 Then
      maxY2:=_ListLines[i].Y2;
   end;
   _xMap:=MaxX+32;
   If MaxY1>MaxY2 Then _yMap:=MaxY1
   else
   _yMap:=MaxY2;
end;

procedure CEngine.SetScroll(Var ScrX:Integer; Var ScrY:Integer);
begin
  if _xObj>=(_ScreenSizeX div 2) Then
     ScrX:=(_xObj-(_ScreenSizeX div 2))
  else
    ScrX:=0;
  if _Xobj>(_xMap-_ScreenSizeX div 2) Then ScrX:=_xMap-(_ScreenSizeX);
  if _yObj>(_ScreenSizeY div 2) Then
     ScrY:=(_YObj-(_ScreenSizeY div 2))
  else
    ScrY:=0;
  if _yobj>((_yMap+32)-_ScreenSizeY div 2) Then ScrY:=(_yMap+32)-(_ScreenSizeY);
  _ScrollMapX:=ScrX;
  _ScrollMapY:=ScrY;
end;
{ CMoveObjects }


function CEngine._GetObjM(Index: Integer): CMovingObjects;
begin
  _GetObjM:=_ListObj[index];
end;

procedure CEngine.AddMovedObj(idObj, Dx, Dy, DistX, DistY: Integer; Act:TActions;StartedAct:TSMove);
begin
  _ListObj[_CountObj]:=CMovingObjects.Create;
  _ListObj[_CountObj]._idObj:=idObj;
  _ListObj[_CountObj]._Dx:=Dx;
  _ListObj[_CountObj]._Dy:=Dy;
  _ListObj[_CountObj]._DistX:=DistX;
  _ListObj[_CountObj]._DistY:=DistY;
  _ListObj[_CountObj]._Action:=Act;
  _ListObj[_CountObj]._StartedMoved:=StartedAct;

  If Act = AlwaysMove Then
   _ListObj[_CountObj]._Move:=True;
  If Act = MoveOnStay Then
   _ListObj[_CountObj]._Move:=False;
  Inc(_CountObj);
end;

procedure CEngine.MoveObj;
Var
  i:Integer;
begin
  For i:=0 to _CountObj-1 do
   begin
    If _ListObj[i]._Action=MoveOnStay Then
      begin
       If  (_LineStayIndex=_ListObj[i]._idObj) Then
        _ListObj[i]._Move:=True;
      end;

     If _ListObj[i]._Move Then
      begin
       If _ListObj[i]._Dy>0 Then
         begin
          If _ListObj[i]._StartedMoved<>StartedMoveUp Then
           Inc(_ListObj[i]._MoveCountY)
          else
           Dec(_ListObj[i]._MoveCountY);
         end
       else
         begin
          If _ListObj[i]._StartedMoved<>StartedMoveUp Then
           Dec(_ListObj[i]._MoveCountY)
          else
           Inc(_ListObj[i]._MoveCountY);
         end;

       IF _ListObj[i]._MoveCountY>_ListObj[i]._DistY Then  _ListObj[i]._Dy:=-_ListObj[i]._Dy;
       If _ListObj[i]._MoveCountY<0 Then  _ListObj[i]._Dy:=-_ListObj[i]._Dy;


       _ListLines[_ListObj[i]._idObj]._XY1.Y:=_ListLines[_ListObj[i]._idObj]._XY1.Y+_ListObj[i]._Dy;
       _ListLines[_ListObj[i]._idObj]._XY2.Y:=_ListLines[_ListObj[i]._idObj]._XY2.Y+_ListObj[i]._Dy;
       _ListLines[_ListObj[i]._idObj]._ySpr:=_ListLines[_ListObj[i]._idObj]._ySpr+_ListObj[i]._Dy;

       If _ListObj[i]._Dx>0 Then
         Inc(_ListObj[i]._MoveCountX)
       else
         Dec(_ListObj[i]._MoveCountX);

       IF _ListObj[i]._MoveCountX>_ListObj[i]._DistX Then _ListObj[i]._Dx:=-_ListObj[i]._Dx;
       If _ListObj[i]._MoveCountX<0 Then _ListObj[i]._Dx:=-_ListObj[i]._Dx;
       _ListLines[_ListObj[i]._idObj]._XY1.X:=_ListLines[_ListObj[i]._idObj]._XY1.X+_ListObj[i]._Dx;
       _ListLines[_ListObj[i]._idObj]._XY2.X:=_ListLines[_ListObj[i]._idObj]._XY2.X+_ListObj[i]._Dx;
       _ListLines[_ListObj[i]._idObj]._xSpr:=_ListLines[_ListObj[i]._idObj]._xSpr+_ListObj[i]._Dx;
       If (_LineStayIndex=_ListObj[i]._idObj) Then
        begin
          _StayOnObj:=_LineStayIndex;
          _IdInClass:=i;
        end;
      end;
   end;
end;

{ CMovingObjects }

constructor CMovingObjects.Create;
begin
  _MoveCountY:=0;
  _MoveCountX:=0;
  _Dx:=0;
  _Dy:=0;
  _DistX:=0;
  _DistY:=0;
  _IdObj:=0;
  _Move:=True;
end;

procedure CEngine.Teleport(Xen, Yen: Integer);
begin
{  If _Xobj=_Xend Then
   _tdx:=0;

  If _Xobj<_Xend Then
    _xObj:=_xObj+_tDx
  else
    _xObj:=_xObj-_tDx;

  If _Yobj=_Yend Then
   _tdy:=0;

  If _Yobj<_Yend Then
    _yObj:=_yObj+_tDy
  else
    _yObj:=_yObj-_tDy;

  If (_tdx = 0) and (_tdy =0 ) Then
  }
  _Stay:=False;
  _Xobj:=Xen;
  _YObj:=Yen;
//  _Teleport:=False;
end;

end.
