the oregon trail ii birthday paradox

a very merry unbirthday

One of my longest-running projects, and certainly one of my most frivolous, is my foray into reverse engineering the 1995 educational game Oregon Trail II. Why Oregon Trail II? Couldn't tell you. But I can tell you a few things about the process.

In our last dispatch, we covered a bug that gave your rugged cross-country journeyer the power of Christ. Today's post isn't quite so supernatural. It's about a bit of secret unused functionality -- and as any game designer or The Cutting Room Floor enjoyer knows, secret unused functionality can be anywhere and involve anything.

(No birthday in sight.)

One of the selling points of Oregon Trail II was the depth of the underlying game simulation compared to its predecessor. The official strategy guide rhapsodizes over this for several pages, from the panoply of period-accurate diseases and the modeling thereof, to the carefully wrought intricacies of wagon axles.

Most of the simulation-fiddling happens behind the scenes, invisible to the player. But there are still plenty of decisions to be made for the min-maxers and Bartle diamonds of the world. On the intro screen, after you click New Game, you're brought to the quite thorough character creation screen above. See those tabs to the left? There's more behind them, too.

Maybe you don't want to think about all that. Maybe you're a teacher using this in a classroom, trying to race the second-period bell, Maybe you're working on a reverse engineering project that requires you to restart the game constantly to test something, and maybe it's really annoying to keep filling that screen out. For you, there is Quick Start.

The Taylor administration

Quick Start randomizes all of the values from the New Game screen... kind of. There are several unspoken differences.

Some of the differences are meant to make the game easier. Quick Start will only choose from the first few professions, which start with more money. You always leave in the spring, giving you plenty of time to avoid winter storms. The game also buys gear for you: a sensibly sized farmwagon, a trusty herd of 6 or 8 oxen, and the standard five months' package deal of supplies (though you can always go back to town and buy more, or get rid of the stuff if you're feeling wasteful).

Some differences are less noticeable, like age. Normal character creation rolls a base age for all six potential party members, with some extra constraints: for instance, party members 3 and 4 will be younger, and party members 5 and 6 will be older. That base age is further scaled until your party comprises the full human lifespan, from children to the elderly.

Quick Start does the same age rolls, but if it does the scaling, it does it somewhere else. And when looking for wherever else it might be, I noticed something weird.

In the decompiled C file, a lot of the character creation code is repeated. This makes the Quick Start code easy to find once you've found its counterpart. There are several random rolls, as you'd expect, to set all those variables. They generally match normal character creation. But then there's this. (Function renaming mine, but I've removed the comments.)

eax105 = boundedRand(ecx96, 1, 12, 1, v56, v14, v12, v10, v104); *reinterpret_cast(&v106) = *reinterpret_cast(&eax105); eax108 = boundedRand(ecx96, 1, 28, 1, v56, v14, v12, v10, v107); *reinterpret_cast(&v109) = *reinterpret_cast(&eax108);

For the longest time, I had no idea what these were. They happen shortly after the age rolls, and the bounds are similar, but they're not age. The bounds are way off the mark for things like party health -- 28 health would mean you were next to dead.

Could they be indices to some array of character options? Probably not; nothing character-related that I could find has 28 options to choose from. (And also there'd need to be an adjustment somewhere for zero indexing, which there isn't.)

Whatever these values are, they get stored alongside the rest of the character data. See, here they are!

(Our protagonist is a Scorpio, it seems.)

The highlight indicates this is the character at index 0, i.e., yourself. Red is age; blue and green are these mysterious values above. And if you didn't already know what to look for, you'd never find them.

The epiphany came later. Pick a number between 1 and 12 -- hey, that's how many months there are! 28 -- that sounds like February 28! I checked a few random characters in the debugger: everything was, and remained, a valid birthday. In Quick Start only.

A natural question, at this point: is your birthday used for anything? As far as I can tell, no. I still haven't found any place in the gameplay code where these values are directly read once your character is created. Nor are they written to again; if a character's birthday passes in game, the character's age remains unchanged. The birthday is just there, a vestige of... well, of something.


postscript

If you'll allow me a philosophical digression: This game has enough nostalgia value that it gets streamed and Let's Played semi-frequently. One older video showcases a glitch, where resting until 1862 or so puts your party into limbo, stuck between life and death:

The explanation for this is pretty mundane. After 400 days on the trail, you start losing health, presumably because your party is growing weary and overtaxed -- but perhaps also so the designers could avoid the implications of an unchanging world.

Throughout the game, you can find newspapers. Each newspaper, when you click it, will display a headline related to the current date. Some of these are historical, like "Whigs Nominate Henry Clay for President." Some of them are jokes, like "Local Man's Cow Can Count to Twenty" (and its inevitable follow-up "Famous 'Counting Cow' Revealed as a Fraud"). Some sound like jokes but are actually historical: "Seagulls Save Mormon Crops from Locusts."

The headlines end in December 1960: "South Carolina Secedes!" But the game doesn't have to end. Time will march on dutifully until 1964 -- specifically, July 7, 1964 -- after which all landmarks become unavailable and travel becomes impossible. (No, I don't know why it's 1964.) After 1964, things get weird, as showcased in another glitch video:

But otherwise, nothing's stopping you from resting, indefinitely, as our world passes your world by. The Civil War happens in real life but not in-game. Technology advances, but not for you. What's more fitting for that world, then, than a birthday that never arrives?


footnotes

  1. unless you happen to be in the Sierra Nevadas in October 1846; the blizzard that doomed the Donner Party is hardcoded into the game 🔼
  2. specifically: children under 16 are aged up 5 years, and everyone else is scaled to a somewhat higher multiple of 5; no, I don't know why the game doesn't just pick an age and that's it 🔼
  3. (It helps that this section of the code also populates the window, and thus contains a lot of strings like "A Trail Guide".) 🔼
  4. basically, party members have hit points that slowly erode and/or recover 🔼
  5. well, not just that; there are some memory addresses in there, among other non-birthday-relevant things 🔼
  6. Why 28 and not 31? To ensure the birthday is valid. There's code elsewhere to handle leap year, but this doesn't use it; February 29, January 30, December 31, etc. are simply impossible birthdays. Sorry, New Year's babies. 🔼
  7. that is, unless you die 🔼
  8. In the executable itself, there's also this self-deprecating fallback headline: "Dr. Wayne Studer Accused of Software Design!" 🔼

return to blog index, or return home