/*
   Texturberzogene 3D-Landschaft
   (C) 1995 by Marko Kleine Berkenbusch
*/

?resize 	  TRUE
?stack           16000

?include "VIDEO.H--"
?include "VGA.H--"
?include "SYSTEM.H--"
?include "MATH.H--"
?include "TRIG.H--"
?include "KEYCODES.H--"
?include "FILE.H--"
?include "DOS.H--"
?include "RANDOM.H--"

?define HScale    300
?define VScale    200
?define Breite    256      	  // Breite (in dieser Version unbenutzt)
?define Laenge    256   	  // Lnge  ("   "      "       "       )
?define RastGr   1024             // Rastergroesse
?define Korrektur 100  		  // Korrekturfaktor
?define Range      32  		  // Zeichenbreite (in Rastereinheiten)
?define HalfRange  16  		  // halbe Zeichenbreite
?define XStart      1
?define YStart	    0
?define XEnd      320
?define YEnd      200

long BPos_x, BPos_y, BPos_z ;     // Betrachterposition

word World ; 	     // Segmentadresse der Landschaftsdaten

word VMem ; 	    // Segmentadresse des RAM-gepufferten Bildschirmspeichers

int  xWinkel, yWinkel, zWinkel ;   // Roll- und Gierwinkel des Betrachters

byte pal=FROM "LSCAPE.PAL";                 // 256-Farben Palette

long ActY ;

word oldkeyboardhandle[2] ;

byte updown, downdown, leftdown, rightdown, throttleup, throttledown, quit ;

int speed ;

long Section_x[Range*Range+1],
     Section_y[Range*Range+1],
     Section_z[Range*Range+1] ;

byte SecCol[Range*Range] ;

?define  ROUGHNESS  12

?define  MINCOLOR    1
?define  MAXCOLOR  255

byte lgetpixel (int x, y)
{
 $ MOV  AX, World
 $ MOV  ES, AX
 $ MOV  AX, x
 $ SHL  AX, 8
 $ ADD  AX, y
 $ MOV  BX, AX
 $ MOV  AL, ESBYTE[BX]
}

void lputpixel (int x, y ; byte c)
{
 $ MOV  AX, World
 $ MOV  ES, AX
 $ MOV  AX, x
 $ SHL  AX, 8
 $ ADD  AX, y
 $ MOV  BX, AX
 $ MOV  AL, c
 $ MOV  ESBYTE[BX], AL
}

void adjust (int xa,ya,x,y,xb,yb)
int d,pixel,average;
{
IF( byte lgetpixel(x,y) )
    RETURN;

AX = ABS(xa-xb);
BX = AX;
AX = ABS(ya-yb);
d = AX + BX;

AL = lgetpixel(xa,ya);
AH = 0;
SI = AX;
AL = lgetpixel(xb,yb);
AH = 0;
average = AX + SI * 64 / 2;   // average = pixel(xa,ya)+pixel(xb,yb)/2

AX = RAND() % 64 - 32;
AX = AX * d * ROUGHNESS;
pixel = AX + average / 64;  // v = random - 0.5 * d * ROUGHNESS + average;

IF( pixel < MINCOLOR )
    pixel = MINCOLOR;
ELSE IF( pixel > MAXCOLOR )
    pixel = MAXCOLOR;
lputpixel(x,y,pixel);
}


void sub_divide (int x1,y1,x2,y2)
int x,y;
{
IF( x2-x1 < 2 )
    IF( y2-y1 < 2 )
        return;

x = x1 + x2 / 2;
y = y1 + y2 / 2;

adjust(x1,y1,x,y1,x2,y1);
adjust(x2,y1,x2,y,x2,y2);
adjust(x1,y2,x,y2,x2,y2);
adjust(x1,y1,x1,y,x1,y2);

IF( byte lgetpixel(x,y) == 0 )
    {
    AL = lgetpixel(x1,y1);
    AH = 0;
    SI = AX;
    AL = lgetpixel(x2,y1);
    AH = 0;
    SI += AX;
    AL = lgetpixel(x2,y2);
    AH = 0;
    SI += AX;
    AL = lgetpixel(x1,y2);
    AH = 0;
    AX = AX + SI / 4;
    SI = AX;
    lputpixel(x,y,SI);
    }

 sub_divide(x1,y1,x,y);
 sub_divide(x,y1,x2,y);
 sub_divide(x,y,x2,y2);
 sub_divide(x1,y,x,y2);
}

