The embedding of the story within what was almost entirely free-form exploration & adventure across a huge galaxy was masterful.
You could feel how close the creators were to the edge of what was possible with the save game system: Basically, the disk was a memory image. As you played the game would rewrite itself, so if you got stuck there was no “reset”. The documentation was emphatic: Only play with a copy of the original disk!!
This was crazy! World gen is hard. Proc world gen is NP hard. Story driven proc world gen with persistence in 1986 was Kaku level brilliance.
Similar techniques apply today. Pregen like 100,000 stars. Give them names and locations in the galaxy, treat them as your "locations of interest" with a seed. The rest can just be another cloud of particles with no interest and if the player visits, you can RNG whatever based on the seed. No two systems can share a seed. They can, however, share a branch.
What I was never clear on was the degree of cherry picking they did. There were 800 worlds on something like nine disks, each unique and peppered with minerals and artifacts.
It's open world, clue based, and with some amazing plot. Like the article mentions, the ending twist alone makes it worth suffering through your notepad of a million little hints thrown at you throughout the game. It's also the sort of game you can beat in [literally] 5 minutes if you know everything ahead of time. So I would strongly recommend avoiding walkthroughs/spoilers. The whole game is about piecing together the puzzle of what's happening and it's amazingly immersive.
Generally a game that was way ahead of its time.
Starflight was my first experience with game patching. When I got my copy it would not run on my PC. I believe it was because I had an EGA graphics adapter. I wrote a letter explaining my problem and mailed it to Electronic Arts. They mailed a letter back. It said there should be a program on my computer named debug.com, and gave instructions about how to load the Starflight executable in it, replace a couple of bytes, and save it out. I followed the patch instructions and it got the game working! After which I spent many happy hours with my friends exploring the Starflight universe.
https://web.archive.org/web/20031218202130/http://www.sonic....
When you navigate those directory archives many of the files are missing. E.g.
https://web.archive.org/web/20030529230704/http://www.sonic....
Some design documents ARE there, e.g. "Specification of 3d display for starquest" : https://web.archive.org/web/20030719111039if_/http://www.son...
> The reason is that Starflight was written in Forth
I recently reverse-engineered another game from the 80's, and had a similar issue because it was written with Turbo Pascal.
The different tools didn't like quirks such as data stored inline between the instructions or every library function having a different calling convention.
Turns out the simplest way to handle this was to write my own decompiler, since Turbo Pascal 3 didn't do any optimisations.
This reminds me of Star Control 2, aka The Ur-Quan Masters
> The game influenced the design of numerous other games for decades after its release.
And in SC2 wiki page I see this:
> Once Reiche and Ford conceived Star Control 2, they would draw large inspiration from Starflight.
https://en.wikipedia.org/wiki/Star_Control_II
Never played Starflight before but seems right up my alley as SC2 is one of my favorite games
Edit: Just finished reading the rest of the readme. Very cool! I honestly knew nothing about Forth (just that it was a programming language) and now I want to play around with it.
80s - 80ths is a fraction (1/80).
Also - the publisher was Electronic Arts, already well-established at that point. Binary Systems were the developers.
Random edit: It's also how I learned the word obsequious.
¹ The name of the planet that the player starts on.
I don’t know when I started the game, but I finished it the summer after my freshman year, which is where I first got Internet access.
Thank you for posting this!
The end result of that is one doesn't write the program in "Forth" per se but in the domain specific language you create for the job. This is how Forth gets more productive than pure assembly language if the team documents things well and follows the prescribed system.
[1] Non-trivial optimizations were just starting to show up on big systems, but Microsoft C in 1985 was still a direct translator.
VAR1 @ VAR2 @ + VAR3 !
will execute this at run time: ; push address of VAR1
inc bx
inc bx
push bx
; fetch and jump to next primitive
lodsw
mov bx,ax
jmp [bx]
; push contents of variable
pop bx
push [bx]
; next primitive...
; push address of VAR2, next...
; push contents of variable, next...
; add top two stack elements, push sum, next...
; push address of VAR3, next...
; store to address, next...
There are some "low-hanging fruits", like keeping top-of-stack in a register, which the Forth used here doesn't do though. Or direct threading.Still, an incredibly stupid compiler could do better (for execution speed, definitely not size) by outputting similar code fragments - including all the pushes and pops, who needs a register allocator? - just without the interpreter overhead (lodsw etc.) in between them.
A compiler producing worse code likely didn't exist before today's glorious world of vibe coding ;)
A slightly better compiler would directly load the variables instead of first pushing their addresses, etc. You don't need to be an expert in compiler theory to come up with enough ideas for boiling it down to the same three instructions that a competent assembly programmer would write for this operation. And at least for this case, Forth doesn't even have the size advantage anymore, the code would only take 10 bytes instead of 14.
It's somewhat closer for 8-bit processors, the most popular ones had either no convenient addressing mode for stack frames at all, or an extremely slow one, like IX/IY on the Z80. For even more primitive CPUs, you might already need a virtual machine to make it "general-purpose programmable" at all -- for example if there is only one memory address register, and no way to save its contents without clobbering another one. I think that some of Chuck Moore's earliest Forth implementations were for architectures like that.
Also memory constraints could have been more important than efficiency of course. I'm not saying Forth is worthless, but it's not competing with any compiled language in terms of speed, and IMHO it also does away with too many "niceties" like local variables or actually readable syntax. Your mileage may vary :)
And modern systems compile optimized native code (VFX Forth, SwiftForth) but still remain fully interactive at the console.
There is still a functioning Forth interpreter implemented in the game. If they hadn’t removed all the word names, it would have been possible to debug at any time and analyze the program state and call functions live with real Forth code. Some crazy feature at that time.
[0] https://web.archive.org/web/20030906124225/http://www.sonic....
The other game this reminds me of is a game for the TI99/4a called Tunnels of Doom. It was a cartridge game that also had a floppy or cassette data load. It had a dynamic dungeon creation so every time you played the game you got a new unique experience. That would be an equally challenging one to reverse engineer due to the oddity of the GROM/GPL architecture in the TI99/4a.
Microblog: https://gamemaking.social/@SpindleyQ/115058149348319018