{labai tvarkingas modulis, kartojasi ne tik tarpai}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄ( C ) Copyright 1994 By Kimmo Fredriksson.ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄYou may use this unit freely in your programs, and distribute them,ÄÄÄÄÄÄ}
{ÄÄÄbut you are *NOT* allowed to distribute any modified form of thisÄÄÄÄÄÄÄÄ}
{ÄÄÄunit, not source, nor the compiled TPU, TPP or whatsoever, *without*ÄÄÄÄÄ}
{ÄÄÄmy permission! In it's original form, this source is freeware.ÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄInternet email: Kimmo.Fredriksson@Helsinki.FIÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}

{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄIf you want the Turbo Pascal and assembler source code for the TxtMapÄÄÄÄ}
{ÄÄÄUnit, register today. Send $20 (or 100 Fmk) to me, and I'll send allÄÄÄÄÄ}
{ÄÄÄthe source to you.ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄKimmo FredrikssonÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄSilvontie 38ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄ37740 HaukilaÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄFINLANDÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}

{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P+,Q-,R-,S-,T-,V-,X+}

UNIT	L3DWorld;

	INTERFACE

USES	TxtMap;

CONST   Copyright 	= '(C) 1994 By Kimmo Fredriksson';

	ChkHit		: Boolean = TRUE;    { check hit-the-wall ?  }
	HitDist		= 4 * WorldXZ DIV 3; { hits the wall at this dist. }

	WXDim		= 256 DIV 2;		{ Size of the world }
	WZDim		= 256 DIV 2;


TYPE	IntARRAY	= ARRAY[ 0..16383 ] OF Integer; { used to casts }
	ByteARRAY	= ARRAY[ 0..16383 ] OF Byte;

	IntAPtr		= ^IntARRAY;
	ByteAPtr	= ^ByteARRAY;

	WallTableTYPE	= ARRAY[ 0..WXDim * 2 DIV 8 - 1, 0..WZDim * 2 - 1 ] OF Byte;

	WallDataTYPE	= RECORD
			    MinWX     : Word; { These are updated when }
			    MinWZ     : Word; { building the world so, that }
			    MaxWX     : Word; { MinW? and MaxW? tell the }
			    MaxWZ     : Word; { upper-left and lower-right }
			    WallTable : ^WallTableTYPE;
			    TableSize : Word;
			  END;

	{ This data structure is used to hit-the-wall-check. }
	{ If the bit corresponding to players position is set, then }
	{ player has hit the wall }

CONST	WallData	: WallDataTYPE = ( MinWX : WXDim;
					   MinWZ : WZDim;
					   MaxWX : 0;
					   MaxWZ : 0 );

PROCEDURE SetWallTxtObjX( xF, xT, Zc : Integer; TI : Byte );
PROCEDURE SetWallTxtObjZ( zF, zT, Xc : Integer; TI : Byte );
PROCEDURE SetWallTxtObjBoxIn ( xF, zF, xT, zT : Integer; T0, T1, T2, T3 : Byte );
PROCEDURE SetWallTxtObjBoxOut( xF, zF, xT, zT : Integer; T0, T1, T2, T3 : Byte );
PROCEDURE SetWallTxtObjPoly( xc, zc : IntAPtr; TI : ByteAPtr; n : Word );
FUNCTION  GetOneWall( xc, zc : Integer ) : Boolean;
PROCEDURE MovePoint( VAR XP, ZP : LongInt; VAR X, Z : Integer; Xd, Zd, Angle : Integer );
PROCEDURE MoveEye( Angle, Speed : Integer );
PROCEDURE TurnEye( Angle : Integer );
PROCEDURE SetEyePos( EyeX, EyeZ, Angle : Integer );

	IMPLEMENTATION

USES	AsmSys;

{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE Initilize                                                     º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE Initialize;
BEGIN
  WallDataPtr := @WallData;
  NormX := WXDim;   { needed to convert user-points to porgrams own internal }
  NormZ := WZDim;   { form }
  WITH WallData DO
    BEGIN
      New( WallTable );
      TableSize := SizeOf( WallTableTYPE );
      FillChar( WallTable^, SizeOf( WallTableTYPE ), 0 ); { begin with no walls }
    END;
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetOneWall                                                    º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Coordinates of the wall                                        º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Set the bit on int the WallTable, corresponding the input wall          º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetOneWall( xc, zc : Integer );
VAR msk : Byte;
BEGIN
  WITH WallData DO
    BEGIN
      MinWX := MinIn( MinWX, xc ); { update the upper-left and lower-right }
      MinWZ := MinIn( MinWZ, zc ); { coordinates of the world, }
      MaxWX := MaxIn( MaxWX, xc ); { needed to draw the map }
      MaxWZ := MaxIn( MaxWZ, zc );
      msk := 1 SHL ( Abs( xc MOD 8 )); { 8-bits/byte --> 8 walls/byte }
      xc := xc DIV 8;
      WallTable^[ xc, zc ] := WallTable^[ xc, zc ] OR msk;
    END
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º FUNCTION GetOneWall                                                     º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : coordinates to check for wall                                  º
 º Output : TRUE, if wall found, FALSE otherwise                           º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º This function is needed to check if player walked against the wall.     º
 º Look also SetOneWall.                                                   º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
FUNCTION GetOneWall( xc, zc : Integer ) : Boolean;
VAR msk : Byte;
BEGIN
  msk := 1 SHL ( Abs( xc MOD 8 ));
  xc := xc DIV 8;
  GetOneWall := ( WallData.WallTable^[ xc, zc ] AND msk ) <> 0;
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º FUNCTION HitTheWallX                                                    º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : moving point's x, z coordinates, and angle of direction        º
 º Output : TRUE, if point hit the wall in x-direction, FALSE otherwise    º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º xc, zc are 8-bit fixed-point numbers.                                   º
 º HitTheWallZ doas the same as this, but in Z-direction                   º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
FUNCTION HitTheWallX( xc, zc : LongInt; Angle : Integer ) : Boolean;
VAR z0, z1 : Integer;
BEGIN
  xc := xc * 2;  { walls was saved that way... }
  zc := zc * 2;
  IF ChkHit THEN  { do we care the hits of... }
    BEGIN
      z0 := ( zc DIV 256 ) DIV WorldXZ; { position in WallTable }
      z1 := ( zc DIV 256 + WorldXZ DIV 2 ) DIV WorldXZ;
      xc := xc DIV 256;
      zc := zc DIV 256 DIV WorldXZ;
      IF ( Angle >= 0 ) AND ( Angle < 180 ) THEN
	  xc := ( xc + WorldXZ + HitDist ) DIV WorldXZ
	ELSE
	  xc := ( xc - HitDist ) DIV WorldXZ;
      HitTheWallX := GetOneWall( xc, zc ) OR GetOneWall( xc, zc + 1 )
    END
  ELSE
    HitTheWallX := FALSE
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º FUNCTION HitTheWallZ                                                    º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : moving point's x, z coordinates, and angle of direction        º
 º Output : TRUE, if point hit the wall, FALSE otherwise                   º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º xc, zc are 8-bit fixed-point numbers.                                   º
 º HitTheWallX does the same as this, but in the X-direction.              º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
FUNCTION HitTheWallZ( xc, zc : LongInt; Angle : Integer ) : Boolean;
VAR x0, x1 : Integer;
BEGIN
  xc := xc * 2;
  zc := zc * 2;
  IF ChkHit THEN
    BEGIN
      x0 := ( xc DIV 256 ) DIV WorldXZ;
      x1 := ( xc DIV 256 + WorldXZ DIV 2 ) DIV WorldXZ;
      xc := xc DIV 256 DIV WorldXZ;
      zc := zc DIV 256;
      IF ( Angle >= 90 ) AND ( Angle < 270 ) THEN
	  zc := ( zc - HitDist ) DIV WorldXZ
	ELSE
	  zc := ( zc + WorldXZ + HitDist ) DIV WorldXZ;
      HitTheWallZ := GetOneWall( xc, zc ) OR GetOneWall( xc + 1, zc )
    END
  ELSE
    HitTheWallZ := FALSE
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE MakeWall                                                      º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Wall-tile's Left and Right coordinates, when viewing from Frontº
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Set the corresponding bits on in the WallTable, which we check out for  º
 º any walls after each step.                                              º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE MakeWall( x1, x2, z1, z2 : Integer );
BEGIN
  x1 := ( x1 + WXDim DIV 2 ) * 2;
  x2 := ( x2 + WXDim DIV 2 ) * 2;
  z1 := ( z1 + WZDim DIV 2 ) * 2;
  z2 := ( z2 + WZDim DIV 2 ) * 2;
  SetOneWall( x1, z1 );   { left edge }
  SetOneWall(( x1 + x2 ) DIV 2, ( z1 + z2 ) DIV 2 ); { center }
  SetOneWall( x2, z2 ); { right edge }
  IF x1 = x2 THEN { where the slab faces to ? }
    BEGIN
      Inc( x1, Sgn( z1 - z2 ));
      Inc( x2, Sgn( z1 - z2 ));
    END
  ELSE
    BEGIN
      Inc( z1, Sgn( x2 - x1 ));
      Inc( z2, Sgn( x2 - x1 ));
    END;
  SetOneWall( x1, z1 ); { make double wall }
  SetOneWall(( x1 + x2 ) DIV 2, ( z1 + z2 ) DIV 2 );
  SetOneWall( x2, z2 );
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE InitWall                                                      º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Wall-tile's Left and Right coordinates, when viewing from      º
 º          Front, and index of desired texture                            º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE InitWall( x1, x2, z1, z2 : Integer; TI : Byte );
BEGIN
  MakeWall( x1, x2, z1, z2 );
  InitWallTxtObj( x1, x2, z1, z2, TI );
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetWallTxtObjX                                                º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Left and Right X-coordinates of the wall, when viewing from    º
 º          Front side, and corresponding Z-coordinate and texture inexes. º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Make a wall which consists of texture TI. Coordinates must be given in  º
 º right order (first left, then right, viewed from front), because if     º
 º vewed from wrong side, the wall is invisible.                           º
 º See also the SetWallTxtObjZ-procedure.                                  º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetWallTxtObjX( xF, xT, Zc : Integer; TI : Byte );
VAR i : Integer;
BEGIN
  IF xF = xT THEN Exit;
  IF xF < xT THEN
    FOR i := xF TO Pred( xT ) DO InitWall( i, i + 1, Zc, Zc, TI )
  ELSE
    FOR i := xF DOWNTO Succ( xT ) DO InitWall( i, i - 1, Zc, Zc, TI );
  InitLongWall( xF, xT, Zc, Zc );
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetWallTxtObjZ                                                º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Left and Right Z-coordinates of the wall, when viewing from    º
 º          Front side, and corresponding X-coordinate and texture inexes. º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Make a wall which consists of texture TI. Coordinates must be given in  º
 º right order (first left, then right, viewed from front), because if     º
 º vewed from wrong side, the wall is invisible.                           º
 º See also the SetWallTxtObjX-procedure.                                  º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetWallTxtObjZ( zF, zT, Xc : Integer; TI : Byte );
VAR i : Integer;
BEGIN
  IF zF = zT THEN Exit;
  IF zF < zT THEN
    FOR i := zF TO Pred( zT ) DO InitWall( Xc, Xc, i, i + 1, TI )
  ELSE
    FOR i := zF DOWNTO Succ( zT ) DO InitWall( Xc, Xc, i, i - 1, TI );
  InitLongWall( Xc, Xc, zF, zT );
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetWallTxtObjBoxIn                                            º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Coordinates of opposite corners, and texture indexes           º
 º          corresponding to each side                                     º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Make a box using walls. Viewer must be inside of this box, because it   º
 º will not be visible when viewed outside.                                º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetWallTxtObjBoxIn( xF, zF, xT, zT : Integer; T0, T1, T2, T3 : Byte );
BEGIN
  IF ( zF = zT ) OR ( xF = xT ) THEN Exit;
  IF xF > xT THEN SwapInt( xF, xT );
  IF zF < zT THEN SwapInt( zF, zT );
  SetWallTxtObjX( xF, xT, zF, T0 );
  SetWallTxtObjZ( zF, zT, xT, T1 );
  SetWallTxtObjX( xT, xF, zT, T2 );
  SetWallTxtObjZ( zT, zF, xF, T3 );
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetWallTxtObjBoxOut                                           º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Coordinates of opposite corners, and texture indexes           º
 º          corresponding to each side                                     º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Make a box using walls. Viewer must be outside of this box, because it  º
 º will not be visible when viewed inside.                                 º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetWallTxtObjBoxOut( xF, zF, xT, zT : Integer; T0, T1, T2, T3 : Byte );
BEGIN
  IF ( zF = zT ) OR ( xF = xT ) THEN Exit;
  IF xF > xT THEN SwapInt( xF, xT );
  IF zF < zT THEN SwapInt( zF, zT );
  SetWallTxtObjX( xT, xF, zF, T0 );
  SetWallTxtObjZ( zT, zF, xT, T1 );
  SetWallTxtObjX( xF, xT, zT, T2 );
  SetWallTxtObjZ( zF, zT, xF, T3 );
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetWallTxtObjPoly                                             º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Pointers to tables, that contai the x, z coordinates, and      º
 º          corresponding texture indexes, and number of the points.       º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Make n walls, which starting and ending points are found in the tables. º
 º You MUST specify the walls so, that first comes the Left edge, and then º
 º the Right edge, when viewing from Front.                                º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetWallTxtObjPoly( xc, zc : IntAPtr; TI : ByteAPtr; n : Word );
VAR i, j : Integer;
BEGIN
  FOR i := 0 TO n - 1 DO
    BEGIN
      j := ( i + 1 ) MOD n; { make closed wall }
      IF xc^[ i ] = xc^[ j ] THEN { where does it face to ? }
	SetWallTxtObjZ( zc^[ i ], zc^[ j ], xc^[ i ], TI^[ i ] )
      ELSE
	SetWallTxtObjX( xc^[ i ], xc^[ j ], zc^[ i ], TI^[ i ] );
    END
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE MovePoint                                                     º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : XP, ZP are 8-bit fixed-pooint coordinates; X, Z are their inte-º
 º          ger parts; Xd, Zd, movement in X and Z directions; Angle is    º
 º          viewing angle, not necessarely to moving direction             º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Move the point, and if it didn't hit the wall, return new position.     º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE MovePoint( VAR XP, ZP : LongInt; VAR X, Z : Integer; Xd, Zd, Angle : Integer );
VAR Xtmp0, Ztmp0, Xtmp1, Ztmp1 : LongInt;
BEGIN
  Xtmp0 := XP + Xd;
  Ztmp0 := ZP + Zd; { check X and Z directions separately }
  IF NOT HitTheWallX( Xtmp0, ZP, Angle ) THEN Xtmp1 := Xtmp0 ELSE Xtmp1 := XP;
  IF NOT HitTheWallZ( XP, Ztmp0, Angle ) THEN Ztmp1 := Ztmp0 ELSE Ztmp1 := ZP;
  XP := Xtmp1; { if we didn't hit the wall, return new coordinates }
  ZP := Ztmp1;
  X := XP DIV 256;
  Z := ZP DIV 256
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE MoveEye                                                       º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : Speed and direction of the movement                            º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º If you want to move backwards, for examble, you should use Angle of 180 º
 º degrees, and positive speed, and NOT angle of 0, and negative speed,    º
 º because that would corrupt the hit-the-wall checking.                   º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE MoveEye( Angle, Speed : Integer );
VAR Xd, Zd : Integer;
BEGIN
  WITH EyePA DO
    BEGIN
      Angle := ( YAng + Angle ) MOD 360;  { make sure that the angle }
      IF Angle < 0 THEN Inc( Angle, 360 ); { is between 0..359 }
      Xd := Integer( DSin[ Angle ] ) * Speed;
      Zd := Integer( DCos[ Angle ] ) * Speed;
      MovePoint( XP, ZP, X, Z, Xd, Zd, Angle )
    END
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE TurnEye                                                       º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : how many degrees to turn, and turning direction (sign)         º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Angle is converted to between 0-359                                     º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE TurnEye( Angle : Integer );
BEGIN
  WITH EyePA DO
    BEGIN
      YAng := ( YAng + Angle ) MOD 360;
      IF YAng < 0 THEN Inc( YAng, 360 )
    END
END;
{
 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
 º PROCEDURE SetEyePos                                                     º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Input  : 'Eye's' coordinates in the XZ plane, and viewing angle         º
 ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¶
 º Coordinates must be between -WXDim/2..WXDim/2 and -WZDim/2..WZDim/2.    º
 º Coordinates are trasformed to positive, or to range 0..WXDim, 0..WZDim, º
 º and then they will be multiplied by WorldXZ, in order to move little    º
 º smaller steps (using integer arithmetic, of cource).                    º
 º XP and ZP contains the coordinates in 8-bit fixed-point form.           º
 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
}
PROCEDURE SetEyePos( EyeX, EyeZ, Angle : Integer );
BEGIN
  WITH EyePA DO
    BEGIN
      X := EyeX;
      Z := EyeZ;
      MakeWorldPoint( X, Z );
      XP := LongInt( X ) * 256;
      ZP := LongInt( Z ) * 256;
      YAng := Angle;
    END;
END;

BEGIN
  Initialize
END.

{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄTexture-mapping & rotation + perspective-projection procedures.ÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄ( C ) Copyright 1994 By Kimmo Fredriksson.ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄThis source is *NOT* public domain, freeware or anything like that!ÄÄÄÄÄÄ}
{ÄÄÄYou may use this unit in your programs freely, but you are *NOT* ÄÄÄÄÄÄÄÄ}
{ÄÄÄallowed to distribute this source in any form. The compiled TPU mayÄÄÄÄÄÄ}
{ÄÄÄbe distributed only in its original unmodified form.ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄInternet email: Kimmo.Fredriksson@Helsinki.FIÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄKimmo FredrikssonÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄSilvontie 38ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄ37740 HaukilaÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄFINLANDÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}

{$A+   Word Alignment                              }
{$B-   Short-circuit Boolean expression evaluation }
{$D-   Debug information off                       }
{$E-   Disable 80x87 run-time library              }
{$F-   Force Far Calls off                         }
{$G+   80286 instructions                          }
{$I-   I/O checking off                            }
{$L-   Local Symbols off                           }
{$N-   Calc reals by software                      }
{$O-   Overlays not allowed                        }
{$P-   Open string parameters disabled             }
{$Q-   Overflow Check off                          }
{$R-   Range-checking off			   }
{$S-   Stack-checking off			   }
{$T-   Type-Check pointers off                     }
{$V-   Strict Var-String off			   }
{$X+   Extended Syntax on			   }


UNIT	TxtMap;

	{$DEFINE DirtyDraw}	{ Copy only the parts that changed }
	{$DEFINE ASMProcs}	{ Use assembler or pascal... }

	INTERFACE

CONST   Copyright 	= '(C) 1994 By Kimmo Fredriksson';
	Version		= '1.04';

	MaxPoints	= 1024;	{ 3D-world coordinate points }
	MaxTxtObjs	= 1024;	{ TxtObj are the objects that make the world }
	MaxTextures	= 32;	{ max. amount of textures }
	MaxWalls	= 128;	{ hidden face removal help walls }

	WW		= 128;  { Wall texture width (in pixels) }
	HW		= 128;	{ Wall texture height (in pixels) }

	WWS		= 7;	{ 2^WWS = WW ... }
	HWS		= 7;	{ 2^HWS = HW ... }

	WC		= 48;   { width of creature (in pixeleiss„) }
	HC		= 64;	{ height of... (in pixeleiss„) }

	HCS		= 6;	{ 2^HCS = HC ... }

	WorldXZ		= 64;		{ Wall width and height in }
	WorldY		= WorldXZ;	{ world co'ordinates }

	RemoveHFF	: Boolean = TRUE;	{ Remove Hidden Front Face }

	VScrXMax	= 256;			{ Screen window max x }
	VScrYMax	= 128;                  { Screen window max y }

	PScrXMax	= 320;			{ Physical screen max x }
	PScrYMax	= 200;                  { Physical screen max y }

	VXCent		= VScrXMax DIV 2;
	VYCent		= VScrYMax DIV 2;

	PXCent		= PScrXMax DIV 2;
	PYCent		= PScrYMax DIV 2;

	XAdj		= ( PScrXMax - VScrXMax ) DIV 2; { Adjust window to screen }
	YAdj		= ( PScrYMax - VScrYMax ) DIV 2; { Adjust window to screen }

	WOAdj		= YAdj * PScrXMax + XAdj;

	FarAway		= ( 25 * WorldXZ ) * ( 25 * WorldXZ );
	VeryClose       = WorldXZ * WorldXZ;

	CeilC		: Byte	= 64 * 2 + 48;
	FloorC		: Byte	= 64 * 3 + 16;

	TxtObj		= 0;	{ object types }
	Creature	= 1;
	Worm		= 2;

	NumOfTxtObjs	: Integer = 0;	{ number of texture objects... }
	NumOfVisTxtObjs	: Integer = 0;  { ...that many are visible }
	NumOfWalls	: Integer = 0;  { used to hidden face removal... }
	NumOfVisWalls	: Integer = 0;  { how many, and how many visible }
	NumOfPoints	: Integer = 0;	{ number of points (really) }
	NumOfTxts	: Integer = 0;	{ number of textures }

	NormX		: Integer = 0;
	NormZ		: Integer = 0;

	{$I SinCos.INC}	{ sin&cos tables, saved as 16-bit integer, }
			{ 8-bit fixed point }

TYPE	TextPtr		= ^Byte;
	Textures	= ARRAY[ 0..MaxTextures - 1 ] OF TextPtr;

	VirtScrTYPE	= ARRAY[ 0..VScrYMax - 1, 0..VScrXMax - 1 ] OF Byte;
	VirtScrPtr	= ^VirtScrTYPE; { we draw to system memory, and }
					{ then copy the finished picture }
					{ to video memory }

	TxtObjTYPE	= RECORD
			    Distance	: LongInt;   { distance to 'eye' }
			    LPInd	: Word;      { indexies to }
			    RPInd	: Word;      { point-tables }
			    TxtInd	: Byte;      { texture-index }
			    ObjType  	: Byte;      { objects type }
			    Special	: Integer;   { could be used to }
			  END;                       { anything }

	WallTYPE	= RECORD
			    Distance	: LongInt;
			    LPInd	: Word;
			    RPInd	: Word;
			  END;

	TxtObjPtr	= ^TxtObjTYPE;
	WallPtr		= ^WallTYPE;

	TxtObjARRAY	= ARRAY[ 0..MaxTxtObjs - 1 ] OF TxtObjPtr;
	TxtObjARRAYPtr	= ^TxtObjARRAY;

	WallARRAY	= ARRAY[ 0..MaxWalls - 1 ] OF WallPtr;
	WallARRAYPtr	= ^WallARRAY;

	XZPoint		= RECORD
			    X	: Integer;
			    Z	: Integer
			  END;

VAR	x	: ARRAY[ 0..MaxPoints - 1 ] OF Integer; { projected screen- }
	y	: ARRAY[ 0..MaxPoints - 1 ] OF Integer; { coordinates }

	dis	: ARRAY[ 0..MaxPoints - 1 ] OF
	  RECORD
	    Xd	: Integer;	{ X and Z distances from 'eye' }
	    Zd	: Integer;
	  END;

	Points	: ARRAY[ 0..MaxPoints - 1 ] OF XZPoint;
				{ coordinates in the 3D-world, }
				{ Y is constant here }
	EyePA	: RECORD
	  X     : Integer;	{ eyes position, Y is const }
	  Z     : Integer;
	  XP    : LongInt;      { X = XP DIV 256, but: XP <> X * 256, }
	  ZP    : LongInt;      { so the position is 8-bit fixed point }
	  YAng  : Integer;	{ viewing angle, 0-359 }
	END;

	TxtMaps	: Textures;
	Obj	: TxtObjARRAY;
	Walls	: WallARRAY;
	VirtScr	: VirtScrPtr;

	i386	: Boolean;	{ CPU 386 or better ? }

CONST	RawData	= 0;		{ texture's file type, }
	PCXData	= 1;            { Raw = raw-data, PCX = PCX (RLE) file }

TYPE   	WallDataTYPE	= RECORD
			    MinWX     : Word; { These are updated when }
			    MinWZ     : Word; { building the world so, that }
			    MaxWX     : Word; { MinW? and MaxW? tell the }
			    MaxWZ     : Word; { upper-left and lower-right }
			    WallTable : Pointer;
			    TableSize : Word;
			  END;

VAR	WallDataPtr	: ^WallDataTYPE; { stupid and peculiar map saving... :-) }

FUNCTION  LoadWorld( CONST f : STRING ) : Boolean;
FUNCTION  SaveWorld( CONST f : STRING ) : Boolean;
PROCEDURE MakeWorldPoint( VAR xn, zn : Integer );
FUNCTION  LoadTexture( CONST f : STRING; TxtType, FileType : Byte ) : Integer;
FUNCTION  CreateNewTxt( TxtType : Byte ) : Integer;
PROCEDURE InitLongWall( x1, x2, z1, z2  : Integer );
FUNCTION  InitAnimObj( x, z : Integer; OT, TI : Byte; S : Integer ) : Integer;
PROCEDURE InitWallTxtObj( x1, x2, z1, z2 : Integer; TI : Byte );
PROCEDURE ShowWholeVirtScr;
PROCEDURE DoMove;

	IMPLEMENTATION

{ For the rest of the unit, please register }