interrupt keyboardhandle()
{
$ PUSH DS
$ PUSH AX
$ PUSH BX
DS = CS ;
$ IN AL, 0x60
BL = TRUE ;
IF ( AL >= 128 )
    {AL -= 128;
    BL = FALSE;
    }
IF ( AL == s_left )
    leftdown = BL;
ELSE IF ( AL == s_right )
    rightdown = BL;
ELSE IF ( AL == s_up )
    updown = BL;
ELSE IF ( AL == s_down )
    downdown = BL;
ELSE IF ( AL == s_a )
    throttleup = BL ;
ELSE IF ( AL == s_z )
    throttledown = BL ;
ELSE IF ( AL == s_esc )
    quit = TRUE ;
EATKEY();
EOI();
$ POP BX
$ POP AX
$ POP DS
}

void ClearWorld ()
{
 $ MOV  ES, World
 $ MOV  DI, 0x00
 $ XOR  EAX, EAX
 $ MOV  CX, 16384
 $ CLD
 $ REPZ
 $ STOSD
}

void InitAll ()
{
 SETVIDEOMODE(0x13) ;
 BPos_x = 0 ; BPos_z = 0 ; BPos_y = 2000 ; ActY = 2000 ;
 xWinkel = 0 ; yWinkel = 0 ; zWinkel = 0 ;
 updown = FALSE ; leftdown = FALSE ; rightdown = FALSE ; downdown = FALSE ;
 throttleup = FALSE ; throttledown = FALSE ; quit = FALSE ;
 speed = 42 ;
 World = GETMEM(4096) ; VMem = GETMEM(4000) ;
 ClearWorld() ; @RANDOMIZE();
 lputpixel(0,0,RAND()%255);
 lputpixel(255,0,RAND()%255);
 lputpixel(255,255,RAND()%255);
 lputpixel(0,255,RAND()%255);
 sub_divide(0,0,255,255);
 SETVGADAC(0, , 768, , , #pal) ;
 GETINTVECT(#oldkeyboardhandle, KEYBOARD_INT) ;
 SETINTVECT(, KEYBOARD_INT, CS, #keyboardhandle) ;
}

void CleanUp ()
{
 FREEMEM(VMem) ; FREEMEM(World) ;
 SETINTVECT(, KEYBOARD_INT, oldkeyboardhandle[2], oldkeyboardhandle[0]) ;
 SETVIDEOMODE(0x03) ;
}

void FlipPages ()
{
 AX = VMem ;
$ PUSH DS
$ MOV DS, AX
 ES = 0xA000 ;
$ MOV SI, 00
$ MOV DI, 00
$ MOV CX, 16000
$ REPZ
$ MOVSD
$ POP DS
}
/*
void setpixel (int x1, y1 ; byte c)
{
 ES = VMem ;
$ MOV  AX, y1
$ MOV  SI, y1
$ SHL  AX, 8
$ SHL  SI, 6
$ ADD  SI, AX
$ ADD  SI, x1
 ESBYTE[SI] = c ;
}

void Line (int x1, y1, x2, y2 ; byte c)
int xs, ys, xd, yd, d ;
byte ready ;
{
 IF (x1 > x2) xs = -1 ; ELSE xs = 1 ;
 IF (y1 > y2) ys = -1 ; ELSE ys = 1 ;
 xd = ABS(x1-x2) ; yd = ABS(y1-y2) ;
 IF (xd == 0) d = -1 ; ELSE d = 0 ;
 do {
  setpixel(x1, y1, c) ;
  IF (d < 0) {
   y1 += ys ; d += xd ;
  }
  ELSE {
   x1 += xs ; d -= yd ;
  }
  ready = FALSE ;
  IF (x1 == x2)
   IF (y1 == y2) ready = TRUE ;
 } while (ready == FALSE) ;
} */

void HLineDown (word x1, x2, y ; byte cols, cole)
{
$ MOV  AX, VMem
$ MOV  ES, AX
$ MOV  DI, y
$ SHL  DI, 8
$ MOV  AX, y
$ SHL  AX, 6
$ ADD  DI, AX
$ ADD  DI, x1
$ MOV  CX, x2
$ SUB  CX, x1
$ CMP  CX, 1
$ JLE  E
$ MOV  AH, cols
$ SUB  AH, cole
$ XOR  AL, AL
$ XOR  DX, DX
$ DIV  CX
$ MOV  DX, AX
$ MOV  AH, cols
$ XOR  AL, AL
L:
 ESBYTE[DI] = AH ;
$ INC  DI
$ SUB  AX, DX
$ LOOP L
E:
}

void HLineUp (word x1, x2, y ; byte cols, cole)
{
$ MOV  AX, VMem
$ MOV  ES, AX
$ MOV  DI, y
$ SHL  DI, 8
$ MOV  AX, y
$ SHL  AX, 6
$ ADD  DI, AX
$ ADD  DI, x1
$ MOV  CX, x2
$ SUB  CX, x1
$ CMP  CX, 1
$ JLE  E
$ MOV  AH, cole
$ SUB  AH, cols
$ XOR  AL, AL
$ XOR  DX, DX
$ DIV  CX
$ MOV  DX, AX
$ MOV  AH, cols
$ XOR  AL, AL
L:
 ESBYTE[DI] = AH ;
$ INC  DI
$ ADD  AX, DX
$ LOOP L
E:
}

void HLine (word x1, x2, y ; byte cols, cole)
{
 IF (ABS(x1-x2) < 270)
  IF (cole > cols) HLineUp(word x1, word x2, word y, byte cols, byte cole) ;
          	   ELSE HLineDown(word x1, word x2, word y, byte cols, byte cole) ;
}

void HHLine (word x1, x2, y ; byte cols, cole)
int h1, h2 ;
{
 IF (int x1 < XStart) {
  h1 = cole-cols ; h1 = XStart-x1 * h1 ;
  h2 = x2-x1 ; h1 = h1/h2 + cols ; cols = h1 ; x1 = XStart-1 ;
 }
 IF (x2 > XEnd) {
  h1 = cole-cols ; h1 = x2-XEnd * h1 ;
  h2 = x2-x1 ; h1 = -h1/h2 + cole ; cole = h1 ; x2 = XEnd ;
 }
 IF (cole > cols) HLineUp(x1, x2, y, byte cols, byte cole) ;
           	  ELSE HLineDown(x1, x2, y, byte cols, byte cole) ;
}

void DrawPoly (int x1, y1, x2, y2, x3, y3, x4, y4 ; int c1, c2, c3, c4)
int  x, mny, mxy, mnx, mxx, yc, mul1, div1, mul2, div2, mul3, div3, mul4, div4, i, gmxx, gmnx ;
byte b1, b2 ;
int  dcs, dce, h1, h2 ;
{
 mny = y1 ; mxy = y1 ;
 IF (y2 < mny) mny = y2 ;
 IF (y2 > mxy) mxy = y2 ;
 IF (y3 < mny) mny = y3 ;
 IF (y3 > mxy) mxy = y3 ;
 IF (y4 < mny) mny = y4 ;
 IF (y4 > mxy) mxy = y4 ;
 IF (mny < YStart) mny = YStart ;
 IF (mxy > YEnd) mxy = YEnd ;
 gmnx = x1 ; gmxx = x1 ;
 IF (x2 < gmnx) gmnx = x2 ;
 IF (x2 > gmxx) gmxx = x2 ;
 IF (x3 < gmnx) gmnx = x3 ;
 IF (x3 > gmxx) gmxx = x3 ;
 IF (x4 < gmnx) gmnx = x4 ;
 IF (x4 > gmxx) gmxx = x4 ;
 IF (gmnx < XStart) gmnx = XStart ;
 IF (gmxx > XEnd) gmxx = XEnd ;
 if (mny <> mxy)
 if (mny < YEnd) {
  if (mxy > YStart) {
   mul1 = x1-x4 ; div1 = y1-y4 ;
   mul2 = x2-x1 ; div2 = y2-y1 ;
   mul3 = x3-x2 ; div3 = y3-y2 ;
   mul4 = x4-x3 ; div4 = y4-y3 ;
   i = mxy-mny+1 ;
   loop (i) {
    yc = mxy-i ;
    mnx = XEnd+1 ; mxx = XStart-1 ;
    b1 = FALSE ; b2 = FALSE ;
    IF (y4 >= yc)||(y1 >= yc) b1 = TRUE ;
    IF (y4 <= yc)||(y1 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      IF (y4 <> y1) {
       x = yc-y4 * mul1 / div1 + x4 ;
       IF (x < mnx) {
        mnx = x ;
        h1 = y4-y1 ; h2 = c4-c1 ;
        dcs = yc-y1*h2 / h1 + c1 ;
       }
       IF (x > mxx) {
        mxx = x ;
        h1 = y4-y1 ; h2 = c4-c1 ;
        dce = yc-y1*h2 / h1 + c1 ;
       }
      }
     }
    }
    b1 = FALSE ; b2 = FALSE ;
    IF (y1 >= yc)||(y2 >= yc) b1 = TRUE ;
    IF (y1 <= yc)||(y2 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      IF (y1 <> y2) {
       x = yc-y1 * mul2 / div2 + x1 ;
       IF (x < mnx) {
        mnx = x ;
        h1 = y2-y1 ; h2 = c2-c1 ;
        dcs = yc-y1*h2 / h1 + c1 ;
       }
       IF (x > mxx) {
        mxx = x ;
        h1 = y2-y1 ; h2 = c2-c1 ;
        dce = yc-y1*h2 / h1 + c1 ;
       }
      }
     }
    }
    b1 = FALSE ; b2 = FALSE ;
    IF (y2 >= yc)||(y3 >= yc) b1 = TRUE ;
    IF (y2 <= yc)||(y3 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      IF (y2 <> y3) {
       x = yc-y2 * mul3 / div3 + x2 ;
       IF (x < mnx) {
        mnx = x ;
        h1 = y3-y2 ; h2 = c3-c2 ;
        dcs = yc-y2*h2 / h1 + c2 ;
       }
       IF (x > mxx) {
        mxx = x ;
        h1 = y3-y2 ; h2 = c3-c2 ;
        dce = yc-y2*h2 / h1 + c2 ;
       }
      }
     }
    }
    b1 = FALSE ; b2 = FALSE ;
    IF (y3 >= yc)||(y4 >= yc) b1 = TRUE ;
    IF (y3 <= yc)||(y4 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      IF (y3 <> y4) {
       x = yc-y3 * mul4 / div4 + x3 ;
       IF (x < mnx) {
        mnx = x ;
        h1 = y4-y3 ; h2 = c4-c3 ;
        dcs = yc-y3*h2 / h1 + c3 ;
       }
       IF (x > mxx) {
        mxx = x ;
        h1 = y4-y3 ; h2 = c4-c3 ;
        dce = yc-y3*h2 / h1 + c3 ;
       }
      }
     }
    }
    IF (mnx < XStart) mnx = XStart ;
    IF (mxx >= XEnd) mxx = XEnd-1 ;
    IF (mnx >= gmnx) IF (mxx <= gmxx)
     IF (mnx <= mxx) HLine(word mnx-1, word mxx+1, word yc, byte dcs, byte dce) ;
   }
  }
 }
}

