I know I’ve been pretty quiet so far this Retrochallenge, but I haven’t been completely sidelined. Since I got back from Convergence in Minneapolis, I’ve been digging into the Questron disks, trying to get the big picture of how the game is put together.
I figured the logical first step was to quickly look at each file on each disk in a hex viewer and see if I could glean anything about the file formats. I was surprised to discover that quite a bit of this game is written in good old BASIC 2.0. This is especially true on side 1, where all the code for the initial menus, instructions, character selection, and so on, is written in BASIC. But that’s not all – there are bits of the gambling games, some data entry subroutines, and even the intro and finale sections of the game itself, all scattered among various files of BASIC instructions. Pretty much anything that’s primarily text-focused seems to have been coded in BASIC.
This has given me something to think about. I went into this project with the idea that Questron was a pretty unsophisticated game. What I’m seeing so far is definitely an argument on that topic, I’m just not sure if it’s for or against. When you think about it, lots of modern games will write parts of their logic in scripting languages, so using BASIC in 1984 isn’t really that outré. And since the C64 stores BASIC files in a tokenized form, you could even compare it to running bytecode in some kind of prehistoric VM. Or not.
Adding to the sophistication is that there is some devious, devious stuff going on in this BASIC code. For example, here’s some interesting code from early in the game’s boot process:
500 restore:forn=0to36:reads:poken+49152,s:next:sys49152:poke49152,0:return 510 data76,14,192,67,79,77,66,73,78,69,68,46,77,76,169,8,162,8,160,1 520 data32,186,255,169,11,162,3,160,192,32,189,255,169,0,76,213,255
If you’re sufficiently old-school to have ever typed in a program listing from a computer magazine, you’ll recognize that this bit of BASIC is poking a machine language subroutine into memory (For example, the data values 76, 14, 192, are hexadecimal $4C, $0E, $C0, which in assembly language is “JMP $C00E”). The whole thing is a routine to load a file named “combined.ml” into memory. The tricky part is that “combined.ml” is loaded at location 49152, overwriting the code that was just poked into place to load it!
In a bunch of places, I found some lines that completely mystified me, such as:
I couldn’t make heads or tails of that SYS command. SYS is a BASIC command used to jump to a machine language subroutine – but it’s only supposed to take one argument: the address of the routine. The purpose of the other arguments seems straightforward enough: a file name, a drive number, and an address. It’s just not valid BASIC syntax.
How would the SYS command know about these extra arguments? How does the BASIC parser deal with this stuff that isn’t supposed to be there? I found one possible explanation at C64-Wiki: The routine called by SYS can make its own calls into the BASIC ROM to parse out the additional arguments. That’s… really pretty clever.
Here’s something that takes the cake, though. In order to read the BASIC files, I was loading them up in the VICE emulator. For example, I might see something like:
But when I printed out those same lines, I got:
Do you see how line 250 and line 260 have more text in the bottom picture? I couldn’t figure out what was going on until I looked at the file in a hex editor. Those strings of ‘.’ characters in the printout version? Those are backspace characters.
Let that sink in.
When the C64 displays those lines onscreen, it prints each character one at a time. So it prints the whole line and then backspaces to hide part of the line. But the BASIC interpreter still sees it.
Yeah, clearly the authors of Questron knew that someone like me would come along and try to figure out how they did what they did. And they decided to mess with that guy. That’s… man. That’s evil!