Author Topic: WIP: Dog fight in space...sort of...  (Read 9271 times)

0 Members and 1 Guest are viewing this topic.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
WIP: Dog fight in space...sort of...
« on: June 16, 2019, 05:20:31 pm »
I thought I would share this little ditty for your amusement, still very much a work in progress, but a work that QB64 has largely made possible in its present and (somewhat) working form. I also need to give a big "Thank you" to Petr for the ASCII image routine that I'm using, great stuff that I'm far too dense to come up with on my own.

I used to be a gamemaster of GDW's Traveller RPG. A science fiction role playing game, which included the possibility of ship to ship space combat. Problem with the game system's rules being that it employed a laborious vector plotting process that was too labor intensive to really use without bogging play down with the details. So I just handled such things off the cuff with no real idea of what would actually be taking place in space. I always dreamed of a program that would handle the maneuvering details, and thus was this project born. I'm tickled with the polar tick display, it was one of those rare bits that worked perfectly out of the gate.

I'm having an issue getting menu choices to display, but the controls are simple:

up/down arrows choose the active (highlighted) unit

"V" initiates vector input for the active unit, and asks for an azimuth direction, elevation and acceleration. Accleration is in "Gs", and a little goes a long way in a turn. Fractions of one G will make noticeable changes.

"T" executes a 1000 second game turn using the vectors input with "V" and updates the new positions at the end of the turn.

"Q" Quits

The display changes with the changes in viewpoint of the active unit. The active unit shows speed and heading, while the inactive ones show bearing and distance from the active unit. There are six units of data for debugging purposes, mostly sitting stationary to start, eventually I'll add input and editing functions. As the units speed away from each other the display scale changes to accomodate them. Don't know how far I'll go with it, as far as my poor tender head can accomodate...

While it's envisioned to track in three dimensions, (which apparently needs some work), it only displays two, the x,y plane. My pay grade has limits...  ;)

There are no brakes in space so if you want to stop, you must counterthrust. Also any vector input is assumed to continue from one turn to another unless it's changed, so if you don't "take your foot off the pedal" on a subsequent turn you can really get haulin'. The numbers get big fast which _INTEGER64 made easy to deal with.

Edit: removing _DISPLAY from several places it shouldn't have been got my menu line back.
Installed dynamic scale grid. Installed range bands, turn counter, rudimentary ship editor and fixed aspect ratio bug.
Mouse support installed, and a Sol sized star at azimuth 45 from the starting point, don't fall into it...bad for ya ;)
Added display toggles: R for ranging, G for grid, and A for azimuth wheel
Added mouse choosing of new active unit in sensor display
Added planets, randomly placed in their orbit tracks. Added breaking counterthrust feature.
Started work on an inclinometer display.
Added selected interstellar bodies, this helped me to nail one persistent bug in the zoom display. 7-6-2019
Added satellites and turn based orbital movement. 7-10-2019
Added gravity effects on ships from system bodies. Ships can now crash into bodies. 7-14-2019
Added improved planet impact routine, and random placement of ships. 7-21-2019
Pushed fix of planet rendering bug. 11-22-2019
Added sensor occlusion of planetary bodies, active ship cannot see what's on the other side of a planet from it. Added a relative coordinate system to deal with calculation issues associated with ray tracing ops in the outer planets of the system. Added instant active ship placement via right mouse click in sensor display. Added orbit track on/off toggle. 12-5-2019

Updated GUI tools (with more to come) and scrolling data fields to handle additional ships. 12-9-2019

Added routines to add ships, delete ships, purge destroyed ships from data list, etc.  Added a graphics based vector input routine. Cleaned up assorted bugs and tightened up code where possible. 12-14-19

Added a ship orientation and direction graphic (see attached image files) and a Z panning slider on right side of screen that rotates views around the X axis for visual aid to ranging. 12-25-2019

Uploaded latest version. Lots of changes, bug fixes and a few new features over the last several weeks. Now attached in zip file with executable and subdirectory structure. 2-16-2020

Got rid of much of the zoom in slow down bug, added ring and planetoid belt display, and autosave crash protection. Added a quick and dirty system editor {syseditII} for creating alternate star systems, another work in progress. Also the humble beginnings of a user guide. 7-26-2020