void DrawCPoly (long x1; long y1; long x2; long y2; long x3; long y3; long x4; long y4 ; int c1; int c2; int c3; int c4)
long  x, mny, mxy, mnx, mxx, yc, mul1, div1, mul2, div2, mul3, div3, mul4, div4, i ;
byte b1, b2 ;
long  dcs, dce, h1, h2 ;
{
 mny = y1 ; mxy = y1 ;
 IF (long y2 < mny) mny = y2 ;
 IF (long y2 > mxy) mxy = y2 ;
 IF (long y3 < mny) mny = y3 ;
 IF (long y3 > mxy) mxy = y3 ;
 IF (long y4 < mny) mny = y4 ;
 IF (long y4 > mxy) mxy = y4 ;
 IF (long mny < YStart) mny = YStart ;
 IF (long mxy > YEnd) mxy = YEnd ;
 if (long mny <> mxy)
 if (long mny < YEnd) {
  if (long mxy > YStart) {
   mul1 = x1-x4 ; div1 = y1-y4 ;
   mul2 = x2-x1 ; div2 = y2-y1 ;
   mul3 = x3-x2 ; div3 = y3-y2 ;
   mul4 = x4-x3 ; div4 = y4-y3 ;
   i = mxy-mny+1 ;
   loop (i) {
    yc = mxy-i ;
    mnx = XEnd+1 ; mxx = XStart-1 ;
    b1 = FALSE ; b2 = FALSE ;
    IF (long y4 >= yc)||(long y1 >= yc) b1 = TRUE ;
    IF (long y4 <= yc)||(long y1 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      if (long y4 <> y1) {
       x = yc-y4 * mul1 / div1 + x4 ;
       IF (long x < mnx) {
        mnx = x ;
        h1 = y4-y1 ; h2 = c4-c1 ;
        dcs = yc-y1*h2 / h1 + c1 ;
       }
       IF (long x > mxx) {
        mxx = x ;
        h1 = y4-y1 ; h2 = c4-c1 ;
        dce = yc-y1*h2 / h1 + c1 ;
       }
      }
     }
    }
    b1 = FALSE ; b2 = FALSE ;
    IF (long y1 >= yc)||(long y2 >= yc) b1 = TRUE ;
    IF (long y1 <= yc)||(long y2 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      if (long y1 <> y2) {
       x = yc-y1 * mul2 / div2 + x1 ;
       IF (long x < mnx) {
        mnx = x ;
        h1 = y2-y1 ; h2 = c2-c1 ;
        dcs = yc-y1*h2 / h1 + c1 ;
       }
       IF (long x > mxx) {
        mxx = x ;
        h1 = y2-y1 ; h2 = c2-c1 ;
        dce = yc-y1*h2 / h1 + c1 ;
       }
      }
     }
    }
    b1 = FALSE ; b2 = FALSE ;
    IF (long y2 >= yc) b1 = TRUE ;
    IF (long y3 >= yc) b1 = TRUE ;
    IF (long y2 <= yc) b2 = TRUE ;
    IF (long y3 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      if (long y2 <> y3) {
       x = yc-y2 * mul3 / div3 + x2 ;
       IF (long x < mnx) {
        mnx = x ;
        h1 = y3-y2 ; h2 = c3-c2 ;
        dcs = yc-y2*h2 / h1 + c2 ;
       }
       IF (long x > mxx) {
        mxx = x ;
        h1 = y3-y2 ; h2 = c3-c2 ;
        dce = yc-y2*h2 / h1 + c2 ;
       }
      }
     }
    }
    b1 = FALSE ; b2 = FALSE ;
    IF (long y3 >= yc)||(long y4 >= yc) b1 = TRUE ;
    IF (long y3 <= yc)||(long y4 <= yc) b2 = TRUE ;
    if (b1 == TRUE) {
     if (b2 == TRUE) {
      if (long y3 <> y4) {
       x = yc-y3 * mul4 / div4 + x3 ;
       IF (long x < mnx) {
        mnx = x ;
        h1 = y4-y3 ; h2 = c4-c3 ;
        dcs = yc-y3*h2 / h1 + c3 ;
       }
       IF (long x > mxx) {
        mxx = x ;
        h1 = y4-y3 ; h2 = c4-c3 ;
        dce = yc-y3*h2 / h1 + c3 ;
       }
      }
     }
    }
    IF (mnx <= mxx) HHLine(word mnx-1, word mxx+1, word yc, byte dcs, byte dce) ;
   }
  }
 }
}

