Jump to content
IGNORED

Decompiling advice with Decision in the Desert


Recommended Posts

Hey there,

 

For the longest time, I've been kinda obsessed with the Sid Meier wargames on the Atari (Crusade in Europe/Decision in the Desert/Conflict in Vietnam), and I've been trying to figure out the code. Partly out of curiosity, and partly to figure out why the airplanes aren't ever worth a damn (every time they attack they complain about the enemy being too strong and then go into reserve mode).

 

So using a trusty emulator, I've loaded into the actual game part (ie, scenario loaded) and then taken a memory snapshot to disassemble. At which point, I'm coming up with a blank -- the code seems really weird.

 

It seems to be using a tonne of jump tables to do all the logic (which confuses the disassembler), and uses the X register along with the Zero Page as a kind of secondary stack (pushing and popping in sets of three). Pretty funky stuff, and it's all pretty labyrinthian.

As looking through the code isn't helping by it's own, I've tried to use breakpoints to isolate the code at specific points and thus figure out where these functions are. So I've tried hunting down the joystick routines.

 

I've set breakpoints at STICK0/1/2/3, STRIG0/1/2/3, PORTA and PORTB. However, they're just not triggering in the game code. PORTA is only firing in the ROM routines which uses that to set the STICKn shadow values. Yet the game responds to the joystick just fine. Obviously I'm missing something - does anyone know how it could get the joystick's values without triggering the breakpoints in Atirra?

 

I've also done a binary search for STICK0's values in the code, and found five references in the RAM. However, these are only in data lists which are referenced en masse in the code but doesn't seem to ever go into the ZP for indirect loading.

 

Similarly, I've tried looking for any keyboard hooks (since the game also works using the cursors and a handful of keyboard commands) but again am drawing a blank.

 

Does anyone have advice for reverse engineering, or any ideas at what I'm missing? This is my first attempt at reverse engineering an Atari game (have previously done Covert Action on DOS, which was quite a bit easier and also quite fun) and I'm probably just ignoring something incredibly obvious.

Link to comment
Share on other sites

Some of Sid Meier's games and probably a good number of strategy type games were done using compilers rather then being written in Assembly.

 

Weird "software stack" could point to that also. If it uses floating point maths then that's another indicator. If it has lots of JSRs that can be another.

Joystick reading might be shadow or direct from the hardware.

Keyboard might be simply checking the CH register that the OS maintains ($2FC), might be by CIO call (you'd likely hear keyclicks), might be by redirected keyboard IRQ or might be by reading the Pokey registers directly.

 

Reverse engineering advice - it's usually a good idea to get a disassembly of the program before it runs. IDA Pro does a great job of building disassemblies but the free tools around can be useful as well.

It can be helpful at times to do stuff with emulation as well, it's often easy to verify the function of a work variable by modifying it on the go and seeing if the results are as expected.

 

If it happens that it's a compiled program, then I suspect the overall job might become harder. All that indirection and subroutine calls makes for a complicated mess.

Link to comment
Share on other sites

Thanks for the advice. Yeah, it really does seem to be the work of a compiler. In many ways it's kinda interesting to see what it's generated in a mechanical way, but it definitely makes disassembling into a bunch of spagetti code.

 

I'll probably try going the route of narrowing down the unit data and try changing memory until something changes, then follow the code from there. It's definitely an interesting challenge.

 

Hmmm, I've just upgraded Altirra and this time the breakpoints on STICK0 have actually fired. I wonder if there was a bug in the older version I was using on (Indirect,X) accesses?

Link to comment
Share on other sites

Bingo -- from research it looks like it was written in Monarch Data System's ABC compiler. A BASIC compiler which compiles to p-code.

 

Huge thanks to Kroah, who has done a decompiler to get these files back to basic. I've now got the original BASIC code for the game engine which I can investigate.

  • Like 1
Link to comment
Share on other sites

In case anyone is following this and is interested, I've found some interesting things going on.

 

The game seems to have two main ABC compiled basic files going on. The first WAR.ABC holds the front end menu which loads in the scenario list, and lets you pick the options. This then loads DRIVER.ABC which is the generic main game handler. What's interesting is that this basic program just handles displaying things on the screen and doing the keyboard/joystick inputs. To actually handle the game logic, it calls a bit of machine code with an index (and potentially setting some variables). This piece of machine code then uses a index to pick a kind of script from SID.WAR which it then parses. This script doesn't appear to be ABC-based (but I could be wrong), but instead is a series of instructions which either:

 

* point to a function to call

* point to a function to call, passing in the next instruction byte as a variable

* push a variable onto a special data stack

* pop the special data stack onto a variable

 

I haven't found in which file holds the functions which these instructions call.

 

This system allows basically the game to reuse the basic parts for each one in the series, whilst only then needing to change the data files and this WAR.SID file to alter the game logic. I'm now going through each of these scripts (there's only about 18 of them). Everything is pretty much falling into place now which is encouraging. However, the script which deals with doing things with a unit (so moving/attacking/defending/etc) is huge (as expected). Unfortunately that'll be the bit I'm interested in. Doh!

  • Like 2
Link to comment
Share on other sites

  • 4 years later...

Hi,
I've been trying to reverse engineer "Crusade in Europe" semi-recently and I've found this thread which seems to contains similar finding us I have.
I've managed to find a bit more information about this "inner" script language.
I'd guess it's a bytecode being a result of compilation of internal Microprose programming language mentioned here: https://www.atarimagazines.com/rom/issue3/interview.php
Implementation of bytecode functions are inside SIDTRAN.OBJ flie. First part are memory offsets of the functions and later there are machine code implementations.
Those functions range from standard stack language constructs: PUSH, POP, ADD, MUL, ... to higher level constructs such as various JUMPS, to opcodes implementing FOR LOOPS,
to opcodes that seem to be specific and common to all the Command Series games (Crusade in Europe, Decision in the Desert, Conflict in Vietnam).
The opcodes that are game specific opcodes, that I've found so far are:

  • find unit or city at specific coordinates
  • count number of adjacent units of given coordinate
  • compute some kind of evaluation function for a coordinate

The last of those functions is quite complex and I dont't follow its logic very well.
My limited understanding is that:
for each hex adjacent to given one, it computes four element bitmap:

 

  1. is_there_enemy unit there
    1. is_there allied unit or "good"? terain there
    2. is there an enemy unit at either previous adjacent hex or next adjacent hex
    3. is there an allied unit at either previous adjacent hex or next adjacent hex
    4. it treats this 4-element bitmap as a number [0;15] and looks up a number (score?) [0-5] in a hardcoded array for given bitmap
  2. it counts how many of each scores appeared among six adjacent hexes
  3. it return sum of coefficients for all [score_value, score_count] pairs

Coefficients seem to taken from HEXES.DTA file (at least that's what I found in one case). Probably it may use different coefficients for different orders or other factors, but I couldn't verify it.

I don't know how to progress further.
My initial plan was to understand and rewrite the whole logic in a higher level language, but I seem to lack skills that would allow decompiling this custom language to a more understandable format.

Later I thought that maybe I could create an engine which would allow playing games using modern controls and maybe modern UI.
It would consist of writing interpreter for this custom bytecode and writing a UI around it.

 

Unfortunately, lately I have pretty limited time for this, so we'll see.


Maybe I should just ask Sid Meier for the source code? :)

 

Best,
Piotr


 

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...