Code: QB64: [Select]
  1. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2. ' CT-Vector (formerly Star Ruttier)
  3. ' 2D6 Sci Fi roleplaying utility
  4. ' coding by Richard Wessel
  5. ' using  QB64 v.1.4
  6. ' Made possible with guidance and code contributions by
  7. ' Bplus, Petr, SMcNeill, and many others at QB64.org forum. Thank you.
  8. ' Thanks to my son Erik for the idea to include an auto counter thrust
  9. ' development and beta test version 0.36  uploaded 7-26-2020
  10. '
  11. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  12.  
  13. '                                                               USER DEFINED VARIABLES
  14. TYPE unitpoint '                                                relative unit placement
  15.     pX AS INTEGER64 '                                           X coordinate / mem 0-7
  16.     pY AS INTEGER64 '                                           Y coordinate / mem 8-15
  17.     pZ AS INTEGER64 '                                           Z coordinate / mem 16-23
  18.  
  19. TYPE ship '                                                     unit info variable
  20.     id AS BYTE '                                                unit ID / mem 0
  21.     Nam AS STRING * 10 '                                        unit name / mem 1 - 10
  22.     MaxG AS SINGLE '                                            Maximum thrust ship can use / mem 11-14
  23.     op AS unitpoint '                                           previous turn x,y,z position op=old position / mem 15-22,23-30,31-38
  24.     OSp AS SINGLE '                                             previous turn velocity / mem 39-42
  25.     OHd AS SINGLE '                                             previous turn heading / mem 43-46
  26.     OIn AS SINGLE '                                             previous turn inclination / mem 47-50
  27.     Ostat AS BYTE '                                             previous turn status / mem 51
  28.     ap AS unitpoint '                                           Absolute x,y,z position ap=absolute position / mem 52-59,60-67,68-75
  29.     Sp AS SINGLE '                                              coasting velocity / mem 76-79
  30.     Hd AS SINGLE '                                              coasting heading / mem 80-83
  31.     In AS SINGLE '                                              coasting inclination / mem 84-87
  32.     status AS BYTE '                                            0=destroyed 1=in flight 2=landed 3=disabled / mem 88
  33.     bogey AS BYTE '                                             target of intercept/evade solution / mem 89
  34.     bstat AS BYTE '                                             type of solution 0=none 1=evade 2=intercept 3=Planetfall / mem 90
  35.     mil AS BYTE '                                               military sensors? true/false / mem 91
  36.  
  37. TYPE Maneuver '                                                 active thrust polar vector
  38.     Azi AS SINGLE '                                             Thrust heading / mem 0-3
  39.     Inc AS SINGLE '                                             Thrust inclination / mem 4-7
  40.     Gs AS SINGLE '                                              Thrust acceleration / mem 8-11
  41.  
  42. TYPE body '                                                     Celestial bodies
  43.     nam AS STRING * 20 '                                        Name / mem 0-19
  44.     parnt AS STRING * 20 '                                      name of parent body / mem 20-39
  45.     radi AS INTEGER64 '                                         Size (needs INTEGER64 in event of large star) / mem 40-47
  46.     orad AS INTEGER64 '                                         Orbital radius / mem 48-55
  47.     oprd AS SINGLE '                                            Orbital period (years) / mem 56-59
  48.     rota AS SINGLE '                                            Rotational period / mem 60-63
  49.     dens AS SINGLE '                                            Density, basis for grav(Gs) calculation / mem 64-67
  50.     rank AS BYTE '                                              1=primary, 2=planet/companion, 3=satelite / mem 68
  51.     star AS BYTE '                                              -1=star  0=non-stellar body 2=planetoid belt / mem 69
  52.     class AS STRING * 2 '                                       Two digit code, use for stellar class, GG, etc. / mem 70-71
  53.     siz AS STRING * 3 '                                         three digit code, use for stellar size, / mem 72-74
  54.     ps AS unitpoint '                                           coordinate position / mem 75-98
  55.  
  56. '                                                               GLOBAL VARIABLES AND ARRAYS
  57. DIM SHARED ttl AS STRING * 15
  58. DIM SHARED clr&(0 TO 15) '                                      32 bit equivalent of SCREEN 0 colors
  59. DIM SHARED hvns(x) AS body '                                    System stars and planets
  60. DIM SHARED cmb(x) AS ship '                                     unit info array (Combatants)
  61. DIM SHARED rcs(x) AS unitpoint '                                Relative Coordinate Ship- x,y,z relative to vpoint
  62. DIM SHARED rcp(x) AS unitpoint '                                Relative Coordinate Planet- "   "   "    "    "
  63. DIM SHARED dcs(x) AS unitpoint '                                Display Coordinate Ship
  64. DIM SHARED dcp(x) AS unitpoint '                                Display Coordinate Planet
  65. DIM SHARED zangle AS SINGLE '                                   Angle from overhead for Z-pan
  66. DIM SHARED Ozang AS SINGLE '                                    Old 3D angle value for fast toggle
  67. DIM SHARED vpoint AS UNSIGNED BYTE '                            active unit pointer
  68. DIM SHARED shipoff AS UNSIGNED BYTE '                           display offset for ship data scroll
  69. DIM SHARED units AS UNSIGNED BYTE '                             number of combatant units
  70. DIM SHARED collision AS BYTE '                                  collision check variable
  71. DIM SHARED Thrust(x) AS Maneuver '                              Applied acceleration
  72. DIM SHARED Gwat AS Maneuver '                                   Acceleration vector of gravitational influences
  73. DIM SHARED Turncount AS INTEGER '                               number of turns of play
  74. DIM SHARED etd AS INTEGER '                                     elapsed time days
  75. DIM SHARED eth AS BYTE '                                        elapsed time hours
  76. DIM SHARED etm AS BYTE '                                        elapsed time minutes
  77. DIM SHARED ets AS BYTE '                                        elapsed time seconds
  78. DIM SHARED chr_img(255) AS LONG '                               handle array for resizeable font
  79. DIM SHARED mouse_x AS INTEGER '                                 for passing mouse click x coordinate to other SUBs
  80. DIM SHARED mouse_y AS INTEGER '                                 for passing mouse click y coordinate to other SUBs
  81. DIM SHARED mouse_left AS BYTE '                                 mouse left button pressed
  82. DIM SHARED mouse_right AS BYTE '                                mouse right button pressed
  83. DIM SHARED ZoomFac AS SINGLE '                                  Display zoom
  84. DIM SHARED orbs AS INTEGER '                                    number of stars/planets/satellites
  85. DIM SHARED oryr AS SINGLE '                                     # of years since 000-0000
  86. DIM SHARED A& '                                                 Main screen handle
  87. DIM SHARED AW& '                                                Azimuth wheel overlay handle
  88. DIM SHARED SS& '                                                Sensor screen handle
  89. DIM SHARED ZS& '                                                Z-pan screen handle
  90. DIM SHARED ORI& '                                               Orientation screen handle
  91. REDIM SHARED ship_box(20) AS LONG '                             Ship data display box
  92. DIM SHARED flight& '                                            Flightplan solution buttons
  93. DIM SHARED evade& '                                             Evade solution buttons
  94. DIM SHARED intercept& '                                         Intercept solution buttons
  95. DIM SHARED XZ& '                                                Zoom extents button
  96. DIM SHARED IZ& '                                                Zoom in button
  97. DIM SHARED OZ& '                                                Zoom out button
  98. DIM SHARED RG& '                                                Ranging button
  99. DIM SHARED OB& '                                                Orbit track button
  100. DIM SHARED GD& '                                                Grid button
  101. DIM SHARED AZ& '                                                Azimuth wheel button
  102. DIM SHARED IN& '                                                Inclinometer button
  103. DIM SHARED JP& '                                                Jump envelope button
  104. DIM SHARED DI& '                                                Jump Diameter button
  105. DIM SHARED DN& '                                                Jump Density button
  106. DIM SHARED QT& '                                                Quit button (program end)
  107. DIM SHARED cancel& '                                            Cancel solution
  108. DIM SHARED strfld AS LONG '                                     Gatekeeper background
  109. DIM SHARED ShpT AS LONG '                                       Thrusting ship image handle
  110. DIM SHARED ShpO AS LONG '                                       Non-thrusting ship image handle
  111. DIM SHARED TLoc AS LONG '                                       Target lock icon handle
  112. DIM SHARED TLocn AS LONG '                                      Target lock not available handle
  113. DIM SHARED Px AS INTEGER '                                      System primary X position
  114. DIM SHARED Py AS INTEGER '                                      System primary Y position
  115. DIM SHARED Pz AS INTEGER '                                      System primary Z position
  116. DIM SHARED togs AS UNSIGNED INTEGER '                           display toggles
  117. '                                                               Undo toggle- prevents more than one turn undo       togs bit=0
  118. '                                                               Z-pan toggle                                        togs bit=1
  119. '                                                               Azimuth wheel toggle                                togs bit=2
  120. '                                                               Grid toggle                                         togs bit=3
  121. '                                                               Ranging circle toggle                               togs bit=4
  122. '                                                               Inclinometer toggle                                 togs bit=5
  123. '                                                               Jump diameter toggle                                togs bit=6
  124. '                                                               Orbit track display toggle                          togs bit=7
  125. '                                                               Gravity zone toggle                                 togs bit=8
  126. '                                                               compute jump diameters accounting for density       togs bit=9
  127. '                                                               Belt/ring display toggle                            togs bit=10
  128. '                                                               bits 11-15 for future expansions
  129.  
  130. '                                                               DEBUGGING VARIABLES (if any present for beta testing)
  131.  
  132.  
  133. '                                                               INITIAL PARAMETERS
  134. ttl = "CT Vector 0.36"
  135. Px = 0: Py = 0: Pz = 0 '                                        (x,y,z) position of system primary aka ORIGIN
  136. cmb(0).ap.pX = 0 '                                              No ships left active unit
  137. cmb(0).ap.pY = 0
  138. cmb(0).ap.pZ = 0
  139. Turncount = 0 '                                                 game turn number- determines elapsed time in scenario
  140. vpoint = 1 '                                                    active unit pointer
  141. ZoomFac = 1 '                                                   Zoom factor
  142. togs = &B0000010110001101 '                                     set toggle initial state
  143. shipoff = 0 '                                                   ship list scrolling offset value
  144.  
  145. CONST KMtoAU = 149597900
  146.  
  147. REDIM SHARED Thrust(x) AS Maneuver '                            unit accelerations/vector
  148. REDIM SHARED Sensor(x, x) AS BYTE '                             Sensor ops- planetary obscuration array, who can see who?
  149. '                                                               bit 0 = Sensor occlusion flag
  150. '                                                               bit 1 = Target lock flag
  151. '                                                               bit 2 = Contact indistinct/Extreme range flag
  152.  
  153. RESTORE colors
  154. FOR x = 0 TO 15 '                                               iterate colors 0 thru 15
  155.     READ r% '                                                   get red component
  156.     READ g% '                                                   get green component
  157.     READ b% '                                                   get blue component
  158.     clr&(x) = RGB32(r%, g%, b%) '                               mix color x into array
  159.  
  160. '                                                               IMAGES AND BUTTONS
  161. FOR Ascii = 0 TO 255 '                                          PETR'S CHARACTER IMAGE LOADER
  162.     chr_img(Ascii) = NEWIMAGE(8, 16, 32) '                      create image for each ASCII character
  163.     DEST chr_img(Ascii) '                                       set image destination of ASCII character
  164.     PRINTMODE KEEPBACKGROUND '                                  transparency for graphics overlays
  165.     COLOR &HFFF5F5F5
  166.     PRINTSTRING (0, 0), CHR$(Ascii), chr_img(Ascii) '           put ASCII character in image
  167. NEXT Ascii '                                                    now any size ASCII character can be printed
  168.  
  169. A& = NEWIMAGE(1250, 700, 32) '                                  Main display
  170. SS& = NEWIMAGE(620, 620, 32) '                                  Sensor screen display
  171. AW& = NEWIMAGE(620, 620, 32) '                                  Azimuth wheel overlay
  172. ZS& = NEWIMAGE(40, 650, 32) '                                   Z-pan slider display
  173. ORI& = NEWIMAGE(254, 254, 32) '                                 Orientation display
  174. flight& = NEWIMAGE(80, 16, 32) '                                Flightplan solution button
  175. evade& = NEWIMAGE(40, 16, 32) '                                 Evade solution button
  176. intercept& = NEWIMAGE(72, 16, 32) '                             Intercept solution button
  177. cancel& = NEWIMAGE(48, 16, 32) '                                Cancel solution button
  178. XZ& = NEWIMAGE(64, 32, 32) '                                    Zoom extents button
  179. IZ& = NEWIMAGE(64, 32, 32) '                                    Zoom In button
  180. OZ& = NEWIMAGE(64, 32, 32) '                                    Zoom Out button
  181. RG& = NEWIMAGE(56, 32, 32) '                                    Ranging button
  182. OB& = NEWIMAGE(56, 32, 32) '                                    Orbit track button
  183. GD& = NEWIMAGE(48, 32, 32) '                                    Grid button
  184. AZ& = NEWIMAGE(40, 32, 32) '                                    Azimuth button
  185. IN& = NEWIMAGE(40, 32, 32) '                                    Inclinometer button
  186. JP& = NEWIMAGE(48, 32, 32) '                                    Jump envelope button
  187. DI& = NEWIMAGE(48, 32, 32) '                                    Jump Diameter button
  188. DN& = NEWIMAGE(48, 32, 32) '                                    Jump Density button
  189. QT& = NEWIMAGE(48, 32, 32) '                                    Quit button (program end)
  190. strfld = LOADIMAGE("images\starfield.jpg", 32) '                Gatekeeper background image
  191. ShpT = LOADIMAGE("images\suleimant.png", 32) '                  ship- thrusting
  192. ShpO = LOADIMAGE("images\suleimano.png", 32) '                  ship- no thrust
  193. TLoc = LOADIMAGE("images\tlock.png", 32) '                      target lock icon
  194. TLocn = LOADIMAGE("images\tlockn.png", 32) '                    target lock n/a
  195.  
  196. Make_Images '                                                   Create overlays
  197. Make_Buttons '                                                  Create control buttons
  198.  
  199. SCREEN A& '                                                     Initiate main screen
  200. DO: LOOP UNTIL SCREENEXISTS
  201. TITLE "CT-vector 0.352 beta testing"
  202. SCREENMOVE 5, 5
  203.  
  204. GateKeeper
  205. SetUp '                                                         Read/Load ships and planets
  206.  
  207. t1% = FREETIMER '                                               Autosave timer
  208. ON TIMER(t1%, 60) Save_Scenario 0 '                             save every minute
  209. TIMER(t1%) ON
  210.  
  211. MainLoop '                                                      Enter main program loop
  212. Terminus '                                                      do housekeeping and exit
  213.  
  214. '                                                               DATA SECTION
  215. colors:
  216. '                                                               colors 0-4
  217. DATA 0,0,0,0,0,168,0,168,0,0,168,168,168,0,0
  218. '                                                               colors 5-9
  219. DATA 168,0,168,168,84,0,168,168,168,84,84,84,84,84,252
  220. '                                                               colors 10-14
  221. DATA 84,252,84,84,252,252,252,84,84,252,84,252,252,252,84
  222. '                                                               color 15
  223. DATA 252,252,252
  224.  
  225. ships: '                                                        Sample ships for demo and debugging
  226. 'index, name, MaxG,ap.pX,ap.pY,ap.pZ,Speed,Heading,Inclination,mil
  227. 'DATA 7
  228. 'DATA 1,"Crotalus",2,-5000000,-5000000,0,0,0,0,0
  229. 'DATA 2,"Zho Trader",2,-5500000,-5780000,0,30,90,0,0
  230. 'DATA 3,"Tigress",6,-5060000,-5300000,5,10,0,90,-1
  231. 'DATA 4,"SDB",6,-5500000,-5400000,0,0,0,0,-1
  232. 'DATA 5,"Corsair",2,-5660000,-5200000,0,0,0,0,0
  233. 'DATA 6,"Beowulf",1,-5400000,-5000000,0,0,0,0,0
  234. 'DATA 7,"Slow Boat",3,-5300000,-5300000,0,0,0,0,0
  235. DATA 1,"PC vessel",2,-500000,-500000,0,0,0,0,0
  236. DATA 2,"bogey 1",2,-650000,-530000,0,0,0,0,0
  237. DATA 3,"bogey 2",2,-700000,230000,0,0,0,0,0
  238.  
  239.  
  240. '                                                               END DATA SECTION
  241. '                                                               END MAIN MODULE
  242. '**********************************************************************************
  243. '                                                               BEGIN SUB/FUNCTION SECTION
  244.  
  245.  
  246. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  247. SUB AddShip
  248.  
  249.     PanelBlank 420, 578, 64, 32, &HFF0F0F0F
  250.     Con_Blok 420, 578, 64, 32, "Adding", 0, &H508C5B4C
  251.     DISPLAY
  252.  
  253.     DIM ts(units, units) AS BYTE
  254.     x = 0 '                                                     save state of Sensor & TLock
  255.     DO
  256.         x = x + 1
  257.         y = 0
  258.         DO
  259.             y = y + 1
  260.             ts(x, y) = Sensor(x, y)
  261.         LOOP UNTIL y = units
  262.     LOOP UNTIL x = units
  263.     units = units + 1 '                                         increment ship counter
  264.     REDIM Sensor(units, units)
  265.     x = 0 '                                                     reload Sensor & TLock
  266.     DO
  267.         x = x + 1
  268.         y = 0
  269.         DO
  270.             y = y + 1
  271.             Sensor(x, y) = ts(x, y)
  272.         LOOP UNTIL y = units - 1
  273.     LOOP UNTIL x = units - 1
  274.  
  275.  
  276.     REDIM PRESERVE cmb(units) AS ship
  277.     REDIM PRESERVE Thrust(units) AS Maneuver
  278.     ship_box(units) = NEWIMAGE(290, 96, 32)
  279.     cmb(units).id = units
  280.     cmb(units).status = 1
  281.     cmb(units).ap.pX = cmb(vpoint).ap.pX + 100000 '             start near active unit
  282.     cmb(units).ap.pY = cmb(vpoint).ap.pY + 100000 '             edit call can change this
  283.     cmb(units).ap.pZ = 0
  284.     FOR x = 1 TO orbs '                                         check planets for interference
  285.         IF Pyth(cmb(units).ap, hvns(x).ps) < hvns(x).radi THEN 'if inside planet
  286.             DO
  287.                 cmb(units).ap.pX = cmb(units).ap.pX + 100000 '  move ship until beyond planet radius
  288.             LOOP UNTIL Pyth(cmb(units).ap, hvns(x).ps) > hvns(x).radi
  289.         END IF
  290.     NEXT x
  291.     vpoint = units
  292.     EditShip -1
  293.     Refresh
  294.  
  295. END SUB 'AddShip
  296.  
  297.  
  298. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  299. FUNCTION Azimuth! (x AS INTEGER64, y AS INTEGER64)
  300.  
  301.     'Returns the azimuth bearing of a relative (x,y) offset
  302.  
  303.     IF x < 0 AND y >= 0 THEN
  304.         Azimuth! = 450 - ABS(R2D(ATAN2(y, x)))
  305.     ELSE
  306.         Azimuth! = 90 - (R2D(ATAN2(y, x)))
  307.     END IF
  308.  
  309. END FUNCTION 'Azimuth!
  310.  
  311.  
  312. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  313. SUB AzimuthWheel (var AS INTEGER)
  314.  
  315.     'Draw Azimuth wheel display - controlled by Aztog
  316.     IF var AND NOT READBIT(togs, 1) THEN
  317.         PUTIMAGE (-1000, 1000)-(1000, -1000), AW& '             Overlay azimuth scale wheel
  318.  
  319.         'Direction to Primary indicator- draw yellow primary azimuth indicator along azimuth wheel
  320.         FCirc 990 * SIN(D2R(Azimuth!(Px - cmb(vpoint).ap.pX, Py - cmb(vpoint).ap.pY))),_
  321.          990 * COS(D2R(Azimuth!(Px - cmb(vpoint).ap.pX, Py - cmb(vpoint).ap.pY))), 10, clr&(14)
  322.  
  323.         'Heading indicator
  324.         'draw heading arrow
  325.         LINE (950 * SIN(D2R(cmb(vpoint).Hd - 1)), 950 * COS(D2R(cmb(vpoint).Hd - 1)))-_
  326.         (1000 * SIN(D2R(cmb(vpoint).Hd)), 1000 * COS(D2R(cmb(vpoint).Hd))), clr&(10)
  327.         LINE (1000 * SIN(D2R(cmb(vpoint).Hd)), 1000 * COS(D2R(cmb(vpoint).Hd)))-_
  328.         (950 * SIN(D2R(cmb(vpoint).Hd + 1)), 950 * COS(D2R(cmb(vpoint).Hd + 1))), clr&(10)
  329.         'heading leader line
  330.         LINE (0, 0)-(1000 * SIN(D2R(cmb(vpoint).Hd)), 1000 * COS(D2R(cmb(vpoint).Hd))), RGBA32(168, 0, 168, 40)
  331.     END IF
  332.  
  333. END SUB 'AzimuthWheel
  334.  
  335.  
  336. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  337. FUNCTION Bearing (unit AS INTEGER)
  338.  
  339.     'determine azimuth bearing on ecliptic plane of 'unit' from viewpoint
  340.     'and check for possible collision/docking
  341.  
  342.     IF rcs(unit).pX = 0 AND rcs(unit).pY = 0 AND rcs(unit).pZ = 0 THEN
  343.         collision = -1
  344.     ELSE
  345.         collision = 0
  346.     END IF
  347.     Bearing = Azimuth!(rcs(unit).pX, rcs(unit).pY)
  348.  
  349. END FUNCTION 'Bearing
  350.  
  351.  
  352. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  353. SUB ButtonBlock
  354.  
  355.     'MANEUVER AND PROGRAM CONTROLS - temorary images
  356.     'Upper corner @ (0,578) just under unit data blocks
  357.     'First tier
  358.     Con_Blok 0, 578, 64, 32, "Vector", 1, &HFF2C9B2C
  359.     Con_Blok 70, 578, 64, 32, "n/a", 0, &HFF2C9B2C 'Con_Blok 70, 578, 64, 32, "Brake", 0, &HFF2C9B2C
  360.     Con_Blok 140, 578, 64, 32, "Turn", 1, &HFF2C9B2C
  361.     Con_Blok 210, 578, 64, 32, "Undo", 1, &HFF2C9B2C
  362.     Con_Blok 280, 578, 64, 32, "Edit", 1, &HFFA6A188 '&HFF8C5B4C
  363.     Con_Blok 350, 578, 64, 32, "Delete", 0, &HFFC80000
  364.     Con_Blok 420, 578, 64, 32, "LoadAll", 0, &HFF2C9B2C
  365.     Con_Blok 490, 578, 64, 32, "SaveAll", 1, &HFF8C5B4C
  366.     'Second tier
  367.     Con_Blok 0, 614, 64, 32, "Gs= 0", 0, &HFF2C9B2C
  368.     Con_Blok 70, 614, 64, 32, "n/a", 0, &HFF2C9B2C
  369.     Con_Blok 140, 614, 64, 32, "n/a", 0, &HFF2C9B2C
  370.     Con_Blok 210, 614, 64, 32, "n/a", 0, &HFF2C9B2C
  371.     Con_Blok 280, 614, 64, 32, "Add", 0, &HFFA6A188 '&HFF8C5B4C
  372.     Con_Blok 350, 614, 64, 32, "Purge", 0, &HFFC80000
  373.     Con_Blok 420, 614, 64, 32, "LoadSys", 0, &HFF2C9B2C
  374.     Con_Blok 490, 614, 64, 32, "SaveSys", 0, &HFF8C5B4C
  375.     'Third tier
  376.     Con_Blok 0, 650, 64, 32, "Brake", 0, &HFF2C9B2C 'Con_Blok 0, 650, 64, 32, "n/a", 0, &HFF2C9B2C
  377.     Con_Blok 70, 650, 64, 32, "n/a", 0, &HFF2C9B2C
  378.     Con_Blok 140, 650, 64, 32, "n/a", 0, &HFF2C9B2C
  379.     Con_Blok 210, 650, 64, 32, "n/a", 0, &HFF2C9B2C
  380.     Con_Blok 280, 650, 64, 32, "Help", 1, &HFF4CCB9C
  381.     IF cmb(vpoint).status = 3 THEN
  382.         Con_Blok 350, 650, 64, 32, "Repair", 0, &HFFC80000
  383.     ELSE
  384.         Con_Blok 350, 650, 64, 32, "Adrift", 0, &HFFC80000
  385.     END IF
  386.     Con_Blok 420, 650, 64, 32, "LoadShp", 0, &HFF2C9B2C
  387.     Con_Blok 490, 650, 64, 32, "SaveShp", 0, &HFF8C5B4C
  388.  
  389.     'sensor screen put @ 560,18 dimensions 620 x 620
  390.     '560,18 -  1180,638
  391.  
  392.     'DISPLAY CONTROL TOGGLES - permanent images
  393.     PUTIMAGE (560, 660), XZ&, A& '                              Zoom Extents
  394.     PUTIMAGE (626, 660), IZ&, A& '                              Zoom In
  395.     PUTIMAGE (692, 660), OZ&, A& '                              Zoom Out
  396.     COLOR clr&(7)
  397.     PRINTSTRING (560, 641), "Zoom Factor: " + STR$(ZoomFac), A&
  398.     PUTIMAGE (762, 660), RG&, A& '                              Ranging Band toggle
  399.     PUTIMAGE (820, 660), OB&, A& '                              Orbit track toggle
  400.     PUTIMAGE (878, 660), GD&, A& '                              Grid toggle
  401.     PUTIMAGE (928, 660), AZ&, A& '                              Azimuth Wheel toggle
  402.     PUTIMAGE (970, 660), IN&, A& '                              Inclinometer toggle
  403.     PUTIMAGE (1012, 660), JP&, A& '                             Jump Envelope toggle
  404.     IF READBIT(togs, 6) THEN
  405.         IF READBIT(togs, 9) THEN
  406.             PUTIMAGE (1062, 660), DI&, A& '                     Jump Diameter toggle
  407.         ELSE
  408.             PUTIMAGE (1062, 660), DN&, A& '                     Jump Density toggle
  409.         END IF
  410.     END IF
  411.     PUTIMAGE (1132, 660), QT&, A& '                             Quit (program) button
  412.     IF READBIT(togs, 1) THEN
  413.         Con_Blok 1204, 660, 40, 32, "3D", 0, &HFFB5651D
  414.     ELSE
  415.         Con_Blok 1204, 660, 40, 32, "2D", 0, &HFFB5651D
  416.     END IF
  417.  
  418. END SUB 'ButtonBlock
  419.  
  420.  
  421. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  422. SUB Cancel_AI (var AS BYTE)
  423.  
  424.     FOR x = 1 TO units '                                        cancel any intercept/evades targeting the wreck
  425.         IF (cmb(x).bstat = 1 OR cmb(x).bstat = 2) AND cmb(x).bogey = var THEN
  426.             cmb(x).bstat = 0: cmb(x).bogey = 0
  427.         END IF
  428.     NEXT x
  429.  
  430. END SUB 'Cancel_AI
  431.  
  432.  
  433. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  434. SUB ColCheck (var AS INTEGER)
  435.  
  436.     'CHECK FOR COLLISION WITH STAR/PLANET
  437.     DIM sphr AS unitpoint '                                     center point of sphere
  438.     DIM strt AS unitpoint '                                     start point of unit vector
  439.     DIM nd AS unitpoint '                                       end point of unit vector
  440.     DIM neari AS unitpoint '                                    near intersection point on surface of sphere
  441.     FOR p = 1 TO orbs '                                         iterate for each body in system against unit (var)
  442.         IF hvns(p).star <> 2 THEN
  443.             IF Pyth(cmb(var).ap, hvns(p).ps) < hvns(p).radi THEN
  444.                 cmb(var).status = 0 '                               ends turn within sphere- crashed
  445.             ELSE
  446.                 IF Pyth(hvns(p).ps, cmb(var).op) - hvns(p).radi < cmb(var).Sp * 1000 THEN 'wait for proximity to calculate
  447.                     sphr = hvns(p).ps
  448.                     strt = cmb(var).op
  449.                     nd = cmb(var).ap
  450.                     'Use FLOAT variables, these numbers are friggin' enormous!
  451.                     dx## = nd.pX - strt.pX: dy## = nd.pY - strt.pY: dz## = nd.pZ - strt.pZ
  452.                     A## = (dx## * dx##) + (dy## * dy##) + (dz## * dz##)
  453.                     B## = 2 * dx## * (strt.pX - sphr.pX) + 2 * dy## * (strt.pY - sphr.pY) + 2 * dz## * (strt.pZ - sphr.pZ)
  454.                 C## = (sphr.pX * sphr.pX) + (sphr.pY * sphr.pY) + (sphr.pZ * sphr.pZ) + (strt.pX * strt.pX) +_
  455.                  (strt.pY * strt.pY) + (strt.pZ * strt.pZ) + -2 * (sphr.pX * strt.pX + sphr.pY * strt.pY + sphr.pZ * strt.pZ)_
  456.                   - (hvns(p).radi * hvns(p).radi)
  457.                     disabc## = (B## * B##) - 4 * A## * C## ' if disabc <0 then no intersection =0 tangent >0 intersects two points
  458.  
  459.                     IF disabc## < 0 THEN
  460.                         'No intersection detected, go on checking other bodies.
  461.                     ELSE '                                          course intersects body
  462.                         t## = (-B## - ((B## * B##) - 4 * A## * C##) ^ .5) / (2 * A##) 'Near intersect quadratic
  463.                         neari.pX = strt.pX + t## * dx##: neari.pY = strt.pY + t## * dy##: neari.pZ = strt.pZ + t## * dz##
  464.  
  465.                         IF Pyth(neari, strt) <= Pyth(nd, strt) THEN ' impact
  466.                             cmb(var).status = 0
  467.                             cmb(var).ap = neari
  468.                             Cancel_AI var
  469.                             'if neari impact point needed in future upgrades, such as landing options, determine that point here
  470.                             'landing option would entail a speed vs maximum thrust potential check.
  471.                             'interestingly a ghost is left on the screen where the ship "died", probably a remnant of vector indicators.
  472.                             'Purge will remove the ghosts.
  473.                         END IF '                                    end: if vector intersects
  474.                     END IF '                                        end: check for intersection
  475.                 END IF '                                            end: if close proximity do the check
  476.             END IF
  477.         END IF
  478.     NEXT p
  479.  
  480. END SUB 'ColCheck
  481.  
  482.  
  483. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  484. SUB Coming
  485.  
  486.     PRINTSTRING (300, 560), "Coming soon...maybe", A&
  487.     DISPLAY
  488.     SLEEP 2
  489.  
  490. END SUB 'Coming
  491.  
  492.  
  493. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  494. SUB Comments
  495.  
  496.     'VERSION COMMENTS
  497.     'Basic algorithm for rewrite of STARRUTR.BAS
  498.     'starship vector movement handler for Classic Traveller RPG
  499.     '
  500.     '
  501.     'HISTORIC COMMENTS
  502.     '              STARRUTR.BAS (8.3 short for Star Ruttier)
  503.     '   The ruttier being an archaic term for the charts and directions
  504.     'that a sailing ships pilot would use to navigate, Star Ruttier is
  505.     'a QBasic based program for tracking 3 dimensional space craft
  506.     'maneuvers in an interplanetary setting.
  507.     '   Conceived as a ship to ship combat game aid for the Traveller
  508.     'Role Playing system, Star Ruttier displays graphic position and numeric
  509.     'data for vector maneuvers in a turn based 3D cartesian (X,Y,Z) system.
  510.     '   On the left each ship unit is displayed with Unit index, Name, Azimuth
  511.     'Heading, Inclination, and Speed with one ship highlighted as the active
  512.     'unit.  All inactive units are additionally displayed with Azimuth Bearing,
  513.     'Inclination, and Distance from the active unit. On the right of the screen
  514.     'a graphics window is displayed showing the relative positions of each
  515.     'indexed unit.  The active unit is displayed in the center of the graphics
  516.     'window, with the other units positioned relative to the active unit. The
  517.     'active unit can be chosen by using the up and down arrows.
  518.     '   The display is dynamically resized to include all units displayed
  519.     'regardless of distance from the active unit. The display is viewed from
  520.     'the Galactic zenith with the top edge being Coreward. Other viewpoints
  521.     'may be offered in subsequent versions. In this release units above or
  522.     'below the active unit are displayed Blue shift and Red shift
  523.     'respectively.
  524.     '   The 'chose' menu in the lower left corner displays the menu options
  525.     'which can be accessed by typing the highlighted letter of each choice.
  526.     'Type 'V' for vector to input new thrust, Azimuth, and Inclination
  527.     'headings for the active unit. If no new values are entered the active
  528.     'unit will default to the last entered values. The unit will continue
  529.     'to thrust until the power is cut by entering zero values for thrust,
  530.     'though the unit will continue to coast at the current vector.
  531.     '   Type 'T' for turn after all desired vectors have been entered and
  532.     'the new vectors will be applied for the current turn. All unit positions
  533.     'will be updated and displayed and new vectors can be entered.
  534.     '   Type 'Q' to quit program
  535.  
  536.     'CT Vector.bas comments
  537.  
  538.     'HOT KEYS       accessible in main loop
  539.  
  540.     ' "S"           Ship display mode (proposed)
  541.     ' "P"           Planet display mode (proposed)
  542.     '[up arrow]     increments active unit pointer
  543.     '[down arrow]   decrements active unit pointer
  544.     '[Delete]       delete the active unit
  545.     '[Insert]       Add new unit and make active
  546.     ' "+"           zoom in
  547.     ' "-"           zoom out
  548.     ' "X"           zoom extents (default zoom factor 1)
  549.     ' "A"           toggle azimuth wheel....................... [default=on]
  550.     ' "B"           toggle planetoid belt/ring display......... [default=on]
  551.     ' "G"           toggle grid................................ [default=on]
  552.     ' "I"           toggle inclinometer........................ [default=off]
  553.     ' "R"           toggle ranging bands....................... [default=off]
  554.     ' "J"           toggle jump diameters...................... [default=off]
  555.     ' "D"           toggle density based jump diameters........ [default=off]
  556.     ' "O"           toggle orbit tracks........................ [default=on]
  557.     ' "Z"           toggle gravity zones....................... [default=on]
  558.     ' "3"           toggle 3D panning.......................... [default=off]
  559.     ' "V"           enter new vector for active unit. Enter azimuth "c" to counter vector
  560.     ' "T"           apply vectors to game turn
  561.     ' "U"           undo previous turn
  562.     ' "E"           edit active unit data
  563.     ' "Q"           end program
  564.  
  565.     'CT Vector has updated displays to 32 bit images. Mouse support has been added.
  566.     'Navigation aids of azimuth wheel, inclinometer, scale grid as well as jump
  567.     'diameter and combat range bands have been added. All may be toggled on and off
  568.     'as needed. Planetary bodies will now occlude sensors of active ship.
  569.     'Right mouse click will reposition active unit, in x,y, to anywhere on the visible
  570.     'sensor screen limits. Z-pan slider rotates view 180 deg. around Y axis. Systems,
  571.     'ships and scenarios may be saved and recalled.
  572.  
  573.     'The program will zoom out to distances of many parsecs, but has difficulty
  574.     'zooming in tightly under several circumstances.
  575.  
  576.     'Tentative ideas for data system...
  577.     'File system: [name].tss for star systems, [name].tvg for vessel group
  578.     '             [scenario].tgn for loading both (game name for saving state for later recall)
  579.  
  580.     'TRAVEL FORMULAE (from Traveller Book)
  581.  
  582.     'Time[s] = 2 * ((Distance[m] / Acceleration[m/s^2])^.5)
  583.  
  584.     'Distance[m] = Acceleration[m/s^2] * Time[s]^2 / 4
  585.  
  586.     'Acceleration[m/s^2] = 4 * Distance[m] / Time[s]^2
  587.  
  588.  
  589.     'GRAVITY FORMULAE (from Traveller Book)
  590.  
  591.     'Radius[100km] = 8 * Diameter[UPP]
  592.  
  593.     'Mass[earth mass] = K[earth densities] * (diameter[UPP] / 8)^3
  594.     'Gs = K[earth densities] * (Diameter[UPP] / 8)
  595.  
  596.     'L = 64 * (Mass / G)^.5
  597.  
  598.     'OTHER USEFUL THINGS
  599.     'from http://braeunig.us/space/vectors.htm
  600.     'longitude=l=azimuth, latitude=b=inclination, and radial distance, r.
  601.     'x = r cos b cos l   it must be noted that x & y are transposed with respect to
  602.     'y = r cos b sin l   this application.
  603.     'z = r sin b
  604.  
  605.     'color legend- for clr&(x) assignments
  606.     '0=black,1=blue,2=green,3=aqua,4=red,5=purple,6=brown,7=white
  607.     '8=gray, +8=bright color, except 14=yellow,
  608.  
  609.     'Mean Density of Earth = 5.514
  610.  
  611.     'LINKS
  612.     'http://www.batesville.k12.in.us/Physics/PhyNet/Mechanics/Gravity/lab/excel_orbits.htm
  613.  
  614.     'USEFUL ALGORITHMS that are faster implemented outside of FUNCTION
  615.     'find the x coordinate of a magnitude and azimuth: x = magnitude * SIN(_D2R(Azimuth))
  616.     'find the y coordinate of a magnitude and azimuth: y = magnitude * COS(_D2R(Azimuth))
  617.  
  618.     'Deceleration = v^2 - u^2 / 2s
  619.     'Where,
  620.     'v = The Final Velocity
  621.     'u = The Initial Velocity
  622.     's = Distance
  623.  
  624.  
  625.     'BUG LIST
  626.  
  627.     'somebody please shoot me...
  628.  
  629. END SUB 'Comments
  630.  
  631.  
  632. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  633. SUB Con_Blok (xpos AS INTEGER, ypos AS INTEGER, xsiz AS INTEGER, ysiz AS INTEGER, label AS STRING, high AS INTEGER, col AS UNSIGNED LONG)
  634.  
  635.     'Create control block
  636.     'upper left corner @ (xpos,ypos), size of (xsiz,ysiz), label, high= highlight character position, col= box color
  637.     CN& = NEWIMAGE(xsiz, ysiz, 32)
  638.     DEST CN&
  639.     COLOR , col
  640.     CLS
  641.     LINE (1, 1)-(xsiz - 2, ysiz - 2), clr&(0), B
  642.     PRINTMODE KEEPBACKGROUND
  643.     x = LEN(label)
  644.     sx = xsiz / 2 - x * 4
  645.     sy = ysiz / 2 - 8
  646.     FOR p = 1 TO x
  647.         IF p = high THEN
  648.             COLOR clr&(4)
  649.         ELSE
  650.             COLOR clr&(0)
  651.         END IF
  652.         IF col = &HFFC80000 THEN COLOR clr&(15)
  653.         PRINTSTRING (sx + (p - 1) * 8, sy), MID$(label, p, 1)
  654.     NEXT p
  655.     PUTIMAGE (xpos, ypos), CN&, A&
  656.     FREEIMAGE CN&
  657.  
  658. END SUB 'Con_Blok
  659.  
  660.  
  661. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  662. SUB CoordUpdate (var1 AS INTEGER, var2 AS STRING)
  663.  
  664.     'convert polar data to cartesian and updates coordinates.x
  665.     'var1 sends unit index
  666.     'var2 sends origin T for turn or I for intercept/evade
  667.     DIM CoastD AS unitpoint
  668.     DIM ThrstD AS unitpoint
  669.     DIM TotalD AS unitpoint
  670.     DIM ms AS MEM
  671.     DIM mt AS MEM
  672.     ms = MEM(cmb())
  673.     mt = MEM(Thrust())
  674.  
  675.     'Determine coasting deltaXYZ
  676.     'CoastDeltaZ&& = cmb(var1).Sp * SIN(_D2R(cmb(var1).In))
  677.     CoastD.pZ = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 76, SINGLE)_
  678.      * SIN(D2R(MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 84, SINGLE)))
  679.     'CoastDeltaX&& = cmb(var1).Sp * COS(_D2R(cmb(var1).In)) * SIN(_D2R(cmb(var1).Hd))
  680.     CoastD.pX = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 76, SINGLE)_
  681.      * COS(D2R(MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 84, SINGLE)))_
  682.       * SIN(D2R(MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 80, SINGLE)))
  683.     'CoastDeltaY&& = cmb(var1).Sp * COS(_D2R(cmb(var1).In)) * COS(_D2R(cmb(var1).Hd))
  684.     CoastD.pY = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 76, SINGLE)_
  685.      * COS(D2R(MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 84, SINGLE)))_
  686.       * COS(D2R(MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 80, SINGLE)))
  687.  
  688.     ''determine coasting deltaXYZ using vector addition  ...experimental but won't add accelerations...????
  689.     'CoastD = cmb(var1).ap: VecAdd CoastD, cmb(var1).op, -1
  690.  
  691.     'Determine thrusting delta XYZ for MoveTurn, InterVade assumes coasting vector
  692.     IF var2 = "T" THEN
  693.         'ThrstD.pZ = (Thrust(var1).Gs * 10000) * SIN(_D2R(Thrust(var1).Inc))
  694.         ThrstD.pZ = (MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE + 8, SINGLE) * 10000)_
  695.          * SIN(D2R(MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE + 4, SINGLE)))
  696.         'ThrstD.pX = (Thrust(var1).Gs * 10000) * COS(_D2R(Thrust(var1).Inc)) * SIN(_D2R(Thrust(var1).Azi))
  697.         ThrstD.pX = (MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE + 8, SINGLE) * 10000)_
  698.          * COS(D2R(MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE + 4, SINGLE)))_
  699.           * SIN(D2R(MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE , SINGLE)))
  700.         'ThrstD.pY = (Thrust(var1).Gs * 10000) * COS(_D2R(Thrust(var1).Inc)) * COS(_D2R(Thrust(var1).Azi))
  701.         ThrstD.pY = (MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE + 8, SINGLE) * 10000)_
  702.          * COS(D2R(MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE + 4, SINGLE)))_
  703.           * COS(D2R(MEMGET(mt, mt.OFFSET + var1 * mt.ELEMENTSIZE , SINGLE)))
  704.     END IF
  705.  
  706.     'Sum Cumulative Coordinates
  707.     TotalD = CoastD: VecAdd TotalD, ThrstD, 1
  708.  
  709.     'Update unit coordinates
  710.     IF var2 = "T" THEN '                                        Permanent position change for MoveTurn
  711.         'cmb(var1).ap.pX = cmb(var1).ap.pX + TotalDeltaX&&
  712.         cmb(var1).ap.pX = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 52, INTEGER64) + TotalD.pX
  713.         'cmb(var1).ap.pY = cmb(var1).ap.pY + TotalDeltaY&&
  714.         cmb(var1).ap.pY = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 60, INTEGER64) + TotalD.pY
  715.         'cmb(var1).ap.pZ = cmb(var1).ap.pZ + TotalDeltaZ&&
  716.         cmb(var1).ap.pZ = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 68, INTEGER64) + TotalD.pZ
  717.         Grav_Well var1
  718.     ELSEIF var2 = "I" THEN '                                    Temporary data for InterVade
  719.         'soltemp.pX = cmb(var1).ap.pX + TotalDeltaX&&
  720.         soltemp.pX = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 52, INTEGER64) + TotalD.pX
  721.         'soltemp.pY = cmb(var1).ap.pY + TotalDeltaY&&
  722.         soltemp.pY = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 60, INTEGER64) + TotalD.pY
  723.         'soltemp.pZ = cmb(var1).ap.pZ + TotalDeltaZ&&
  724.         soltemp.pZ = MEMGET(ms, ms.OFFSET + var1 * ms.ELEMENTSIZE + 68, INTEGER64) + TotalD.pZ
  725.     END IF
  726.     MEMFREE ms: MEMFREE mt
  727.  
  728. END SUB 'CoordUpdate
  729.  
  730.  
  731. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  732. SUB DelShip '
  733.  
  734.     DialogBox "You're about to delete " + RTRIM$(cmb(vpoint).Nam) + ". Continue?", 400, 200, 100, clr&(4), clr&(15)
  735.     Con_Blok 450, 225, 120, 32, "Yes [enter]", 0, clr&(4)
  736.     Con_Blok 630, 225, 120, 32, "No [Esc]", 0, clr&(4)
  737.     DISPLAY
  738.     Cancel_AI vpoint
  739.  
  740.     DO
  741.         x$ = UCASE$(INKEY$)
  742.         Mouse_Loop 0, 0
  743.         mouse_left = MOUSEBUTTON(1)
  744.         IF mouse_left THEN
  745.             SELECT CASE mouse_y
  746.                 CASE 225 TO 257
  747.                     SELECT CASE mouse_x
  748.                         CASE 450 TO 570 '                       delete with mouseclick on "Yes"
  749.                             dl% = -1
  750.                         CASE 630 TO 750 '                       abort delete with mouseclick on "No"
  751.                             EXIT SUB
  752.                     END SELECT
  753.             END SELECT
  754.         END IF
  755.         IF x$ = CHR$(13) THEN dl% = -1 '                        delete with ENTER
  756.         IF x$ = CHR$(27) THEN EXIT SUB '                        abort delete with ESC keypress
  757.     LOOP UNTIL dl%
  758.     FOR p = vpoint TO units '                                   pancake the variables down on deleted unit
  759.         IF p < units THEN
  760.             cmb(p) = cmb(p + 1)
  761.             Thrust(p) = Thrust(p + 1)
  762.             Sensor(p, p) = Sensor(p + 1, p + 1)
  763.             cmb(p).id = p
  764.         ELSE '                                                  uppermost unit?
  765.             FREEIMAGE ship_box(units) '                         free data box memory
  766.             vpoint = vpoint - 1 '                               decrement the active counter avoiding subscript range fault
  767.             IF vpoint < 1 THEN
  768.                 IF units >= 1 THEN
  769.                     vpoint = 1
  770.                 ELSE
  771.                     vpoint = 0
  772.                 END IF
  773.             END IF
  774.             EXIT FOR '                                          let redims handle the rest
  775.         END IF
  776.     NEXT p
  777.     units = units - 1 '                                         decrement unit counter
  778.     REDIM PRESERVE cmb(units) AS ship
  779.     REDIM PRESERVE Thrust(units) AS Maneuver
  780.     REDIM PRESERVE Sensor(units, units) AS BYTE
  781.     Refresh
  782.  
  783. END SUB 'DelShip
  784.  
  785.  
  786. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  787. SUB DialogBox (heading AS STRING, xsiz AS INTEGER, ysiz AS INTEGER, ypos AS INTEGER, bcol AS UNSIGNED LONG, tcol AS UNSIGNED LONG)
  788.  
  789.     'superimpose a screen centered input box for various input routines
  790.  
  791.     'call syntax: DialogBox <heading string>, box x, box y, y position, bounding box color, text color
  792.     T& = NEWIMAGE(xsiz, ysiz, 32) '                             define box
  793.     DEST T&
  794.     COLOR tcol, clr&(0) '                                       set text color with black background
  795.     CLS
  796.     FOR x = 0 TO 5 '                                            draw bounding box 3 pixels thick
  797.         IF x < 2 THEN
  798.             LINE (0 + x, 0 + x)-(WIDTH(T&) - 1 - x, HEIGHT(T&) - 1 - x), clr&(0), B
  799.         ELSE
  800.             LINE (0 + x, 0 + x)-(WIDTH(T&) - 1 - x, HEIGHT(T&) - 1 - x), bcol, B
  801.         END IF
  802.     NEXT x
  803.     l = WIDTH(T&) / 2 - (LEN(heading) * 8) / 2 '                set heading position
  804.     PRINTSTRING (l, 31), heading, T& '                          print heading
  805.     PUTIMAGE (WIDTH(A&) / 2 - WIDTH(T&) / 2, ypos), T&, A& '    display box
  806.     DEST A&
  807.     FREEIMAGE T&
  808.  
  809. END SUB 'DialogBox
  810.  
  811.  
  812. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  813. SUB DispShipData
  814.  
  815.     '**************************************************************************************************
  816.     FOR x = 1 TO units
  817.         DEST ship_box(x)
  818.         IF x = vpoint THEN '                                    Active white others aqua
  819.             COLOR clr&(15), clr&(8)
  820.         ELSE
  821.             IF READBIT(Sensor(vpoint, x), 0) OR cmb(x).status = 0 THEN
  822.                 COLOR clr&(8), clr&(0)
  823.             ELSE
  824.                 COLOR clr&(3), clr&(0)
  825.             END IF
  826.         END IF
  827.         CLS
  828.         PRINT cmb(x).id; " ";
  829.         PRINT cmb(x).Nam;
  830.  
  831.         IF Pyth(cmb(vpoint).ap, cmb(x).ap) > 1500000000 THEN
  832.             PRINT: PRINT "Contact Indistinct/ Extreme Range"
  833.         ELSE
  834.  
  835.             IF READBIT(Sensor(vpoint, x), 0) THEN
  836.                 PRINT: PRINT "Sensor Occluded"
  837.             ELSE
  838.                 IF cmb(x).status = 0 THEN '                         has unit been destroyed?
  839.                     PRINT " destroyed";
  840.                     IF x = vpoint THEN '                            was destroyed unit active?
  841.                         ct% = 0
  842.                         DO '                                        find next available unit to be active
  843.                             vpoint = vpoint + 1
  844.                             IF vpoint > units THEN vpoint = 1
  845.                             IF cmb(vpoint).status > 0 THEN EXIT DO
  846.                             ct% = ct% + 1
  847.                         LOOP UNTIL ct% = units
  848.                         IF ct% = units THEN '                       if all units destroyed center on primary
  849.                             vpoint = 0
  850.                         END IF
  851.                     END IF
  852.                     UDest x '                                       if destroyed set movement to zero
  853.                 END IF
  854.                 IF x = vpoint THEN '                                Active unit title line
  855.                     PRINT "  active unit"
  856.                 ELSE
  857.                     PRINT
  858.                 END IF
  859.                 PRINT "X:";: TruncCoord cmb(x).ap.pX: PRINT " "; '  Absolute coordinate position
  860.                 PRINT "Y:";: TruncCoord cmb(x).ap.pY: PRINT " ";
  861.                 PRINT "Z:";: TruncCoord cmb(x).ap.pZ: PRINT
  862.                 PRINT "Sp:";
  863.                 IF Thrust(x).Gs > cmb(x).MaxG THEN COLOR clr&(12) ' Red speed if overdrive  subscript out of range when loading new ships???
  864.                 PRINT INT((cmb(x).Sp / 1000) * 100) / 100; '        round to 100th km for display
  865.                 IF x = vpoint THEN '                                Return to original colors
  866.                     COLOR clr&(15)
  867.                 ELSE
  868.                     IF READBIT(Sensor(vpoint, x), 0) OR cmb(x).status = 0 THEN
  869.                         COLOR clr&(8)
  870.                     ELSE
  871.                         COLOR clr&(3)
  872.                     END IF
  873.                 END IF
  874.                 PRINT "kps Hdg:";
  875.                 PRINT USING "###.##"; cmb(x).Hd;
  876.                 PRINT " Z:"; USING "##.##"; cmb(x).In
  877.                 IF x <> vpoint THEN
  878.                     d = Bearing(x)
  879.                     IF collision THEN COLOR clr&(12)
  880.                     PRINT "Brng:"; USING "###.#"; d;
  881.                     LOCATE , 11: PRINT " "; "Z="; INT(Slope!(cmb(x).ap, cmb(vpoint).ap) * 100) / 100; "";
  882.                     PRINT "Dist:";
  883.                     IF Pyth(cmb(vpoint).ap, cmb(x).ap) < 10000000 THEN
  884.                         PRINT USING "#######"; Pyth(cmb(vpoint).ap, cmb(x).ap);: PRINT "km"
  885.                     ELSE
  886.                         PRINT USING "###.###"; Pyth(cmb(vpoint).ap, cmb(x).ap) / KMtoAU;: PRINT "AU"
  887.                     END IF
  888.                     IF collision THEN COLOR clr&(3)
  889.                     collision = NOT collision
  890.                 END IF
  891.                 IF cmb(x).status <> 0 THEN
  892.                     IF x <> vpoint THEN
  893.                         IF x = cmb(vpoint).bogey THEN
  894.                             PUTIMAGE (0, 63), cancel&, ship_box(x)
  895.                         ELSE
  896.                             PUTIMAGE (0, 63), evade&, ship_box(x)
  897.                             PUTIMAGE (49, 63), intercept&, ship_box(x)
  898.                         END IF
  899.                         IF READBIT(Sensor(vpoint, x), 1) THEN
  900.                             COLOR clr&(12)
  901.                             PRINTSTRING (3, 79), ">>Target Locked<<", ship_box(x)
  902.                         ELSE
  903.                             IF cmb(vpoint).mil THEN
  904.                                 b = 600000
  905.                             ELSE
  906.                                 b = 150000
  907.                             END IF
  908.                             IF Pyth(cmb(vpoint).ap, cmb(x).ap) <= b THEN
  909.                                 PUTIMAGE (273, 63), TLoc, ship_box(x)
  910.                             ELSE
  911.                                 PUTIMAGE (273, 63), TLocn, ship_box(x)
  912.                             END IF
  913.  
  914.                         END IF
  915.                     ELSE
  916.                         PUTIMAGE (0, 63), flight&, ship_box(x)
  917.                     END IF
  918.                 END IF
  919.             END IF
  920.  
  921.         END IF
  922.  
  923.         LINE (0, 0)-(289, 95), clr&(4), B
  924.     NEXT x
  925.     '**************************************************************************************************
  926.     c% = 0: g% = 0
  927.     IF units >= 6 THEN '                                        if enough units to fill display area
  928.         lp% = 6 '                                               then fill it
  929.     ELSE
  930.         lp% = units '                                           otherwise only use what you got
  931.     END IF
  932.     FOR y = 1 TO lp%
  933.         g% = g% + 1
  934.         IF units <= 6 THEN shipoff = 0
  935.         PUTIMAGE (0, c%), ship_box(y + shipoff), A& '           invalid handle error thrown once
  936.         c% = c% + 96
  937.     NEXT y
  938.     DEST A&
  939.     COLOR clr&(15)
  940.  
  941. END SUB 'DispShipData
  942.  
  943.  
  944. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  945. SUB EditShip (var AS BYTE)
  946.  
  947.     IF var THEN
  948.         u$ = "Editing new vessel"
  949.     ELSE
  950.         PanelBlank 280, 578, 64, 32, &HFF0F0F0F
  951.         Con_Blok 280, 578, 64, 32, "Editing", 1, &H508C5B4C
  952.         u$ = "Editing " + TRIM$(cmb(vpoint).Nam)
  953.     END IF
  954.  
  955.     t% = 400: r% = 5
  956.     DialogBox u$, t%, 250, 100, &HFF8C5B4C, clr&(15)
  957.     in1$ = "Enter new value or press ENTER to default"
  958.     l = WIDTH(A&) / 2 - (LEN(in1$) * 8) / 2
  959.     PRINTSTRING (l, 320), in1$, A&
  960.     DISPLAY
  961.     col% = ((WIDTH(A&) / 2) - (t% / 2)) / 8 + 4
  962.     IF var = 0 THEN
  963.         LOCATE 6 + r%, col%
  964.         INPUT "new name:"; n$
  965.         IF n$ <> "" THEN cmb(vpoint).Nam = n$
  966.         LOCATE 7 + r%, col%
  967.         INPUT "Max Gs:"; mg$
  968.         IF mg$ <> "" THEN cmb(vpoint).MaxG = VAL(mg$)
  969.         LOCATE 8 + r%, col%
  970.         INPUT "X pos:"; xp$
  971.         IF xp$ <> "" THEN cmb(vpoint).ap.pX = VAL(xp$)
  972.         LOCATE 9 + r%, col%
  973.         INPUT "Y pos:"; yp$
  974.         IF yp$ <> "" THEN cmb(vpoint).ap.pY = VAL(yp$)
  975.         LOCATE 10 + r%, col%
  976.         INPUT "Z pos:"; zp$
  977.         IF zp$ <> "" THEN cmb(vpoint).ap.pZ = VAL(zp$)
  978.         LOCATE 11 + r%, col%
  979.         INPUT "Speed (kps):"; sp$
  980.         IF sp$ <> "" THEN cmb(vpoint).Sp = VAL(sp$) * 1000
  981.         LOCATE 12 + r%, col%
  982.         INPUT "Heading:"; hd$
  983.         IF hd$ <> "" THEN cmb(vpoint).Hd = VAL(hd$)
  984.         LOCATE 13 + r%, col%
  985.         INPUT "Inclination:"; in$
  986.         IF in$ <> "" THEN cmb(vpoint).In = VAL(in$)
  987.         DO
  988.             b = 0
  989.             LOCATE 14 + r%, col%
  990.             PRINT "                                         "
  991.             LOCATE 14 + r%, col%
  992.             INPUT "Scout/military sensors? y/n ", mil$
  993.             SELECT CASE UCASE$(mil$)
  994.                 CASE IS = "Y"
  995.                     cmb(vpoint).mil = -1: b = -1
  996.                 CASE IS = "N"
  997.                     cmb(vpoint).mil = 0: b = -1
  998.                 CASE IS = ""
  999.                     b = -1
  1000.                 CASE ELSE
  1001.             END SELECT
  1002.         LOOP UNTIL b
  1003.     ELSE
  1004.         LOCATE 7 + r%, col%
  1005.         INPUT "Max Gs:"; mg$
  1006.         IF mg$ <> "" THEN cmb(vpoint).MaxG = VAL(mg$)
  1007.     END IF
  1008.  
  1009. END SUB 'EditShip
  1010.  
  1011.  
  1012. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1013. SUB FCirc (CX AS INTEGER64, CY AS INTEGER64, RR AS INTEGER64, C AS UNSIGNED LONG)
  1014.     DIM R AS INTEGER64, RError AS INTEGER64
  1015.     DIM X AS INTEGER64, Y AS INTEGER64
  1016.  
  1017.     R = ABS(RR) '                                               radius value along positive x
  1018.     RError = -R '                                               opposite side of circle? negative x
  1019.     X = R '                                                     point along positive x position
  1020.     Y = 0 '                                                     starting at the equator
  1021.     IF R = 0 THEN PSET (CX, CY), C: EXIT SUB '                  zero radius is point, not circle
  1022.     LINE (CX - X, CY)-(CX + X, CY), C, BF '                     draw equatorial line
  1023.     WHILE X > Y
  1024.         RError = RError + Y * 2 + 1
  1025.         IF RError >= 0 THEN
  1026.             IF X <> Y + 1 THEN
  1027.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1028.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1029.             END IF
  1030.             X = X - 1
  1031.             RError = RError - X * 2
  1032.         END IF
  1033.         Y = Y + 1
  1034.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1035.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1036.     WEND
  1037. END SUB 'FCirc
  1038.  
  1039.  
  1040. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1041. FUNCTION FindParent (var AS INTEGER)
  1042.  
  1043.     'Accepts a planetary body index (var) and finds the index of its parent body
  1044.  
  1045.     FOR x = 1 TO orbs
  1046.         IF hvns(var).parnt = hvns(x).nam THEN p = x
  1047.     NEXT x
  1048.     FindParent = p
  1049.  
  1050. END FUNCTION 'FindParent
  1051.  
  1052.  
  1053. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1054. SUB FlightPlan
  1055.  
  1056.     'routine to choose planet- input box
  1057.     'DIM unitpoints for startpoint, midpoint and endpoint
  1058.     'FlightPlan to be called on vpoint each turn while bstat=3
  1059.     'check movement of end point and update, also update midpoint
  1060.     'acceleration until at or past updated midpoint, spread mathematically over remaining distance
  1061.     'deceleration after midpoint, spread mathematically over remaining distance.
  1062.  
  1063.     Coming
  1064.  
  1065. END SUB 'FlightPlan
  1066.  
  1067.  
  1068. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1069. SUB GateKeeper
  1070.  
  1071.     SCREEN A&
  1072.     DEST A&
  1073.     COLOR , clr&(0)
  1074.     CLS
  1075.     PUTIMAGE (0, 0), strfld, A&
  1076.     Prnt TRIM$(ttl), 6, -6, 250, 100, 48, 0, &HFF5050A0
  1077.     Prnt "Classic Traveller starship maneuvers", 2, -2, 320, 200, 16, 0, &HFF505040
  1078.     COLOR clr&(7)
  1079.     PRINTSTRING (200, 250), "Ditch the compasses and protractors! CT-Vector will handle the starship maneuvers, and even do it in 3D.", A&
  1080.     PRINTSTRING (200, 270), "If you know a star system's name and path you may load it now, or press [enter] to default to Sol", A&
  1081.     DO
  1082.         T& = NEWIMAGE(950, 200, 32)
  1083.         DEST T&
  1084.         CLS
  1085.         FOR x = 0 TO 2
  1086.             LINE (0 + x, 0 + x)-(949 - x, 199 - x), &HFF5050A0, B
  1087.         NEXT x
  1088.         PUTIMAGE (150, 290), T&, A&
  1089.         DEST A&
  1090.         LOCATE 20, 25
  1091.         INPUT "Input {path/filename}.tss or [enter] to default to Sol :", sys$
  1092.         IF sys$ = "" THEN
  1093.             sys$ = "systems/Sol.tss"
  1094.         ELSE
  1095.             IF TRIM$(RIGHT$(sys$, 4)) = ".tss" THEN
  1096.                 sys$ = TRIM$(sys$)
  1097.             ELSE
  1098.                 sys$ = TRIM$(sys$) + ".tss"
  1099.             END IF
  1100.  
  1101.             IF MID$(sys$, 1, 7) = "systems/" THEN
  1102.             ELSE
  1103.                 sys$ = "systems/" + TRIM$(sys$)
  1104.             END IF
  1105.         END IF
  1106.         IF FILEEXISTS(sys$) THEN
  1107.             'load file into hvns() array
  1108.             OPEN sys$ FOR RANDOM AS #1 LEN = LEN(hvns(0)) '     Open filename constructed above.
  1109.             orbs = LOF(1) / LEN(hvns(0))
  1110.             REDIM hvns(orbs) AS body
  1111.             FOR x = 1 TO orbs '                                 Load data array
  1112.                 GET #1, x, hvns(x)
  1113.             NEXT x
  1114.             CLOSE #1
  1115.             LOCATE 22, 25: INPUT "Input year: ", yr
  1116.             LOCATE 23, 25: INPUT "Input day (0-365): ", dy
  1117.             IF dy = 0 THEN
  1118.                 oryr = yr
  1119.             ELSE
  1120.                 oryr = yr + (dy / 365)
  1121.             END IF
  1122.             FREEIMAGE T&
  1123.             EXIT DO
  1124.         ELSE
  1125.             LOCATE 22, 25: PRINT "File does not exist. Please check your path and file name."
  1126.             SLEEP 3
  1127.         END IF
  1128.     LOOP
  1129.     t$ = ttl + " " + sys$
  1130.     TITLE t$
  1131.     FREEIMAGE strfld
  1132.  
  1133. END SUB 'GateKeeper
  1134.  
  1135.  
  1136. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1137. SUB Grav_Well (var AS INTEGER)
  1138.  
  1139.     'Apply gravity perturbations of nearby massive bodies
  1140.     'Grav_Well call should probably go in CoordUpdate after AbsXYZ is set
  1141.  
  1142.     IF cmb(var).status > 0 THEN '                               if unit (var) is destroyed there's no point in doing this
  1143.         DIM grav AS Maneuver '                                  grav influence of every body in system
  1144.         DIM mdpnt AS unitpoint '                                midpoint of ship's vector
  1145.         DIM Ppnt AS unitpoint '                                 planetary gravity centers
  1146.         xdr! = 0: ydr! = 0: zdr! = 0
  1147.  
  1148.         'locate turn vector midpoint- now * 0.5, was / 2
  1149.         mdpnt.pX = cmb(var).op.pX + (cmb(var).ap.pX - cmb(var).op.pX) * 0.5
  1150.         mdpnt.pY = cmb(var).op.pY + (cmb(var).ap.pY - cmb(var).op.pY) * 0.5
  1151.         mdpnt.pZ = cmb(var).op.pZ + (cmb(var).ap.pZ - cmb(var).op.pZ) * 0.5
  1152.  
  1153.         'Iterate all bodies in system
  1154.         FOR O = 1 TO orbs
  1155.             IF hvns(O).star <> 2 THEN
  1156.                 'find distance to massive body o from unit's vector mid point
  1157.                 Ppnt = hvns(O).ps
  1158.                 ds## = Pyth(Ppnt, mdpnt) '                          distance between bodies, use float variable
  1159.                 IF ds## < hvns(O).radi THEN ds## = hvns(O).radi
  1160.  
  1161.                 'compute gravitational force exerted upon unit at distance
  1162.                 'multiply density by Earth volumes for G value then divide by square of distance
  1163.                 'divide by 26687 setting one Earth mass to one G @ Earth radius
  1164.                 radius## = hvns(O).radi '                           convert radii to float variable
  1165.                 grav.Gs = ((hvns(O).dens * ((4 / 3) * PI * (radius## * radius## * radius##))) / 26687) / (ds## * ds##)
  1166.  
  1167.                 'get relative offset positions of ship vector midpoint to gravity well source to obtain source of G force vector
  1168.                 DIM Pull AS unitpoint
  1169.                 Pull = hvns(O).ps: VecAdd Pull, mdpnt, -1
  1170.  
  1171.                 grav.Azi = Azimuth!(Pull.pX, Pull.pY) '             Azimuth bearing of perturbation
  1172.                 grav.Inc = Slope!(Ppnt, mdpnt) '                    Declination of perturbation
  1173.  
  1174.                 'add vector to a vector tally
  1175.                 zgrav! = (grav.Gs * 10000) * SIN(D2R(grav.Inc))
  1176.                 xgrav! = (grav.Gs * 10000) * COS(D2R(grav.Inc)) * SIN(D2R(grav.Azi))
  1177.                 ygrav! = (grav.Gs * 10000) * COS(D2R(grav.Inc)) * COS(D2R(grav.Azi))
  1178.                 xdr! = xdr! + xgrav!
  1179.                 ydr! = ydr! + ygrav!
  1180.                 zdr! = zdr! + zgrav!
  1181.             END IF
  1182.         NEXT O
  1183.  
  1184.         'apply the combined vector to unit
  1185.         cmb(var).ap.pX = cmb(var).ap.pX + ROUND(xdr!)
  1186.         cmb(var).ap.pY = cmb(var).ap.pY + ROUND(ydr!)
  1187.         cmb(var).ap.pZ = cmb(var).ap.pZ + ROUND(zdr!)
  1188.  
  1189.         'temporary for watch variable of active unit- need to exprapolate out the Maneuver data
  1190.         IF var = vpoint THEN
  1191.             'find the distance of xdr!, ydr! & zdr!
  1192.             DIM xu AS unitpoint
  1193.             xu.pX = xdr!: xu.pY = ydr!: xu.pZ = zdr!
  1194.             Gwat.Gs = HYPOT(HYPOT(xdr!, ydr!), zdr!) / 10000
  1195.             Gwat.Azi = Azimuth!(xdr!, ydr!)
  1196.             Gwat.Inc = Slope!(xu, cmb(var).ap)
  1197.         END IF
  1198.  
  1199.     END IF
  1200.  
  1201. END SUB 'Grav_Well
  1202.  
  1203.  
  1204. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1205. SUB IncMeter (var AS BYTE, vecin AS BYTE)
  1206.  
  1207.     'togs bit 5= inclinometer display
  1208.  
  1209.     IF var AND NOT READBIT(togs, 1) THEN '                      true and not z-pan
  1210.         'Display inclinometer scale
  1211.         c& = RGBA32(127, 127, 127, 127)
  1212.         COLOR c&
  1213.         IF vecin THEN
  1214.             a = 0: b = 180: c = -90: d = -1
  1215.         ELSE
  1216.             SELECT CASE cmb(vpoint).Hd
  1217.                 CASE 0 TO 180
  1218.                     a = 0: b = 180: c = -90: d = -1
  1219.                 CASE IS > 180
  1220.                     a = 180: b = 360: c = -270: d = 1
  1221.             END SELECT
  1222.         END IF
  1223.         FOR whl = a TO b
  1224.             IF whl MOD 45 = 0 THEN
  1225.                 y = 800
  1226.                 Prnt STR$((whl + c) * d), 2.8, 2.8, ((y + 20) * SIN(D2R(whl))) - 60, (y + 20) * COS(D2R(whl)), 24, 0, c&
  1227.             ELSEIF whl MOD 10 = 0 THEN
  1228.                 y = 850
  1229.             ELSEIF whl MOD 5 = 0 THEN
  1230.                 y = 870
  1231.             ELSE
  1232.                 y = 890
  1233.             END IF
  1234.             LINE (900 * SIN(D2R(whl)), 900 * COS(D2R(whl)))-(y * SIN(D2R(whl)), y * COS(D2R(whl))), c&
  1235.         NEXT whl
  1236.  
  1237.         'Display unit inclination arrow
  1238.         IF cmb(vpoint).In >= 0 THEN '                           Moving with or toward the zenith of the plane
  1239.             IF cmb(vpoint).Hd <= 180 THEN '                     right side
  1240.                 zdeg! = ABS(cmb(vpoint).In - 90)
  1241.             ELSE '                                              left side
  1242.                 zdeg! = ABS(270 - NOT SGN(d) * cmb(vpoint).In)
  1243.             END IF
  1244.         ELSE '                                                  Moving toward the nadir of the plane
  1245.             IF cmb(vpoint).Hd > 180 THEN '                      left side
  1246.                 zdeg! = ABS(270 - NOT SGN(d) * cmb(vpoint).In)
  1247.             ELSE '                                              right side
  1248.                 zdeg! = ABS(cmb(vpoint).In - 90)
  1249.             END IF
  1250.         END IF
  1251.         LINE (850 * SIN(D2R(zdeg! - 1)), 850 * COS(D2R(zdeg! - 1)))-(900 * SIN(D2R(zdeg!)), 900 * COS(D2R(zdeg!))), RGBA32(127, 127, 127, 200)
  1252.         LINE (900 * SIN(D2R(zdeg!)), 900 * COS(D2R(zdeg!)))-(850 * SIN(D2R(zdeg! + 1)), 850 * COS(D2R(zdeg! + 1))), RGBA32(127, 127, 127, 200)
  1253.  
  1254.     END IF
  1255.  
  1256. END SUB 'IncMeter
  1257.  
  1258.  
  1259. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1260. SUB InterVadeII (tar AS INTEGER, sol AS INTEGER, mode AS INTEGER)
  1261.  
  1262.     '"The others are as archaic as dinosaurs compared to InterVadeII, a whole new approach..."
  1263.     '-Dr. Richard Daystrom ;)
  1264.     'and this one's turning out just about as well...
  1265.  
  1266.     ' Conduct evade/intercept calculations
  1267.     ' tar = target unit: tar is also carried in cmb(sol).bogey
  1268.     ' sol is solution unit, i.e. unit executing the nav solution
  1269.     ' mode is mode of call 0 from MoveTurn or 1+ from MouseOps
  1270.     '       MoveTurn mode (0) automatically applies computed maneuvers
  1271.     '       MouseOps mode queries user to accept solution upon initiation
  1272.     '           mode is now carried in cmb(sol).bstat for automation
  1273.     '               1=evade
  1274.     '               2=intercept
  1275.     'typical syntax: InterVadeII cmb(x).bogey, cmb(x).id, [0 - 2]
  1276.     'we can later expand mode mode to include flightplan maneuvers
  1277.     'using .bogey to hold planet index.
  1278.  
  1279.     'We cannot know the future, so we must use the past as the basis of calculation
  1280.     DIM origin AS unitpoint '                                   used as 0,0,0 base for Pyth distance calculations
  1281.     DIM tarpos AS unitpoint '                                   target unit position
  1282.     DIM solpos AS unitpoint '                                   solution unit position
  1283.     DIM tarmov AS unitpoint '                                   last target movement vector
  1284.     DIM solmov AS unitpoint '                                   last solution movement vector
  1285.     DIM tarfut AS unitpoint '                                   projected future target position
  1286.     DIM solfut AS unitpoint '                                   projected future solution position
  1287.     DIM difmov AS unitpoint '
  1288.     DIM clsmov AS unitpoint '
  1289.     origin.pX = 0: origin.pY = 0: origin.pZ = 0
  1290.     tarpos = cmb(tar).ap: solpos = cmb(sol).ap
  1291.     tarmov = cmb(tar).ap: VecAdd tarmov, cmb(tar).op, -1 '  compute last target movement vector (target velocity)
  1292.     solmov = cmb(sol).ap: VecAdd solmov, cmb(sol).op, -1 '  compute last solution movement vector (solution velocity)
  1293.     tarfut = tarpos: VecAdd tarfut, tarmov, 1 '             compute projected future target position
  1294.     solfut = solpos: VecAdd solfut, solmov, 1 '             compute projected future solution position   Do we need this? the whole point is to change it
  1295.  
  1296.     SELECT CASE mode '                                          is unit evading or intercepting?
  1297.         '_____________________________________________________________________________________________________________________________EVADE
  1298.         CASE IS = 1 'TO EVADE
  1299.             'what movement vector (solmov) maximizes distance between tarfut and solfut
  1300.             'take a break from intercept
  1301.  
  1302.             '_________________________________________________________________________________________________________________________INTERCEPT
  1303.         CASE IS = 2 'TO INTERCEPT will move to intercept, but need timely braking thrust
  1304.             'need a match vector AND a close vector to intercept, subject to maxG of solution unit
  1305.             DIM uclsmov AS unitpoint
  1306.             DIM usolmov AS unitpoint
  1307.  
  1308.             clsmov = tarfut: VecAdd clsmov, solfut, -1 'now clsmov has the cartesian vector to close range with the target this turn
  1309.             difmov = solmov: VecAdd difmov, tarmov, -1 'now difmov has the cartesian vector that adjusts to the target movement this turn
  1310.             VecAdd clsmov, difmov, 1 'combine the two ...and this is the vector to close with target's future position
  1311.  
  1312.             uclsmov = clsmov: VecNorm uclsmov
  1313.             usolmov = solmov: VecNorm usolmov
  1314.             dotP&& = uclsmov.pX * usolmov.pX + uclsmov.pY * usolmov.pY + uclsmov.pZ * usolmov.pZ '<<<<DOT PRODUCT equation if needed
  1315.             'dotP&& = clsmov.pX * solmov.pX + clsmov.pY * solmov.pY + clsmov.pZ * solmov.pZ '<<<<DOT PRODUCT equation if needed
  1316.             IF dotP&& > 0.8 THEN
  1317.                 T2m## = Pyth(origin, difmov) / (cmb(sol).MaxG * 10000) 'turns to match target speed
  1318.                 T2c## = Pyth(origin, clsmov) / (cmb(sol).MaxG * 10000)
  1319.                 d2m## = Pyth(origin, clsmov) '                      distance between future points (kms)
  1320.                 vav## = (Pyth(origin, solmov) + Pyth(origin, tarmov)) / 2
  1321.                 IF d2m## / vav## <= T2m## + 1 THEN
  1322.                     l% = -1
  1323.                 ELSE
  1324.                     l% = 1
  1325.                 END IF
  1326.             ELSE
  1327.                 l% = 1
  1328.             END IF
  1329.             'apply results to Thrust of solution unit
  1330.             Thrust(sol).Azi = Azimuth!(clsmov.pX * l%, clsmov.pY * l%)
  1331.             Thrust(sol).Inc = Slope!(tarfut, solfut) * l%
  1332.             IF Pyth(solfut, tarfut) < cmb(sol).MaxG * 10000 THEN
  1333.                 Thrust(sol).Gs = Pyth(solfut, tarfut) / 10000
  1334.             ELSE
  1335.                 Thrust(sol).Gs = cmb(sol).MaxG
  1336.             END IF
  1337.     END SELECT
  1338.  
  1339.     'dotP&& = tarmov.pX * solmov.pX + tarmov.pY * solmov.pY + tarmov.pZ * solmov.pZ '<<<<DOT PRODUCT equation if needed
  1340.     's = (v * t) - (.5 * a * t ^ 2) 'where
  1341.     'Deceleration = v^2 - u^2 / 2s 'Where, v = The Final Velocity  u = The Initial Velocity  s = Distance
  1342.     'Time[s] = 2 * ((Distance[m] / Acceleration[m/s^2])^.5)
  1343.     'Distance[m] = Acceleration[m/s^2] * Time[s]^2 / 4
  1344.     'Acceleration[m/s^2] = 4 * Distance[m] / Time[s]^2
  1345.     'Deceleration Distance[m] = Acceleration[m/s^2] * Time[sec]^2 / 2
  1346.  
  1347.  
  1348. END SUB 'InterVadeII
  1349.  
  1350.  
  1351. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1352. SUB Load_System
  1353.  
  1354.     'Load star system file
  1355.     'call syntax: DialogBox <heading string>, box x, box y, y position, bounding box color, text color
  1356.     DialogBox "LOAD NEW STAR SYSTEM", 400, 250, 50, &HFF2C9B2C, clr&(15)
  1357.     in1$ = "Enter path and filename of system"
  1358.     l = WIDTH(A&) / 2 - (LEN(in1$) * 8) / 2
  1359.     PRINTSTRING (l, 113), in1$, A&
  1360.     DISPLAY
  1361.     LOCATE 10, 57
  1362.     INPUT "systems\+ :", fn$
  1363.     IF RIGHT$(fn$, 4) <> ".tss" THEN
  1364.         fn$ = "systems\" + fn$ + ".tss"
  1365.     ELSE
  1366.         fn$ = "systems\" + fn$
  1367.     END IF
  1368.     IF FILEEXISTS(fn$) THEN
  1369.         ERASE hvns
  1370.         OPEN fn$ FOR RANDOM AS #1 LEN = LEN(hvns(0))
  1371.         orbs = LOF(1) / LEN(hvns(0))
  1372.         REDIM hvns(orbs) AS body
  1373.         Turncount = 0
  1374.         FOR x = 1 TO orbs
  1375.             GET #1, x, hvns(x)
  1376.         NEXT x
  1377.         CLOSE #1
  1378.         PlanetMove 1 '                                          planets to date positions
  1379.     ELSE
  1380.         LOCATE 12, 57
  1381.         PRINT "File not found, check path and name."
  1382.         _DISPLAY
  1383.         SLEEP 3
  1384.     END IF
  1385.  
  1386. END SUB 'Load_System
  1387.  
  1388.  
  1389. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1390. SUB Load_Ships
  1391.  
  1392.     DialogBox "LOAD NEW VESSEL GROUP", 400, 250, 50, &HFF2C9B2C, clr&(15)
  1393.     in1$ = "Enter filename of ships"
  1394.     l = WIDTH(A&) / 2 - (LEN(in1$) * 8) / 2
  1395.     PRINTSTRING (l, 113), in1$, A&
  1396.     DISPLAY
  1397.     LOCATE 10, 57
  1398.     INPUT "ships/+ :", fn$
  1399.     IF RIGHT$(fn$, 4) <> ".tvg" THEN
  1400.         fn$ = "ships/" + fn$ + ".tvg"
  1401.     ELSE
  1402.         fn$ = "ships/" + fn$
  1403.     END IF
  1404.     IF FILEEXISTS(fn$) THEN
  1405.         ERASE cmb
  1406.         FOR x = 1 TO units '                                    erase old ship data displays
  1407.             FREEIMAGE ship_box(x)
  1408.         NEXT x
  1409.         OPEN fn$ FOR RANDOM AS #1 LEN = LEN(cmb(0))
  1410.         units = LOF(1) / LEN(cmb(0))
  1411.         REDIM cmb(units) AS ship
  1412.         REDIM Sensor(units, units)
  1413.         REDIM Thrust(units) AS Maneuver
  1414.         REDIM ship_box(units)
  1415.         FOR x = 1 TO units
  1416.             ship_box(x) = NEWIMAGE(290, 96, 32)
  1417.         NEXT x
  1418.         Turncount = 0: vpoint = 1: shipoff = 0
  1419.         FOR x = 1 TO units
  1420.             GET #1, x, cmb(x)
  1421.         NEXT x
  1422.         CLOSE #1
  1423.         FOR x = 1 TO units '                                    nested loop to avoid planet/star collisions here
  1424.             FOR y = 1 TO orbs
  1425.                 IF Pyth(cmb(x).ap, hvns(y).ps) < hvns(p).radi THEN 'inside a body's radius? then move it
  1426.                     DO '                                        loop to accomodate large stars/GGs
  1427.                         cmb(x).ap.pX = cmb(x).ap.pX + 100000 '  Move ship 100K coreward and trailing
  1428.                         cmb(x).ap.pY = cmb(x).ap.pY + 100000
  1429.                     LOOP UNTIL Pyth(cmb(x).ap, hvns(y).ps) > hvns(p).radi 'stop once the unit's clear
  1430.                 END IF
  1431.             NEXT y
  1432.         NEXT x
  1433.         VCS
  1434.     ELSE
  1435.         LOCATE 12, 57
  1436.         PRINT "File not found, check path and name."
  1437.         SLEEP 3
  1438.     END IF
  1439.  
  1440. END SUB 'Load_Ships
  1441.  
  1442.  
  1443. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1444. SUB Load_Scenario
  1445.  
  1446.     t% = 400: r% = 2
  1447.     DialogBox "LOAD SCENARIO", t%, 250, 50, &HFF8C5B4C, clr&(15)
  1448.     DISPLAY
  1449.     LOCATE r% + 5, ((WIDTH(A&) / 2) - (t% / 2)) / 8 + 4
  1450.     INPUT "Enter a scenario name: ", fl$
  1451.     IF TRIM$(fl$) = "auto" THEN fl$ = "autosave/auto"
  1452.     LOCATE r% + 7, ((WIDTH(A&) / 2) - 40) / 8
  1453.     vl$ = "scenarios\" + TRIM$(fl$) + ".tvg" '                  Vessel group #2
  1454.     pl$ = "scenarios\" + TRIM$(fl$) + ".tss" '                  Planets #1
  1455.     sl$ = "scenarios\" + TRIM$(fl$) + ".tgn" '                  saved state #4
  1456.     tl$ = "scenarios\" + TRIM$(fl$) + ".tvt" '                  Thrust keeper (.tvt) #3
  1457.     tt$ = "scenarios\" + TRIM$(fl$) + ".ttl" '                  Sensor state keeper #5
  1458.     IF FILEEXISTS(vl$) AND FILEEXISTS(pl$) THEN
  1459.         ERASE hvns, cmb, Thrust, Sensor '                       reset environment/ remove TLock
  1460.         OPEN pl$ FOR RANDOM AS #1 LEN = LEN(hvns(0)) '          Load new planetary system
  1461.         orbs = LOF(1) / LEN(hvns(0))
  1462.         REDIM hvns(orbs) AS body
  1463.         FOR x = 1 TO orbs
  1464.             GET #1, x, hvns(x)
  1465.         NEXT x
  1466.         CLOSE #1
  1467.         OPEN vl$ FOR RANDOM AS #2 LEN = LEN(cmb(0))
  1468.         units = LOF(2) / LEN(cmb(0))
  1469.         REDIM cmb(units) AS ship
  1470.         FOR x = 1 TO units
  1471.             GET #2, x, cmb(x)
  1472.         NEXT x
  1473.         CLOSE #2
  1474.         IF FILEEXISTS(tl$) THEN '                              important but not fatal if missing
  1475.             OPEN tl$ FOR RANDOM AS #3 LEN = LEN(Thrust(0))
  1476.             REDIM Thrust(units) AS Maneuver
  1477.             FOR x = 1 TO units
  1478.                 GET #3, x, Thrust(x)
  1479.             NEXT x
  1480.             CLOSE #3
  1481.         ELSE
  1482.             REDIM Thrust(units) AS Maneuver
  1483.         END IF
  1484.         IF FILEEXISTS(sl$) THEN '
  1485.             OPEN sl$ FOR INPUT AS #4
  1486.             INPUT #4, Turncount, oryr, vpoint, shipoff
  1487.             CLOSE #4
  1488.         END IF
  1489.         IF FILEEXISTS(tt$) THEN '                               remove entire file structure TLock subsumed by Sensor
  1490.             OPEN tt$ FOR RANDOM AS #5 LEN = LEN(Sensor(0, 0))
  1491.             REDIM Sensor(units, units) AS BYTE
  1492.             FOR x = 1 TO units
  1493.                 FOR y = 1 TO units
  1494.                     GET #5, ((x - 1) * units) + y, Sensor(x, y)
  1495.                 NEXT y
  1496.             NEXT x
  1497.             CLOSE #5
  1498.         ELSE
  1499.             REDIM Sensor(units, units) AS BYTE
  1500.         END IF
  1501.         Turn2Clock Turncount
  1502.         Refresh
  1503.     ELSE
  1504.         'essential file(s) are not present, abort
  1505.         LOCATE r% + 9, ((WIDTH(A&) / 2) - (t% / 2)) / 8 + 4
  1506.         PRINT "Essential files missing, check filename."
  1507.         SLEEP 3
  1508.     END IF
  1509.  
  1510. END SUB 'Load_Scenario
  1511.  
  1512.  
  1513. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1514. SUB Make_Buttons
  1515.  
  1516.     DEST flight& '                                             Create flightplan button
  1517.     CLS
  1518.     COLOR , RGBA32(22, 166, 211, 255)
  1519.     PRINTSTRING (0, 0), "FLIGHTPLAN", flight&
  1520.  
  1521.     DEST evade& '                                              Create evade button
  1522.     CLS
  1523.     COLOR , RGBA32(244, 11, 17, 255)
  1524.     PRINTSTRING (0, 0), "EVADE", evade&
  1525.  
  1526.     DEST intercept& '                                          Create intercept button
  1527.     CLS
  1528.     COLOR , RGBA32(17, 139, 17, 255)
  1529.     PRINTSTRING (0, 0), "INTERCEPT", intercept&
  1530.  
  1531.     DEST cancel& '                                             Create cancel button
  1532.     CLS
  1533.     COLOR , RGBA32(67, 67, 150, 255)
  1534.     PRINTSTRING (0, 0), "CANCEL", cancel&
  1535.  
  1536.     DEST XZ& ' 64x32                                           Create Zoom extents control
  1537.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1538.     CLS
  1539.     LINE (1, 1)-(62, 30), clr&(4), B
  1540.     PRINTSTRING (8, 8), "Zoom", XZ&
  1541.     COLOR clr&(4)
  1542.     PRINTSTRING (48, 8), "X", XZ&
  1543.  
  1544.     DEST IZ& ' 64x32                                           Create Zoom in control
  1545.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1546.     CLS
  1547.     LINE (1, 1)-(62, 30), clr&(4), B
  1548.     PRINTSTRING (8, 8), "Zoom", IZ&
  1549.     COLOR clr&(4)
  1550.     PRINTSTRING (48, 8), "+", IZ&
  1551.  
  1552.     DEST OZ& ' 64x32                                           Create Zoom out control
  1553.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1554.     CLS
  1555.     LINE (1, 1)-(62, 30), clr&(4), B
  1556.     PRINTSTRING (8, 8), "Zoom", OZ&
  1557.     COLOR clr&(4)
  1558.     PRINTSTRING (48, 8), "-", OZ&
  1559.  
  1560.     DEST RG& ' 56x32                                           Create Range band toggle
  1561.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1562.     CLS
  1563.     LINE (1, 1)-(54, 30), clr&(4), B
  1564.     c& = RGBA(252, 252, 84, 100)
  1565.     FCirc 28, 16, 20, RGBA(252, 252, 84, 100)
  1566.     c& = RGBA(252, 84, 84, 100)
  1567.     FCirc 28, 16, 12, RGBA(0, 0, 0, 0)
  1568.     FCirc 28, 16, 12, RGBA(252, 84, 84, 200)
  1569.     PRINTMODE KEEPBACKGROUND
  1570.     COLOR clr&(4)
  1571.     PRINTSTRING (8, 8), "R", RG&
  1572.     COLOR clr&(0)
  1573.     PRINTSTRING (16, 8), "ange", RG&
  1574.  
  1575.     DEST OB& ' 56x32                                           Create Orbit track toggle
  1576.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1577.     CLS
  1578.     LINE (1, 1)-(54, 30), clr&(4), B
  1579.     CIRCLE (-15, -5), 58, clr&(1)
  1580.     CIRCLE (40, 15), 10, clr&(1)
  1581.     PRINTMODE KEEPBACKGROUND
  1582.     COLOR clr&(4)
  1583.     PRINTSTRING (8, 8), "O", OB&
  1584.     COLOR clr&(0)
  1585.     PRINTSTRING (16, 8), "rbit", OB&
  1586.  
  1587.     DEST GD& ' 48x32                                           Create Grid toggle
  1588.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1589.     CLS
  1590.     LINE (1, 1)-(46, 30), clr&(4), B
  1591.     FOR h = 8 TO 48 STEP 8
  1592.         LINE (0, h)-(47, h), clr&(8), BF
  1593.         LINE (h, 0)-(h, 31), clr&(8), BF
  1594.     NEXT h
  1595.     PRINTMODE KEEPBACKGROUND
  1596.     COLOR clr&(4)
  1597.     PRINTSTRING (8, 8), "G", GD&
  1598.     COLOR clr&(0)
  1599.     PRINTSTRING (16, 8), "rid", GD&
  1600.  
  1601.     DEST AZ& ' 40x32                                           Create Azimuth toggle
  1602.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1603.     CLS
  1604.     LINE (1, 1)-(38, 30), clr&(4), B
  1605.     FOR whl = 0 TO 3375 STEP 225
  1606.         outerx = (14 * SIN(D2R(whl / 10))) + 20
  1607.         outery = (14 * COS(D2R(whl / 10))) + 16
  1608.         innerx = (12 * SIN(D2R(whl / 10))) + 20
  1609.         innery = (12 * COS(D2R(whl / 10))) + 16
  1610.         LINE (outerx, outery)-(innerx, innery), clr&(5) '  draw tick
  1611.     NEXT whl
  1612.     PRINTMODE KEEPBACKGROUND
  1613.     COLOR clr&(4)
  1614.     PRINTSTRING (8, 8), "A", AZ&
  1615.     COLOR clr&(0)
  1616.     PRINTSTRING (16, 8), "zi", AZ&
  1617.  
  1618.     DEST IN& ' 40x32                                           Create Inclinometer toggle
  1619.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1620.     CLS
  1621.     LINE (1, 1)-(38, 30), clr&(4), B
  1622.     FOR whl = 0 TO 1800 STEP 225
  1623.         outerx = (14 * SIN(D2R(whl / 10))) + 20
  1624.         outery = (14 * COS(D2R(whl / 10))) + 16
  1625.         innerx = (12 * SIN(D2R(whl / 10))) + 20
  1626.         innery = (12 * COS(D2R(whl / 10))) + 16
  1627.         LINE (outerx, outery)-(innerx, innery), clr&(8) '  draw tick
  1628.     NEXT whl
  1629.     LINE (20, 16)-((14 * SIN(D2R(135))) + 20, (14 * COS(D2R(135))) + 16), clr&(8)
  1630.     PRINTMODE KEEPBACKGROUND
  1631.     COLOR clr&(4)
  1632.     PRINTSTRING (8, 8), "I", IN&
  1633.     COLOR clr&(0)
  1634.     PRINTSTRING (16, 8), "nc", IN&
  1635.  
  1636.     DEST JP& ' 48x32                                           Create Jump envelope toggle
  1637.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1638.     CLS
  1639.     LINE (1, 1)-(46, 30), clr&(4), B
  1640.     FCirc 24, 16, 12, RGBA(150, 116, 116, 200)
  1641.     PRINTMODE KEEPBACKGROUND
  1642.     COLOR clr&(4)
  1643.     PRINTSTRING (8, 8), "J", JP&
  1644.     COLOR clr&(0)
  1645.     PRINTSTRING (16, 8), "ump", JP&
  1646.  
  1647.     DEST DI& ' 48x32                                           Create Jump Diameter button
  1648.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1649.     CLS
  1650.     LINE (1, 1)-(46, 30), clr&(4), B
  1651.     PRINTMODE KEEPBACKGROUND
  1652.     COLOR clr&(4)
  1653.     PRINTSTRING (8, 8), "D", DI&
  1654.     COLOR clr&(0)
  1655.     PRINTSTRING (16, 8), "iam.", DI&
  1656.  
  1657.     DEST DN& ' 48x32                                           Create Jump Density button
  1658.     COLOR clr&(0), RGBA32(72, 128, 222, 255)
  1659.     CLS
  1660.     LINE (1, 1)-(46, 30), clr&(4), B
  1661.     'density graphic
  1662.     PRINTMODE KEEPBACKGROUND
  1663.     COLOR clr&(4)
  1664.     PRINTSTRING (8, 8), "D", DN&
  1665.     COLOR clr&(0)
  1666.     PRINTSTRING (16, 8), "ens.", DN&
  1667.  
  1668.     DEST QT& ' 48x32                                           Create Quit (program) button
  1669.     COLOR clr&(0), RGBA32(255, 0, 50, 255)
  1670.     CLS
  1671.     LINE (1, 1)-(46, 30), clr&(0), B
  1672.     COLOR clr&(11)
  1673.     PRINTSTRING (8, 8), "Q", QT&
  1674.     COLOR clr&(0)
  1675.     PRINTSTRING (16, 8), "uit", QT&
  1676.  
  1677. END SUB 'Make_Buttons
  1678.  
  1679.  
  1680. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1681. SUB Make_Images
  1682.  
  1683.     'Azimuth wheel image
  1684.     DEST AW&
  1685.     WINDOW (-1000, 1000)-(1000, -1000)
  1686.     SCREEN AW&
  1687.     CLEARCOLOR RGB(0, 0, 0)
  1688.     CLS
  1689.     FOR whl = 0 TO 359 '                                    iterate through azimuth wheel
  1690.         IF whl MOD 45 = 0 THEN '                            45 degree tick and number
  1691.             y = 900
  1692.             Prnt STR$(whl), 2.8, 2.8, (y + 20) * SIN(D2R(whl)) - 60, (y + 20) * COS(D2R(whl)), 24, 0, &H7FA800A8
  1693.         ELSEIF whl MOD 10 = 0 THEN '                        10 degree tick
  1694.             y = 950
  1695.         ELSEIF whl MOD 5 = 0 THEN '                         5 degree tick
  1696.             y = 970
  1697.         ELSE '                                              1 degree tick
  1698.             y = 990
  1699.         END IF
  1700.         'Draw azimuth tick
  1701.         LINE (1000 * SIN(D2R(whl)), 1000 * COS(D2R(whl)))-(y * SIN(D2R(whl)), y * COS(D2R(whl))), &H7FA800A8
  1702.     NEXT whl
  1703.  
  1704. END SUB 'Make_Images
  1705.  
  1706.  
  1707. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1708. SUB MainLoop
  1709.  
  1710.     STATIC in AS BYTE
  1711.     Refresh '                                                   initial display refresh
  1712.     DO '                                                        outer loop running computations when inputs
  1713.         DO '                                                    inner loop waiting for inputs while no change
  1714.             IF units <= 6 THEN
  1715.                 shipoff = 0: of%% = 0
  1716.             ELSE
  1717.                 of%% = -1
  1718.             END IF
  1719.             x$ = INKEY$
  1720.             IF x$ <> "" THEN in = -1
  1721.             Mouse_Loop of%%, units
  1722.  
  1723.             mouse_left = MOUSEBUTTON(1)
  1724.             mouse_right = MOUSEBUTTON(2)
  1725.             IF mouse_left = -1 THEN
  1726.                 DELAY .2
  1727.                 Mouse_Ops mouse_x, mouse_y
  1728.                 in = -1
  1729.             END IF
  1730.             IF mouse_right = -1 THEN
  1731.                 DELAY .2
  1732.                 Place_Ship mouse_x, mouse_y
  1733.                 ZoomFac = 1
  1734.                 in = -1
  1735.             END IF
  1736.             IF x$ = CHR$(66) OR x$ = CHR$(98) THEN togs = TOGGLEBIT(togs, 10) '     "B" belt/ring
  1737.             IF x$ = CHR$(82) OR x$ = CHR$(114) THEN togs = TOGGLEBIT(togs, 4) '
  1738.             IF x$ = CHR$(65) OR x$ = CHR$(97) THEN togs = TOGGLEBIT(togs, 2) '
  1739.             IF x$ = CHR$(71) OR x$ = CHR$(103) THEN togs = TOGGLEBIT(togs, 3) '
  1740.             IF x$ = CHR$(73) OR x$ = CHR$(105) THEN togs = TOGGLEBIT(togs, 5) '
  1741.             IF x$ = CHR$(74) OR x$ = CHR$(106) THEN togs = TOGGLEBIT(togs, 6) '
  1742.             IF x$ = CHR$(79) OR x$ = CHR$(111) THEN togs = TOGGLEBIT(togs, 7) '
  1743.             IF x$ = CHR$(68) OR x$ = CHR$(100) THEN togs = TOGGLEBIT(togs, 9) '
  1744.             IF x$ = CHR$(90) OR x$ = CHR$(122) THEN togs = TOGGLEBIT(togs, 8) '
  1745.             IF x$ = CHR$(51) THEN '                                                 2D/3D toggle
  1746.                 togs = TOGGLEBIT(togs, 1)
  1747.                 IF READBIT(togs, 1) THEN
  1748.                     zangle = Ozang
  1749.                 ELSE
  1750.                     Ozang = zangle: zangle = 0
  1751.                 END IF
  1752.             END IF
  1753.             IF x$ = CHR$(86) OR x$ = CHR$(118) THEN NewVector '
  1754.             IF x$ = CHR$(84) OR x$ = CHR$(116) THEN MoveTurn 0 '
  1755.             IF x$ = CHR$(85) OR x$ = CHR$(117) THEN MTurnUndo 0 '
  1756.             IF x$ = CHR$(69) OR x$ = CHR$(101) THEN EditShip 0 '
  1757.             IF x$ = CHR$(70) OR x$ = CHR$(102) THEN FlightPlan '
  1758.             IF x$ = CHR$(72) OR x$ = CHR$(104) THEN Help
  1759.             IF x$ = CHR$(88) OR x$ = CHR$(120) THEN ZoomFac = 1 '
  1760.             IF x$ = CHR$(43) THEN ZoomFac = ZoomFac / .5 '
  1761.             IF x$ = CHR$(45) THEN ZoomFac = ZoomFac * .5 '
  1762.             IF x$ = CHR$(81) OR x$ = CHR$(113) THEN
  1763.                 TIMER(t1%) OFF: Save_Scenario 0: EXIT SUB '
  1764.             END IF
  1765.             IF x$ = CHR$(0) + CHR$(82) THEN AddShip
  1766.             IF x$ = CHR$(0) + CHR$(83) THEN DelShip '
  1767.             IF x$ = CHR$(0) + CHR$(80) THEN '                           down arrow  20480
  1768.                 vpoint = vpoint + 1
  1769.                 IF vpoint > units THEN vpoint = 1: shipoff = 0
  1770.                 IF units > 6 AND vpoint > 6 THEN shipoff = vpoint - 6
  1771.                 DO
  1772.                     IF cmb(vpoint).status = 0 THEN vpoint = vpoint + 1
  1773.                     IF vpoint > units THEN vpoint = 1
  1774.                 LOOP UNTIL cmb(vpoint).status > 0
  1775.             END IF
  1776.             IF x$ = CHR$(0) + CHR$(72) THEN '                           up arrow  18432
  1777.                 vpoint = vpoint - 1
  1778.                 IF vpoint < 1 THEN vpoint = units: shipoff = units - 6
  1779.                 IF units > 6 AND vpoint <= shipoff THEN shipoff = vpoint - 1
  1780.                 DO
  1781.                     IF cmb(vpoint).status = 0 THEN vpoint = vpoint - 1
  1782.                     IF vpoint < 1 THEN vpoint = units
  1783.                 LOOP UNTIL cmb(vpoint).status > 0
  1784.             END IF
  1785.             KEYCLEAR
  1786.             OriScreen vpoint '                                  keep up with ori-screen animation while waiting
  1787.             DispShipData '                                      update ship data display via mouse wheel while waiting
  1788.             DISPLAY
  1789.             LIMIT 50
  1790.         LOOP UNTIL in
  1791.         in = 0
  1792.         Refresh
  1793.         LIMIT 50
  1794.     LOOP
  1795.  
  1796. END SUB 'MainLoop
  1797.  
  1798.  
  1799. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1800. SUB Mouse_Loop (var AS INTEGER, var2 AS INTEGER)
  1801.  
  1802.     '-------------------------ALGORITHM--------------------------------------------------CLEARED
  1803.     ' SUB: Mouse_Loop
  1804.     '
  1805.     ' Purpose:
  1806.     ' Primary mouse input loop. Controls mousewheel scrolling and conditions
  1807.     ' x,y position data.
  1808.     '
  1809.     ' Passed Variables:
  1810.     ' var sends whether data list is extensive enough for using offset printing values
  1811.     ' var2 sends maximum allowed offset value
  1812.     '
  1813.     '------------------------------------------------------------------------------------
  1814.  
  1815.     DO WHILE MOUSEINPUT '                                      scan for changes in mouse position and save to global variables
  1816.         IF var = -1 THEN
  1817.             shipoff = shipoff + MOUSEWHEEL '                   mousewheel offset determines starting element to print
  1818.             IF shipoff < 0 THEN shipoff = 0 '                   don't go beyond bottom of array
  1819.             IF shipoff + 6 > var2 THEN shipoff = var2 - 6 '     don't go beyond the end of the array
  1820.         END IF
  1821.         IF MOUSEBUTTON(1) OR MOUSEBUTTON(2) THEN
  1822.             mouse_y = MOUSEY '                                 get y on mouse click
  1823.             mouse_x = MOUSEX '                                 get x on mouse click
  1824.         END IF
  1825.     LOOP
  1826.  
  1827. END SUB 'Mouse_Loop
  1828.  
  1829.  
  1830. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  1831. SUB Mouse_Ops (xpos AS INTEGER, ypos AS INTEGER)
  1832.     SELECT CASE xpos
  1833.         CASE 0 TO 559 '                                         Left text display
  1834.             DELAY .2
  1835.             SELECT CASE ypos '                                  Divide left into top and bottom
  1836.                 CASE 0 TO 575
  1837.                     SELECT CASE xpos '                          Divide upper left into ship and center display
  1838.                         CASE 0 TO 287
  1839.                             'ship data display
  1840.                             y = INT(ypos / 96) + 1 '            unit # range - modify by shipoff for proper unit
  1841.                             IF y > units THEN y = units
  1842.                             y1 = INT(ypos / 16) + 1 '           row # of mouse click
  1843.                             IF y + shipoff <> vpoint AND y1 MOD 6 = 5 THEN 'not vpoint and 5th line of unit data
  1844.                                 IF xpos < 121 THEN
  1845.                                     IF y + shipoff = cmb(vpoint).bogey THEN ' Cancel was clicked
  1846.                                         IF xpos < 48 THEN
  1847.                                             cmb(vpoint).bogey = 0 ' unit no longer a solution target
  1848.                                             cmb(vpoint).bstat = 0
  1849.                                         END IF
  1850.                                     ELSE
  1851.                                         IF cmb(vpoint).bogey = 0 THEN
  1852.                                             cmb(vpoint).bogey = y + shipoff
  1853.                                             SELECT CASE xpos
  1854.                                                 CASE 0 TO 39 '      Evade
  1855.                                                     cmb(vpoint).bstat = 1
  1856.                                                 CASE 49 TO 120 '    Intercept
  1857.                                                     cmb(vpoint).bstat = 2
  1858.                                             END SELECT
  1859.                                             InterVadeII y + shipoff, vpoint, cmb(vpoint).bstat 'then evade/intercept call
  1860.                                         END IF
  1861.                                     END IF
  1862.                                 ELSEIF xpos > 272 THEN
  1863.                                     IF cmb(vpoint).mil THEN
  1864.                                         b = 600000 '            military sensor range
  1865.                                     ELSE
  1866.                                         b = 150000 '            civilian sensor range
  1867.                                     END IF
  1868.                                     IF Pyth(cmb(vpoint).ap, cmb(y + shipoff).ap) < b THEN
  1869.                                         Sensor(vpoint, y + shipoff) = SETBIT(Sensor(vpoint, y + shipoff), 1)
  1870.                                     END IF
  1871.                                 ELSE
  1872.                                     vpoint = y + shipoff
  1873.                                 END IF
  1874.                             ELSEIF y + shipoff = vpoint AND y1 MOD 6 = 5 THEN
  1875.                                 IF xpos < 80 THEN
  1876.                                     FlightPlan
  1877.                                 END IF
  1878.                             ELSE
  1879.                                 vpoint = y + shipoff '          otherwise set new vpoint
  1880.                             END IF
  1881.                         CASE 288 TO 559
  1882.                             'center display
  1883.                             SELECT CASE ypos
  1884.                                 CASE 0 TO 324
  1885.                                     'Upper center screen area
  1886.                                 CASE 325 TO 573
  1887.                                     'OriScreen area
  1888.                             END SELECT
  1889.                     END SELECT
  1890.                 CASE 576 TO 608
  1891.                     ' buttons tier 1
  1892.                     SELECT CASE xpos
  1893.                         CASE 0 TO 63
  1894.                             NewVector2
  1895.                         CASE 70 TO 133
  1896.                             Coming 'VectorBrake
  1897.                         CASE 140 TO 203
  1898.                             MoveTurn 1
  1899.                         CASE 210 TO 273
  1900.                             MTurnUndo 1
  1901.                         CASE 280 TO 343
  1902.                             EditShip 0
  1903.                         CASE 350 TO 413
  1904.                             DelShip
  1905.                         CASE 420 TO 483
  1906.                             Load_Scenario
  1907.                         CASE 490 TO 553
  1908.                             TIMER(t1%) OFF
  1909.                             Save_Scenario -1
  1910.                             TIMER(t1%) ON
  1911.                     END SELECT
  1912.                     ' buttons tier 2
  1913.                 CASE 614 TO 646
  1914.                     SELECT CASE xpos
  1915.                         CASE 0 TO 63
  1916.                             PanelBlank 0, 614, 64, 32, &HFF0F0F0F
  1917.                             Con_Blok 0, 614, 64, 32, "Thrust 0", 0, &H502C9B2C
  1918.                             DISPLAY
  1919.                             DELAY .5
  1920.                             Thrust(vpoint).Gs = 0
  1921.                         CASE 70 TO 133
  1922.                             Coming
  1923.                         CASE 140 TO 203
  1924.                             Coming
  1925.                         CASE 210 TO 273
  1926.                             Coming
  1927.                         CASE 280 TO 343
  1928.                             AddShip
  1929.                         CASE 350 TO 413
  1930.                             Purge
  1931.                         CASE 420 TO 483
  1932.                             Load_System
  1933.                         CASE 490 TO 553
  1934.                             Save_System
  1935.                     END SELECT
  1936.                     ' buttons tier 3
  1937.                 CASE 650 TO 682
  1938.                     SELECT CASE xpos
  1939.                         CASE 0 TO 63
  1940.                             VectorBrake 'Coming
  1941.                         CASE 70 TO 133
  1942.                             Coming
  1943.                         CASE 140 TO 203
  1944.                             Coming
  1945.                         CASE 210 TO 273
  1946.                             Coming
  1947.                         CASE 280 TO 343
  1948.                             Help
  1949.                         CASE 350 TO 413
  1950.                             IF cmb(vpoint).status = 3 THEN
  1951.                                 cmb(vpoint).status = 1
  1952.                                 EditShip 1
  1953.                             ELSE
  1954.                                 Thrust(vpoint).Gs = 0
  1955.                                 cmb(vpoint).MaxG = 0
  1956.                                 cmb(vpoint).status = 3
  1957.                             END IF
  1958.                         CASE 420 TO 483
  1959.                             Load_Ships
  1960.                         CASE 490 TO 553
  1961.                             Save_Ships
  1962.                     END SELECT
  1963.             END SELECT
  1964.         CASE 560 TO 1179 '                                      Right graphics screen
  1965.             'DELAY .2
  1966.             SELECT CASE ypos
  1967.                 CASE 19 TO 639
  1968.                     ' find relative sensor screen coordinates of mouse click
  1969.                     WindowMouseX = (xpos - 560) * (2000 / 620) - 1000 '      xpos was mouse_x
  1970.                     WindowMouseY = ((ypos - 18) * (2000 / 620) - 1000) * -1 'ypos was mouse_y
  1971.                     ' check to see if click is close to any combat units
  1972.                     q! = Prop!
  1973.                     DIM clk AS unitpoint
  1974.                     clk.pX = WindowMouseX / q! '                get screen click x position
  1975.                     clk.pY = WindowMouseY * SIN(_D2R(zangle)) / q! 'get screen click y position
  1976.                     prox = vpoint
  1977.                     FOR a = 1 TO units
  1978.  
  1979.                         IF a <> vpoint THEN '                   if not active unit
  1980.                             IF PythXY(clk, dcs(a)) < PythXY(clk, dcs(vpoint)) THEN 'if closer to 'a' then active
  1981.                                 IF PythXY(clk, dcs(a)) < PythXY(clk, dcs(prox)) THEN 'if closer to 'a' then any other 'a' tested
  1982.                                     prox = a '                  set proximity unit
  1983.                                 END IF
  1984.                             END IF
  1985.                         END IF
  1986.  
  1987.                         'IF a <> vpoint THEN '                   if not active unit
  1988.                         '    IF PythXY(clk, dcs(a)) < PythXY(clk, dcs(vpoint)) THEN 'if closer to 'a' then active
  1989.                         '        prox = a
  1990.                         '        FOR b = 1 TO units
  1991.                         '            IF PythXY(clk, dcs(b)) < PythXY(clk, dcs(prox)) THEN 'if closer to 'a' then any other 'a' tested
  1992.                         '                prox = b '                  set proximity unit
  1993.                         '            END IF
  1994.                         '        NEXT b
  1995.                         '    END IF
  1996.                         'END IF
  1997.  
  1998.                     NEXT a
  1999.                     vpoint = prox '                             set active to closest proximity unit
  2000.  
  2001.  
  2002.                 CASE 660 TO 691
  2003.                     SELECT CASE xpos
  2004.                         CASE 560 TO 623
  2005.                             ZoomFac = 1 '                       Zoom to extents
  2006.                         CASE 626 TO 689
  2007.                             ZoomFac = ZoomFac / .5 '            Zoom in
  2008.                         CASE 692 TO 755
  2009.                             ZoomFac = ZoomFac * .5 '            Zoom out
  2010.                         CASE 762 TO 817
  2011.                             togs = TOGGLEBIT(togs, 4) '         Range toggle
  2012.                         CASE 820 TO 875
  2013.                             togs = TOGGLEBIT(togs, 7) '         Orbit toggle
  2014.                         CASE 878 TO 925
  2015.                             togs = TOGGLEBIT(togs, 3) '         Grid toggle
  2016.                         CASE 928 TO 967
  2017.                             togs = TOGGLEBIT(togs, 2) '         Azimuth wheel toggle
  2018.                         CASE 970 TO 1009
  2019.                             togs = TOGGLEBIT(togs, 5) '         Inclinometer toggle
  2020.                         CASE 1012 TO 1059
  2021.                             togs = TOGGLEBIT(togs, 6) '         Jump zone toggle
  2022.                         CASE 1062 TO 1109
  2023.                             IF READBIT(togs, 6) THEN '          if jump zone then
  2024.                                 togs = TOGGLEBIT(togs, 9) '     Diameter/Density toggle
  2025.                             END IF
  2026.                         CASE 1132 TO 1179
  2027.                             TIMER(t1%) OFF
  2028.                             Save_Scenario 0
  2029.                             SYSTEM
  2030.                     END SELECT
  2031.             END SELECT
  2032.         CASE 1204 TO 1244 '                                     Z-pan slider      1204-1244 4-654
  2033.             SELECT CASE ypos
  2034.                 CASE 4 TO 18
  2035.                     togs = SETBIT(togs, 1)
  2036.                     zangle = -90
  2037.                 CASE 19 TO 321
  2038.                     togs = SETBIT(togs, 1)
  2039.                     zangle = ((ypos - 329) / 310) * 90
  2040.                 CASE 322 TO 337
  2041.                     togs = RESETBIT(togs, 1)
  2042.                     zangle = 0
  2043.                 CASE 338 TO 637
  2044.                     togs = SETBIT(togs, 1)
  2045.                     zangle = ((ypos - 329) / 310) * 90
  2046.                 CASE 638 TO 653
  2047.                     togs = SETBIT(togs, 1)
  2048.                     zangle = 90
  2049.                 CASE 660 TO 691
  2050.                     WHILE MOUSEINPUT: WEND
  2051.                     togs = TOGGLEBIT(togs, 1)
  2052.                     IF READBIT(togs, 1) THEN
  2053.                         zangle = Ozang
  2054.                     ELSE
  2055.                         Ozang = zangle: zangle = 0
  2056.                     END IF
  2057.             END SELECT
  2058.     END SELECT
  2059.  
  2060. END SUB 'Mouse_Ops
  2061.  
  2062.  
  2063. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2064. SUB MoveTurn (var AS BYTE)
  2065.  
  2066.     'Apply all unit movements
  2067.     Turncount = Turncount + 1
  2068.     Turn2Clock Turncount
  2069.  
  2070.     '                                                           store previous turn for future turn undo
  2071.     IF units > 0 THEN
  2072.         DIM m AS MEM: DIM ms AS MEM: DIM mf AS MEM
  2073.         'm = MEM(cmb())
  2074.         'c = 1
  2075.         'DO '                                                    move all unit's current data to old data block
  2076.         '    MEMCOPY m, m.OFFSET + c * m.ELEMENTSIZE + 52, 37 TO m, m.OFFSET + c * m.ELEMENTSIZE + 15
  2077.         '    c = c + 1
  2078.         'LOOP UNTIL c = units + 1
  2079.         c = 1
  2080.         DO '                                                    iterate all units
  2081.             IF cmb(c).status > 0 THEN '                         if unit destroyed skip the computations
  2082.                 DIM start AS unitpoint
  2083.                 DIM finis AS unitpoint
  2084.                 m = MEM(cmb())
  2085.                 ms = MEM(start)
  2086.                 mf = MEM(finis)
  2087.                 MEMCOPY m, m.OFFSET + c * m.ELEMENTSIZE + 52, 24 TO ms, ms.OFFSET 'same as...
  2088.                 'start = cmb(x).ap
  2089.                 IF MEMGET(m, m.OFFSET + c * m.ELEMENTSIZE + 90, BYTE) > 0 THEN 'same as...
  2090.                     'IF cmb(c).bstat > 0 THEN
  2091.                     InterVadeII MEMGET(m, m.OFFSET + c * m.ELEMENTSIZE + 89, BYTE), c, MEMGET(m, m.OFFSET + c * m.ELEMENTSIZE + 90, BYTE) 'same as...
  2092.                     'InterVadeII cmb(c).bogey, c, cmb(c).bstat
  2093.                 END IF
  2094.  
  2095.                 '***********
  2096.  
  2097.                 MEMCOPY m, m.OFFSET + c * m.ELEMENTSIZE + 52, 37 TO m, m.OFFSET + c * m.ELEMENTSIZE + 15 'same as...
  2098.                 'cmb(c).op = cmb(c).ap
  2099.                 '***********
  2100.  
  2101.                 CoordUpdate c, "T" '                            Update unit position
  2102.                 ColCheck c '                                    check for collision with star/planet
  2103.                 MEMCOPY m, m.OFFSET + c * m.ELEMENTSIZE + 52, 24 TO mf, mf.OFFSET 'same as...
  2104.                 'finis = cmb(x).ap
  2105.                 MEMPUT m, m.OFFSET + c * m.ELEMENTSIZE + 76, Pyth(start, finis) AS SINGLE 'same as...
  2106.                 'cmb(c).Sp = Pyth(start, finis)
  2107.                 MEMPUT m, m.OFFSET + c * m.ELEMENTSIZE + 80, Azimuth!(finis.pX - start.pX, finis.pY - start.pY) AS SINGLE 'same as...
  2108.                 'cmb(c).Hd = Azimuth!(finis.pX - start.pX, finis.pY - start.pY)
  2109.                 MEMPUT m, m.OFFSET + c * m.ELEMENTSIZE + 84, Slope!(finis, start) AS SINGLE 'same as...
  2110.                 'cmb(c).In = Slope!(finis, start)
  2111.             END IF
  2112.             c = c + 1
  2113.         LOOP UNTIL c = units + 1
  2114.     END IF
  2115.     PlanetMove 1
  2116.     togs = RESETBIT(togs, 0) '                                  clear turn undo flag
  2117.     IF var = 1 THEN
  2118.         PanelBlank 140, 578, 64, 32, &HFF0F0F0F
  2119.         Con_Blok 140, 578, 64, 32, "Applied", 0, &H502C9B2C
  2120.         DISPLAY
  2121.         DELAY .2
  2122.     END IF
  2123.     MEMFREE m: MEMFREE ms: MEMFREE mf
  2124.  
  2125. END SUB 'MoveTurn
  2126.  
  2127.  
  2128. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2129. SUB MTurnUndo (var AS BYTE)
  2130.  
  2131.     IF READBIT(togs, 0) THEN
  2132.         'put "cannot undo" message here, if desired. Otherwise just disallow second consecutive undo
  2133.     ELSE
  2134.         Turncount = Turncount - 1
  2135.         Turn2Clock Turncount
  2136.         IF units > 0 THEN
  2137.             DIM m AS MEM '                                      move old ship data block back to current data block
  2138.             m = MEM(cmb())
  2139.             c = 1
  2140.             DO
  2141.                 MEMCOPY m, m.OFFSET + c * m.ELEMENTSIZE + 15, 37 TO m, m.OFFSET + c * m.ELEMENTSIZE + 52
  2142.                 c = c + 1
  2143.             LOOP UNTIL c = units + 1
  2144.             MEMFREE m
  2145.         END IF
  2146.  
  2147.         PlanetMove -1 '                                         back peddle the planets
  2148.         togs = SETBIT(togs, 0) '                                set turn undo flag
  2149.         IF var = 1 THEN
  2150.             PanelBlank 210, 578, 64, 32, &HFF0F0F0F
  2151.             Con_Blok 210, 578, 64, 32, "Undone", 0, &H502C9B2C
  2152.             DISPLAY
  2153.             DELAY .2
  2154.         END IF
  2155.     END IF
  2156.  
  2157. END SUB 'MTurnUndo
  2158.  
  2159.  
  2160. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2161. SUB NewVector
  2162.  
  2163.     'Text based vector input
  2164.     'Input new thrust data for active unit.
  2165.     'Data is used to adjust heading & speed for that unit.
  2166.     cmb(vpoint).bstat = 0: cmb(vpoint).bogey = 0 '              taking back control from AI
  2167.     DialogBox "ENTER NEW VECTOR", 400, 250, 50, &HFF2C9B2C, clr&(15)
  2168.     LOCATE 8, 56 '+3, +16
  2169.     PRINT "c= counterthrust"
  2170.     LOCATE 9, 56
  2171.     INPUT "New Azimuth:"; x$
  2172.     IF x$ = "c" OR x$ = "C" THEN
  2173.         VectorBrake
  2174.     ELSE
  2175.         Thrust(vpoint).Azi = VAL(x$)
  2176.         LOCATE 10, 56
  2177.         INPUT "New Inclination:"; Thrust(vpoint).Inc
  2178.         LOCATE 11, 56
  2179.         INPUT "New Acceleration:"; Thrust(vpoint).Gs
  2180.         IF Thrust(vpoint).Gs > cmb(vpoint).MaxG THEN
  2181.             LOCATE 12, 56
  2182.             PRINT "Confirm overdrive"
  2183.             DISPLAY
  2184.             SLEEP 1
  2185.         END IF
  2186.     END IF
  2187.  
  2188. END SUB 'NewVector
  2189.  
  2190.  
  2191. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2192. SUB NewVector2
  2193.  
  2194.     PanelBlank 0, 578, 64, 32, &HFF0F0F0F '                     dim vector button
  2195.     Con_Blok 0, 578, 64, 32, "Vector", 1, &H502C9B2C
  2196.  
  2197.     togs = RESETBIT(togs, 1) '                                  reset back to overhead view
  2198.     zangle = 0
  2199.     Refresh
  2200.  
  2201.     'Conduct graphic based vector input
  2202.  
  2203.     SST& = NEWIMAGE(620, 620, 32) '                             Vector input overlay
  2204.     DEST SST&
  2205.     VIEW (0, 0)-(619, 619), clr&(0), clr&(3) '                  set graphics port full image SS& w/box
  2206.     WINDOW (-1000, 1000)-(1000, -1000) '                        set relative cartesian coords
  2207.  
  2208.     DIM mosX: DIM mosY
  2209.     cmb(vpoint).bstat = 0: cmb(vpoint).bogey = 0 '              taking back control from AI
  2210.  
  2211.     DO
  2212.         LIMIT 60
  2213.         CLS
  2214.         Mouse_Loop 0, 0
  2215.         CLEARCOLOR RGBA(0, 0, 0, 0)
  2216.         IF NOT READBIT(togs, 2) THEN '                          draw azimuth if not already enabled
  2217.             AzimuthWheel -1
  2218.         END IF
  2219.         FOR x = 200 TO 800 STEP 200
  2220.             CIRCLE (0, 0), x, clr&(4) '                         Draw thrust percentage circle
  2221.             COLOR clr&(4)
  2222.             PRINTMODE KEEPBACKGROUND
  2223.             PRINTSTRING (310 + (x / 200) * 62, 294), STR$((x / 800) * cmb(vpoint).MaxG) + "Gs", SST&
  2224.         NEXT x
  2225.  
  2226.         mosX = (MOUSEX - 560) * (2000 / 620) - 1000 '           Set relative coordinates
  2227.         mosY = ((MOUSEY - 18) * (2000 / 620) - 1000) * -1
  2228.         az = Azimuth!(mosX, mosY)
  2229.         ds = HYPOT(mosX, mosY)
  2230.         IF ABS(mosX) < 1000 AND ABS(mosY) < 1000 THEN '         If mouse is in window then draw vector rays
  2231.             LINE (0, 0)-(1000 * SIN(_D2R(az)), 1000 * COS(_D2R(az))), clr&(4)
  2232.             LINE (0, 0)-(mosX, mosY), clr&(14)
  2233.             PRINTSTRING (3, 3), "Azi. " + STR$(az), SST& '      Echo info in top left corner
  2234.             PRINTSTRING (3, 21), "Acceleration " + STR$(INT((ds * cmb(vpoint).MaxG / 800) * 100) / 100) + " Gs", SST&
  2235.         END IF
  2236.         IF MOUSEBUTTON(1) THEN
  2237.             Thrust(vpoint).Azi = az '                           Set azimuth heading
  2238.             Thrust(vpoint).Gs = ds * cmb(vpoint).MaxG / 800 '   Apply percentage of 800 radius circle as thrust
  2239.             DO UNTIL NOT MOUSEBUTTON(1) '                       Clear the mouse button buffer
  2240.                 WHILE MOUSEINPUT: WEND
  2241.             LOOP
  2242.             DO
  2243.                 LIMIT 60
  2244.                 CLS
  2245.                 WHILE MOUSEINPUT: WEND
  2246.                 CLEARCOLOR RGBA(0, 0, 0, 0)
  2247.                 IF NOT READBIT(togs, 5) THEN
  2248.                     IncMeter -1, -1
  2249.                 END IF
  2250.                 mos.pX = (MOUSEX - 560) * (2000 / 620) - 1000 '        Set relative coordinates
  2251.                 mos.pZ = ((MOUSEY - 18) * (2000 / 620) - 1000) * -1
  2252.                 az = Azimuth!(mos.pX, mos.pZ)
  2253.                 COLOR RGBA32(127, 127, 127, 255)
  2254.                 IF mos.pX >= 0 THEN
  2255.                     LINE (0, 0)-(1000 * SIN(_D2R(az)), 1000 * COS(_D2R(az))), clr&(4)
  2256.                     PRINTSTRING (3, 21), "Inclination= " + STR$((az - 90) * -1) + " deg.", SST&
  2257.                 ELSE
  2258.                     LINE (0, 0)-(1000, 0), clr&(4)
  2259.                     PRINTSTRING (3, 21), "Inclination= 0 ", SST&
  2260.                 END IF
  2261.                 PRINTSTRING (3, 37), "click left half for 0", SST&
  2262.                 IF MOUSEBUTTON(1) THEN
  2263.                     IF mos.pX < 0 THEN
  2264.                         Thrust(vpoint).Inc = 0
  2265.                     ELSE
  2266.                         Thrust(vpoint).Inc = (az - 90) * -1 '   Set inclination
  2267.                     END IF
  2268.                     EXIT DO
  2269.                 END IF
  2270.                 PUTIMAGE (560, 18), SS&, A& '                   Erase previous rays
  2271.                 PUTIMAGE (560, 18), SST&, A& '                  draw new ray
  2272.                 DISPLAY
  2273.             LOOP
  2274.             EXIT DO
  2275.         END IF
  2276.         PUTIMAGE (560, 18), SS&, A& '                           Erase previous rays
  2277.         PUTIMAGE (560, 18), SST&, A& '                          draw new ray
  2278.         DISPLAY
  2279.     LOOP
  2280.  
  2281.     PUTIMAGE (560, 18), SS&, A& '                               return to normal
  2282.     DISPLAY
  2283.     FREEIMAGE SST&
  2284.     DO UNTIL NOT MOUSEBUTTON(1) '                               Clear the mouse button buffer
  2285.         WHILE MOUSEINPUT: WEND '                                to prevent changing active unit
  2286.     LOOP '                                                      by accidental click through
  2287.  
  2288. END SUB 'NewVector2
  2289.  
  2290.  
  2291. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2292. SUB OriScreen (var AS BYTE)
  2293.  
  2294.     'Display orientation graphic
  2295.  
  2296.     'place and move stars according to heading and speed
  2297.     STATIC starx(12) AS SINGLE
  2298.     STATIC stary(12) AS SINGLE
  2299.     STATIC ovar AS BYTE
  2300.     IF ovar > units THEN ovar = units
  2301.     IF ovar <> var THEN '                                       if new active unit
  2302.         FOR x = 1 TO 12 '                                       Random star placement
  2303.             starx(x) = (INT(RND(1) * 254)) - 127
  2304.             stary(x) = (INT(RND(1) * 254)) - 127
  2305.         NEXT x
  2306.         ovar = var '                                            retain active unit # to keep stars
  2307.     END IF
  2308.  
  2309.     DEST ORI&
  2310.     WINDOW (-127, 127)-(127, -127)
  2311.     CLS
  2312.     IF cmb(var).Hd >= 180 THEN starhd = INT(cmb(var).Hd - 180)
  2313.     IF cmb(var).Hd < 180 THEN starhd = INT(cmb(var).Hd + 180)
  2314.     IF cmb(var).Sp = 0 THEN
  2315.         sp = 0
  2316.     ELSE
  2317.         sp = cmb(var).Sp / 10000
  2318.         IF sp < 1 THEN sp = 1
  2319.         IF sp > 8 THEN sp = 8
  2320.     END IF
  2321.     xm = sp * SIN(D2R(starhd)) '                                Removed INT as it is in PSET below
  2322.     ym = sp * COS(D2R(starhd))
  2323.     FOR x = 1 TO 12 '                                           iterate through stars
  2324.         IF starx(x) > 127 THEN starx(x) = -127 '                recycle those that leave screen to the opposite side
  2325.         IF starx(x) < -127 THEN starx(x) = 127
  2326.         IF stary(x) > 127 THEN stary(x) = -127
  2327.         IF stary(x) < -127 THEN stary(x) = 127
  2328.         PSET (INT(starx(x)), INT(stary(x)))
  2329.         starx(x) = starx(x) + xm
  2330.         stary(x) = stary(x) + ym
  2331.     NEXT x
  2332.     LINE (-127, 127)-(127, -127), clr&(4), B
  2333.     PRINTMODE KEEPBACKGROUND
  2334.     PRINTSTRING (127 - LEN((_TRIM$(cmb(var).Nam))) * 4, 2), cmb(var).Nam, ORI&
  2335.     IF Thrust(var).Gs = 0 THEN
  2336.         RotoZoom2 127, 127, ShpO, 1, 1, Thrust(var).Azi
  2337.     ELSE
  2338.         RotoZoom2 127, 127, ShpT, 1, 1, Thrust(var).Azi
  2339.     END IF
  2340.     PUTIMAGE (295, 325)-(543, 573), ORI&, A&
  2341.  
  2342. END SUB 'OriScreen
  2343.  
  2344.  
  2345. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2346. SUB PanelBlank (xpos AS INTEGER, ypos AS INTEGER, xsiz AS INTEGER, ysiz AS INTEGER, col AS LONG)
  2347.  
  2348.     'Background blank to mark and mask button use and/or changes
  2349.     CN& = NEWIMAGE(xsiz, ysiz, 32) '                            active button overlay
  2350.     DEST CN&
  2351.     COLOR , col '                                               set overlay background color
  2352.     CLS
  2353.     PUTIMAGE (xpos, ypos), CN&, A& '                            cover button
  2354.     FREEIMAGE CN&
  2355.  
  2356. END SUB 'PanelBlank
  2357.  
  2358.  
  2359. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2360. SUB Place_Ship (xpos AS INTEGER, ypos AS INTEGER)
  2361.  
  2362.     'Moves active ship, on right click, to new x,y coordinate on the screen.
  2363.     'Use <E>dit to set new z coordinate.
  2364.  
  2365.     SELECT CASE xpos
  2366.         CASE 560 TO 1199 '                                      Right graphics screen
  2367.             SELECT CASE ypos
  2368.                 CASE 19 TO 639
  2369.                     ' find relative sensor screen coordinates of mouse click
  2370.                     WindowMouseX = (xpos - 560) * (2000 / 620) - 1000 '      xpos was mouse_x
  2371.                     WindowMouseY = ((ypos - 18) * (2000 / 620) - 1000) * -1 'ypos was mouse_y
  2372.                     'WindowMouseX & Y both divided by results of Prop! give .Abs offsets from active position
  2373.                     q! = Prop!
  2374.                     'cmb(vpoint).ap.pX = (WindowMouseX / q!) + cmb(vpoint).ap.pX 'This is the old way that works well
  2375.                     'cmb(vpoint).ap.pY = (WindowMouseY / q!) + cmb(vpoint).ap.pY 'but only in zangle=0
  2376.  
  2377.                     'TRANSFORMATION MATRIX CALCULATION- extending ship placement into 3D based upon display plane
  2378.                     'account for zangle by defining new screen plane, don't have a clue how to go about it...yet
  2379.                     'transformation should probably occur at the windowmouse/q! element and then add to cmb(vpoint).ap
  2380.                     cmb(vpoint).ap.pX = (WindowMouseX / q!) + cmb(vpoint).ap.pX ' x-axis stays the same at all times
  2381.                     WMY_Ycomp = WindowMouseY * COS(_D2R(-zangle))
  2382.                     WMY_Zcomp = WindowMouseY * -SIN(_D2R(-zangle))
  2383.                     cmb(vpoint).ap.pY = WMY_Ycomp / q! + cmb(vpoint).ap.pY
  2384.                     cmb(vpoint).ap.pZ = WMY_Zcomp / q! + cmb(vpoint).ap.pZ
  2385.  
  2386.                     q2! = Prop!
  2387.                     ZoomFac = ZoomFac * (q! / q2!) '            reset zoom factor to new limits
  2388.             END SELECT
  2389.     END SELECT
  2390.  
  2391. END SUB 'Place_Ship
  2392.  
  2393.  
  2394. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2395. SUB PlanetDist
  2396.  
  2397.     T& = NEWIMAGE(248, 315, 32)
  2398.     DEST T&
  2399.     CLS
  2400.     LINE (0, 0)-(247, 314), clr&(4), B
  2401.     PRINTSTRING (156, 2), "AU", T&
  2402.     PRINTSTRING (202, 2), "Brng", T&
  2403.     x = 0: yp = 2
  2404.     DO
  2405.         x = x + 1
  2406.         IF hvns(x).star <> 2 THEN '                             don't show planetoid belts or rings
  2407.             IF hvns(x).rank < 3 THEN '                          show only main planets
  2408.                 IF yp MOD 2 = 0 THEN
  2409.                     bb& = &H1F7F7F7F
  2410.                 ELSE
  2411.                     bb& = &HFF000000
  2412.                 END IF
  2413.                 COLOR , bb&
  2414.                 ds = INT((Pyth(cmb(vpoint).ap, hvns(x).ps) / KMtoAU) * 100) / 100
  2415.                 br = INT(Azimuth!(rcp(x).pX, rcp(x).pY) * 10) / 10
  2416.                 LOCATE yp, 2
  2417.                 PRINT TRIM$(hvns(x).nam); SPC(16 - LEN(TRIM$(hvns(x).nam)));
  2418.                 LOCATE , 18
  2419.                 PRINT USING "###.##"; ds; SPC(2);
  2420.                 LOCATE , 26
  2421.                 PRINT USING "###.#"; br
  2422.                 yp = yp + 1
  2423.             END IF
  2424.         END IF
  2425.     LOOP UNTIL x = orbs
  2426.     PUTIMAGE (295, 5)-(543, 320), T&, A&
  2427.     DEST A&
  2428.     FREEIMAGE T&
  2429.  
  2430. END SUB 'PlanetDist
  2431.  
  2432.  
  2433. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2434. SUB PlanetMove (var AS BYTE)
  2435.  
  2436.     'Using orbital period figures, move the planets and their satellites
  2437.     'along their orbit tracks. Convert orbital periods into 1000 sec turns
  2438.     'divide 360 by the number of turns to get an azimuth change value.
  2439.     'Azimuth change can be applied to update x,y,z of moving planet.
  2440.     'At this point the exact same azimuth update should be applied to the
  2441.     'satellites relative to the primary, the same as their parent. Only
  2442.     'then can the azimuth changes of the satellites be applied relative to
  2443.     'their parent planets. Also called for initial date setup.
  2444.     'var=turncount (1 for normal turn, -1 for undo)
  2445.     'outermost iteration should be for .rank
  2446.     DIM t AS unitpoint
  2447.     DIM c AS unitpoint
  2448.     FOR x = 2 TO 4 '                                            rank iteration, rank 1 primary doesn't move
  2449.         FOR v = 1 TO orbs '                                     iterate all bodies
  2450.             IF hvns(v).star <> 2 THEN '                         don't move belt/ring systems except relative to parent
  2451.                 IF hvns(v).rank = x THEN
  2452.                     'compute new x,y,z for body v of x rank relative to primary/parent
  2453.                     c = hvns(FindParent(v)).ps: t = hvns(v).ps
  2454.                     d&& = Pyth(t, c)
  2455.                     przaz## = Azimuth!(t.pX - c.pX, t.pY - c.pY) 'get present azimuth
  2456.  
  2457.                     IF Turncount = 0 THEN '                     Initial date setup
  2458.                         IF oryr > 0 THEN '                      If year/day not zero compute rotation from baseline
  2459.                             rot = oryr / hvns(v).oprd '         Divide years from baseline by orbital period of body
  2460.                             IF rot <> INT(rot) THEN rot = rot - INT(rot) 'discard all full periods and get remainder
  2461.                             prdtrnaz## = (rot * 360) '          multiply remainder by 360 for azimuth change
  2462.                         END IF
  2463.                     ELSE '                                      Not initial setup so compute turn change
  2464.                         prdtrnaz## = 360 / (hvns(v).oprd * 31557.6 * var) 'azimuth change / turn  negative .oprd yields retrograde motion
  2465.                     END IF
  2466.                     '  \/ \/ \/     add azimuth change to present azimuth or subtract with if newaz!<0 then newaz=newaz+360 for opposite rotation
  2467.                     newaz## = przaz## + prdtrnaz##
  2468.                     oldx&& = hvns(v).ps.pX '                    preserve old x,y,z temporarily for
  2469.                     oldy&& = hvns(v).ps.pY '                    baseline satellite movement calculation
  2470.                     oldz&& = hvns(v).ps.pZ
  2471.                     hvns(v).ps.pX = (hvns(v).orad * SIN(D2R(newaz##))) + c.pX
  2472.                     hvns(v).ps.pY = (hvns(v).orad * COS(D2R(newaz##))) + c.pY
  2473.                     'put new planet Z position here if the option for tilted orbits is later added
  2474.  
  2475.                     'reiterate to pick out the children to drag along
  2476.                     FOR s = 1 TO orbs
  2477.                         IF hvns(s).parnt = hvns(v).nam THEN
  2478.                             'apply same motion as parent relative to parent's primary
  2479.                             hvns(s).ps.pX = hvns(s).ps.pX + (hvns(v).ps.pX - oldx&&)
  2480.                             hvns(s).ps.pY = hvns(s).ps.pY + (hvns(v).ps.pY - oldy&&)
  2481.                             hvns(s).ps.pZ = hvns(s).ps.pZ + (hvns(v).ps.pZ - oldz&&)
  2482.                         END IF
  2483.                     NEXT s
  2484.  
  2485.                 END IF
  2486.             END IF 'end belt/ring test
  2487.         NEXT v
  2488.     NEXT x
  2489.  
  2490.  
  2491. END SUB 'PlanetMove
  2492.  
  2493.  
  2494. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2495. SUB Prnt (text AS STRING, wsize AS SINGLE, hsize AS SINGLE, StartX AS INTEGER64, StartY AS INTEGER64, Xspace AS INTEGER, Yspace AS INTEGER, col AS UNSIGNED LONG)
  2496.  
  2497.     '------------------------------------------------------------------------------------
  2498.     ' SUB: Prnt (adaptation of Petr's excellent approach to text resizing)
  2499.     '
  2500.     ' Purpose:
  2501.     ' Display text as resizable and recolorable images that have been previously
  2502.     ' defined in the main module.
  2503.     '
  2504.     ' Passed parameters:
  2505.     ' text sends string value to be printed
  2506.     ' wsize sends width size of text to be displayed: 1=original
  2507.     ' hsize sends height size of text to be displayed: 1=original
  2508.     ' StartX sends upper left x position for PUTIMAGE
  2509.     ' StartY sends upper left y position for PUTIMAGE
  2510.     ' Xspace sends horizontal spacing
  2511.     ' Yspace sends vertical spacing
  2512.     ' col sends color of character
  2513.     '
  2514.     '------------------------------------------------------------------------------------
  2515.  
  2516.     x = StartX
  2517.     y = StartY
  2518.     FOR f = 1 TO LEN(text)
  2519.         ch = ASC(text, f)
  2520.         x = x + Xspace
  2521.         y = y + Yspace
  2522.         ColoredChar = swapcolor(chr_img(ch), &HFFF5F5F5, col) ' colorize character:
  2523.         _PUTIMAGE (x, y)-(x + (wsize * 8), y - (hsize * 16)), ColoredChar, 0
  2524.         _FREEIMAGE ColoredChar
  2525.     NEXT
  2526.  
  2527. END SUB 'Prnt
  2528.  
  2529.  
  2530. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2531. FUNCTION Prop!
  2532.  
  2533.     'keep it in proportion...
  2534.     'find the relative offsets of all units to the active unit and
  2535.     'resize to keep all in the picture, subject to zoom factor override.
  2536.  
  2537.     DIM deltamax AS INTEGER64 ' carries the widest axial separation of units in km
  2538.  
  2539.     IF units > 1 THEN '                                         multiple units present
  2540.         deltamax = 1000
  2541.         x = 0
  2542.         DO
  2543.             x = x + 1
  2544.             IF cmb(x).status > 0 AND x <> vpoint THEN '         skip if active, destroyed or immobile
  2545.                 IF ABS(dcs(x).pX) > deltamax THEN deltamax = ABS(dcs(x).pX) 'X limits
  2546.                 IF ABS(dcs(x).pY) > deltamax THEN deltamax = ABS(dcs(x).pY) 'Y limits
  2547.             END IF
  2548.         LOOP UNTIL x = units
  2549.     ELSE '                                                      only single unit present
  2550.         deltamax = 1000000: ZoomFac = 1
  2551.     END IF
  2552.  
  2553.     Prop! = 800 * (ZoomFac / deltamax) '                        all units on screen subject to zoom factor
  2554.  
  2555. END FUNCTION 'Prop!
  2556.  
  2557.  
  2558. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2559. SUB Purge
  2560.  
  2561.     'Remove wrecked vessels from list if not desired
  2562.  
  2563.     ct = 0
  2564.     I$ = cmb(vpoint).Nam '                                      preserve an active unit identifier
  2565.     FOR x = 1 TO units
  2566.         IF cmb(x).status = 0 THEN
  2567.             ct = ct + 1 '                                       count the number if units to remove
  2568.         END IF
  2569.     NEXT x
  2570.     IF ct = 0 THEN '                                            No destroyed units?
  2571.         EXIT SUB '                                              leave without unnecessary processing
  2572.     ELSE
  2573.         n% = units - ct '                                       dim sufficient temp variables
  2574.         DIM tmpshp(n%) AS ship
  2575.         DIM tmpthrs(n%) AS Maneuver
  2576.         DIM tmpsens(n%, n%) AS BYTE
  2577.         y = 0
  2578.         FOR x = 1 TO units '                                    keep all existing units in temps
  2579.             IF cmb(x).status <> 0 THEN
  2580.                 y = y + 1
  2581.                 tmpshp(y) = cmb(x)
  2582.                 tmpthrs(y) = Thrust(x)
  2583.                 FOR q = 1 TO units
  2584.                     tmpsens(x, q) = Sensor(x, q)
  2585.                 NEXT q
  2586.             END IF
  2587.         NEXT x
  2588.         units = n% '                                            redimension primary variables
  2589.         REDIM cmb(units) AS ship
  2590.         REDIM Thrust(units) AS Maneuver
  2591.         REDIM Sensor(units, units) AS _BYTE
  2592.         FOR x = 1 TO units '                                    Move temps back into primary variables
  2593.             cmb(x) = tmpshp(x)
  2594.             Thrust(x) = tmpthrs(x)
  2595.             FOR y = 1 TO units
  2596.                 Sensor(x, y) = tmpsens(x, y)
  2597.             NEXT y
  2598.             cmb(x).id = x
  2599.             IF cmb(x).Nam = I$ THEN vpoint = x '                set active to new position
  2600.         NEXT x
  2601.         a = units + 1: b = n% + ct
  2602.         FOR x = a TO b '                                        free abandoned ship display memory
  2603.             _FREEIMAGE ship_box(x)
  2604.         NEXT x
  2605.     END IF
  2606.  
  2607. END SUB 'Purge
  2608.  
  2609.  
  2610. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2611. FUNCTION Pyth (var1 AS unitpoint, var2 AS unitpoint)
  2612.  
  2613.     'Use to find distance between two 3D points
  2614.     'Also calculate speed/magnitude of updated vectors
  2615.  
  2616.     Pyth = HYPOT(HYPOT(ABS(var1.pX - var2.pX), ABS(var1.pY - var2.pY)), ABS(var1.pZ - var2.pZ))
  2617.  
  2618.  
  2619.  
  2620. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2621. FUNCTION PythXY (var1 AS unitpoint, var2 AS unitpoint)
  2622.  
  2623.     'Use to find distance between two 2D points
  2624.     'Also calculate speed/magnitude of updated vectors
  2625.  
  2626.     PythXY = HYPOT(ABS(var1.pX - var2.pX), ABS(var1.pY - var2.pY))
  2627.  
  2628. END FUNCTION 'PythXY
  2629.  
  2630.  
  2631. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2632. FUNCTION RayTrac## (var1 AS unitpoint, var2 AS unitpoint, var3 AS unitpoint, var4 AS INTEGER64)
  2633.  
  2634.     'Same algorithm as in ColCheck with following substitutions
  2635.     'strt=var1 : first ship
  2636.     'nd=  var2 : second ship
  2637.     'sphr=var3 : planet position
  2638.     '     var4 : planet radius
  2639.     'checking only for intersection of body in line of sight, not impact position
  2640.  
  2641.     dx## = var2.pX - var1.pX: dy## = var2.pY - var1.pY: dz## = var2.pZ - var1.pZ
  2642.     A## = (dx## * dx##) + (dy## * dy##) + (dz## * dz##)
  2643.     B## = 2 * dx## * (var1.pX - var3.pX) + 2 * dy## * (var1.pY - var3.pY) + 2 * dz## * (var1.pZ - var3.pZ)
  2644.     C## = (var3.pX * var3.pX) + (var3.pY * var3.pY) + (var3.pZ * var3.pZ) + (var1.pX * var1.pX) + (var1.pY * var1.pY) +_
  2645.                 (var1.pZ * var1.pZ) + -2 * (var3.pX * var1.pX + var3.pY * var1.pY + var3.pZ * var1.pZ) - (var4 * var4)
  2646.     disabc## = (B## * B##) - 4 * A## * C## ' if disabc## < 0 then no intersection =0 tangent >0 intersects two points
  2647.     RayTrac## = disabc##
  2648.  
  2649. END FUNCTION 'RayTrac##
  2650.  
  2651.  
  2652. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2653. SUB Refresh
  2654.  
  2655.     VCS '                                                   Set viewpoint coordinate system
  2656.     SensorMask '                                            determine sensor occlusions
  2657.     ScreenLimits '                                          Open sensor display viewport
  2658.     SensorScreen '                                          Display sensor data
  2659.     DispShipData '                                          Print unit positions, speeds and headings
  2660.     ButtonBlock '                                           control panel
  2661.     PlanetDist '                                            show main planet bearings and distances
  2662.     DISPLAY
  2663.  
  2664. END SUB 'Refresh
  2665.  
  2666.  
  2667. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2668. SUB RotoZoom2 (X AS LONG, Y AS LONG, Image AS LONG, xScale AS SINGLE, yScale AS SINGLE, Rotation AS SINGLE)
  2669.  
  2670.     '------------------------------------------------------------------------------------CLEARED
  2671.     ' SUB: RotoZoom2 (author Bplus of QB64 forum, not my own creation, but damn useful)
  2672.     '
  2673.     ' Purpose:
  2674.     ' Locate and display image, scaling and/or rotating the displayed image around
  2675.     ' its central point.
  2676.     '
  2677.     ' Passed parameters:
  2678.     ' X, Y sends the center point of where the image is to be displayed
  2679.     ' Image sends the source image handle
  2680.     ' xScale and yScale send width and height stretching parameters 1=original size
  2681.     ' Rotation sends rotation of image in degrees 0=east, 270=north
  2682.     '
  2683.     '------------------------------------------------------------------------------------
  2684.  
  2685.     DIM px(3) AS SINGLE: DIM py(3) AS SINGLE
  2686.     W& = WIDTH(Image&): H& = HEIGHT(Image&)
  2687.     px(0) = -W& / 2: py(0) = -H& / 2: px(1) = -W& / 2: py(1) = H& / 2
  2688.     px(2) = W& / 2: py(2) = H& / 2: px(3) = W& / 2: py(3) = -H& / 2
  2689.     sinr! = SIN(-Rotation / 57.2957795131): cosr! = COS(-Rotation / 57.2957795131)
  2690.     FOR i& = 0 TO 3
  2691.         x2& = (px(i&) * cosr! + sinr! * py(i&)) * xScale + X: y2& = (py(i&) * cosr! - px(i&) * sinr!) * yScale + Y
  2692.         px(i&) = x2&: py(i&) = y2&
  2693.     NEXT
  2694.     MAPTRIANGLE (0, 0)-(0, H& - 1)-(W& - 1, H& - 1), Image& TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
  2695.     MAPTRIANGLE (0, 0)-(W& - 1, 0)-(W& - 1, H& - 1), Image& TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
  2696.  
  2697. END SUB 'RotoZoom2
  2698.  
  2699.  
  2700. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2701. SUB Save_Scenario (var AS BYTE)
  2702.  
  2703.     'Save present system state and vessel group
  2704.     IF var THEN
  2705.         t% = 400: r% = 2
  2706.         DialogBox "SAVING PRESENT SCENARIO", t%, 250, 50, &HFF8C5B4C, clr&(15)
  2707.         DISPLAY
  2708.         LOCATE r% + 5, ((_WIDTH(A&) / 2) - (t% / 2)) / 8 + 4
  2709.         INPUT "Enter a scenario name: ", fl$
  2710.         LOCATE r% + 7, ((_WIDTH(A&) / 2) - 40) / 8
  2711.         PRINT "Saving..."
  2712.     ELSE
  2713.         fl$ = "autosave/auto"
  2714.     END IF
  2715.     vl$ = "scenarios/" + TRIM$(fl$) + ".tvg"
  2716.     pl$ = "scenarios/" + TRIM$(fl$) + ".tss"
  2717.     sl$ = "scenarios/" + TRIM$(fl$) + ".tgn"
  2718.     tl$ = "scenarios/" + TRIM$(fl$) + ".tvt"
  2719.     tt$ = "scenarios/" + TRIM$(fl$) + ".ttl"
  2720.     IF FILEEXISTS(pl$) THEN KILL pl$
  2721.     OPEN pl$ FOR RANDOM AS #1 LEN = LEN(hvns(0))
  2722.     FOR x = 1 TO orbs
  2723.         PUT #1, x, hvns(x)
  2724.     NEXT x
  2725.     CLOSE #1
  2726.     IF FILEEXISTS(vl$) THEN KILL vl$
  2727.     OPEN vl$ FOR RANDOM AS #2 LEN = LEN(cmb(0))
  2728.     FOR x = 1 TO units
  2729.         PUT #2, x, cmb(x)
  2730.     NEXT x
  2731.     CLOSE #2
  2732.     IF FILEEXISTS(tl$) THEN KILL tl$
  2733.     OPEN tl$ FOR RANDOM AS #3 LEN = LEN(Thrust(0))
  2734.     FOR x = 1 TO units
  2735.         PUT #3, x, Thrust(x)
  2736.     NEXT x
  2737.     CLOSE #3
  2738.     IF FILEEXISTS(sl$) THEN KILL sl$
  2739.     OPEN sl$ FOR OUTPUT AS #4
  2740.     WRITE #4, Turncount, oryr, vpoint, shipoff
  2741.     CLOSE #4
  2742.     IF FILEEXISTS(tt$) THEN KILL tt$
  2743.     OPEN tt$ FOR RANDOM AS #5 LEN = LEN(Sensor(0, 0))
  2744.     FOR x = 1 TO units
  2745.         FOR y = 1 TO units
  2746.             PUT #5, ((x - 1) * units) + y, Sensor(x, y)
  2747.         NEXT y
  2748.     NEXT x
  2749.     CLOSE #5
  2750.  
  2751. END SUB 'Save_Scenario
  2752.  
  2753.  
  2754. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2755. SUB Save_Ships
  2756.  
  2757.     'Save the present ship scenario
  2758.     'call syntax: DialogBox <heading string>, box x, box y, y position, bounding box color, text color
  2759.     t% = 400
  2760.     DialogBox "SAVING PRESENT VESSEL(S) & POSITION(S)", t%, 250, 50, &HFF8C5B4C, clr&(15)
  2761.     DISPLAY
  2762.     LOCATE r% + 5, ((_WIDTH(A&) / 2) - (t% / 2)) / 8 + 4
  2763.     INPUT "Enter a vessel group name: ", fl$
  2764.     LOCATE r% + 7, ((_WIDTH(A&) / 2) - 40) / 8
  2765.     PRINT "Saving..."
  2766.     fl$ = "ships\" + fl$ + ".tvg"
  2767.     OPEN fl$ FOR RANDOM AS #2 LEN = LEN(cmb(0))
  2768.     FOR x = 1 TO units
  2769.         PUT #2, x, cmb(x)
  2770.     NEXT x
  2771.     CLOSE #2
  2772.     'add thrust file
  2773.  
  2774. END SUB 'Save_Ships
  2775.  
  2776.  
  2777. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2778. SUB Save_System
  2779.  
  2780.     t% = 600
  2781.     DialogBox "SAVING SYSTEM", t%, 250, 50, &HFF8C5B4C, clr&(15)
  2782.  
  2783.     in1$ = "Enter system name or press ENTER to default to " + TRIM$(hvns(1).nam)
  2784.     l = WIDTH(A&) / 2 - (LEN(in1$) * 8) / 2
  2785.     PRINTSTRING (l, 217), in1$, A&
  2786.     col% = ((WIDTH(A&) / 2) - (t% / 2)) / 8 + 4
  2787.     DISPLAY
  2788.     LOCATE 10, col%
  2789.     INPUT "System name:"; n$
  2790.     IF n$ <> "" THEN
  2791.         n$ = TRIM$(n$)
  2792.     ELSE
  2793.         n$ = TRIM$(hvns(1).nam)
  2794.     END IF
  2795.  
  2796.     sys$ = "systems/" + n$ + ".tss"
  2797.     OPEN sys$ FOR RANDOM AS #1 LEN = LEN(hvns(1))
  2798.     FOR x = 1 TO orbs
  2799.         PUT #1, x, hvns(x)
  2800.     NEXT x
  2801.     CLOSE #1
  2802.  
  2803. END SUB 'Save_System
  2804.  
  2805.  
  2806. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2807. SUB ScreenLimits
  2808.  
  2809.     '0=black,1=blue,2=green,3=aqua,4=red,5=purple,6=brown,7=white
  2810.     '8=gray, +8=bright color, except 14=yellow,
  2811.  
  2812.     DEST A&
  2813.     SCREEN A&
  2814.     COLOR , RGBA32(15, 15, 15, 10)
  2815.     CLS
  2816.     c = 3 'color variable (local)
  2817.  
  2818.     PRINTSTRING (560, 0), "Turn #" + STR$(Turncount), A& '     Turn and time elapsed
  2819.     IF etd THEN tm$ = TRIM$(STR$(etd)) + "d "
  2820.     IF eth OR Turncount > 3 THEN tm$ = tm$ + TRIM$(STR$(eth)) + "h "
  2821.     IF Turncount > 0 THEN tm$ = tm$ + TRIM$(STR$(etm)) + "m " + TRIM$(STR$(ets)) + "s"
  2822.     PRINTSTRING (672, 0), tm$, A&
  2823.  
  2824.     IF READBIT(togs, 1) THEN
  2825.         SELECT CASE zangle '                                    set galactic orientation strings to rotation angle
  2826.             CASE IS < -45
  2827.                 bt$ = "NADIR facing rimward"
  2828.                 bb$ = "ZENITH facing rimward"
  2829.             CASE -45 TO 45
  2830.                 bt$ = "COREWARD"
  2831.                 bb$ = "RIMWARD"
  2832.             CASE IS > 45
  2833.                 bt$ = "ZENITH facing coreward"
  2834.                 bb$ = "NADIR facing coreward"
  2835.         END SELECT
  2836.     ELSE
  2837.         bt$ = "COREWARD"
  2838.         bb$ = "RIMWARD"
  2839.     END IF
  2840.  
  2841.     PRINTSTRING (839, 0), bt$, A& '                             Galactic orientation screen top
  2842.     PRINTSTRING (839, 639), bb$, A& '                           Galactic orientation screen bottom
  2843.  
  2844.     FOR x = 1 TO 8 '                                            Galactic orientation screen right
  2845.         PRINTSTRING (1187, 249 + (x * 16)), MID$("TRAILING", x, 1), A&
  2846.     NEXT x
  2847.     FOR x = 1 TO 8 '                                            Galactic orientation screen left
  2848.         PRINTSTRING (547, 249 + (x * 16)), MID$("SPINWARD", x, 1), A&
  2849.     NEXT x
  2850.     OriScreen vpoint
  2851.     ZPanner
  2852.  
  2853. END SUB 'ScreenLimits
  2854.  
  2855.  
  2856. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2857. SUB SensorMask
  2858.  
  2859.     'Determine which units may be sensor occluded by planetary bodies.
  2860.     'this must be refreshed each turn, but we should do something to
  2861.     'avoid it each display loop. Sensor(x,y) will handle display loop.
  2862.     'Sensor occlusion will break target locks.
  2863.  
  2864.     'Determine which units are visible to others
  2865.     FOR x = 1 TO units '                                        Active unit iteration  x=active
  2866.         FOR y = 1 TO units '                                    Passive unit iteration  y=passive
  2867.             Sensor(x, y) = RESETBIT(Sensor(x, y), 0)
  2868.             IF x <> y THEN '                                    if unit is self then skip and leave at zero
  2869.                 FOR z = 1 TO orbs '                             Planetary body iteration
  2870.                     IF hvns(z).star <> 2 THEN '                 Skip belt/ring systems
  2871.                         IF Pyth(rcs(x), rcp(z)) < Pyth(rcs(x), rcs(y)) THEN ' is planet closer to active than passive?
  2872.                             IF Pyth(rcs(y), rcp(z)) < Pyth(rcs(x), rcs(y)) THEN ' is planet closer to passive than active?
  2873.                                 'We've now determined that the planet is generally
  2874.                                 'within the separation radius of both units simultaneously
  2875.                                 'so that we won't waste processing resources in ray tracing
  2876.                                 'distant objects.
  2877.                                 IF RayTrac##(rcs(x), rcs(y), rcp(z), hvns(z).radi) < 0 THEN 'if ray trace indicates LOS then
  2878.                                     'do nothing as above reset has already made passives visible by default
  2879.                                 ELSE '                              LOS not available
  2880.                                     Sensor(x, y) = SETBIT(Sensor(x, y), 0) '             Passive is sensor occluded and not visible to Active
  2881.                                     IF READBIT(Sensor(x, y), 1) THEN Sensor(x, y) = RESETBIT(Sensor(x, y), 1) 'no target lock if occluded
  2882.                                 END IF
  2883.                             END IF '                            end is planet between?
  2884.                         END IF '                                end is planet close?
  2885.                     END IF '                                    end belt/ring test
  2886.                 NEXT z '                                        end planetary body iteration
  2887.             END IF '                                            end self unit skip
  2888.         NEXT y '                                                end passive unit iteration
  2889.     NEXT x '                                                    end active unit iteration
  2890.  
  2891. END SUB 'SensorMask
  2892.  
  2893.  
  2894. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  2895. SUB SensorScreen
  2896.  
  2897.     'Graphic navigation screen
  2898.     SCREEN SS& '                                                set output to sensor screen display
  2899.     DEST SS&
  2900.     CLS
  2901.  
  2902.     c = 4
  2903.     COLOR clr&(c)
  2904.     VIEW (1, 1)-(618, 618), clr&(0), clr&(c) '                  set graphics port full image SS& w/box
  2905.     WINDOW (-1000, 1000)-(1000, -1000) '                        set relative cartesian coords
  2906.     AzimuthWheel READBIT(togs, 2)
  2907.     IncMeter READBIT(togs, 5), 0
  2908.     LINE (0, 50)-(0, 25), clr&(c) '                             draw active unit reference point xhair
  2909.     LINE (0, -25)-(0, -50), clr&(c)
  2910.     LINE (-50, 0)-(-25, 0), clr&(c)
  2911.     LINE (25, 0)-(50, 0), clr&(c)
  2912.     COLOR clr&(15)
  2913.  
  2914.     SysMap '                                                    draw system details
  2915.     'SysMapII
  2916.  
  2917.     'Dynamic scale grid display
  2918.     DIM q!
  2919.     q! = Prop!
  2920.     IF READBIT(togs, 3) THEN '                                  If grid toggle is TRUE
  2921.         DIM dynagrid AS SINGLE
  2922.         dynagrid = .001 '                                       start at 1 meters grid size
  2923.         DO
  2924.             IF (q! * dynagrid) > 60 THEN '                      adjust the number to change the grid behaviour
  2925.                 EXIT DO
  2926.             END IF
  2927.             dynagrid = dynagrid * 10 '                          jump by power of 10 when necessary
  2928.         LOOP
  2929.  
  2930.         g = 0: c = 0
  2931.         DO UNTIL g > 1000 '                                     Draw grid
  2932.             IF c MOD 10 = 0 THEN
  2933.                 COLOR RGBA32(255, 255, 255, 40) '               semi-transparent white for grid by 10s
  2934.             ELSE
  2935.                 COLOR RGBA32(255, 255, 255, 15) '               semi-transparent white for grid
  2936.             END IF
  2937.             LINE (-1000, g)-(1000, g) '                         horizontal grid lines
  2938.             IF g > 0 THEN LINE (-1000, (-1 * g))-(1000, (-1 * g))
  2939.             LINE (g, -1000)-(g, 1000) '                         vertical grid lines
  2940.             IF g > 0 THEN LINE ((-1 * g), -1000)-((-1 * g), 1000)
  2941.             g = g + (q! * dynagrid)
  2942.             c = c + 1
  2943.         LOOP
  2944.         scalelegend$ = "grid=" + STR$(dynagrid) + " km"
  2945.         Prnt scalelegend$, 2.8, 2.8, -990, -950, 24, 0, &H48FFFFFF 'print legend in lower left corner
  2946.     END IF
  2947.  
  2948.     'UNIT PLACEMENTS, VECTORS, RANGES AND ID                   Draw each unit and index number on screen
  2949.     'Translate/Transform variables
  2950.     DIM UDisp AS unitpoint '                                    proportional dcs unit placement
  2951.     DIM IDisp AS unitpoint '                                    vector indicator
  2952.     DIM VDisp AS unitpoint '                                    vector indicator transformation
  2953.  
  2954.     shipcl& = clr&(2) '                                         set default ship name color to green (going)
  2955.     FOR x = 1 TO units '                                        Iterate through all ships
  2956.         UDisp = dcs(x): VecMult UDisp, q! '                     unit positions for display
  2957.         'This gives the vector tail displayed from zenith view
  2958.         IDisp.pX = rcs(x).pX + cmb(x).Sp * COS(D2R(cmb(x).In)) * SIN(D2R(cmb(x).Hd)) '
  2959.         IDisp.pY = rcs(x).pY + cmb(x).Sp * COS(D2R(cmb(x).In)) * COS(D2R(cmb(x).Hd)) '
  2960.         IDisp.pZ = rcs(x).pZ + cmb(x).Sp * SIN(D2R(cmb(x).In)) '
  2961.         'This skews the vector tail relative to the dcs plane, coordinate transformation of IDisp
  2962.         VDisp.pX = IDisp.pX * q!
  2963.         VDisp.pY = (IDisp.pY * COS(D2R(zangle)) + IDisp.pZ * SIN(_D2R(zangle))) * q!
  2964.         VDisp.pZ = (IDisp.pY * -SIN(D2R(zangle)) + IDisp.pZ * COS(D2R(zangle))) * q!
  2965.  
  2966.         'maybe this could go in CoordUpdate; resets target lock bit if beyond 3 light seconds
  2967.         IF Pyth(cmb(vpoint).ap, cmb(x).ap) > 900000 THEN Sensor(vpoint, x) = RESETBIT(Sensor(vpoint, x), 1)
  2968.  
  2969.         'put an out of frame if then here also
  2970.         IF ABS(UDisp.pX) > 1300 AND ABS(UDisp.pY) > 1300 THEN ' skip draw if out of frame
  2971.         ELSE
  2972.             IF READBIT(Sensor(vpoint, x), 0) THEN '             If ship x is invisible to active unit then skip display
  2973.             ELSE '                                              if not occluded then display it
  2974.                 c = 7
  2975.                 IF dcs(x).pZ > dcs(vpoint).pZ THEN c = 9 '      zenith color (blue shift)
  2976.                 IF dcs(x).pZ < dcs(vpoint).pZ THEN c = 12 '     nadir color (red shift)
  2977.  
  2978.                 IF cmb(x).status > 0 THEN '                     Draw point box and name
  2979.                     LINE (UDisp.pX - 5, UDisp.pY + 5)-(UDisp.pX + 5, UDisp.pY - 5), clr&(c), BF
  2980.                     IF x <> vpoint AND READBIT(Sensor(vpoint, x), 1) THEN 'Draw target "X box" lock indicator if targeted by active
  2981.                         LINE (UDisp.pX - 20, UDisp.pY + 20)-(UDisp.pX + 20, UDisp.pY - 20), &H3FFC5454, B
  2982.                         LINE (UDisp.pX - 20, UDisp.pY + 20)-(UDisp.pX + 20, UDisp.pY - 20), &H3FFC5454
  2983.                         LINE (UDisp.pX + 20, UDisp.pY + 20)-(UDisp.pX - 20, UDisp.pY - 20), &H3FFC5454
  2984.                     END IF
  2985.                     IF x = vpoint AND cmb(x).status <> 3 THEN ' bright green unless damaged
  2986.                         shipcl& = clr&(10)
  2987.                         Prnt cmb(x).Nam, 2.8, 2.8, UDisp.pX + 10, UDisp.pY - 10, 24, 0, shipcl&
  2988.                         shipcl& = clr&(2)
  2989.                     ELSE
  2990.                         IF cmb(x).status = 3 THEN '             red if damaged and drifting, active or otherwise
  2991.                             shipcl& = clr&(4)
  2992.                             Prnt cmb(x).Nam, 2.8, 2.8, UDisp.pX + 10, UDisp.pY - 10, 24, 0, shipcl&
  2993.                             shipcl& = clr&(2)
  2994.                         ELSE '                                  green undamaged non-active units
  2995.                             Prnt cmb(x).Nam, 2.8, 2.8, UDisp.pX + 10, UDisp.pY - 10, 24, 0, shipcl&
  2996.                             shipcl& = clr&(2)
  2997.                         END IF
  2998.                     END IF
  2999.                 END IF
  3000.  
  3001.                 ' VECTOR INDICATORS adjusted for Z-pan
  3002.                 IF x = vpoint THEN '                            draw active unit's vector indicator
  3003.                     LINE (0, 0)-(VDisp.pX, VDisp.pY), RGB32(222, 188, 17)
  3004.                 ELSE
  3005.                     LINE (UDisp.pX, UDisp.pY)-(VDisp.pX, VDisp.pY), RGB32(17, 188, 222)
  3006.                 END IF
  3007.             END IF '                                            end Sensor(vpoint,x) check
  3008.         END IF '                                                end out of frame skip
  3009.  
  3010.         ' RANGING BANDS & CIRCLES
  3011.         IF READBIT(togs, 4) THEN '                              if range toggle is true
  3012.             IF x = vpoint THEN '                                Draw ranging circles of active unit
  3013.                 FCirc 0, 0, 500000 * q!, RGBA(252, 252, 84, 5) 'Medium range band  clr&(14)w/alpha
  3014.                 FCirc 0, 0, 250000 * q!, RGBA(252, 84, 84, 20) 'Short range band
  3015.                 IF cmb(vpoint).mil THEN
  3016.                     dtct = 600000 '                             military detection range
  3017.                 ELSE
  3018.                     dtct = 150000 '                             civilian detection range
  3019.                 END IF
  3020.                 CIRCLE (0, 0), dtct * q!, clr&(8) '             minimum detection range .5 or 2 light seconds
  3021.                 CIRCLE (0, 0), 900000 * q!, clr&(4) '           maximum detection range 3 light seconds
  3022.             END IF
  3023.         END IF
  3024.     NEXT x
  3025.  
  3026.     'Grav watcher- upper right sensor screen
  3027.     PRINTMODE KEEPBACKGROUND
  3028.     COLOR RGBA(0, 255, 0, 50) 'clr&(2)
  3029.     PRINTSTRING (550, 5), STR$(_ROUND(Gwat.Gs * 100) / 100), SS&
  3030.     PRINTSTRING (550, 21), STR$(Gwat.Azi), SS&
  3031.     PRINTSTRING (550, 37), STR$(Gwat.Inc), SS&
  3032.  
  3033.     DEST A& '                                                   return output to main screen
  3034.     SCREEN A&
  3035.     PUTIMAGE (560, 18), SS&, A& '                               update sensor screen to mainscreen
  3036.  
  3037. END SUB 'SensorScreen
  3038.  
  3039.  
  3040. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3041. SUB SetUp
  3042.  
  3043.     'Debugging setup- to be replaced by file inputs eventually
  3044.  
  3045.     RESTORE ships
  3046.     READ a
  3047.     units = a
  3048.     REDIM cmb(a) AS ship '                                      set up ships (units)
  3049.     REDIM Thrust(units) AS Maneuver '                           unit accelerations/vector
  3050.     REDIM Sensor(units, units) AS BYTE '                        Sensor ops- planetary obscuration array, who can see who?
  3051.     FOR x = 1 TO units '                                        Ship data display handle array
  3052.         ship_box(x) = NEWIMAGE(290, 96, 32)
  3053.     NEXT x
  3054.  
  3055.     FOR x = 1 TO units '                                        initialize unit data
  3056.         READ cmb(x).id: READ cmb(x).Nam: READ cmb(x).MaxG
  3057.         READ cmb(x).ap.pX: READ cmb(x).ap.pY: READ cmb(x).ap.pZ
  3058.         READ cmb(x).Sp: READ cmb(x).Hd: READ cmb(x).In: READ cmb(x).mil
  3059.         cmb(x).op = cmb(x).ap
  3060.         cmb(x).status = 1
  3061.         Thrust(x).Azi = INT(RND(1) * 360) '                     random orientation
  3062.     NEXT x
  3063.  
  3064.     'Initial planet position determined by date
  3065.     PlanetMove 1
  3066.  
  3067.     RANDOMIZE TIMER '                                           temporary random placement seed
  3068.     'Put units randomly around a random body
  3069.     DO
  3070.         pl% = INT(RND * orbs) + 1
  3071.     LOOP UNTIL hvns(pl%).star <> 2 '                            don't place in belt/ring
  3072.     'or place around a specific body
  3073.     'pl% = 3 'Terra/Earth
  3074.     FOR y = 1 TO units
  3075.         AZ = RND * 360 '                                        random azimuth placement
  3076.         ds = RND * 500 + 40 '                                   random distance in radii of body
  3077.         dz = RND * 20 - 10
  3078.         cmb(y).ap.pX = (hvns(pl%).radi * ds) * SIN(D2R(AZ)) + hvns(pl%).ps.pX
  3079.         cmb(y).ap.pY = (hvns(pl%).radi * ds) * COS(D2R(AZ)) + hvns(pl%).ps.pY
  3080.         cmb(y).ap.pZ = hvns(pl%).radi * dz
  3081.         'cmb(y).ap.pZ = 0
  3082.     NEXT y
  3083.  
  3084. END SUB 'SetUp
  3085.  
  3086.  
  3087. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3088. FUNCTION Slope! (var1 AS unitpoint, var2 AS unitpoint)
  3089.  
  3090.     'returns degree declination of var1 point relative to var2
  3091.  
  3092.     DIM D AS INTEGER64
  3093.     D = HYPOT(var1.pX - var2.pX, var1.pY - var2.pY) '          distance on X,Y plane
  3094.     Slope! = R2D(ATAN2(var1.pZ - var2.pZ, D))
  3095.  
  3096.  
  3097. END FUNCTION 'Slope!
  3098.  
  3099.  
  3100. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3101. FUNCTION swapcolor (handle&, oldcolor~&, newcolor~&)
  3102.  
  3103.     'Petr's character color swapping function, called from SUB Prnt
  3104.  
  3105.     DIM m AS _MEM, c AS _UNSIGNED LONG
  3106.     swapcolor = _COPYIMAGE(handle&, 32)
  3107.     m = _MEMIMAGE(swapcolor)
  3108.     DO UNTIL x& = m.SIZE - 4
  3109.         x& = x& + 4
  3110.         c = _MEMGET(m, m.OFFSET + x&, _UNSIGNED LONG)
  3111.         IF c = oldcolor~& THEN _MEMPUT m, m.OFFSET + x&, newcolor~&
  3112.     LOOP
  3113.     _MEMFREE m
  3114.  
  3115. END FUNCTION 'swapcolor
  3116.  
  3117.  
  3118. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3119. SUB SysMap
  3120.  
  3121.     'Displays the star system, called from SUB SensorScreen
  3122.  
  3123.     DIM g! '                                                    holds result of Prop! call for this display loop
  3124.     DIM OT AS unitpoint '                                       locates orbit tracks & belt/ring systems
  3125.     g! = Prop!
  3126.  
  3127.     'Iterate through all system bodies
  3128.     FOR p = 1 TO orbs
  3129.  
  3130.         'on jump toggle display diameters- rejecting those out of frame
  3131.         IF READBIT(togs, 6) AND hvns(p).star <> 2 THEN '    jump zones toggled & not asteroid belt
  3132.             IF READBIT(togs, 9) THEN l! = hvns(p).dens ELSE l! = 1 'density or diameter jump zone
  3133.             '100 diameters/densities
  3134.             bug = FrameSect(rcs(vpoint), rcp(p), hvns(p).radi * 200 * l!, g!)
  3135.             IF bug > 1 THEN
  3136.                 FCirc (dcp(p).pX) * g!, (dcp(p).pY) * g!, (hvns(p).radi * 200 * l!) * g!, RGBA(150, 116, 116, 10)
  3137.             END IF
  3138.             '10 diameters/densities
  3139.             bug = FrameSect(rcs(vpoint), rcp(p), hvns(p).radi * 20 * l!, g!)
  3140.             IF bug > 1 THEN
  3141.                 FCirc (dcp(p).pX) * g!, (dcp(p).pY) * g!, (hvns(p).radi * 20 * l!) * g!, RGBA(200, 116, 116, 5)
  3142.             END IF
  3143.         END IF
  3144.  
  3145.         'If star then build star and star corona otherwise set planet color
  3146.         IF hvns(p).star = -1 THEN '                              if a star then build star corona
  3147.             'DETERMINE ANY STELLAR CLASS CONSTANTS HERE- use them in place of 50000
  3148.             bug = FrameSect(rcs(vpoint), rcp(p), hvns(p).radi + (30 * 50000), g!)
  3149.             IF bug > 0 THEN
  3150.                 FOR x = 1 TO 30
  3151.                     bug = FrameSect(rcs(vpoint), rcp(p), hvns(p).radi + (x * 50000), g!)
  3152.                     IF bug > 0 THEN
  3153.                         FCirc (dcp(p).pX) * g!, (dcp(p).pY) * g!, (hvns(p).radi + (x * 50000)) * g!, RGBA32(127, 127, 227, 30 - x)
  3154.                     END IF
  3155.                 NEXT x
  3156.             END IF
  3157.             c& = &HFFFC5454 '                               star photosphere color
  3158.         ELSE
  3159.             c& = &HFF545454 '                               planet color
  3160.         END IF
  3161.  
  3162.         'find orbit track center
  3163.         IF hvns(p).rank > 1 THEN
  3164.             OT = rcp(FindParent(p))
  3165.         ELSE
  3166.             OT.pX = 0: OT.pY = 0: OT.pZ = 0
  3167.         END IF
  3168.  
  3169.         IF hvns(p).star < 2 THEN
  3170.  
  3171.             'display orbit tracks
  3172.             IF READBIT(togs, 7) THEN '                          if orbit toggle is true
  3173.                 IF READBIT(togs, 1) THEN '                      if Z-pan toggle is true
  3174.                     'adjust so orbit track center moves with parent body
  3175.                     'draw all orbit tracks as some may be visible on extreme Z-pan
  3176.                         CIRCLE (OT.pX * g!, (OT.pY * (COS(D2R(zangle))) + (OT.pZ * SIN(D2R(zangle)))) * g!),_
  3177.                          hvns(p).orad * g!, RGBA(111, 72, 233, 70), , , 1 * COS(D2R(zangle))
  3178.                 ELSE
  3179.                     bug = FrameSect(rcs(vpoint), rcp(FindParent(p)), hvns(p).orad, g!)
  3180.                     IF bug = 3 THEN 'exclude circles that don't intersect view port to speed zoom in
  3181.                         CIRCLE (OT.pX * g!, OT.pY * g!), hvns(p).orad * g!, RGBA(111, 72, 233, 70)
  3182.                     END IF
  3183.                 END IF
  3184.             END IF
  3185.  
  3186.             'display gravity zones
  3187.             IF READBIT(togs, 8) THEN '                          if grav zone toggle is true
  3188.                 IF hvns(p).star <> 2 THEN
  3189.                     grv! = 0
  3190.                     radius## = hvns(p).radi
  3191.                     dsx## = hvns(p).dens * ((4 / 3) * PI * (radius## * radius## * radius##)) / 26687
  3192.                     DO
  3193.                         grv! = grv! + .25
  3194.                         ds## = (dsx## / grv!) ^ .5
  3195.                         bug = FrameSect(rcs(vpoint), rcp(p), ds##, g!)
  3196.                         IF bug = 3 THEN
  3197.                             CIRCLE (dcp(p).pX * g!, dcp(p).pY * g!), ds## * g!, RGBA(0, 255, 0, 25)
  3198.                         END IF
  3199.                     LOOP UNTIL ds## < hvns(p).radi
  3200.                 END IF 'end belt/ring test
  3201.             END IF
  3202.  
  3203.             'display star/planet body, rejecting those that are out of frame
  3204.             bug = FrameSect(dcs(vpoint), dcp(p), hvns(p).radi, g!)
  3205.             IF bug > 0 THEN
  3206.                 FCirc dcp(p).pX * g!, dcp(p).pY * g!, hvns(p).radi * g!, c&
  3207.                 CIRCLE (dcp(p).pX * g!, dcp(p).pY * g!), hvns(p).radi * g!, &HFF777777
  3208.  
  3209.                 'display name if there's room
  3210.                 IF g! > .0003 AND hvns(p).rank = 3 THEN '       drop satellite names first
  3211.                     GOSUB print_name
  3212.                 END IF
  3213.                 IF g! > .00000003 AND hvns(p).rank = 2 THEN '   Then drop planets names
  3214.                     GOSUB print_name
  3215.                 END IF
  3216.                 IF hvns(p).star THEN '                          always keep star names visible
  3217.                     GOSUB print_name
  3218.                 END IF
  3219.             END IF '                                            end planet out of frame reject
  3220.         ELSE
  3221.             'Display planetoid belts and rings
  3222.             IF READBIT(togs, 10) THEN
  3223.                 IF hvns(p).orad * 2 * g! > 100 THEN
  3224.                     aster& = &H087F7F7F '                               belt/ring color
  3225.                     IF hvns(p).dens > 0 THEN '                          belt/ring width- stored in dens element
  3226.                         wid = hvns(p).dens / 2
  3227.                     ELSE
  3228.                         wid = .15
  3229.                     END IF
  3230.                     inbnd&& = (hvns(p).orad - (hvns(p).orad * wid)) 'inner limit of planetoid/ring belt wid% orbital radius
  3231.                     outbnd&& = (hvns(p).orad + (hvns(p).orad * wid)) 'outer limit of planetoid/ring belt wid% orbital radius
  3232.                     bug = FrameSect(rcs(vpoint), rcp(FindParent(p)), outbnd&&, g!)
  3233.                     IF bug > 1 THEN
  3234.                         rng = INT(outbnd&& - inbnd&&)
  3235.                         'If belt/ring fills frame, then exclude it for speed & clarity.
  3236.                         bugin = FrameSect(rcs(vpoint), rcp(FindParent(p)), inbnd&&, g!)
  3237.                         bugout = FrameSect(rcs(vpoint), rcp(FindParent(p)), outbnd&&, g!)
  3238.                         IF bugin = 0 AND bugout = 1 THEN
  3239.                             'Don't display belt/ring when fully encompassing screen
  3240.                             'PUT A LOW ALPHA CALL TO [GOSUB print_name] HERE
  3241.                             'B& = NEWIMAGE(620, 620, 32)
  3242.                             'DEST B&
  3243.                             'CLEARCOLOR RGBA32(0, 0, 0, 0)
  3244.                             'Prnt hvns(p).nam, 14, 14, 100, 280, 24, 0, &H7000FF70
  3245.                             'DEST SS&
  3246.                             'PUTIMAGE , B&, SS&
  3247.                             'FREEIMAGE B&
  3248.                         ELSEIF bugout = 0 THEN
  3249.                             'Don't display when belt/ring is beyond screen
  3250.                         ELSE
  3251.                             FOR pb = 0 TO rng STEP 1 / g!
  3252.                                 IF READBIT(togs, 1) THEN '                  if Z-pan toggle is true
  3253.                                     CIRCLE (OT.pX * g!, (OT.pY * (COS(D2R(zangle))) + (OT.pZ * SIN(D2R(zangle)))) * g!), (inbnd&& + pb) * g!, aster&, , , 1 * COS(D2R(zangle))
  3254.                                 ELSE
  3255.                                     bug = FrameSect(rcs(vpoint), rcp(FindParent(p)), (inbnd&& + pb), g!)
  3256.                                     IF bug > 0 THEN
  3257.                                         CIRCLE (OT.pX * g!, OT.pY * g!), (inbnd&& + pb) * g!, aster&
  3258.                                     END IF
  3259.                                 END IF 'end Z-pan test
  3260.                             NEXT pb
  3261.                         END IF '                                            end full frame exclusion
  3262.                     END IF
  3263.                 END IF
  3264.             END IF
  3265.         END IF '                                                end planetary or belt display
  3266.     NEXT p
  3267.  
  3268.     EXIT SUB
  3269.     print_name:
  3270.     fl$ = ""
  3271.     IF zangle < 0 THEN
  3272.         fl = -1
  3273.         FOR n = LEN(TRIM$(hvns(p).nam)) TO 1 STEP -1
  3274.             fl$ = fl$ + MID$(hvns(p).nam, n, 1)
  3275.         NEXT n
  3276.     ELSE
  3277.         fl = 1
  3278.         fl$ = hvns(p).nam
  3279.     END IF
  3280.     Prnt fl$, 3.5 * fl, 3.5 * fl, (dcp(p).pX * g!) + (hvns(p).radi * g! * .7), (dcp(p).pY * g!) - (hvns(p).radi * g! * .7), 24, 0, RGBA32(200, 67, 55, 170)
  3281.     RETURN
  3282.  
  3283. END SUB 'SysMap
  3284.  
  3285.  
  3286. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3287. SUB SysMapII
  3288.  
  3289.     'REDESIGN IN PROGRESS...
  3290.     DIM g! '                                                    holds result of Prop! call for this display loop
  3291.     DIM OBC AS unitpoint '                                      locates center of orbits & belt/ring systems
  3292.     DIM ctr AS unitpoint
  3293.     DIM ptr AS unitpoint
  3294.  
  3295.     g! = Prop!
  3296.     ctr = rcs(vpoint)
  3297.  
  3298.     FOR p = 1 TO orbs '                                         iterate through all bodies
  3299.  
  3300.         'ptr = dcp(p)
  3301.  
  3302.         'find orbit/belt/ring track center
  3303.         IF hvns(p).rank > 1 THEN
  3304.             OBC = rcp(FindParent(p))
  3305.         ELSE
  3306.             OBC.pX = 0: OBC.pY = 0: OBC.pZ = 0
  3307.         END IF
  3308.  
  3309.         'Planetary rendering
  3310.         IF hvns(p).star < 2 THEN
  3311.  
  3312.             'Orbit tracks
  3313.             IF READBIT(togs, 7) THEN '                          if orbit toggle is true
  3314.                 p_ot = FrameSect(ctr, rcp(FindParent(p)), hvns(p).orad, g!)
  3315.                 IF READBIT(togs, 1) THEN '                      if Z-pan toggle is true
  3316.                     'adjust so orbit track center moves with parent body
  3317.                     'draw all orbit tracks as some may be visible on extreme Z-pan
  3318.                 CIRCLE (OBC.pX * g!, (OBC.pY * (COS(D2R(zangle))) + (OBC.pZ * SIN(D2R(zangle)))) * g!),_
  3319.                  hvns(p).orad * g!, RGBA(111, 72, 233, 70), , , 1 * COS(D2R(zangle))
  3320.                 ELSE
  3321.                     IF p_ot = 3 THEN 'exclude circles that don't intersect view port to speed zoom in
  3322.                         CIRCLE (OBC.pX * g!, OBC.pY * g!), hvns(p).orad * g!, RGBA(111, 72, 233, 70)
  3323.                     END IF
  3324.                 END IF
  3325.             END IF
  3326.  
  3327.             IF READBIT(togs, 9) THEN l! = hvns(p).dens ELSE l! = 1 'density or diameter jump zone
  3328.             p_jmp100% = FrameSect(ctr, rcp(p), hvns(p).radi * 200 * l!, g!)
  3329.             p_jmp10% = FrameSect(ctr, rcp(p), hvns(p).radi * 20 * l!, g!)
  3330.             p_rad% = FrameSect(ctr, rcp(p), hvns(p).radi, g!)
  3331.             IF p_jmp100% > 0 THEN
  3332.                 IF READBIT(togs, 6) THEN '                      Jump zones activated
  3333.                     IF p_jmp100% > 1 THEN '                     100 diameters/densities
  3334.                         FCirc (dcp(p).pX) * g!, (dcp(p).pY) * g!, (hvns(p).radi * 200 * l!) * g!, RGBA(150, 116, 116, 10)
  3335.                     END IF
  3336.                     IF p_jmp10% > 1 THEN '                      10 diameters/densities
  3337.                         FCirc (dcp(p).pX) * g!, (dcp(p).pY) * g!, (hvns(p).radi * 20 * l!) * g!, RGBA(200, 116, 116, 5)
  3338.                     END IF
  3339.                 END IF
  3340.                 IF hvns(p).star = -1 THEN
  3341.                     'ADD STELLAR CLASS CORONA EFFECTS HERE AND PUT IN PLACE OF 50000
  3342.                     p_cron% = FrameSect(ctr, rcp(p), hvns(p).radi + (30 * 50000), g!)
  3343.                     IF p_cron% > 0 THEN
  3344.                         FOR x = 1 TO 30
  3345.                             p_cr_bd% = FrameSect(ctr, rcp(p), hvns(p).radi + (x * 50000), g!)
  3346.                             IF p_cr_bd% > 0 THEN
  3347.                                 FCirc (dcp(p).pX) * g!, (dcp(p).pY) * g!, (hvns(p).radi + (x * 50000)) * g!, RGBA32(127, 127, 227, 31 - x)
  3348.                             END IF
  3349.                         NEXT x
  3350.                     END IF
  3351.                     c& = &HFFFC5454 '                           star photosphere color
  3352.                 ELSE
  3353.                     c& = &HFF545454 '                           planet color
  3354.                 END IF
  3355.                 IF p_rad% > 0 THEN
  3356.                     FCirc dcp(p).pX * g!, dcp(p).pY * g!, hvns(p).radi * g!, c&
  3357.                     CIRCLE (dcp(p).pX * g!, dcp(p).pY * g!), hvns(p).radi * g!, &HFF777777
  3358.                     'display name if there's room
  3359.                     IF g! > .0003 AND hvns(p).rank = 3 THEN '       drop satellite names first
  3360.                         GOSUB print_name
  3361.                     END IF
  3362.                     IF g! > .00000003 AND hvns(p).rank = 2 THEN '   Then drop planets names
  3363.                         GOSUB print_name
  3364.                     END IF
  3365.                     IF hvns(p).star THEN '                          always keep star names visible
  3366.                         GOSUB print_name
  3367.                     END IF
  3368.  
  3369.                 END IF
  3370.             END IF
  3371.  
  3372.             'Belt/ring rendering
  3373.         ELSE
  3374.             IF READBIT(togs, 10) THEN '                         belt/ring toggle
  3375.                 IF hvns(p).orad * 2 * g! > 100 THEN '           only draw if big enough to see
  3376.                     aster& = &H087F7F7F '                       belt/ring color
  3377.                     IF hvns(p).dens > 0 THEN '                  belt/ring width- stored in dens element
  3378.                         wid = hvns(p).dens / 2
  3379.                     ELSE
  3380.                         wid = .15
  3381.                     END IF
  3382.                     inbnd&& = hvns(p).orad - (hvns(p).orad * wid)
  3383.                     outbnd&& = hvns(p).orad + (hvns(p).orad * wid)
  3384.                     p_bi% = FrameSect(ctr, rcp(FindParent(p)), inbnd&&, g!)
  3385.                     p_bo% = FrameSect(ctr, rcp(FindParent(p)), outbnd&&, g!)
  3386.                     IF p_bo% > 0 OR p_bi% <> 1 THEN '                         outer boundary within frame
  3387.                         IF p_bi% = 0 AND p_bo% = 1 THEN
  3388.                             'fully within the confines of the belt/ring
  3389.                         ELSE
  3390.                             rng&& = INT(outbnd&& - inbnd&&)
  3391.                             FOR pb = 0 TO rng&& STEP 1 / g!
  3392.                                 IF READBIT(togs, 1) THEN '                  if Z-pan toggle is true
  3393.                                     CIRCLE (OBC.pX * g!, (OBC.pY * (COS(D2R(zangle))) + (OBC.pZ * SIN(D2R(zangle)))) * g!),_
  3394.                                      (inbnd&& + pb) * g!, aster&, , , 1 * COS(D2R(zangle))
  3395.                                 ELSE
  3396.                                     frm_chk = FrameSect(ctr, rcp(FindParent(p)), (inbnd&& + pb), g!)
  3397.                                     IF frm_chk > 1 THEN
  3398.                                         CIRCLE (OBC.pX * g!, OBC.pY * g!), (inbnd&& + pb) * g!, aster&
  3399.                                     END IF
  3400.                                 END IF 'end Z-pan test
  3401.                             NEXT pb
  3402.                         END IF
  3403.                     END IF
  3404.                 END IF
  3405.             END IF
  3406.         END IF
  3407.  
  3408.     NEXT p
  3409.  
  3410.     EXIT SUB
  3411.     print_name:
  3412.     fl$ = ""
  3413.     IF zangle < 0 THEN
  3414.         fl = -1
  3415.         FOR n = LEN(TRIM$(hvns(p).nam)) TO 1 STEP -1
  3416.             fl$ = fl$ + MID$(hvns(p).nam, n, 1)
  3417.         NEXT n
  3418.     ELSE
  3419.         fl = 1
  3420.         fl$ = hvns(p).nam
  3421.     END IF
  3422.     Prnt fl$, 3.5 * fl, 3.5 * fl, (dcp(p).pX * g!) + (hvns(p).radi * g! * .7), (dcp(p).pY * g!) - (hvns(p).radi * g! * .7), 24, 0, RGBA32(200, 67, 55, 170)
  3423.     RETURN
  3424.  
  3425. END SUB 'SysMapII
  3426.  
  3427.  
  3428. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3429. FUNCTION FrameSect (active AS unitpoint, feature AS unitpoint, range AS INTEGER64, ratio AS SINGLE)
  3430.  
  3431.     'Determine feature's relation to active's viewport
  3432.     'SYNTAX: FrameSect(active unitpoint, feature center unitpoint, feature radius, result of Prop! call)
  3433.     Sact = 1415 / ratio '                                       gives display sphere radius
  3434.     dist## = PythXY(active, feature) '                          distance between active unit and feature center point
  3435.     'dist## = Pyth(active, feature) '                          distance between active unit and feature center point
  3436.  
  3437.     IF dist## > Sact + range THEN FrameSect = 0 ' feature is beyond display
  3438.     IF dist## < range - Sact THEN FrameSect = 1 ' feature encompasses entire display
  3439.     IF dist## < Sact - range THEN FrameSect = 2 ' feature is encompassed by display
  3440.     IF dist## < Sact + range AND dist## > range - Sact THEN FrameSect = 3 ' feature intersects display
  3441.  
  3442. END FUNCTION 'FrameSect
  3443.  
  3444.  
  3445. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3446. SUB Turn2Clock (var AS INTEGER)
  3447.  
  3448.     s = var * 1000 '                                            convert turns to seconds
  3449.     etd = INT(s / 86400) '                                      elapsed time days
  3450.     eth = INT((s - etd * 86400) / 3600) '                       elapsed time hours
  3451.     etm = INT((s - (etd * 86400 + eth * 3600)) / 60) '          elapsed time minutes
  3452.     ets = s - (etd * 86400 + eth * 3600 + etm * 60) '           elapsed time seconds
  3453.  
  3454. END SUB 'Turn2Clock
  3455.  
  3456.  
  3457. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3458. SUB TruncCoord (var AS INTEGER64)
  3459.  
  3460.     'convert long coordinates to abbreviated versions
  3461.     IF ABS(var) >= 100000000 THEN
  3462.         x$ = STR$(INT(var / 1000000)) + "M"
  3463.     ELSEIF ABS(var) >= 100000000000 THEN
  3464.         x$ = STR$(INT(var / 1000000000)) + "G"
  3465.     ELSE
  3466.         x$ = STR$(var)
  3467.     END IF
  3468.     PRINT x$;
  3469.  
  3470. END SUB 'TruncCoord
  3471.  
  3472.  
  3473. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3474. SUB UDest (var AS INTEGER)
  3475.  
  3476.     'Unit (var) destroyed set all vectors to zero
  3477.     cmb(var).ap = cmb(var).op
  3478.     cmb(var).Sp = 0
  3479.     Thrust(var).Azi = 0
  3480.     Thrust(var).Inc = 0
  3481.     Thrust(var).Gs = 0
  3482.  
  3483. END SUB ' UDest
  3484.  
  3485.  
  3486. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3487. SUB VCS
  3488.  
  3489.     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  3490.     '//       VCS - Viewpoint Coordinate System
  3491.     '// local coordinate system centered on active unit
  3492.     '// used to improve action of SensorMask and MouseOps
  3493.     '// sensor screen click active unit choices in the outer
  3494.     '// system by reducing absolute coordinate number ranges.
  3495.     '
  3496.     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  3497.  
  3498.     REDIM rcs(units) AS unitpoint '                             Relative Coordinate / Ship
  3499.     REDIM rcp(orbs) AS unitpoint '                              Relative Coordinate / Planet
  3500.     REDIM dcs(units) AS unitpoint '                             Display Coordinate / Ship
  3501.     REDIM dcp(orbs) AS unitpoint '                              Display Coordinate / Planet
  3502.     DIM ms AS MEM: ms = MEM(cmb())
  3503.     DIM mp AS MEM: mp = MEM(hvns())
  3504.     DIM msr AS MEM: msr = MEM(rcs())
  3505.     DIM msd AS MEM: msd = MEM(dcs())
  3506.     DIM mpr AS MEM: mpr = MEM(rcp())
  3507.     DIM mpd AS MEM: mpd = MEM(dcp())
  3508.  
  3509.     IF units = 0 THEN vpoint = 0
  3510.     IF READBIT(togs, 1) THEN '                                  if Z-pan toggle is true then alternate Z view coordinates
  3511.         c = 1
  3512.         DO
  3513.             t&& = MEMGET(ms, ms.OFFSET + c * ms.ELEMENTSIZE + 52, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 52, INTEGER64)
  3514.             MEMPUT msr, msr.OFFSET + c * msr.ELEMENTSIZE, t&& 'SAME AS
  3515.             'rcs(c).pX = (cmb(c).ap.pX - cmb(vpoint).ap.pX)
  3516.             t&& = MEMGET(ms, ms.OFFSET + c * ms.ELEMENTSIZE + 60, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 60, INTEGER64)
  3517.             MEMPUT msr, msr.OFFSET + c * msr.ELEMENTSIZE + 8, t&& 'SAME AS
  3518.             'rcs(c).pY = (cmb(c).ap.pY - cmb(vpoint).ap.pY)
  3519.             t&& = MEMGET(ms, ms.OFFSET + c * ms.ELEMENTSIZE + 68, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 68, INTEGER64)
  3520.             MEMPUT msr, msr.OFFSET + c * msr.ELEMENTSIZE + 16, t&& 'SAME AS
  3521.             'rcs(c).pZ = (cmb(c).ap.pZ - cmb(vpoint).ap.pZ)
  3522.             MEMCOPY msr, msr.OFFSET + c * msr.ELEMENTSIZE, 8 TO msd, msd.OFFSET + c * msd.ELEMENTSIZE 'SAME AS
  3523.             'dcs(c).pX = rcs(c).pX
  3524.             t&& = (MEMGET(msr, msr.OFFSET + c * msr.ELEMENTSIZE + 8, INTEGER64) * COS(D2R(zangle)))_
  3525.              + ((MEMGET(msr, msr.OFFSET + c * msr.ELEMENTSIZE + 16, INTEGER64)) * SIN(D2R(zangle)))
  3526.             MEMPUT msd, msd.OFFSET + c * msd.ELEMENTSIZE + 8, t&& 'SAME AS
  3527.             'dcs(c).pY = (rcs(c).pY * COS(_D2R(zangle))) + ((rcs(c).pZ) * SIN(_D2R(zangle)))
  3528.             t&& = (MEMGET(msr, msr.OFFSET + c * msr.ELEMENTSIZE + 8, INTEGER64) * -SIN(D2R(zangle)))_
  3529.              + ((MEMGET(msr, msr.OFFSET + c * msr.ELEMENTSIZE + 16, INTEGER64)) * COS(D2R(zangle)))
  3530.             MEMPUT msd, msd.OFFSET + c * msd.ELEMENTSIZE + 16, t&& 'SAME AS
  3531.             'dcs(c).pZ = (rcs(c).pY * -SIN(D2R(zangle))) + (rcs(c).pZ * COS(D2R(zangle)))
  3532.             c = c + 1
  3533.         LOOP UNTIL c = units + 1
  3534.         c = 1
  3535.         DO
  3536.             IF hvns(c).star <> 2 THEN
  3537.                 t&& = MEMGET(mp, mp.OFFSET + c * mp.ELEMENTSIZE + 75, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 52, INTEGER64)
  3538.                 MEMPUT mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE, t&& 'SAME AS
  3539.                 'rcp(c).pX = (hvns(c).ps.pX - cmb(vpoint).ap.pX)
  3540.                 t&& = MEMGET(mp, mp.OFFSET + c * mp.ELEMENTSIZE + 83, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 60, INTEGER64)
  3541.                 MEMPUT mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 8, t&& 'SAME AS
  3542.                 'rcp(c).pY = (hvns(c).ps.pY - cmb(vpoint).ap.pY)
  3543.                 t&& = MEMGET(mp, mp.OFFSET + c * mp.ELEMENTSIZE + 91, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 68, INTEGER64)
  3544.                 MEMPUT mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 16, t&& 'SAME AS
  3545.                 'rcp(c).pZ = (hvns(c).ps.pZ - cmb(vpoint).ap.pZ)
  3546.                 MEMCOPY mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE, 8 TO mpd, mpd.OFFSET + c * mpd.ELEMENTSIZE 'SAME AS
  3547.                 'dcp(c).pX = rcp(c).pX
  3548.             t&& = (MEMGET(mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 8, INTEGER64) * COS(D2R(zangle)))_
  3549.              + ((MEMGET(mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 16, INTEGER64)) * SIN(D2R(zangle)))
  3550.                 MEMPUT mpd, mpd.OFFSET + c * mpd.ELEMENTSIZE + 8, t&& 'SAME AS
  3551.                 'dcp(c).pY = (rcp(c).pY * COS(_D2R(zangle))) + ((rcp(c).pZ) * SIN(_D2R(zangle)))
  3552.             t&& = (MEMGET(mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 8, INTEGER64) * -SIN(D2R(zangle)))_
  3553.              + ((MEMGET(mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 16, INTEGER64)) * COS(D2R(zangle)))
  3554.                 MEMPUT mpd, mpd.OFFSET + c * mpd.ELEMENTSIZE + 16, t&& 'SAME AS
  3555.                 'dcp(c).pZ = (rcp(c).pY * -SIN(D2R(zangle))) + (rcp(c).pZ * COS(D2R(zangle)))
  3556.             END IF
  3557.             c = c + 1
  3558.         LOOP UNTIL c = orbs + 1
  3559.     ELSE '                                                      Top down 2D coordinates
  3560.         c = 1
  3561.         DO
  3562.             t&& = MEMGET(ms, ms.OFFSET + c * ms.ELEMENTSIZE + 52, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 52, INTEGER64)
  3563.             MEMPUT msr, msr.OFFSET + c * msr.ELEMENTSIZE + 0, t&& 'rcs(c).pX = cmb(c).ap.pX - cmb(vpoint).ap.pX
  3564.             t&& = MEMGET(ms, ms.OFFSET + c * ms.ELEMENTSIZE + 60, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 60, INTEGER64)
  3565.             MEMPUT msr, msr.OFFSET + c * msr.ELEMENTSIZE + 8, t&& 'rcs(c).pY = cmb(c).ap.pY - cmb(vpoint).ap.pY
  3566.             t&& = MEMGET(ms, ms.OFFSET + c * ms.ELEMENTSIZE + 68, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 68, INTEGER64)
  3567.             MEMPUT msr, msr.OFFSET + c * msr.ELEMENTSIZE + 16, t&& 'rcs(c).pZ = cmb(c).ap.pZ - cmb(vpoint).ap.pZ
  3568.             MEMCOPY msr, msr.OFFSET + c * msr.ELEMENTSIZE, 24 TO msd, msd.OFFSET + c * msd.ELEMENTSIZE 'dcs(c) = rcs(c)
  3569.             c = c + 1
  3570.         LOOP UNTIL c = units + 1
  3571.         c = 1
  3572.         DO
  3573.             IF hvns(c).star <> 2 THEN
  3574.                 t&& = MEMGET(mp, mp.OFFSET + c * mp.ELEMENTSIZE + 75, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 52, INTEGER64)
  3575.                 MEMPUT mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE, t&& 'rcp(y).pX = hvns(y).ps.pX - cmb(vpoint).ap.pX
  3576.                 t&& = MEMGET(mp, mp.OFFSET + c * mp.ELEMENTSIZE + 83, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 60, INTEGER64)
  3577.                 MEMPUT mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 8, t&& 'rcp(y).pY = hvns(y).ps.pY - cmb(vpoint).ap.pY
  3578.                 t&& = MEMGET(mp, mp.OFFSET + c * mp.ELEMENTSIZE + 91, INTEGER64) - MEMGET(ms, ms.OFFSET + vpoint * ms.ELEMENTSIZE + 68, INTEGER64)
  3579.                 MEMPUT mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE + 16, t&& 'rcp(y).pZ = hvns(y).ps.pZ - cmb(vpoint).ap.pZ
  3580.                 MEMCOPY mpr, mpr.OFFSET + c * mpr.ELEMENTSIZE, 24 TO mpd, mpd.OFFSET + c * mpd.ELEMENTSIZE 'dcp(y) = rcp(y)
  3581.             END IF
  3582.             c = c + 1
  3583.         LOOP UNTIL c = orbs + 1
  3584.     END IF
  3585.     MEMFREE ms: MEMFREE mp: MEMFREE msr: MEMFREE msd: MEMFREE mpr: MEMFREE mpd:
  3586.  
  3587. END SUB 'VCS
  3588.  
  3589.  
  3590. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3591. SUB VectorBrake
  3592.  
  3593.     PanelBlank 0, 650, 64, 32, &HFF0F0F0F
  3594.     Con_Blok 0, 650, 64, 32, "Applied", 0, &H502C9B2C
  3595.     DISPLAY
  3596.     DELAY .5
  3597.  
  3598.     IF cmb(vpoint).Hd >= 180 THEN Thrust(vpoint).Azi = cmb(vpoint).Hd - 180
  3599.     IF cmb(vpoint).Hd < 180 THEN Thrust(vpoint).Azi = cmb(vpoint).Hd + 180
  3600.     Thrust(vpoint).Inc = -cmb(vpoint).In
  3601.     IF cmb(vpoint).Sp / 10000 < Thrust(vpoint).Gs THEN
  3602.         Thrust(vpoint).Gs = cmb(vpoint).Sp / 10000
  3603.     END IF
  3604.     IF Thrust(vpoint).Gs > cmb(vpoint).MaxG THEN
  3605.         Thrust(vpoint).Gs = cmb(vpoint).MaxG
  3606.     END IF
  3607.  
  3608. END SUB 'VectorBrake
  3609.  
  3610.  
  3611. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3612. SUB ZPanner
  3613.  
  3614.     DEST ZS&
  3615.     SCREEN ZS&
  3616.     CLS
  3617.     LINE (0, 0)-(39, 649), clr&(4), B '                         red border
  3618.     LINE (2, 2)-(37, 15), clr&(8), BF '                         top button
  3619.     LINE (2, 317)-(37, 332), clr&(8), BF '                      centering button
  3620.     LINE (2, 634)-(37, 647), clr&(8), BF '                      bottom button
  3621.     IF READBIT(togs, 1) THEN '                                  if Z-pan toggle is true
  3622.         yp = ((zangle / 90) * 310) + 325
  3623.         LINE (1, yp)-(6, yp - 5), clr&(12) '                    arrow indicator
  3624.         LINE (1, yp)-(6, yp + 5), clr&(12)
  3625.         COLOR clr&(12)
  3626.         PRINTMODE KEEPBACKGROUND
  3627.         PRINTSTRING (10, yp - 8), TRIM$(STR$(INT(90 - zangle))) + CHR$(248) 'degree value and degree symbol
  3628.     END IF
  3629.     PUTIMAGE (1204, 4), ZS&, A&
  3630.  
  3631. END SUB 'ZPanner
  3632.  
  3633.  
  3634. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3635. SUB Help
  3636.  
  3637.     DialogBox "HELP", 1200, 650, 25, &HFF4CCB9C, clr&(15)
  3638.     DISPLAY
  3639.     DO
  3640.         x$ = INKEY$
  3641.         PRINTSTRING (0, 639), "Press any key to continue...", A&
  3642.         DISPLAY
  3643.     LOOP UNTIL x$ <> ""
  3644.  
  3645. END SUB 'Help
  3646.  
  3647.  
  3648. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3649. SUB VecAdd (var AS unitpoint, var2 AS unitpoint, var3 AS INTEGER)
  3650.  
  3651.     var.pX = var.pX + (var2.pX * var3) '                        add (or subtract) two vectors defined by unitpoint
  3652.     var.pY = var.pY + (var2.pY * var3) '                        var= base vector, var2= vector to add
  3653.     var.pZ = var.pZ + (var2.pZ * var3) '                        var3 multiple of var2 to add (-sign to subtract)
  3654.  
  3655. END SUB 'VecAdd
  3656.  
  3657.  
  3658. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3659. SUB VecMult (vec AS unitpoint, multiplier AS SINGLE)
  3660.  
  3661.     'multiply vector by scalar value
  3662.     vec.pX = vec.pX * multiplier
  3663.     vec.pY = vec.pY * multiplier
  3664.     vec.pZ = vec.pZ * multiplier
  3665.  
  3666. END SUB 'VecMult
  3667.  
  3668.  
  3669. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3670. SUB VecNorm (var AS unitpoint)
  3671.  
  3672.     'convert var to unit vector
  3673.     m = SQR(var.pX * var.pX + var.pY * var.pY + var.pZ * var.pZ)
  3674.     var.pX = var.pX / m
  3675.     var.pY = var.pY / m
  3676.     var.pZ = var.pZ / m
  3677.  
  3678. END SUB 'VecNorm
  3679.  
  3680.  
  3681. '±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
  3682. SUB Terminus
  3683.  
  3684.     FREEIMAGE SS&
  3685.     FREEIMAGE AW&
  3686.     FREEIMAGE ZS&
  3687.     FREEIMAGE ORI&
  3688.     FREEIMAGE flight&
  3689.     FREEIMAGE evade&
  3690.     FREEIMAGE intercept&
  3691.     FREEIMAGE cancel&
  3692.     FREEIMAGE XZ&
  3693.     FREEIMAGE IZ&
  3694.     FREEIMAGE OZ&
  3695.     FREEIMAGE RG&
  3696.     FREEIMAGE OB&
  3697.     FREEIMAGE GD&
  3698.     FREEIMAGE AZ&
  3699.     FREEIMAGE IN&
  3700.     FREEIMAGE JP&
  3701.     FREEIMAGE DI&
  3702.     FREEIMAGE DN&
  3703.     FREEIMAGE QT&
  3704.     FREEIMAGE ShpT
  3705.     FREEIMAGE ShpO
  3706.     FREEIMAGE TLoc
  3707.     FREEIMAGE TLocn
  3708.  
  3709. END SUB 'Terminus
  3710.  
« Last Edit: July 26, 2020, 08:35:38 pm by OldMoses »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #1 on: June 16, 2019, 06:01:11 pm »
Hi OldMoses
I like this your begin version of your rpg...
waiting future developing
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #2 on: June 16, 2019, 09:00:27 pm »
Hi OldMoses,

Wow, this is going to be something. Were you a pilot or navigator? this has realistic technical look and jargon.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #3 on: June 16, 2019, 09:54:24 pm »
Hi OldMoses,

Wow, this is going to be something. Were you a pilot or navigator? this has realistic technical look and jargon.

Never did anything that cool, I'm a farmer/gamer nerd that knows just enough trig to get himself into trouble. My head's full of ideas that I likely don't have the skill to implement, but if I don't try it I achieve nothing. I gotta pump the iron to build the muscle. I started this one way back in the QBasic days, and I just couldn't get it to work much at all. Shelved it for a long time, and I'm still not sure I understand the algorithm I started developing. Now it's starting to behave and look like something with a few tweaks.

I conceived this one as more of a Gamemaster aid than an actual game in itself, but the display is starting to have a cool look to it, to where it would make a cool sensor visual for players too.

I'm working on a dynamically resizing scale grid for it now. Hoping I can get it to resize anywhere from 1 Km squares out to 1 light second squares. Once you get these things moving it's hard to slow them down, much less stop them. I guess I better add an ALL STOP button.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #4 on: June 17, 2019, 07:59:27 am »
I've installed the grid I mentioned above. As units fly farther from, or nearer to, each other the grid will resize by factors of ten as the necessary display scale changes. It was a head scratcher, but I managed to do it in 18 lines of code, in SUB SensorScreen.

I'm pushing all changes into the original posting. I assume this is good etiquette, but correct me if I'm wrong.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #5 on: June 17, 2019, 09:39:12 am »
...

I'm pushing all changes into the original posting. I assume this is good etiquette, but correct me if I'm wrong.

Good etiquette question might be properly discussed in Discussion board or Off-Topic, I think too distracting from your game to be discussed here. In your particular case, I agree with your choice, you are just adding to work in progress.
« Last Edit: June 17, 2019, 09:46:02 am by bplus »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #6 on: June 17, 2019, 12:47:00 pm »
Hi Oldmoses, I'm honored. I am pleased that some of my programs are so useful for you. I was very interested in the ways of calculating space in your program. I wish you much success in further developing this program. If I can, I'll be happy to advise. So far I'm in the space novice - i am something as programmer's toddler ...

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #7 on: June 17, 2019, 11:14:40 pm »
Thanks Petr, I've learned a lot from you guys in the last year or so, to the point that I felt like I could finally tackle some of the stickier aspects of this thing. I ran it through 42 turns at 14 Gs and covered something like 88 billion km with no overflow errors like the old version would do. I plugged the signed range of _INTEGER64 into a Km to lightyear converter and came up with 974911.19 ly. Seems like it has room to grow.

Tonight I pushed a quick and dirty ship editor, added range band circles to the active unit and a turn counter.

Adding the range bands revealed an aspect ratio bug, as the perfect circles should have met the grid perfectly too, but didn't. It turned out the VIEW statement in SUB ScreenLimits was out of square and was squishing the vertical axis slightly. It took a while to find that one.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #8 on: June 20, 2019, 09:52:32 am »
After some display redesign with a lot of help from the forum and a few bug hunts, I've got the latest installment.

Some mouse support has been added. Clicking on the unit name line will choose the unit as the active unit, and clicking on the menu items at the bottom left will invoke those functions.

For those who like a little drama, vector the opening unit "1 Crotalus" at 45 degrees 0 inclination and 2 G thrust. Then toggle "Turn" for 17 turns....

"OMG we're flying straight for the sun at 340 kilometers per second!!!!"

Quick!! We need a new vector!  ;)

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #9 on: June 28, 2019, 10:38:24 pm »
Added a few display toggles to help clean up the sensor display of things the user may not need or want
"R" toggles ranging circles for the active unit on/off
"A" toggles the azimuth wheel display on/off
"G" toggles the grid on/off
Just some easy peasy stuff, while working myself up to tackle thornier puzzles.

Also put in some quick and dirty solar system details just to see how it would work

Forgive the artifact numbers displayed on the left, they're debugging feedback for tweaking the mouse locating equations Steve showed me.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #10 on: July 01, 2019, 08:28:21 pm »
Todays additions are a zoom function. The program defaults to a 'zoom extents' display that resizes to keep all units on the screen. This can now be bypassed to zoom in on areas around the active unit, or zoom out to get "the bigger picture". Hotkey "+" zooms in on the active unit, "-" zooms out to wider views. Hotkey "X" returns to the default state.

I also added image buttons for vector solutions, specifically to evade or to intercept an opponent. The buttons work, as evidenced by the momentary string display unique to each, but the actual algorithms are still in the conceptual stage. More easy peasy...

"But Mommy, I don't wanna do the math..." ;)

I find that I tend to program to the display and try to shoe horn the actual data crunching into it later.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #11 on: July 04, 2019, 12:42:51 am »
Still avoiding math, I am the arch procrastinator.

Added randomly placed, stationary planetary and stellar bodies along their orbit tracks. Perfect circle orbits at this stage. Damn, but space is big! Moving to a planet is like finding the needle in a haystack without some flight plan feedback. Maybe something for later.

The planets don't move or exert gravity...yet...

While able to zoom out to interstellar scales, I find the program gets really glitchy when zooming in to around 10,000km per grid. Stellar auras start cropping up where they don't belong as well as planets appearing in odd places. That's a head scratcher for sure.

My son suggested a counterthrust feature which I've implemented, proud father that I am. He's a thinker, that one. It's as good as having a break pedal. When queried for an azimuth in the vector input, typing "c" [enter] automatically applies the exact opposite thrust to the ship's heading. "All stop, Scotty."

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #12 on: July 06, 2019, 07:41:02 pm »
Added a rather neandertal intercept/evade subroutine, some more sophisticated math should make it a little smarter. Any unit tasked with evading or intercepting another unit will attempt to flee from, or close with, that chosen unit, respectively. The algorithm is dead simple and sometimes results in a "rebounding spring" effect during interceptions. Too much pedal to the metal...

Added some interstellar points, the Alpha Centauri complex as well as Barnard's Star, Wolf 359, Sirius and even Betelgeuse (222 parsecs distant). All as a quick and dirty test just to see the program zoom them all in proportion to each other. The actual placement is probably wrong with respect to galactic positioning, but I just converted right ascension coordinates to what was already set up in the program. It did help me to find and swat a persistent bug that was placing ghost images in the display at certain zoom factors. I probably won't implement things on that scale ultimately, but it's amusing to see QB64 field it nicely.

The bug turned out to be that I was using SUB fcirc; to fill celestial body orbs, stars and coronas, which was originally designed with INTEGER values for X & Y, but in my application it needed _INTEGER64 due to the extreme distances and sizes. My poor ships kept finding themselves in the core of Betelgeuse as fcirc couldn't figure out where to place it. It's a long way off...

Whew!....gotta love it....

Close in zooming still bogs down, but this is a vast improvement.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #13 on: July 10, 2019, 11:40:31 pm »
Fleshed out the system details.

Planets now "orbit", that is, they change position based upon the turn based time criteria. They also have moons that orbit them via the same algorithm. Moons and inner planets move noticeably, the outer planets... eh...not sure. They are subjected to the same process, but the effect is too small to see. I'll have to watch the coordinate data to tell. The process is data based rather than gravity computational, in keeping with the nature of a game utility as opposed to an astrophysics simulator.

I generally only included the biggest moons. When you're a planet walking around, swinging moons, size matters.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: WIP: Dog fight in space...sort of...
« Reply #14 on: July 14, 2019, 02:45:19 pm »
Ship vectors are now affected by gravity generated by nearby celestial bodies. "Nearby" being a function of the relative strength of that body's gravity. The numbers seem to track pretty well with game conventions. The Sun will reach out quite a ways, while smaller planets less so. Infinitesimally small gravity numbers are discarded. Neptune won't mess with you while you're flying around Mars.

It's been amusing trying to get a stable orbit on a moving planet, which I assume is theoretically possible, but maybe not. I usually end up spiraling in and crashing. The distance and vector would have to be very precise.

I also added a rudimentary crash routine, though that will need some work. It presently checks if the vector midpoint is within a star/planet radius. The take away from that is, if you are going fast enough, you can still fly clean through.