void Clear (byte c1, c2)
long ms, mc, x1, y1, x2, y2, mv, mvp ;
{
 ES = VMem ;
$ MOV  DI, 0
$ CLD
$ MOV  CX, 16000
$ MOV  BL, c1
$ MOV  BH, BL
$ MOV  AX, BX
$ SHL  EAX, 16
$ MOV  AX, BX
$ REPZ
$ STOSD
 AX = zWinkel << 1 ; BX = AX ;
 ms = sin[BX] ; mc = cos[BX] ;
 x1 = -ms*55 ; x1 -= mc*300 ; x1 = x1 >> 7 ;
 y1 = mc*55 ; y1 -= ms*300 ; y1 = y1 >> 7 ;
 x2 = -ms*55 ; x2 += mc*300 ; x2 = x2 >> 7 ;
 y2 = mc*55 ; y2 += ms*300 ; y2 = y2 >> 7 ;
 y1 = y1*3 >> 2 ; y2 = y2*3 >> 2 ;
 AX = xWinkel << 1 ; BX = AX ;
 mv = -sin[BX]*VScale ; mv = mv >> 7 ;
 IF (xWinkel > 90) IF (xWinkel < 270) -mv ;
 IF (zWinkel > 90) IF (zWinkel < 270) -mv ;
 IF (xWinkel > 90) IF (zWinkel > 90)
 IF (xWinkel < 270) IF (zWinkel < 270) c1 >< c2 ;
 mvp = BPos_y / 100 ;
 IF (xWinkel > 90) IF (xWinkel < 270) -mvp ;
 IF (zWinkel > 90) IF (zWinkel < 270) -mvp ;
 mv += mvp ;
 DrawCPoly(long 160+x1, long 105-y1+mv, long 160+x2, long 105-y2+mv, long 160-x1,
           long y1+105+mv, long 160-x2, long y2+105+mv, byte c1, byte c1, byte c2, byte c2) ;
}

