+' 3D rocket simulator. Rocket takes off from the surface of the planet.
+'
+' By Svjatoslav Agejenko.
+' Email: svjatoslav@svjatoslav.eu
+' Homepage: http://www.svjatoslav.eu
+
+' Changelog:
+' 2001, Initial version
+' 2024, Improved program readability using AI
+'
+' Usage:
+' arrow keys - move around
+' 2, 6, 4, 8 - look around
+' - - fly up
+' + - fly down
+
+DECLARE SUB addp ()
+DECLARE SUB addl ()
+DEFDBL A-Z
+DECLARE SUB teerock ()
+DECLARE SUB teemaa ()
+DECLARE SUB start ()
+DECLARE SUB n3d ()
+
+DIM SHARED pointX(1 TO 1500)
+DIM SHARED pointY(1 TO 1500)
+DIM SHARED pointZ(1 TO 1500)
+
+DIM SHARED linePoint1(1 TO 3000)
+DIM SHARED linePoint2(1 TO 3000)
+DIM SHARED lc(1 TO 3000)
+
+DIM SHARED onScreenPointX(1 TO 1900)
+DIM SHARED onScreenPointY(1 TO 1900)
+
+DIM SHARED rkx(1 TO 200)
+DIM SHARED rky(1 TO 200)
+DIM SHARED rkz(1 TO 200)
+
+DIM SHARED pointCount, lineCount
+DIM SHARED cameraX, cameraY, cameraZ
+DIM SHARED cameraXSpeed, cameraYSpeed, cameraZSpeed
+DIM SHARED my1, my2
+
+DIM SHARED ox1(1 TO 2500)
+DIM SHARED oy1(1 TO 2500)
+DIM SHARED ox2(1 TO 2500)
+DIM SHARED oy2(1 TO 2500)
+DIM SHARED frm, frm2, frm3
+
+DIM SHARED mk, mks, rs, rst
+DIM SHARED pi
+DIM SHARED rkb, rke, rkm
+DIM SHARED rx, ry, rz, rxp, ryp, rzp
+
+DIM SHARED tmr$, ts
+DIM SHARED ale
+
+start
+my1 = -pi / 2
+
+' Initialize the rocket position and velocity
+rx = 0
+ry = mk / 2 + .009
+rz = 0
+
+cameraX = 0
+cameraY = mk / 2
+cameraZ = -.05
+
+ts = 0
+frm2 = 999999
+tmr$ = TIME$
+1
+frm = frm + 1
+frm2 = frm2 + 1
+
+' Display the current values of some variables
+LOCATE 1, 1
+PRINT pointCount, lineCount, mk, mks
+LOCATE 2, 1
+PRINT rkb, rke, TIMER
+
+' Update rocket position and velocity
+rx = rx + (rxp * ts)
+ry = ry + (ryp * ts)
+rz = rz + (rzp * ts)
+
+' Update the rocket's pitch and roll rates
+ryp = ryp + (.0098 * ts)
+rxp = SIN(frm / 20) / 50
+
+' Update the points that make up the rocket
+FOR a = 1 TO rkm
+ pointX(a + rkb - 1) = rkx(a) + rx
+ pointY(a + rkb - 1) = rky(a) + ry
+ pointZ(a + rkb - 1) = rkz(a) + rz
+NEXT a
+
+' Update the observer position and velocity
+cameraX = cameraX + (cameraXSpeed * ts)
+cameraY = cameraY + (cameraYSpeed * ts)
+cameraZ = cameraZ + (cameraZSpeed * ts)
+
+' Draw the 3D scene
+n3d
+
+' Handle user input
+a$ = INKEY$
+IF a$ <> "" THEN
+ IF a$ = CHR$(0) + "H" THEN
+ ' Move forward
+ cameraZSpeed = cameraZSpeed - SIN(my1) / 100
+ cameraXSpeed = cameraXSpeed + COS(my1) / 100
+ END IF
+ IF a$ = CHR$(0) + "P" THEN
+ ' Move backward
+ cameraZSpeed = cameraZSpeed + SIN(my1) / 100
+ cameraXSpeed = cameraXSpeed - COS(my1) / 100
+ END IF
+ IF a$ = CHR$(0) + "M" THEN
+ ' Move right
+ cameraZSpeed = cameraZSpeed + COS(my1) / 100
+ cameraXSpeed = cameraXSpeed + SIN(my1) / 100
+ END IF
+ IF a$ = CHR$(0) + "K" THEN
+ ' Move left
+ cameraZSpeed = cameraZSpeed - COS(my1) / 100
+ cameraXSpeed = cameraXSpeed - SIN(my1) / 100
+ END IF
+
+ ' Change the viewing angle
+ IF a$ = CHR$(27) THEN SYSTEM
+ IF a$ = "4" THEN my1 = my1 + .1
+ IF a$ = "6" THEN my1 = my1 - .1
+ IF a$ = "2" THEN my2 = my2 + .1
+ IF a$ = "8" THEN my2 = my2 - .1
+ IF a$ = "-" THEN cameraYSpeed = cameraYSpeed + .01
+ IF a$ = "+" THEN cameraYSpeed = cameraYSpeed - .01
+ IF a$ = " " THEN cameraZSpeed = cameraZSpeed / 2: cameraXSpeed = cameraXSpeed / 2
+END IF
+
+' Calculate the speed and distance of the rocket
+v = SQR(rx * rx + ry * ry + rz * rz)
+s = SQR(rxp * rxp + ryp * ryp + rzp * rzp)
+
+' Display the current frame rate and other information
+IF tmr$ <> TIME$ THEN
+ tmr$ = TIME$
+
+ LOCATE 29, 1
+ PRINT "speed"; INT(s * 1000)
+ LOCATE 30, 1
+ PRINT "fps"; frm3; "timeslice"; INT(ts * 1000); "distance"; v;
+
+ ' Update the frame rate and time slice
+ frm3 = frm2
+ ts = 1 / frm3
+ frm2 = 0
+
+ ' Add new points to the scene
+ addp
+ addl
+END IF
+GOTO 1
+
+SUB addl
+pointCount = pointCount + 1
+pointX(pointCount) = rx
+pointY(pointCount) = ry
+pointZ(pointCount) = rz
+
+IF ale > 0 THEN
+ lineCount = lineCount + 1
+ linePoint1(lineCount) = ale
+ linePoint2(lineCount) = pointCount
+ lc(lineCount) = 13
+END IF
+
+ale = pointCount
+END SUB
+
+SUB addp
+' Add new points to the scene
+pointCount = pointCount + 1
+pointX(pointCount) = rx
+pointY(pointCount) = ry
+pointZ(pointCount) = rz
+
+pointCount = pointCount + 1
+pointX(pointCount) = rx - .001
+pointY(pointCount) = ry - .001
+pointZ(pointCount) = rz
+
+pointCount = pointCount + 1
+pointX(pointCount) = rx + .001
+pointY(pointCount) = ry - .001
+pointZ(pointCount) = rz
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount
+linePoint2(lineCount) = pointCount - 1
+lc(lineCount) = 14
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount - 2
+linePoint2(lineCount) = pointCount - 1
+lc(lineCount) = 14
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount
+linePoint2(lineCount) = pointCount - 2
+lc(lineCount) = 14
+
+END SUB
+
+SUB n3d
+' Convert the 3D points to 2D for drawing
+s1 = SIN(my1)
+c1 = COS(my1)
+
+s2 = SIN(my2)
+c2 = COS(my2)
+
+FOR a = 1 TO pointCount
+ x = pointX(a) - cameraX
+ y = pointY(a) - cameraY
+ z = pointZ(a) - cameraZ
+
+ ' Apply the rotation transformations
+ x1 = x * s1 + z * c1
+ z1 = x * c1 - z * s1
+
+ y1 = z1 * s2 + y * c2
+ z2 = z1 * c2 - y * s2
+
+ ' Project the 3D point to 2D
+ IF z2 < .00001 THEN
+ onScreenPointX(a) = -1
+ ELSE
+ onScreenPointX(a) = x1 / z2 * 200 + 320
+ onScreenPointY(a) = 240 - y1 / z2 * 200
+
+ ' Check if the point is within the screen boundaries
+ IF onScreenPointX(a) < -50 OR onScreenPointX(a) > 1000 OR onScreenPointY(a) > 1000 THEN
+ onScreenPointX(a) = -1
+ END IF
+ END IF
+NEXT a
+
+' Draw the lines that make up the rocket
+FOR a = 1 TO lineCount
+ p1 = linePoint1(a)
+ p2 = linePoint2(a)
+ x1 = onScreenPointX(p1)
+ y1 = onScreenPointY(p1)
+ x2 = onScreenPointX(p2)
+ y2 = onScreenPointY(p2)
+
+ ' Check if the line is within the screen boundaries.
+ ' If so, erase line at old locations
+ IF ox1(a) = -1 OR ox2(a) = -1 THEN
+ ELSE
+ LINE (ox1(a), oy1(a))-(ox2(a), oy2(a)), 0
+ END IF
+
+ ' Draw the line if both endpoints are within the screen boundaries
+ IF x1 <> -1 AND x2 <> -1 THEN
+ LINE (x1, y1)-(x2, y2), lc(a)
+ END IF
+
+ ' Update the old endpoints of the line for the next frame
+ ox1(a) = x1
+ oy1(a) = y1
+ ox2(a) = x2
+ oy2(a) = y2
+NEXT a
+
+END SUB
+
+SUB start
+' Initialize the graphics mode and set up the scene
+SCREEN 12
+VIEW PRINT 1 TO 30
+
+mk = 12714
+mks = 500
+rst = 4
+pi = 3.142657
+rs = .00002
+frm2 = 0
+
+ale = -1
+pointX(1) = -.001
+pointY(1) = mk / 2
+pointZ(1) = -.001
+
+pointX(2) = .001
+pointY(2) = mk / 2
+pointZ(2) = -.001
+
+pointX(3) = .001
+pointY(3) = mk / 2
+pointZ(3) = .001
+
+pointX(4) = -.001
+pointY(4) = mk / 2
+pointZ(4) = .001
+
+pointCount = 4
+
+' Set up the initial lines that make up the rocket
+linePoint1(1) = 1
+linePoint2(1) = 2
+lc(1) = 14
+
+linePoint1(2) = 2
+linePoint2(2) = 3
+lc(2) = 14
+
+linePoint1(3) = 3
+linePoint2(3) = 4
+lc(3) = 14
+
+linePoint1(4) = 4
+linePoint2(4) = 1
+lc(4) = 14
+
+lineCount = 4
+
+' Initialize the observer position and velocity
+cameraX = 0
+cameraY = mk * 2
+cameraZ = -35
+
+teemaa
+cameraXSpeed = 0
+cameraYSpeed = 0
+cameraZSpeed = 0
+
+my1 = 0
+
+rkb = pointCount + 1
+teerock
+rke = pointCount
+
+' Calculate the number of points that make up the rocket
+rkm = rke - rkb + 1
+
+' Copy the initial points to the arrays for the rocket
+FOR a = 1 TO rkm
+ p = rkb + a - 1
+ rkx(a) = pointX(p)
+ rky(a) = pointY(p)
+ rkz(a) = pointZ(p)
+NEXT a
+
+END SUB
+
+SUB teemaa
+' Generate the points that make up the earth
+tmpp = pointCount
+le2 = 0
+
+FOR z = -(mk / 3) TO (mk / 3) STEP mks
+ le = 0
+ le2 = le2 + 1
+
+ FOR x = -(mk / 3) TO (mk / 3) STEP mks
+ ' Check if the point is within the rocket's radius
+ IF SQR(x * x + z * z) > (mk / 2.5) THEN GOTO 4
+
+ le = le + 1
+
+ ' Add the first point of the line
+ IF le = 1 THEN
+ xs = x / mks
+ END IF
+
+ pointCount = pointCount + 1
+ pointX(pointCount) = x
+ v = SQR(x * x + z * z)
+ pointY(pointCount) = SQR((v + (mk / 2)) * ((mk / 2) - v))
+ pointZ(pointCount) = z
+
+ ' Add the line to the list of lines
+ IF le > 1 THEN
+ lineCount = lineCount + 1
+ linePoint1(lineCount) = pointCount
+ linePoint2(lineCount) = pointCount - 1
+ lc(lineCount) = 3
+ END IF
+
+ ' Add the line to the list of lines if it is part of a circle
+ IF le2 > 1 THEN
+ IF xso > (x / mks) THEN GOTO 4
+ IF xso + leo <= (x / mks) THEN GOTO 4
+
+ lineCount = lineCount + 1
+ linePoint1(lineCount) = pointCount
+ linePoint2(lineCount) = pointCount - leo - xso + xs
+ lc(lineCount) = 3
+ END IF
+
+ 4
+ NEXT x
+
+ ' Update the variables for the next circle
+ leo = le
+ xso = xs
+NEXT z
+
+END SUB
+
+SUB teerock
+' Generate the points that make up the rocket
+s = 50
+
+FOR y = -9 TO 10 STEP rst
+ st = pi * 2 / 6
+
+ IF y > 5 THEN
+ s = s - 3
+ END IF
+
+ IF y > 8 THEN
+ s = s - 6
+ END IF
+
+ FOR a = 0 TO pi * 2 STEP st
+ x1 = SIN(a) * s
+ z1 = COS(a) * s
+
+ pointCount = pointCount + 1
+ pointX(pointCount) = x1 * rs
+ pointY(pointCount) = y * 50 * rs
+ pointZ(pointCount) = z1 * rs
+
+ ' Add the line to the list of lines
+ IF a > 0 THEN
+ lineCount = lineCount + 1
+ linePoint1(lineCount) = pointCount
+ linePoint2(lineCount) = pointCount - 1
+ lc(lineCount) = 10
+ END IF
+
+ ' Add the line to the list of lines if it is part of a circle
+ IF y > -9 THEN
+ lineCount = lineCount + 1
+ linePoint1(lineCount) = pointCount
+ linePoint2(lineCount) = pointCount - 7
+ lc(lineCount) = 10
+ END IF
+
+ NEXT a
+NEXT y
+
+' Add the points that make up the top of the rocket
+pointCount = pointCount + 1
+pointX(pointCount) = 0
+pointY(pointCount) = 11 * 50 * rs
+pointZ(pointCount) = 0
+
+FOR a = 1 TO 6
+ lineCount = lineCount + 1
+ linePoint1(lineCount) = pointCount
+ linePoint2(lineCount) = pointCount - a
+ lc(lineCount) = 10
+NEXT a
+
+' Add the points that make up the bottom of the rocket
+pointCount = pointCount + 1
+pointX(pointCount) = -100 * rs
+pointY(pointCount) = -450 * rs
+pointZ(pointCount) = 0
+
+pointCount = pointCount + 1
+pointX(pointCount) = 100 * rs
+pointY(pointCount) = -450 * rs
+pointZ(pointCount) = 0
+
+pointCount = pointCount + 1
+pointX(pointCount) = 0
+pointY(pointCount) = -200 * rs
+pointZ(pointCount) = 0
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount
+linePoint2(lineCount) = pointCount - 1
+lc(lineCount) = 12
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount - 2
+linePoint2(lineCount) = pointCount - 1
+lc(lineCount) = 12
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount
+linePoint2(lineCount) = pointCount - 2
+lc(lineCount) = 12
+
+
+
+pointCount = pointCount + 1
+pointX(pointCount) = 0
+pointY(pointCount) = -450 * rs
+pointZ(pointCount) = -100 * rs
+
+pointCount = pointCount + 1
+pointX(pointCount) = 0
+pointY(pointCount) = -450 * rs
+pointZ(pointCount) = 100 * rs
+
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount
+linePoint2(lineCount) = pointCount - 1
+lc(lineCount) = 12
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount - 2
+linePoint2(lineCount) = pointCount - 1
+lc(lineCount) = 12
+
+lineCount = lineCount + 1
+linePoint1(lineCount) = pointCount
+linePoint2(lineCount) = pointCount - 2
+lc(lineCount) = 12
+
+END SUB