I'd like to blog about this. Maybe I'll take some notes first and then turn the notes into a post?

Click here if you want to play Super Star Trek in your browser! (Someday I want an iframe embed of the game here.)

I should also upload the game to itch.io or something!

What is Super Star Trek?

Super Star Trek is a circa-1978 roguelike space combat game set in the original Star Trek series universe. It's implemented in BASIC and offers an ASCII art interface to a roughly turn-based game loop.

The goal is to explore a galactic grid of randomized space sectors, in order to hunt down and destroy all enemy Klingon ships before the given deadline elapses. Time passes during ship movement, repairs, and firing weapons - so there's pressure to be efficient in exploration and there's a cost to taking damage or using up ship resources.

The ship has limited energy and an array of functional systems like scanners, shields, phasers, torpedoes, warp drive, and a library-computer that offers a handful of utility functions. Any of these systems can be damaged & disabled in combat, which can radically alter game play at any point. Systems also have a chance to fail, improve, or be repaired during travel.

Finally, there are a number of Starbases scattered around the galaxy that can effect repairs and replenish the ship on docking - though these need to be discovered through exploration just like enemy ships.

All-in-all, I think Super Star Trek is an impressively sophisticated game considering the limitations of BASIC and the computers on which it originally ran. It also inspired a few other games - such as Atari's Star Raiders, another personal favorite of mine!

Super Star Trek and Me

It was probably around 1983 when I first encountered Super Star Trek as a type-in program listing in David Ahl's BASIC Computer Games.

I chased any excuse to get a computer keyboard under my hands as a kid. I'd play a typing tutor just to get to push the buttons. So, as a text-based type-in game, Super Star Trek demanded a lot of reading, typing, and retaining little scraps of information like directions and distances. At a time when I was making cardboard starfighter cockpits, the whole thing made me feel like I was role-playing a starship captain engaged in technical, tactical combat just like in the TV show!

It was one of the longer listings in the book, so there was plenty of opportunity to mess up while typing it and get familiar with fixing the code. And since I was working on borrowed computers when I first got that book, I typed it in more than once and on more than one model of computer.

Over the years, after I finally had my own Commodore 64 with a disk drive, I tried tweaking and expanding it. Played with the random numbers to make it easier or harder. Made the galaxy bigger for longer games. Tried implementing saved games. Changed all the references to Star Trek: The Next Generation - Romulans instead of Klingons, Data instead of Sulu, etc. Even tried to make it into an isometric 3D thing, but I never quite made that work.

Knowing the code behind the game, running through all the interactions of typing commands, letting the game thoroughly live in my head - it was pretty magical for a tiny nerd who loved taking things apart and wanted to go to space.

Why Super Star Trek now and why JavaScript?

Back in February, I saw a Tweet from Jeff Atwood asking "What if.. we re-built these two books, with the programs rewritten and rearchitected into well written examples of Ruby, Python, JavaScript, and http://VB.NET versions of each game?"

Looking at the repo on GitHub, I saw the directory for Super Star Trek and had a big spike of nostalgia. I tweeted a reply, "I am very tempted to bang my head on multiple versions of Super Star Trek here".

I picked JavaScript to start with because it's my current daily-driver language and also for the irony - after all, Atwood's Law states: "any application that can be written in JavaScript, will eventually be written in JavaScript."

The process took me a couple weeks longer than I'd planned, but I got there in time for MAR10 day.

Transliteration

One way I could have handled porting Super Star Trek from BASIC to JavaScript was to have started with a blank slate. Just kind of read through and stare at the BASIC and then write JavaScript roughly inspired by the original. That probably would have been fine.

But, thanks to that aforementioned nostalgia - and remembering how much time I'd spent with the BASIC code as a kid - I wanted to pay another visit to the old neighborhood. So, I started with transliteration - essentially straight manual conversion from BASIC to JavaScript syntax with only minimal changes to structure. I even kept all the upper-case, single-letter global variables.

I even spent an hour or so trying to untangle a bit of goto spaghetti for calculating distance & direction into an attempt at not entirely garbage JavaScript - only to punt and fall back to a simple `Math.atan2()` call when I couldn't quite debug it.

Modernization

  • Renamed all the single-letter variables to more descriptive things
  • Converted most arrays from 1-based index to 0-based - or objects with constant-based property names.
  • Gathered up all the global variables involved in tracking game state into a single global gameState object
  • Squashed all the other global variables down to local function scope
  • Tried to extract all the magic number constants into a global gameOptions object
  • Tried to tidy code in many spots without totally rewriting or changing game behavior - not sure how well I did in that, probably introduced a bug or two
  • Got carried away in a few spots using regexes to split up the sector map string
  • Hacked together a bit of I/O abstraction to let the game run within both node.js CLI and browser-based xterm.js shells

Restraint

  • I kept it all as one big module, rather than splitting it up into more sensible submodules.
  • Only fixed one actual game logic bug.
  • Tried not to fix many typos in game text.
  • Left all the strings in original uppercase format
  • Left the galaxy map as a 1-based array - switching to a 0-based array seemed like it would touch a lot of assumptions in the code, and I was too lazy to follow through on that
  • I'm annoyed that coordinates throughout the game are in (Y,X) order, rather than (X,Y) - but I tried to resist the temptation to rework that everywhere

Clever bits

After getting the game running and updated in JavaScript, I was refreshed on a bunch of the clever bits of the code that had wowed me almost 40 years ago. (Yikes!)

The game uses the same data for both display and game state in bunch of places.

The galaxy map is a 2-dimensional array of three-digit numbers encoding the number of enemies, starbases, and stars in each sector.

These numbers are printed directly in long-range scanner readouts. Then, as your ship moves between sectors, the number is split into decimal places and used in the code that populates space with objects - the locations of things are random within the sector, but their amounts are consistent on repeat visits (unless destroyed, of course).

There's also a "CUMULATIVE GALACTIC RECORD" readout in the computer menu that keeps track of every sector you've discovered. The nice thing about this is that it's just a copy of the hidden galaxy map that gets filled in over time.

The current sector map is a string of 192 characters. The string is treated as a grid of 8 rows with 8 columns. Each cell composed of 3 characters - so 8 x 8 x 3 = 192. Entities in the sector map are ASCII-art representations - i.e. * for a star, +K+ for an enemy, >!< for a starbase, and <*> for your ship.

To build the short-range scan readout, this string is split up into lines of 24 characters and printed along with vital ship details.

But, when it comes to collision detection for weapons and ship movement, string comparison is used. As a torpedo travels along, each grid cell along the path is checked for an ASCII-art occupant in the string. A hit on an enemy causes them damage, a collision with a star is a wasted torpedo.

Making these chunks of data all work double duty really seemed like neat tricks, back when I first started wrapping my 8-year-old head around the code.

Next steps

  • ANSI color?
  • Vector Trek?
  • Further re-org of the code into modules?
  • Add some features of my own?
  • Play more with gameState
    • Load / save games
    • Import canned game scenarios
  • Play more with the gameOptions object
    • Range of difficulty settings
    • Themes to swap in replacement strings - maybe ST:TNG? B5? Battlestar Galactica?