void DrehePunkte (int xWi, yWi, zWi)
word i ;
int xs, xc, ys, yc, zs, zc ;
long h_x, h_y, h_z, z_x, z_y, z_z ;
{
 AX = xWi << 1 ; BX = AX ; xs = sin[BX] ; xc = cos[BX] ;
 AX = yWi << 1 ; BX = AX ; ys = sin[BX] ; yc = cos[BX] ;
 AX = zWi << 1 ; BX = AX ; zs = sin[BX] ; zc = cos[BX] ;
 i = Range*Range ;
 loop (i) {
  AX = i-1 << 2 ; SI = AX ;

  h_x = Section_x[SI] ;
  z_y = Section_y[SI]-BPos_y ;
  h_z = Section_z[SI] ;

  z_x = -ys*h_z ; z_x += yc*h_x ;
  z_z = yc*h_z ; z_z += ys*h_x ;
  z_x = z_x >> 7 ; z_z = z_z >> 7 ;

  h_y = z_y ; h_z = z_z ;
  z_z = -xs*h_y ; z_z += xc*h_z ;
  z_y = xc*h_y ; z_y += xs*h_z ;
  z_z = z_z >> 7 ; z_y = z_y >> 7 ;

  h_x = z_x ; h_y = z_y ;
  z_x = -zs*h_y ; z_x += zc*h_x ;
  z_y = zc*h_y ; z_y += zs*h_x ;
  z_x = z_x >> 7 ; z_y = z_y >> 7 ;

  Section_x[SI] = z_x ;
  Section_y[SI] = z_y+BPos_y ;
  Section_z[SI] = z_z ;
 }
}

