diff --git a/presets/zmachine/ztrek.inf b/presets/zmachine/ztrek.inf new file mode 100644 index 00000000..1eff4af1 --- /dev/null +++ b/presets/zmachine/ztrek.inf @@ -0,0 +1,1815 @@ +!************************************************************************* +!** +!** Super Z Trek: Star Trek for the Z Machine +!** +!** Ported to Inform by John Menichelli +!** +!************************************************************************* + +!** The Star Trek game has been around since the dawn of personal computers. +!** This version, written in Inform by John Menichelli, is just the latest +!** incarnation of this classic game. If you have any questions, comments +!** or bug reports, please email them to me at menichel@@0064pixi.com. This +!** program and its source code are in the public domain. +!** +!** This version is based on the C port of an old BASIC program. The C version +!** was written by Chris Nystrom and is available from: +!** +!** http://www.cfi.org/pub/ccn/startrek +!** +!** You can contact the author of C port at: +!** +!** Chris Nystrom +!** 1013 Prairie Dove Circle +!** Austin, Texas 78758 +!** +!** E-Mail: chris@gnu.ai.mit.edu, nystrom@cactus.org, or ccn@cfi.org + +!** The original Super Star Trek game comes from the book "BASIC Computer +!** Games" edited by David Ahl of Creative Computing fame. It was published +!** in 1978 by Workman Publishing, 1 West 39 Street, New York, New York, +!** and the ISBN is: 0-89489-052-3. +!** +!** Here is the original BASIC header: +!** +!** SUPER STARTREK - MAY 16, 1978 - REQUIRES 24K MEMORY +!** +!** **** STAR TREK **** **** +!** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE, +!** AS SEEN ON THE STAR TREK TV SHOW. +!** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION +!** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL. +!** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB +!** LEEDOM - APRIL & DECEMBER 1974, +!** WITH A LITTLE HELP FROM HIS FRIENDS . . . +!** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED -- +!** SEND TO: R. C. LEEDOM +!** WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR. +!** BOX 746, M.S. 338 +!** BALTIMORE, MD 21203 +!** +!** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN BORDERS +!** LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS +!** MUCH AS POSSIBLE WHILE USING MULTIPLE STATMENTS PER LINE +!** +!** Notes on the Inform version: +!** +!** Since Inform only works with integers, this version eliminates the +!** guesswork involved in moving and firing torpedoes. To make up for +!** this, the torpedo algorithm gives the torped a random chance to miss, +!** which increases as the range increases. + +!** Constants + +Constant MAX_TORPS 10; +Constant KLINGON_POWER 200; +Constant MAX_POWER 3000; +Constant SCREEN_SIZE 6; +Constant ENTERPRISE 1; +Constant KLINGON 2; +Constant BASE 3; +Constant STAR 4; +Constant WARP_ENGINES 0; +Constant SHORT_RANGE 1; +Constant LONG_RANGE 2; +Constant PHASER_CONTROL 3; +Constant PHOTON_TUBES 4; +Constant DAMAGE_CONTROL 5; +Constant SHIELD_CONTROL 6; +Constant LIBRARY_COMPUTER 7; + +!** Global Variables + +Global trek_docked_flag; ! 1 or 2 if Enterprise is docked +Global trek_current_energy; ! Current energy +Global trek_shield_value; ! Current shield value +Global trek_torp_capacity = MAX_TORPS; ! Photon torpedo capacity +Global trek_torps_remaining; ! Photon torpedoes left +Global trek_max_speed; ! Maximum allowed speed +Global trek_end_of_time; ! End of time/game +Global trek_current_date; ! Current stardate +Global trek_total_bases; ! Total starbases +Global trek_total_klingons; ! Klingons at start +Global trek_klingons_left; ! Total Klingons left +Global trek_quadrant_position; ! These two variables are used +Global trek_sector_position; ! to calculate the quadrant and + ! sector location of the Enterprise +!** Arrays + +Array trek_long_range_galaxy --> 64; ! Holds long range scan data +Array trek_galaxy_history --> 64; ! Hold history of all long and short + ! range scans +Array trek_temp_array --> 64; ! Used for printing long range scans +Array trek_sector -> 64; ! Sector data array +Array trek_damage_array -> 8; ! Damage Array +Array trek_klingon_array -> 3; ! Array used to track Klingon damage; +Array text_array -> 60; ! Input array for keyboard entry + +! Main Program + +[ Main ; + PlayTrek(); +]; + +[ PlayTrek ; + TrekIntro(); + Initialize(); + EndScreen(); +]; + +[ TrekIntro ; + font off; + box "************************************" + "* *" + "* *" + "* * * Super Z Trek * * *" + "* *" + "* *" + "************************************"; + + print "^^^"; + print "Press any key to begin..."; + + Pause(); +]; + +[ Initialize i j bases stars klingons; + + ! Initialize time + + trek_current_date = (20 + random(10)) * 1000; + trek_end_of_time = (25 + random(10)) * 10; + + ! Setup What Exists in Galaxy + + for (i = 0: i < 64: i++) + trek_galaxy_history-->i = 999; + + for (i = 0: i < 64: i++) + { + j = random(100); + switch(j) + { + 98 to 99: klingons = 3; + 95 to 97: klingons = 2; + 81 to 94: klingons = 1; + default: klingons = 0; + } + + trek_klingons_left = trek_klingons_left + klingons; + + if (random(100) > 96) + bases = 1; + else + bases = 0; + + trek_total_bases = trek_total_bases + bases; + + stars = random(8); + + trek_long_range_galaxy-->i = (klingons * 100) + + (bases * 10) + + stars; + } + + if (trek_total_bases == 0) + { + i = random(64) - 1; + j = trek_long_range_galaxy-->i; + j = j + 10; + trek_long_range_galaxy-->i = j; + trek_total_bases++; + } + + if (trek_klingons_left > trek_end_of_time / 10) + trek_end_of_time = (trek_klingons_left + 1) * 10; + + trek_total_klingons = trek_klingons_left; + + ! Initialize Enterprise + + trek_docked_flag = 0; + trek_current_energy = MAX_POWER; + trek_torps_remaining = trek_torp_capacity; + trek_shield_value = 0; + trek_max_speed = 8; + trek_quadrant_position = random(64) - 1; + trek_sector_position = random(64) - 1; + + for (i = 0: i < 8: i++) + trek_damage_array->i = 5; + + MissionBrief(); + SetScreen(); + NewQuadrant(); + UpdateStatus(); + ShortRangeScan(); + MainMenu(); +]; + +[ NewQuadrant i j k b s ; + trek_galaxy_history-->trek_quadrant_position = + trek_long_range_galaxy-->trek_quadrant_position; + + for (i = 0: i < 3: i++) + trek_klingon_array->i = KLINGON_POWER; + + i = trek_long_range_galaxy-->trek_quadrant_position; + + k = i / 100; ! Klingons + b = i / 10 - (10 * k); ! Bases + s = i - (100 * k) - (10 * b); ! Stars + + for (i = 0: i < 64: i++) + trek_sector->i = 0; + + trek_sector->trek_sector_position = ENTERPRISE; + + for (i = 1: i <= k: i++) ! Position Klingons + { +.Retry1; + j = random(64) - 1; + if (trek_sector->j ~= 0) + jump Retry1; + else + trek_sector->j = KLINGON; + } + + for (i = 1: i <= b: i++) ! Position base + { +.Retry2; + j = random(64) - 1; + if (trek_sector->j ~= 0) + jump Retry2; + else + trek_sector->j = BASE; + } + + for (i = 1: i <= s: i++) ! Position stars + { +.Retry3; + j = random(64) - 1; + if (trek_sector->j ~= 0) + jump Retry3; + else + trek_sector->j = STAR; + } +]; + + +[ SetScreen i j; + @erase_window $ffff; + @split_window SCREEN_SIZE; + @set_window 1; + style reverse; + j = SCREEN_SIZE; + for (i = 1 : i <= j: i++) + { + @set_cursor i 1; + spaces (0->33)-1; + } + style roman; +]; + +[ MissionBrief ; + @erase_window $ffff; + new_line; + new_line; + print "To: Captain, USS Enterprise, NCC-1701^^"; + + print "From: Starfleet Command^^"; + + print "Subject: War Warning^^"; + + print "1. Approximately three (3) hours ago, warships of the Imperial + Klingon Empire Navy crossed the border into Federation space. These + vessels have destroyed all outposts and ships in their path and + have not answered any hails.^^"; + + print "2. Therefore, effective immediately, a state of war exists between + the United Federation of Planets and the Imperial Klingon + Empire.^^"; + + print "3. As the Enterprise is the only vessel available in this portion + of the galaxy, your orders are as follows:^^"; + + print "4. Engage and destroy any and all Klingon vessels you encounter + within your designated patrol zone. Long range sensor scans indicate + a total of ", trek_klingons_left, " Klingon battlecruisers + in your area.^^"; + + print "5. Starfleet Operations calculates that it will take + approximately ", trek_end_of_time / 10, " days to mobilize our + forces and begin sending reinforcements to the front. We need you + to hold off the invading Klingon fleet until those reinforcements + arrive.^^"; + + print "6. Good luck and good hunting.^^"; + + print "[Press any key to accept command]"; + + Pause(); +]; + +[ UpdateStatus i; + @set_window 1; + + @set_cursor 1 1; + style reverse; + for (i = 1: i <= 2: i++) { + @set_cursor i 1; + spaces (0->33)-1; } + + @set_cursor 1 1; + print "Current Date: Days Remaining:"; + @set_cursor 2 1; + print "Klingons Remaining: Bases Remaining:"; + @set_cursor 3 1; + print "Shield Value: Total Energy Remaining:"; + + @set_cursor 5 1; + print "1: Nav 2: SRS 3: LRS 4: Phaser 5: Torp"; + @set_cursor 6 1; + print "6: Shield 7: Damage 8: Library 9: Help 0: Quit"; + + @set_cursor 1 15; + print (trek_current_date / 10), ".", (trek_current_date % 10); + + if (trek_end_of_time < 100) + @set_cursor 1 50; + else + @set_cursor 1 49; + + print trek_end_of_time / 10, ".", trek_end_of_time % 10; + + @set_cursor 2 21; + print trek_klingons_left; + @set_cursor 2 52; + print trek_total_bases; + + @set_cursor 3 15; + print trek_shield_value; + i = trek_current_energy + trek_shield_value; + @set_cursor 3 49; + + switch(i) + { + 0 to 9 : print " ", i; + 10 to 99 : print " ", i; + 100 to 999 : print " ", i; + default : print i; + } + + style roman; + + @set_window 0; +]; + +[ MainMenu i ; + for (::) + { + @read_char 1 -> i; + + switch(i) + { + '0' : break; + '1' : CourseControl(); + '2' : ShortRangeScan(); + '3' : LongRangeScan(); + '4' : PhaserControl(); + '5' : PhotonTorps(); + '6' : ShieldControl(); + '7' : DamageControl(); + '8' : Library(); + '9' : Help(); + } + if (i == '0') break; + } +]; + +[ CourseControl i course speed; + PrintCompass(); + + print "^Enter course (1-8): "; + @read_char 1 -> i; + + if (i < '1' || i > '8') + "^Lt. Sulu reports: ~Incorrect course data, sir!~^"; + + course = i - 48; + print course; + + trek_max_speed = trek_damage_array->WARP_ENGINES; + trek_max_speed = trek_max_speed + 3; + print "^^Enter warp speed (1-", trek_max_speed, "): "; + @read_char 1 -> i; + speed = i - 48; + + if (speed < 1) + "^Lt. Sulu reports: ~Incorrect speed, sir!~^^"; + + if (speed > trek_max_speed) + "^Chief Engineer Scott reports: ~The engines won't take more than warp ", + trek_max_speed, "!~^^"; + + if (speed * 10 > trek_current_energy + trek_shield_value) + "^Chief Engineer Scott reports: ~We don't have enough energy power to go + that fast!~^^"; + + trek_current_energy = trek_current_energy - (speed * 10); + + print speed, "^^"; + + if (trek_current_energy < 0) + { + print "^Shield Control supplies energy to complete the maneuver.^"; + + trek_shield_value = trek_shield_value + trek_current_energy; + trek_current_energy = 0; + + if (trek_shield_value < 0) + trek_shield_value = 0; + + } + CompleteManeuver(course, speed); + if (trek_current_energy + trek_shield_value <= 0) + OutOfEnergy(); +]; + +[ CompleteManeuver course speed i j xs ys xq yq; + xs = (trek_sector_position % 8) + 1; + ys = 8 - (trek_sector_position / 8); + + xq = (trek_quadrant_position % 8) + 1; + yq = 8 - (trek_quadrant_position / 8); + + j = trek_sector_position; + + for (i = 1: i <= speed: i++) + { + + if (OutOfBounds(course) == 1) + { + print "^Movement aborted - you may not leave your designated + patrol area.^"; + break; + } + + switch(course) + { + 1: ys++; + 2: xs++; ys++; + 3: xs++; + 4: xs++; ys--; + 5: ys--; + 6: ys--; xs--; + 7: xs--; + 8: xs--; ys++; + } + + if (xs < 1 || xs > 8 || ys < 1 || ys > 8) + { + if (xs < 1) { xs = 8; xq--; } + if (xs > 8) { xs = 1; xq++; } + if (ys < 1) { ys = 8; yq--; } + if (ys > 8) { ys = 1; yq++; } + + j = (8 * (8 - ys)) + xs - 1; + trek_sector_position = j; + trek_quadrant_position = (8 * (8 - yq)) + xq - 1; + if (trek_docked_flag > 0) + trek_docked_flag = 0; + NewQuadrant(); + } + else + { + j = (8 * (8 - ys)) + xs - 1; + + if (trek_sector->j == KLINGON or STAR) ! You can pass through a base + { + print "^Movement aborted due to improper navigation.^"; + break; + } + if (trek_sector->j == BASE) + { + if (i == speed) + { + print "^The Enterprise is now docked.^"; + trek_docked_flag = 1; + trek_sector->trek_sector_position = 0; + trek_sector_position = j; +! jump DoneMoving; + } + else + continue; + } + else + { + trek_sector->j = ENTERPRISE; + if (trek_docked_flag > 0) + { + trek_docked_flag = 0; + trek_sector->trek_sector_position = BASE; + } + else + trek_sector->trek_sector_position = 0; + + trek_sector_position = j; + } + } + } +!.DoneMoving; + trek_current_date = trek_current_date + speed; + trek_end_of_time = trek_end_of_time - speed; + if (trek_end_of_time <= 0) + EndOfTime(); + UpdateStatus(); + DamageRepair(); + UpdateStatus(); + ShortRangeScan(); +]; + +[ OutOfBounds course xs ys xq yq; + xs = (trek_sector_position % 8) + 1; + ys = 8 - (trek_sector_position / 8); + + xq = (trek_quadrant_position % 8) + 1; + yq = 8 - (trek_quadrant_position / 8); + + if (xq == 1 && yq == 1 && xs == 1 && ys == 1) ! Lower left corner + { + if (course == 4 or 5 or 6 or 7 or 8) + return 1; + else + return 0; + } + + if (xq == 8 && yq == 8 && xs == 8 && ys == 8) ! Upper right corner + { + if (course == 1 or 2 or 3 or 4 or 8) + return 1; + else + return 0; + } + + if (xq == 8 && yq == 1 && xs == 8 && ys == 1) ! Lower right corner + { + if (course == 2 or 3 or 4 or 5 or 6) + return 1; + else + return 0; + } + + if (xq == 1 && yq == 8 && xs == 1 && ys == 8) ! Upper left corner + { + if (course == 1 or 2 or 6 or 7 or 8) + return 1; + else + return 0; + } + + if (xq == 1 && xs == 1) ! Left edge + { + if (course == 6 or 7 or 8) + return 1; + else + return 0; + } + + if (xq == 8 && xs == 8) ! Right Edge + { + if (course == 2 or 3 or 4) + return 1; + else + return 0; + } + + if (yq == 8 && ys == 8) ! Top edge + { + if (course == 1 or 2 or 8) + return 1; + else + return 0; + } + + if (yq == 1 && ys == 1) ! Bottom edge + { + if (course == 4 or 5 or 6) + return 1; + else + return 0; + } + + return 0; +]; + +[ PrintCompass ; + new_line; + print " 8 1 2^"; + print " @@0092 | /^"; + print "7 -+- 3^"; + print " / | @@0092^"; + print " 6 5 4^"; +]; + +[ ShortRangeScan x y ; + if (trek_damage_array->SHORT_RANGE < 5) + "^Short Range Sensors are inoperative.^"; + + ! Determine Quadrant + + x = (trek_quadrant_position % 8) + 1; + y = 8 - (trek_quadrant_position / 8); + + print "^Short range scan of quadrant "; + print x, ", ", y, " ("; + PrintQuadrantName(x, y); + print ")^^"; + + print " 1 2 3 4 5 6 7 8^"; + print " --- --- --- --- --- --- --- ---^"; + for (x = 0: x < 64: x++) + { + if (x % 8 == 0) + { + print " "; + print 8 - (x/8); + print ":"; + } + + switch (trek_sector->x) + { + 0 : print " . "; + 1 : print " +E+"; + 2 : print " +K+"; + 3 : if (trek_docked_flag == 0) + print " >B<"; + else + print " >D<"; + 4 : print " # "; + } + + if ((x + 1) % 8 == 0) + print "^"; + } + + y = 0; + for (x = 1: x < 64: x++) + if (trek_sector->x == 2) y++; + + print "^Alert Condition: "; + + if (y > 0) + print "Red^"; + else if (trek_current_energy * 10 < MAX_POWER) + print "Yellow^"; + else + print "Green^"; + +]; + +[ LongRangeScan i j temp_pos; + if (trek_damage_array->LONG_RANGE < 5) + "^Long Range Sensors are inoperative.^"; + + for (i = 0: i < 64: i++) + trek_temp_array-->i = 999; + + temp_pos = trek_quadrant_position; + + if (temp_pos == 0) ! Upper left + { + trek_temp_array-->0 = trek_long_range_galaxy-->0; + trek_temp_array-->1 = trek_long_range_galaxy-->1; + trek_temp_array-->8 = trek_long_range_galaxy-->8; + trek_temp_array-->9 = trek_long_range_galaxy-->9; + + trek_galaxy_history-->0 = trek_long_range_galaxy-->0; + trek_galaxy_history-->1 = trek_long_range_galaxy-->1; + trek_galaxy_history-->8 = trek_long_range_galaxy-->8; + trek_galaxy_history-->9 = trek_long_range_galaxy-->9; + + jump Printit; + } + + if (temp_pos == 7) ! Upper right + { + trek_temp_array-->6 = trek_long_range_galaxy-->6; + trek_temp_array-->7 = trek_long_range_galaxy-->7; + trek_temp_array-->14 = trek_long_range_galaxy-->14; + trek_temp_array-->15 = trek_long_range_galaxy-->15; + + trek_galaxy_history-->6 = trek_long_range_galaxy-->6; + trek_galaxy_history-->7 = trek_long_range_galaxy-->7; + trek_galaxy_history-->14 = trek_long_range_galaxy-->14; + trek_galaxy_history-->15 = trek_long_range_galaxy-->15; + + jump Printit; + } + + if (temp_pos == 56) ! Lower left + { + trek_temp_array-->48 = trek_long_range_galaxy-->48; + trek_temp_array-->49 = trek_long_range_galaxy-->49; + trek_temp_array-->56 = trek_long_range_galaxy-->56; + trek_temp_array-->57 = trek_long_range_galaxy-->57; + + trek_galaxy_history-->48 = trek_long_range_galaxy-->48; + trek_galaxy_history-->49 = trek_long_range_galaxy-->49; + trek_galaxy_history-->56 = trek_long_range_galaxy-->56; + trek_galaxy_history-->57 = trek_long_range_galaxy-->57; + + jump Printit; + } + + if (temp_pos == 63) ! Lower right + { + trek_temp_array-->54 = trek_long_range_galaxy-->54; + trek_temp_array-->55 = trek_long_range_galaxy-->55; + trek_temp_array-->62 = trek_long_range_galaxy-->62; + trek_temp_array-->63 = trek_long_range_galaxy-->63; + + trek_galaxy_history-->54 = trek_long_range_galaxy-->54; + trek_galaxy_history-->55 = trek_long_range_galaxy-->55; + trek_galaxy_history-->62 = trek_long_range_galaxy-->62; + trek_galaxy_history-->63 = trek_long_range_galaxy-->63; + + jump Printit; + } + + if (temp_pos < 8) ! Top edge + { + trek_temp_array-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_temp_array-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_temp_array-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_temp_array-->(temp_pos+7) = trek_long_range_galaxy-->(temp_pos+7); + trek_temp_array-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_temp_array-->(temp_pos+9) = trek_long_range_galaxy-->(temp_pos+9); + + trek_galaxy_history-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_galaxy_history-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_galaxy_history-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_galaxy_history-->(temp_pos+7) = trek_long_range_galaxy-->(temp_pos+7); + trek_galaxy_history-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_galaxy_history-->(temp_pos+9) = trek_long_range_galaxy-->(temp_pos+9); + + jump Printit; + } + + if (temp_pos > 55) ! Bottom edge + { + trek_temp_array-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_temp_array-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_temp_array-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_temp_array-->(temp_pos-7) = trek_long_range_galaxy-->(temp_pos-7); + trek_temp_array-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_temp_array-->(temp_pos-9) = trek_long_range_galaxy-->(temp_pos-9); + + trek_galaxy_history-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_galaxy_history-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_galaxy_history-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_galaxy_history-->(temp_pos-7) = trek_long_range_galaxy-->(temp_pos-7); + trek_galaxy_history-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_galaxy_history-->(temp_pos-9) = trek_long_range_galaxy-->(temp_pos-9); + + jump Printit; + } + + if (temp_pos % 8 == 0) ! Left edge + { + trek_temp_array-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_temp_array-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_temp_array-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_temp_array-->(temp_pos-7) = trek_long_range_galaxy-->(temp_pos-7); + trek_temp_array-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_temp_array-->(temp_pos+9) = trek_long_range_galaxy-->(temp_pos+9); + + trek_galaxy_history-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_galaxy_history-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_galaxy_history-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_galaxy_history-->(temp_pos-7) = trek_long_range_galaxy-->(temp_pos-7); + trek_galaxy_history-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_galaxy_history-->(temp_pos+9) = trek_long_range_galaxy-->(temp_pos+9); + + jump Printit; + } + if ((temp_pos+1) % 8 == 0) ! Right edge + { + trek_temp_array-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_temp_array-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_temp_array-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_temp_array-->(temp_pos+7) = trek_long_range_galaxy-->(temp_pos+7); + trek_temp_array-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_temp_array-->(temp_pos-9) = trek_long_range_galaxy-->(temp_pos-9); + + trek_galaxy_history-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_galaxy_history-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_galaxy_history-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_galaxy_history-->(temp_pos+7) = trek_long_range_galaxy-->(temp_pos+7); + trek_galaxy_history-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_galaxy_history-->(temp_pos-9) = trek_long_range_galaxy-->(temp_pos-9); + + jump Printit; + } + + ! Everything else + + trek_temp_array-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_temp_array-->(temp_pos-9) = trek_long_range_galaxy-->(temp_pos-9); + trek_temp_array-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_temp_array-->(temp_pos-7) = trek_long_range_galaxy-->(temp_pos-7); + trek_temp_array-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_temp_array-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_temp_array-->(temp_pos+7) = trek_long_range_galaxy-->(temp_pos+7); + trek_temp_array-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_temp_array-->(temp_pos+9) = trek_long_range_galaxy-->(temp_pos+9); + + trek_galaxy_history-->temp_pos = trek_long_range_galaxy-->temp_pos; + trek_galaxy_history-->(temp_pos-9) = trek_long_range_galaxy-->(temp_pos-9); + trek_galaxy_history-->(temp_pos-8) = trek_long_range_galaxy-->(temp_pos-8); + trek_galaxy_history-->(temp_pos-7) = trek_long_range_galaxy-->(temp_pos-7); + trek_galaxy_history-->(temp_pos-1) = trek_long_range_galaxy-->(temp_pos-1); + trek_galaxy_history-->(temp_pos+1) = trek_long_range_galaxy-->(temp_pos+1); + trek_galaxy_history-->(temp_pos+7) = trek_long_range_galaxy-->(temp_pos+7); + trek_galaxy_history-->(temp_pos+8) = trek_long_range_galaxy-->(temp_pos+8); + trek_galaxy_history-->(temp_pos+9) = trek_long_range_galaxy-->(temp_pos+9); + +.Printit; + new_line; + new_line; + + print " Long Range Scan Results^^"; + print " 1 2 3 4 5 6 7 8^"; + print " ----- ----- ----- ----- ----- ----- ----- -----^"; + + for (i = 0: i < 64: i++) + { + if (i%8 == 0) + { + print " "; + print 8 - i/8; + print ":"; + } + + j = trek_temp_array-->i; + + print " "; + + if (i == temp_pos) + style reverse; + else + style roman; + + switch(j) + { + 0 to 9 : print " 00"; print j; + 10 to 98 : print " 0"; print j; + 999 : print " ***"; + default : print " "; print j; + } + + print " "; + + style roman; + + if (i%8 == 7) + print "^"; + } +]; + +[ TextToNumber n x len mul tot; + text_array -> 0 = 60; + read text_array 0; + + if (text_array->1 > 4) + return -1; + + x = 0; + len = text_array->1; + + if (len == 4) mul=1000; + if (len == 3) mul=100; + if (len == 2) mul=10; + if (len == 1) mul=1; + + tot = 0; + + for (n = 0: n < len: n++) + { + if (text_array->(n+2) > 47 && text_array->(n+2) < 58) + { + x = text_array->(n+2); + x = x - 48; + tot = tot + mul * x; + mul = mul/10; + } + else + return -1; + } + return tot; +]; + +[ PhaserControl i j k x1 y1 x2 y2 z rng dmg; + if (trek_damage_array->PHASER_CONTROL < 5) + "^Science Officer Spock reports: ~Phasers are inoperative, Captain.~^"; + + k = trek_long_range_galaxy-->trek_quadrant_position; + + k = k / 100; ! Klingons + + if (k == 0) + "^Science Officer Spock reports: ~Sensors show no enemy ships in this + quadrant~^"; + + if (trek_damage_array->LIBRARY_COMPUTER < 5) + print "^Science Officer Spock reports: ~Computer failure will hamper + accuracy, Captain.~^"; + + print "^Phasers locked on target. Energy available = ", + trek_current_energy + trek_shield_value; + + print "^Enter number of units to fire: "; + + i = TextToNumber(); + + if (i <= 0) + "^Science Officer Spock reports: ~Phaser fire aborted.~^"; + + if (i > trek_current_energy) + "^Science Officer Spock reports: ~Insufficient energy for that + attack.~^"; + + trek_current_energy = trek_current_energy - i; + + if (trek_damage_array->LIBRARY_COMPUTER < 5) ! Computer damage affects targeting + i = i * trek_damage_array->LIBRARY_COMPUTER / 5; + + i = i / k; ! Divide the energy between each target + + x1 = (trek_sector_position % 8) + 1; + y1 = 8 - (trek_sector_position / 8); + + k = -1; + + for (j = 0: j < 64: j++) + { + if (trek_sector->j == KLINGON) + { + k++; + x2 = (j % 8) + 1; + y2 = 8 - (j / 8); + + rng = Range(x1, y1, x2, y2); + + dmg = i; + + dmg = dmg * 10 / (rng + random(5) - 1); + + z = trek_klingon_array->k; + + if (dmg <= 0) + "^Science Officer Spock reports: ~Sensors show no damage to + the Klingon battlecruiser at ", x2, ", ", y2, ".~^"; + + if (dmg >= z) + { + print "^Science Officer Spock reports: ~The Klingon battlecruiser + at ", x2, ", ", y2, " has been destroyed.~^"; + trek_klingon_array->k = 0; + trek_sector->j = 0; + trek_klingons_left--; + if (trek_klingons_left == 0) + WonGame(); + + z = trek_long_range_galaxy-->trek_quadrant_position; + z = z - 100; + trek_long_range_galaxy-->trek_quadrant_position = z; + if (z / 100 == 0) + ShortRangeScan(); + UpdateStatus(); + } + + else + { + z = z - dmg; + trek_klingon_array->k = z; + print "^Science Officer Spock reports: ~Sensors show that the + Klingon battlecruiser at ", x2, ", ", y2, " suffered a ", + dmg, " unit hit.~^"; + } + } + } + KlingonsShoot(); +]; + +[ PhotonTorps course i x1 y1 x2 y2 z index ; + if (trek_torps_remaining == 0) + "^Ensign Chekov reports: ~All photon torpedoes expended, sir!~^"; + + if (trek_damage_array->PHOTON_TUBES < 5) + "^Ensign Chekov reports: ~Photon torpedo tubes not operational, sir!~^"; + + i = trek_long_range_galaxy-->trek_quadrant_position; + + i = i / 100; ! Klingons + + if (i == 0) + "^Ensign Chekov reports: ~There are no Klingons in this quadrant, sir!~^"; + + trek_torps_remaining--; + x1 = (trek_sector_position % 8) + 1; + y1 = 8 - (trek_sector_position / 8); + + PrintCompass(); + + print "^Enter torpedo course (1-8): "; + + @read_char 1 -> i; + + if (i < '1' || i > '8') + "^Ensign Chekov reports: ~Incorrect course data, sir!~^"; + + course = i - 48; + + print course, "^"; + + for (i = 1: i < 8: i++) + { + switch(course) + { + 1: y1++; + 2: x1++; y1++; + 3: x1++; + 4: x1++; y1--; + 5: y1--; + 6: y1--; x1--; + 7: x1--; + 8: x1--; y1++; + } + + if (x1 < 1 || x1 > 8 || y1 < 1 || y1 > 8) + { + print "^Ensign Chekov reports: ~The torpedo missed, sir!~^"; + break; + } + + index = (8 * (8 - y1)) + x1 - 1; + + if (trek_sector->index == KLINGON) + { + x2 = (trek_sector_position % 8) + 1; + y2 = 8 - (trek_sector_position / 8); + + z = Range(x1, y1, x2, y2); + + z = z / 15; + + if (random(10) - 1 < z) + { + print "^Ensign Chekov reports: ~The torpedo missed, sir!~^"; + break; + } + else + { + trek_sector->index = 0; + trek_klingons_left--; + if (trek_klingons_left == 0) + WonGame(); + z = trek_long_range_galaxy-->trek_quadrant_position; + z = z - 100; + trek_long_range_galaxy-->trek_quadrant_position = z; + print "^Ensign Chekov reports: ~The Klingon battlecruiser in + sector ", x2, ", ", y2, " has been destroyed, sir!~^"; + UpdateStatus(); + ShortRangeScan(); + break; + } + } + + if (trek_sector->index == BASE) + { + print "^Ensign Chekov reports: ~You destroyed a base, sir!~^"; + trek_total_bases--; + z = trek_long_range_galaxy-->trek_quadrant_position; + z = z - 10; + trek_long_range_galaxy-->trek_quadrant_position = z; + + if (trek_total_bases == 0 && + trek_klingons_left <= (trek_current_date / 10) - + trek_end_of_time / 10) + { + print "That does it, Captain!! You are hereby relieved of command + and sentenced to 99 stardates of hard labor on Cygnus 12!! "; + LoseGame(); + } + + if (trek_docked_flag > 0) ! Undock + { + trek_docked_flag = 0; + trek_sector->trek_sector_position = ENTERPRISE; + ShortRangeScan(); + } + + break; + } + + if (trek_sector->index == STAR) + { + print "^Ensign Chekov reports: ~The star absorbed the torpedo's + energy, sir!~^"; + break; + } + } + KlingonsShoot(); +]; + +[ DamageControl ; + new_line; + new_line; + print "System Status^"; + print "-------------------------------------^"; + + print "Warp Engines "; + if (trek_damage_array->WARP_ENGINES == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Short Range Sensors "; + if (trek_damage_array->SHORT_RANGE == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Long Range Sensors "; + if (trek_damage_array->LONG_RANGE == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Phaser Control "; + if (trek_damage_array->PHASER_CONTROL == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Photon Torpedo Tubes "; + if (trek_damage_array->PHOTON_TUBES == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Damage Control "; + if (trek_damage_array->DAMAGE_CONTROL == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Shield Control "; + if (trek_damage_array->SHIELD_CONTROL == 5) + print "Operational^"; + else + print "Damaged^"; + + print "Library-Computer "; + if (trek_damage_array->LIBRARY_COMPUTER == 5) + print "Operational^"; + else + print "Damaged^"; +]; + +[ ShieldControl i; + if (trek_damage_array->SHIELD_CONTROL < 5) + "Shield Control is inoperative."; + + print "^Total energy available = ", trek_current_energy + trek_shield_value; + + print "^Input number of units to shields: "; + + i = TextToNumber(); + + if (i == -1) + "^Shield Control reports: ~Invalid request - shields unchanged.~^"; + + if (i == trek_shield_value) + "^^"; + + if (i >= trek_current_energy + trek_shield_value) + "^Shield Control reports: ~There is insufficient energy available - + shields unchanged.~^"; + + trek_current_energy = trek_current_energy + trek_shield_value - i; + trek_shield_value = i; + + print "^Shield Control reports: ~Shields now at ", trek_shield_value, + " units per your command.~^"; + UpdateStatus(); +]; + +[ Library i; + if (trek_damage_array->LIBRARY_COMPUTER < 5) + "^The Library Computer is inoperative.^"; + + print "^Choose which library-computer function you wish to use:^^"; + print "1: Galactic Record^"; + print "2: Status Report^"; + print "3: Exit^^"; + print "Enter choice: "; + + @read_char 1 -> i; + print i - 48, "^"; + switch(i) + { + '1' : GalacticRecord(); + '2' : StatusReport(); + '3' : "^Library-computer exited.^^"; + default: "^Invalid choice.^"; + } +]; + +[ GalacticRecord i j; + new_line; + new_line; + + print " The Galaxy^^"; + print " 1 2 3 4 5 6 7 8^"; + print " ----- ----- ----- ----- ----- ----- ----- -----^"; + + for (i = 0: i < 64: i++) + { + if (i%8 == 0) + { + print " "; + print 8 - i/8; + print ":"; + } + + j = trek_galaxy_history-->i; + + print " "; + + if (i == trek_quadrant_position) + style reverse; + else + style roman; + + switch(j) + { + 0 to 9 : print " 00"; print j; + 10 to 98 : print " 0"; print j; + 999 : print " ***"; + default : print " "; print j; + } + + print " "; + + style roman; + + if (i%8 == 7) + print "^"; + } +]; + +[ StatusReport i j x y; + for (i = 1: i < 64: i++) + if (trek_sector->i == KLINGON) j++; + + print "^Status Report:^^"; + + print "Startdate: ", (trek_current_date / 10), ".", + (trek_current_date % 10), "^^"; + + print "Time remaining in mission: ", trek_end_of_time / 10, ".", + trek_end_of_time % 10, " days^^"; + + x = (trek_quadrant_position % 8) + 1; + y = 8 - (trek_quadrant_position / 8); + + print "Position:^^"; + print " Quadrant: ", x, ", ", y, " ("; + PrintQuadrantName(x, y); + print ")^^"; + + x = (trek_sector_position % 8) + 1; + y = 8 - (trek_sector_position / 8); + + print " Sector: ", x, ", ", y, "^^"; + + print "Alert Condition: "; + + if (j > 0) + print "Red^^"; + else if (trek_current_energy * 10 < MAX_POWER) + print "Yellow^^"; + else + print "Green^^"; + + print "Klingon warships remaining: ", trek_klingons_left, "^^"; + + print "Total bases remaining: ", trek_total_bases, "^^"; + + print "Total energy remaining: ", trek_current_energy + + trek_shield_value, "^^"; + + print "Current shield setting: ", trek_shield_value, "^^"; + + print "Total torpedoes remaining: ", trek_torps_remaining, "^"; +]; + +[ KlingonsShoot i j k x1 y1 x2 y2 rng dmg; + i = trek_long_range_galaxy-->trek_quadrant_position; + + i = i / 100; ! Klingons + + if (i == 0) return; + + if (trek_docked_flag > 0) + "^Starbase shields protect the Enterprise^^"; + + j = -1; + for (k = 0: k < 64: k++) + { + if (trek_sector->k == KLINGON) + { + j++; + x1 = (k % 8) + 1; + y1 = 8 - (k / 8); + + x2 = (trek_sector_position % 8) + 1; + y2 = 8 - (trek_sector_position / 8); + + rng = Range(x1, y1, x2, y2); + + dmg = trek_klingon_array->j; + + x2 = trek_klingon_array->j; + + x2 = x2 * 2 / 3; ! Reduce available Klingon energy by 1/3 + + trek_klingon_array->j = x2; + + dmg = dmg * 10 / (rng + random(5) - 1); + + print "^The Klingon battlecruiser at ", x1, ", ", y1, + " fires on you for ", dmg, " units of damage.^"; + + if (dmg > trek_shield_value) + { + ShipDestroyed(); + } + else + { + trek_shield_value = trek_shield_value - dmg; + print "^Shield energy is down to ", trek_shield_value, + " units.^"; + if (dmg >= 20) + { + if (random(10) < 7 || (dmg * 10 / trek_shield_value > 2)) + { + dmg = random(8) - 1; + if (trek_damage_array->dmg > 0) + { + x2 = trek_damage_array->dmg; + x2--; + trek_damage_array->dmg = x2; + } + print "^Damage control reports: ~"; + switch(dmg) + { + 0 : print "The warp engines were"; + 1 : print "The short range sensors were"; + 2 : print "The long range sensors were"; + 3 : print "Phaser controls were"; + 4 : print "The photon torpedo tubes were"; + 5 : print "Damage control was"; + 6 : print "Shield control was"; + 7 : print "The library-computer was"; + } + print " damaged in the attack.~^"; + } + } + } + } + } + KlingonsMove(); + UpdateStatus(); + ShortRangeScan(); +]; + +[ KlingonsMove i j k; + j = 0; + for (i = 0: i < 64: i++) + { + if (trek_sector->i == KLINGON) + { + j++; ! Count the number of Klingons in the sector + trek_sector->i = 0; ! and zero their location + } + } + + for (i = 1: i <= j: i++) ! Position Klingons + { +.Retry4; + k = random(64) - 1; + if (trek_sector->k ~= 0) + jump Retry4; + else + trek_sector->k = KLINGON; + } + + if (trek_klingon_array->0 == 0) ! "Garbage collect" the damage array + trek_klingon_array->0 = trek_klingon_array->1; + + if (trek_klingon_array->1 == 0) + trek_klingon_array->1 = trek_klingon_array->2; +]; + +[ DamageRepair i j k; + if (trek_docked_flag == 1) ! Docked + { + trek_docked_flag = 2; + trek_current_energy = MAX_POWER; + trek_torps_remaining = trek_torp_capacity; + if (trek_shield_value > 0) + print "^Shields dropped for docking purposes.^"; + + trek_shield_value = 0; + + j = 0; + for (i = 0: i < 8: i++) + { + if (trek_damage_array->i < 5) + j = j + (5 - trek_damage_array->i); + } + + if (j > 0) + { + print "^Technicians are standing by to effect repairs to your ship. + These repairs will take ", j / 10, ".", j % 10, " days to + complete. Will you authorize the repair order? (Y/N) "; + + @read_char->k; + if (k == 'Y' or 'y') + { + trek_current_date = trek_current_date + j; + trek_end_of_time = trek_end_of_time - j; + if (trek_end_of_time <= 0) + EndOfTime(); + for (i = 0: i < 8: i++) + trek_damage_array->i = 5; + print "^"; + } + else + "^"; + } + } + else + { + k = trek_damage_array->DAMAGE_CONTROL; + for (i = 0: i < 8: i++) + { + if (trek_damage_array->i < 5 && random(20) < k) + { + j = trek_damage_array->i; + j++; + trek_damage_array->i = j; + print "^Damage control reports: ~The "; + switch(i) + { + 0 : print "warp engines have"; + 1 : print "short range sensors have"; + 2 : print "long range sensors have"; + 3 : print "phaser control system has"; + 4 : print "photon torpedo tubes have"; + 5 : print "damage control system has"; + 6 : print "shield control system has"; + 7 : print "library-computer has"; + } + if (j < 5) + print " been partially repaired.~^"; + else + print " been completely repaired.~^"; + } + } + } +]; + +[ PrintQuadrantName x y; + if (x == 1 or 2) + { + if (y == 1 or 2) + print "Antares"; + if (y == 3 or 4) + print "Rigel"; + if (y == 5 or 6) + print "Procyon"; + if (y == 7 or 8) + print "Vega"; + } + if (x == 3 or 4) + { + if (y == 1 or 2) + print "Canopus"; + if (y == 3 or 4) + print "Altair"; + if (y == 5 or 6) + print "Sagittarius"; + if (y == 7 or 8) + print "Pollux"; + } + if (x == 5 or 6) + { + if (y == 1 or 2) + print "Sirius"; + if (y == 3 or 4) + print "Deneb"; + if (y == 5 or 6) + print "Capella"; + if (y == 7 or 8) + print "Betelgeuse"; + } + if (x == 7 or 8) + { + if (y == 1 or 2) + print "Aldebaran"; + if (y == 3 or 4) + print "Regulus"; + if (y == 5 or 6) + print "Arcturus"; + if (y == 7 or 8) + print "Spica"; + } + + if (x == 1 or 3 or 5 or 7) + { + if (y == 1 or 3 or 5 or 7) + print " I"; + else + print " III"; + } + + if (x == 2 or 4 or 6 or 8) + { + if (y == 1 or 3 or 5 or 7) + print " II"; + else + print " IV"; + } +]; + +[ Range x1 y1 x2 y2 delta_x delta_y result; + delta_x = (x1 - x2) * 10; + delta_x = delta_x * delta_x; + + delta_y = (y1 - y2) * 10; + delta_y = delta_y * delta_y; + + result = SquareRoot(delta_x + delta_y); + + return result; +]; + +! Brute force approach to finding the square root of a number + +[ SquareRoot a b; + for (b = 1: b <= 110: b++) + { + if (b * b > a) + return (b - 1); + } +]; + +[ ShipDestroyed ; + print "The Enterprise has been destroyed. You have failed. "; + LoseGame(); +]; + +[ OutOfEnergy ; + print "^You've stranded yourself in space without enough energy to get to + a base! "; + LoseGame(); +]; + +[ EndOfTime ; + print "You've run out of time, Captain! "; + LoseGame(); +]; + +[ LoseGame ; + print "It is stardate ", (trek_current_date / 10), ".", + (trek_current_date % 10), ". "; + + print "There "; + + if (trek_klingons_left == 1) + print "was "; + else + print "were "; + print trek_klingons_left, " Klingon battlecruiser"; + + if (trek_klingons_left ~= 1) + print "s"; + + print " left at the end of your mission.^^"; + + print "[Press any key to continue.]^"; + Pause(); + EndScreen(); +]; + +[ WonGame ; + print "Congratulations, Captain! You have destroyed the last Klingon + battlecruiser in your patrol area.^^"; + + print "[Press any key to continue.]^"; + Pause(); + EndScreen(); +]; + +[ EndScreen ; + @set_cursor 1 1; + @split_window 0; + @erase_window $ffff; + + print "^Thanks for playing Super Z Trek.^^"; + @quit; +]; + +[ Pause dummy; + @read_char 1 dummy; + return dummy; +]; + +[ Help i; + print "^Choose which file to read:^^"; + print "1: How To Play Super Z Trek^"; + print "2: About This Game^"; + print "3: Exit^^"; + print "Enter choice: "; + + @read_char 1 -> i; + print i - 48, "^"; + switch(i) + { + '1' : HowToPlay(); + '2' : About(); + '3' : "^Library-computer exited.^^"; + default: "^Invalid choice.^"; + } +]; + +[ HowToPlay ; + print "^Welcome to Super Z Trek, the classic computer game ported to the + Z machine.^^"; + + print "The Z Trek galaxy is divided into an 8 x 8 quadrant grid, and each + quadrant is further divided into an 8 x 8 sector grid.^^"; + + print "You will be assigned a starting point somewhere in the galaxy to + begin a tour of duty as captain of the starship Enterprise. Your + mission: to seek out and destroy a fleet of Klingon warships which + have invaded the United Federation of Planets.^^"; + + print "COMMANDS^^"; + + print "The menu bar at the top of the screen displays information about the + current game and a list of allowable commands. Each command (numbered + '1' through '0') is activated by pressing the appropriate key. Each + key only has to be pressed once; you do not have to press 'Enter' + to complete the command. Each command is described below.^^"; + + print "1. Nav: This command is used to move the Enterprise around the + galaxy. Two additional pieces of information are required to + complete this command: course and speed. Course is an integer + from 1 to 8, as follows:^^"; + + PrintCompass(); + + print "^As with the command keys, only one keypress is required to enter + the course.^^"; + + print "The second entry is the speed, which is also an integer. The + Enterprise's speed ranges from 1 up to a maximum of 8, but this + maximum may be reduced due to damage to the warp engines. Speed is + entered in the same way as course, with only one keypress + required.^^"; + + print "If you wish to abort the movement command, enter an invalid value + for either the course or speed.^^"; + + print "2. SRS: This command prints out the results of a Short Range Sensor + scan. The print out shows what occupies the Enterprise's current + quadrant. The symbols used are:^^"; + + print " +E+ = Your starship's position^"; + print " +K+ = Klingon battlecruiser^"; + print " >B< = Federation starbase (Refuel/Repair/Re-Arm here)^"; + print " >D< = Federation starbase with the Enterprise docked^"; + print " # = Star^"; + print " . = Empty space^^"; + + print "3. LRS: This shows shows conditions in space for one quadrant on + each side of the Enterprise (which is in the middle of the scan + in reverse video). The scan is coded in the form ~###~ where the + units digit is the number of stars, the tens digit is the number + of starbases, and the hundreds digit is the number of Klingons.^^"; + + print "Example: 207 = 2 Klingons, No Starbases, and 7 stars.^^"; + + print "4. Phaser: Allows you to destroy the Klingon battlecruisers by + zapping them with suitably large units of energy to deplete their + shield power. With this command, you must enter the number of units + of energy you want to fire, then press the 'Enter' key. The amount + of energy you use will be divided evenly between all of the Klingons + in the quadrant.^^"; + + print "5. Torp: This commands fires one photon torpedo at one Klingon + ship. You will have to enter the torpedo's course, which is the + same used in movement. If you hit the Klingon vessel, it is + destroyed and cannot fire back at you. If you miss, you are subject + to the disrupter fire of all other Klingons in the quadrant.^^"; + + print "Note: Since Inform only works with integers, this version + eliminates the guesswork involved in moving and firing torpedoes. + To make up for this, the torpedo algorithm gives the torpedo a + random chance to miss, which increases as the range increases.^^"; + + print "6. Shield: This command defines the number of energy units to be + assigned to the shields. Energy for the shields is taken from the + ship's total energy. + If the Enterprise is hit and the shield value is reduced to zero or + less, the Enterprise is destroyed. Don't forget to put energy into + the shields before entering combat! Note that the ~Total Energy + Remaining~ heading on the menu bar includes shield energy.^^"; + + print "7. Damage: This command shows the state of repair of all devices, + either ~Operational~ or ~Damaged.~ If a device is damaged, the + ship's crew will attempt to repair it each time the ship moves. + All damaged may be repaired while docked at a starbase. To dock, + simply move into the same sector as the starbase.^^"; + + print "8. Library: The library-computer has two functions: ^^"; + + print "Function 1: Cumulative Galactic Record. This shows computer + memory of the results of all previous short and long range sensor + scans.^^"; + + print "Function 2: Status Report. This function shows the number of + Klingons, stardates, and starbases remaining in the game.^^"; + + print "9. Help: Brings up the help menu.^^"; + + print "0. Quit: Quits the game.^^"; + +]; + +[ About ; + print "^The Star Trek game has been around since the dawn of personal + computers. This version, written in Inform by John Menichelli, + is just the latest incarnation of this classic game. If you + have any questions, comments or bug reports, please email them to + me at menichel@@0064pixi.com. This program and its source code are + in the public domain.^^"; + + print "The Inform version is based on the C port of an old BASIC program. + The C version was written by Chris Nystrom and is available + from:^^"; + + print "http://www.cfi.org/pub/ccn/startrek^^"; + + print "You can contact the author of the C port at:^^"; + + print "Chris Nystrom^ + 1013 Prairie Dove Circle^ + Austin, Texas 78758^^ + E-Mail: chris@@0064gnu.ai.mit.edu, nystrom@@0064cactus.org, + or ccn@@0064cfi.org^^"; + + print "The original Super Star Trek game comes from the book ~BASIC + Computer Games~ edited by David Ahl of Creative Computing fame. It + was published in 1978 by Workman Publishing, 1 West 39 Street, + New York, New York, and the ISBN is: 0-89489-052-3.^^"; + + print "Here is the original BASIC header:^^"; + + print "SUPER STARTREK - MAY 16, 1978 - REQUIRES 24K MEMORY^^"; + + print " **** STAR TREK ****^"; + + print "SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,^"; + print "AS SEEN ON THE STAR TREK TV SHOW.^"; + print "ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION^"; + print "PUBLISHED IN DEC'S ~101 BASIC GAMES~, BY DAVE AHL.^"; + print "MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB^"; + print "LEEDOM - APRIL & DECEMBER 1974,^"; + print "WITH A LITTLE HELP FROM HIS FRIENDS . . .^"; + print "COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --^"; + print "SEND TO: R. C. LEEDOM^"; + print " WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.^"; + print " BOX 746, M.S. 338^"; + print " BALTIMORE, MD 21203^^"; + + print "CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN BORDERS^"; + print "LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS^"; + print "MUCH AS POSSIBLE WHILE USING MULTIPLE STATMENTS PER LINE^^"; +]; diff --git a/src/common/baseplatform.ts b/src/common/baseplatform.ts index 76b1a731..5248f69b 100644 --- a/src/common/baseplatform.ts +++ b/src/common/baseplatform.ts @@ -122,6 +122,7 @@ export interface Platform { getRasterScanline?() : number; setBreakpoint?(id : string, cond : DebugCondition); clearBreakpoint?(id : string); + hasBreakpoint?(id : string) : boolean; getCPUState?() : CpuState; debugSymbols? : DebugSymbols; @@ -226,6 +227,9 @@ export abstract class BaseDebugPlatform extends BasePlatform { clearBreakpoint(id : string) { delete this.breakpoints.id2bp[id]; } + hasBreakpoint(id : string) { + return this.breakpoints.id2bp[id] != null; + } getDebugCallback() : DebugCondition { return this.breakpoints.getDebugCondition(); } diff --git a/src/ide/views.ts b/src/ide/views.ts index d841f98f..82b7af5a 100644 --- a/src/ide/views.ts +++ b/src/ide/views.ts @@ -399,14 +399,19 @@ export class SourceEditor implements ProjectView { this.editor.execCommand('undo'); } - toggleBreakpoint(lineno: number) { + toggleBreakpoint(lineno: number) { + // TODO: we have to always start at beginning of frame if (this.sourcefile != null) { var targetPC = this.sourcefile.line2offset[lineno+1]; - /* TODO: breakpoints + /* var bpid = "pc" + targetPC; - platform.setBreakpoint(bpid, () => { - return platform.getPC() == targetPC; - }); + if (platform.hasBreakpoint(bpid)) { + platform.clearBreakpoint(bpid); + } else { + platform.setBreakpoint(bpid, () => { + return platform.getPC() == targetPC; + }); + } */ runToPC(targetPC); } @@ -1352,6 +1357,7 @@ class TreeNode { this.getDiv(); var text = ""; // is it a function? call it first, if we are expanded + // TODO: only call functions w/ signature if (typeof obj == 'function' && this._content != null) { obj = obj(); } @@ -1478,6 +1484,7 @@ export class DebugBrowserView extends TreeViewBase implements ProjectView { interface CallGraphNode { count : number; SP : number; + PC : number; calls : {[id:string] : CallGraphNode}; } @@ -1508,7 +1515,7 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView { } reset() { - this.stack = []; // TODO??? should continue across frames + this.stack = []; this.lastsp = -1; this.jsr = false; } @@ -1518,28 +1525,34 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView { switch (op) { case ProbeFlags.SP_PUSH: // need a new root? - if (this.stack.length == 0 || addr > this.stack[0].SP) { - this.graph = {count:0, SP:addr, calls:{}}; + if (this.stack.length == 0) { + this.graph = {count:0, PC:null, SP:addr, calls:{}}; + this.stack.unshift(this.graph); + } else if (addr > this.stack[0].SP) { + let calls = {}; + if (this.stack[0].PC !== null) calls[this.stack[0].PC] = this.stack[0]; + this.graph = {count:0, PC:null, SP:addr, calls:calls}; this.stack.unshift(this.graph); } case ProbeFlags.SP_POP: if (this.stack.length) { - var top = this.stack[this.stack.length-1]; + let top = this.stack[this.stack.length-1]; if ((this.lastsp - addr) == 2 && addr < top.SP) { // TODO: look for opcode? this.jsr = true; } if ((this.lastsp - addr) == -2 && this.stack.length > 1 && addr > top.SP) { this.stack.pop(); } - this.lastsp = addr; } + this.lastsp = addr; break; case ProbeFlags.EXECUTE: if (this.jsr && this.stack.length) { - var top = this.stack[this.stack.length-1]; - var sym = this.addr2str(addr); - var child = top.calls[sym]; - if (child == null) { child = top.calls[sym] = {count:0, SP:this.lastsp, calls:{}}; } + let top = this.stack[this.stack.length-1]; + let sym = this.addr2str(addr); + let child = top.calls[sym]; + if (child == null) { child = top.calls[sym] = {count:0, PC:addr, SP:this.lastsp, calls:{}}; } + else if (child.PC === null) child.PC = addr; //this.stack.forEach((node) => node.count++); this.stack.push(child); child.count++; @@ -1548,6 +1561,7 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView { break; } }); + if (this.graph) this.graph['_stack'] = this.stack; return this.graph; } } diff --git a/src/platform/zmachine.ts b/src/platform/zmachine.ts index 7808177b..8c62fc13 100644 --- a/src/platform/zmachine.ts +++ b/src/platform/zmachine.ts @@ -22,6 +22,7 @@ const ZMACHINE_PRESETS = [ { id: 'balances.inf', name: 'Balances' }, { id: 'museum.inf', name: 'Museum of Inform' }, { id: 'advent.inf', name: 'Colossal Cave Adventure' }, + { id: 'ztrek.inf', name: 'Super Z Trek' }, ]; declare var ZVM; @@ -38,9 +39,14 @@ interface IFZVM { pc: number; ram: DataView; stack: DataView; - read_data: { buffer?}; + read_data: { buffer?, routine?, time?}; handle_line_input(len: number); handle_char_input(charcode: number); + handle_create_fileref(fref: number); +} + +function debug(...args: any[]) { + //console.log(arguments); } class GlkWindow { @@ -72,11 +78,12 @@ class GlkWindow { } ensureline() { if (this.curline == null) { - this.curline = $('
')[0]; - this.page.appendChild(this.curline); - this.row++; - this.col = 0; - this.lines[this.row] = this.curline; + this.curline = this.lines[++this.row]; + if (this.curline == null) { + this.curline = $('
')[0]; + this.page.appendChild(this.curline); + this.lines[this.row] = this.curline; + } } } flushline() { @@ -86,24 +93,42 @@ class GlkWindow { addtext(line: string, style: number) { this.ensureline(); if (line.length) { - var span = $("").text(line).appendTo(this.curline); + // in fixed mode, only do characters + if (this.fixed && line.length > 1) { + for (var i = 0; i < line.length; i++) + this.addtext(line[i], style); + return; + } + var span = $("").text(line); for (var i = 0; i < 8; i++) { if (style & (1 << i)) span.addClass("transcript-style-" + (1 << i)); } if (this.reverse) span.addClass("transcript-reverse"); //span.data('vmip', this.vm.pc); + // in fixed mode, we can overwrite individual characters + if (this.fixed && line.length == 1 && this.col < this.curline.childNodes.length) { + this.curline.replaceChild(span[0], this.curline.childNodes[this.col]); + } else { + span.appendTo(this.curline); + } this.col += line.length; } } + newline() { + this.flushline(); + this.col = 0; + } + // TODO: bug in interpreter where it tracks cursor position but maybe doesn't do newlines? put_jstring(val: string) { + // split by newlines var lines = val.split("\n"); for (var i = 0; i < lines.length; i++) { - if (i > 0) this.flushline(); + if (i > 0) this.newline(); this.addtext(lines[i], this.curstyle); } } - move_cursor(col:number, row:number) { + move_cursor(col: number, row: number) { if (!this.fixed) return; // fixed windows only // ensure enough row elements while (this.lines.length <= row) { @@ -115,24 +140,23 @@ class GlkWindow { this.row = row; // get children in row (individual text cells) var children = $(this.curline).children(); - // truncate line, or add whitespace + // add whitespace to line? if (children.length > col) { - children.slice(col).remove(); this.col = col; } else { while (this.col < col) this.addtext(' ', this.curstyle); } } - setrows(size:number) { + setrows(size: number) { if (!this.fixed) return; // fixed windows only - this.flushline(); // truncate rows? var allrows = $(this.page).children(); if (allrows.length > size) { + this.flushline(); allrows.slice(size).remove(); this.lines = this.lines.slice(0, size); - this.move_cursor(0,0); + //this.move_cursor(0,0); } } } @@ -237,28 +261,40 @@ class GlkImpl { this.windows[1].addtext("** Game exited **", 1); } glk_window_clear(win) { - console.log('glk_window_clear', arguments); + debug('glk_window_clear', arguments); this.windows[win].clear(); } glk_request_line_event_uni(win, buf, initlen) { this.waitingfor = 'line'; this.focusinput(); + this.startinputtimer(); } glk_request_char_event_uni(win, buf, initlen) { this.waitingfor = 'char'; this.focusinput(); + this.startinputtimer(); + } + startinputtimer() { + /* TODO? + var rd = this.vm.read_data; + if (rd.routine && rd.time) { + this.vm['call'](rd.routine); + //this.vm.run(); + setTimeout(this.startinputtimer.bind(this), rd.time*10); + } + */ } glk_put_jstring(val: string, allbytes) { - //console.log('glk_put_jstring', arguments); + //debug('glk_put_jstring', arguments); this.curwnd.put_jstring(val); } glk_put_jstring_stream(stream: number, val: string) { - //console.log('glk_put_jstring_stream', arguments); + //debug('glk_put_jstring_stream', arguments); this.windows[stream].put_jstring(val); } glk_put_char_stream_uni(stream: number, ch: number) { - //console.log('glk_put_char_stream_uni', arguments); + //debug('glk_put_char_stream_uni', arguments); this.windows[stream].put_jstring(String.fromCharCode(ch)); } glk_set_style(val) { @@ -266,31 +302,31 @@ class GlkImpl { } /* glk_put_char(ch) { - console.log('glk_put_char', arguments); + debug('glk_put_char', arguments); } glk_put_string(val) { - console.log('glk_put_string', arguments); + debug('glk_put_string', arguments); } glk_put_string_stream(str, val) { - console.log('glk_put_string_stream', arguments); + debug('glk_put_string_stream', arguments); } glk_put_buffer(arr) { - console.log('glk_put_buffer', arguments); + debug('glk_put_buffer', arguments); } glk_put_buffer_stream(str, arr) { - console.log('glk_put_buffer_stream', arguments); + debug('glk_put_buffer_stream', arguments); } glk_set_style_stream(str, val) { - console.log('glk_set_style_stream', arguments); + debug('glk_set_style_stream', arguments); } glk_get_char_stream(str) { - console.log('glk_get_char_stream', arguments); + debug('glk_get_char_stream', arguments); } glk_get_line_stream(str, buf) { - console.log('glk_get_line_stream', arguments); + debug('glk_get_line_stream', arguments); } glk_get_buffer_stream(str, buf) { - console.log('glk_get_buffer_stream', arguments); + debug('glk_get_buffer_stream', arguments); } */ glk_char_to_lower(val) { @@ -308,10 +344,10 @@ class GlkImpl { return val; } glk_stylehint_set(wintype, styl, hint, value) { - //console.log('glk_stylehint_set', arguments); + //debug('glk_stylehint_set', arguments); } glk_stylehint_clear(wintype, styl, hint) { - //console.log('glk_stylehint_clear', arguments); + //debug('glk_stylehint_clear', arguments); } glk_style_distinguish(win, styl1, styl2) { return 0; @@ -322,62 +358,76 @@ class GlkImpl { return 0; } glk_select(eventref) { - console.log('glk_select', arguments); + debug('glk_select', arguments); } glk_window_open(splitwin, method, size, wintype, rock) { - console.log('glk_window_open', arguments); + debug('glk_window_open', arguments); if (splitwin) { - // only support status lines for now - if (method != 0x12 || wintype != 4 || size != 1) return 0; - $(this.windows[2].page).show(); + if (method != 0x12 || wintype != 4) return 0; + if (size) { + $(this.windows[2].page).show(); + return 2; // split window + } else { + return 3; // fake window + } + } else { + return 1; // main window } - return ++this.windowcount; } glk_window_close(win) { - console.log('glk_window_close', arguments); - if (win == 2) $(this.windows[win].page).hide(); + debug('glk_window_close', arguments); + if (win == 2) { + this.windows[win].clear(); + $(this.windows[win].page).hide(); + } } glk_window_get_parent(win) { - console.log('glk_window_get_parent', arguments); + debug('glk_window_get_parent', arguments); if (win == 1) return 0; else return 1; } glk_window_move_cursor(win, col, row) { - console.log('glk_window_move_cursor', arguments); + debug('glk_window_move_cursor', arguments); this.windows[win].move_cursor(col, row); } glk_window_set_arrangement(win, method, size, unknown) { - console.log('glk_window_set_arrangement', arguments); - // TODO? this.windows[win].setrows(size); + debug('glk_window_set_arrangement', arguments); + if (win == 1) this.windows[2].setrows(size); } glk_window_get_stream(win) { - console.log('glk_window_get_stream', arguments); + debug('glk_window_get_stream', arguments); return this.windows[win].stream; } glk_set_window(win) { - console.log('glk_set_window', arguments); + debug('glk_set_window', arguments); this.curwnd = this.windows[win]; if (this.curwnd == null) this.fatal_error("no window " + win); } glk_window_get_size(win, widthref: RefBox, heightref: RefBox) { - console.log('glk_window_get_size', arguments); + debug('glk_window_get_size', arguments); // TODO: made up sizes, only status line supported if (widthref) widthref.set_value(STATUS_NUM_COLS); if (heightref) heightref.set_value(win == 1 ? 25 : 1); } garglk_set_reversevideo(val) { - console.log('garglk_set_reversevideo', arguments); + debug('garglk_set_reversevideo', arguments); this.curwnd.reverse = !!val; } garglk_set_reversevideo_stream(win, val) { - console.log('garglk_set_reversevideo_stream', arguments); - this.windows[win].reverse = !!val; // TODO: per window + debug('garglk_set_reversevideo_stream', arguments); + this.windows[win].reverse = !!val; + } + glk_fileref_create_by_prompt(usage, mode, rock) { + debug('glk_fileref_create_by_prompt', arguments); + // TODO: support files? + this.vm.handle_create_fileref(0); + this.vm.run(); } glk_gestalt(sel, val) { return this.glk_gestalt_ext(sel, val, null); } glk_gestalt_ext(sel, val, arr) { - //console.log('glk_gestalt_ext', arguments); + //debug('glk_gestalt_ext', arguments); switch (sel) { case 0: // gestalt_Version @@ -750,7 +800,7 @@ class ZmachinePlatform implements Platform { this.resize(); } - resize : () => void; + resize: () => void; loadROM(title, data) { this.zfile = data; @@ -833,6 +883,7 @@ class ZmachinePlatform implements Platform { if (this.zvm != null) { root['Objects'] = () => this.getRootObjects(); root['Globals'] = () => this.getGlobalVariables(); + //root['VM'] = () => this.zvm; } return root; }