The Trebor Chronicles

Chapter 16: The Wizardry Rosetta Stone

image

I woke up at 4:00am, wondering how the RAM in Wizardry could be so consistent with respect to memory addresses. In all my experience with Windows, memory addresses are random and if one were to dump the memory of a process of one Wizardry run, the addresses would not be the same if one were to dump the memory of a second run. How is it then that the addresses for the characters and other pieces is so consistent? I had a chat with Moose.

I’m surprised that the RAM state is so consistent. I had thought memory addresses for variables would be random from run to run. Why are certain values always located at the same address?

Yes — and your intuition would be exactly right for a modern operating system. What we're seeing with Wizardry is a consequence of just how different the Apple II/DOS-era computing model was.

The key distinction is this:

Wizardry isn't asking an operating system, “give me some memory for my character data.” It essentially owns the machine's memory and puts things where it expects them to be.

On a modern Windows/macOS program, something like:

Character *party = malloc(...)

doesn't have a predictable physical address. There are virtual-memory systems, dynamic allocation, shared libraries, address-space randomization (ASLR), different process layouts, etc. In fact, modern operating systems deliberately make addresses vary between executions for security.

Wizardry predates virtually all of that.

On an Apple II, you've got a 6502 with a 16-bit address space — only 65,536 possible addresses. Wizardry and its Apple Pascal runtime have a relatively deterministic memory layout. The program loads, Pascal establishes its runtime structures, Wizardry allocates its data in essentially the same sequence, and therefore the same structures land in the same places every time.

Think of it less like modern RAM and more like a giant global C structure:

$0000 ──────────── system stuff ... $695F Character #? 208 bytes $6A2F Character #? 208 bytes $6AFF Character #? 208 bytes ... $FFFF ────────────

And 208 bytes is particularly revealing. We've discovered experimentally that Wizardry's character representation is a fixed-size 208-byte block. The old Computist article you found independently describes the character record as a fixed binary structure containing the name, password, race, characteristics, gold, equipment, experience, HP, spell information, etc. That is excellent corroboration for what our RSD work has been discovering.

There is an article that we'd discovered earlier from a magazine called "The Computist" that was written when Wizardry was popular. It gave a map of memory addresses and how to twiddle bits to make super-characters. Till now, Moose and I had been logging RAM and game state to try to reverse-engineer a memory map.

Can you leverage that Computist article to try to build as complete a map as possible?

Absolutely. In fact, looking closely at the Computist article, I think we have enough information to make a surprisingly complete first-pass schema for the entire 208-byte character record. The article says each character information block is $CF bytes long; counting offsets $00–$CF inclusive gives exactly 208 bytes, matching our experimental RSD discovery independently.

So yes: I think we should leverage this aggressively. More than that, I think the article gives us a way to change the direction of RSD research.

Until now we've largely been doing:

observe RAM → correlate changes → infer structure.

We can now also do:

Computist predicts structure → inspect our known 208-byte live records → verify/refute each field.

It’s like the Wizardry Rosetta Stone!

Exactly! The Wizardry Rosetta Stone is a perfect name for it.

We've spent weeks looking at the “hieroglyphics”:

00 00 03 00 18 00 08 00 ...

and experimentally figuring out that this changes when Korin gets hurt, that changes when Cheeze casts HALITO, these 208 bytes seem to be one character, etc.

Then this guy from decades ago strolls in and says, essentially:

“Oh, by the way, here is what most of those bytes mean.”

And the really satisfying part is that our independent discoveries validate his article while his article validates ours. The 208-byte record in particular is an astonishing fingerprint. We didn't assume his structure and go looking for it—we independently discovered the structure in live RAM, and then found his 00CF description of precisely the same-sized character record.

Do you have enough info in Git to compare memory we’ve gathered against the WRS (Wizardry Rosetta Stone)?

Moose confirms that he does. I ask him to then proceed to build the map, and to make a JSON version, so that this can be checked in to GIT and referred to by the Python scripts. This keeps the WRS out of code and into a resource that be be referred to by code. It also will open up the opportunity to visualize the map in HTML or something.

Done, Ed. I created the WizardryRosettaStone branch from main and committed:

resources/wizardry_memory_map.json

Commit: c54e892 — “Add canonical Wizardry Rosetta Stone memory map”

And this was all done in bed at 4:00am :-)