void InitSection (long bpx; long bpz)
long i, j, mx, mz, hx, hz, hl, h ;
word h1, h2 ;
{
 FS = World ;
 mx = bpx >> 10 ; mx += Breite >> 1 ;
 mz = bpz >> 10 ; mz += Laenge >> 1 ;
 hx = -Breite >> 1 + mx << 10 ; hx = BPos_x - hx ;
 hz = -Laenge >> 1 + mz << 10 ; hz = BPos_z - hz ;
 h1 = mx << 8 + mz ; SI = h1 ; ActY = FSBYTE[SI] ; ActY = ActY*10 ;
 i = Range ;
 loop (i) {
  hl = i-HalfRange << 10 - hx ;
  h1 = i+mx-HalfRange-1 << 8 + mz-HalfRange-1 ;
  j = Range ;
  loop (j) {
   h2 = i-1 << 5 + j-1 << 2 ; DI = h2 ; SI = h1 + j ;
   h = FSBYTE[SI] ;
   AX = i-1 << 5 + j-1 ; BX = AX ; SecCol[BX] = h ;
   h = h * 10 ;
   Section_y[DI] = h ;
   Section_x[DI] = hl ;
   Section_z[DI] = j-HalfRange << 10 - hz ;
  }
 }
}

void DisplayTerrain ()
long xb[Range*Range], yb[Range*Range], dz;
word i, j ;
byte ddir ;
{
 InitSection(long BPos_x, long BPos_z) ;
 DrehePunkte(xWinkel, yWinkel, zWinkel) ;
 i = Range*Range ;
 loop (i) {
  AX = i-1 << 2 ; DI = AX ; dz = Section_z[DI] ;
  IF (long dz > Korrektur) {
   xb[DI] = Section_x[DI] * HScale / dz + 160 ;
   yb[DI] = BPos_y-Section_y[DI] * VScale / dz + 100 ;
  }
  ELSE xb[DI] = -50000 ;
 }
 IF (yWinkel > 314) ddir = 2 ;
 IF (yWinkel < 46) ddir = 2 ;
 IF (yWinkel > 45) IF (yWinkel < 136) ddir =  1 ;
 IF (yWinkel > 135) IF (yWinkel < 226) ddir = 3 ;
 IF (yWinkel > 225) IF (yWinkel < 315) ddir = 4 ;
 IF (xWinkel > 90) IF (xWinkel < 270) {
  IF (ddir == 1) ddir = 4 ;
  IF (ddir == 2) ddir = 3 ;
  IF (ddir == 3) ddir = 2 ;
  IF (ddir == 4) ddir = 1 ;
 }
 if (ddir == 1) {
  i = Range-1 ;
  loop (i) {
   j = Range-1 ;
   loop (j) {
    AX = i-1 << 5 + j-1 << 2 ; DI = AX ;
    AX = AX >> 2 ; SI = AX ;
    IF (long xb[DI] <> -50000)
     IF (long xb[DI+128] <> -50000)
      DrawPoly(word xb[DI], word yb[DI], word xb[DI+4], word yb[DI+4], word xb[DI+132], word yb[DI+132], word xb[DI+128], word yb[DI+128],
               SecCol[SI], SecCol[SI+1], SecCol[SI+33], SecCol[SI+32]) ;
   }
  }
 }
 if (ddir == 2) {
  i = Range-1 ;
  loop (i) {
   j = Range-1 ;
   loop (j) {
    AX = j-1 << 5 +i-1 << 2 ; DI = AX ;
    AX = AX >> 2 ; SI = AX ;
    IF (long xb[DI] <> -50000)
     IF (long xb[DI+128] <> -50000)
      DrawPoly(word xb[DI], word yb[DI], word xb[DI+4], word yb[DI+4], word xb[DI+132], word yb[DI+132], word xb[DI+128], word yb[DI+128],
               SecCol[SI], SecCol[SI+1], SecCol[SI+33], SecCol[SI+32]) ;
   }
  }
 }
 if (ddir == 3) {
  i = Range-1 ;
  loop (i) {
   j = Range-1 ;
   loop (j) {
    AX = j-1 << 5 + Range-1-i << 2 ; DI = AX ;
    AX = AX >> 2 ; SI = AX ;
    IF (long xb[DI] <> -50000)
     IF (long xb[DI+128] <> -50000)
      DrawPoly(word xb[DI], word yb[DI], word xb[DI+4], word yb[DI+4], word xb[DI+132], word yb[DI+132], word xb[DI+128], word yb[DI+128],
               SecCol[SI], SecCol[SI+1], SecCol[SI+33], SecCol[SI+32]) ;
   }
  }
 }
 if (ddir == 4) {
  i = Range-1 ;
  loop (i) {
   j = Range-1 ;
   loop (j) {
    AX = Range-1-i << 5 +j-1 << 2 ; DI = AX ;
    AX = AX >> 2 ; SI = AX ;
    IF (long xb[DI] <> -50000)
     IF (long xb[DI+128] <> -50000)
      DrawPoly(word xb[DI], word yb[DI], word xb[DI+4], word yb[DI+4], word xb[DI+132], word yb[DI+132], word xb[DI+128], word yb[DI+128],
               SecCol[SI], SecCol[SI+1], SecCol[SI+33], SecCol[SI+32]) ;
   }
  }
 }
/* Line(10, 10, 70, 10, 15) ; Line(70, 10, 70, 50, 15) ;
 Line(70, 50, 10, 50, 15) ; Line(10, 50, 10, 10, 15) ;
 mx = BPos_x >> 10 ; mx += Breite >> 1 ;
 mz = BPos_z >> 10 ; mz += Laenge >> 1 ;
 setpixel(mx&255*60 >> 8 + 10, mz&255*40 >> 8 + 10, 15) ; */
}

void KeyControls ()
long sign, hspeed, bo, bu ;
{
 sign = 1 ;
 IF (xWinkel > 89) IF (xWinkel < 271) sign = -1 ;
 IF (leftdown == TRUE) zWinkel -= 5 ;
 IF (rightdown == TRUE) zWinkel += 5 ;
 IF (zWinkel < 0) zWinkel = 359+zWinkel ;
 IF (zWinkel > 359) zWinkel = zWinkel-359 ;
 IF (updown == TRUE) {
  AX = zWinkel << 1 ; BX = AX ;
  xWinkel += cos[BX] >> 6 ;
 }
 IF (downdown == TRUE) {
  AX = zWinkel << 1 ; BX = AX ;
  xWinkel -= cos[BX] >> 6 ;
 }
 IF (xWinkel > 359) xWinkel = xWinkel-359 ;
 IF (xWinkel < 0) xWinkel = 359+xWinkel ;
 IF (throttleup == TRUE) IF (speed < 500) speed += 6 ;
 IF (throttledown == TRUE) IF (speed > 2) speed -= 6 ;

 IF (zWinkel > 90)
  IF (zWinkel < 179) zWinkel += 2 ;
 IF (zWinkel < 90)
  IF (zWinkel > 1) zWinkel -= 2 ;
 IF (zWinkel > 270)
  IF (zWinkel < 358) zWinkel += 2 ;
                ELSE zWinkel = 0 ;
 IF (zWinkel < 270)
  IF (zWinkel > 181) zWinkel -= 2 ;
 IF (zWinkel == 181) zWinkel = 180 ;
 IF (zWinkel == 179) zWinkel = 180 ;
 IF (zWinkel == 359) zWinkel = 0 ;
 IF (zWinkel == 1) zWinkel = 0 ;

 AX = zWinkel << 1 ; BX = AX ;
 yWinkel += sin[BX]*sign >> 5 ;
 IF (yWinkel > 359) yWinkel = 0 ;
 IF (yWinkel < 0) yWinkel = 359 ;

 AX = yWinkel << 1 ; BX = AX ; AX = xWinkel << 1 ; DI = AX ;
 hspeed = cos[DI]*speed >> 7 ;
 BPos_z += cos[BX]*hspeed >> 7 ;
 BPos_x += sin[BX]*hspeed >> 7 ;
 bu = ActY + 1200 ; IF (long bu > BPos_y) BPos_y = bu+100 ;
 bo = ActY + 4000 ; IF (long bo < BPos_y) BPos_y = bo-100 ;
 hspeed = -sin[DI]*speed >> 7 + BPos_y ;
 IF (long hspeed < bo) IF (long hspeed > bu) BPos_y = hspeed ;
 IF (long hspeed > bo) {
  IF (xWinkel > 180) xWinkel += 1 ;
                ELSE xWinkel -= 1 ;
 }
 IF (long hspeed < bu) {
  IF (xWinkel > 180) xWinkel += 1 ;
	        ELSE xWinkel -= 1 ;
 }
 IF (xWinkel < 0) xWinkel = 0 ; IF (xWinkel > 359) xWinkel = 0 ;
}

main ()
{
 InitAll() ;
 do {
  KeyControls() ; Clear(33, 75) ;
  DisplayTerrain() ;
  FlipPages() ;
 } while (quit == FALSE) ;
 CleanUp() ;
}
