Commando disassembled – fully commented code

Commando
Commando

In order to create Commando 2084, I had to disassemble Commando. My original intention was to patch what was only needed and stop there. But I got carried away and I ended up analyzing and commenting the entire Commando code.

The commented code (that can be recompiled to generate the exact original binary) is here:

Findings – Level 2

Apparently, the original idea was to ship Commando with 4 levels instead of 3. There is a lot of code/data that indicates that a “level 2” (the levels that are shipped with Commando are level 0, 1 and 3) was in progress, or even finished.

All the actions, charset-mask, trigger rows are present. What’s missing is the map and a partial charset. The charset used for the main screen is likely the one designed for level 2.

Speculation from my part, “Level 2” was probably removed due to lack of time (?) or due lack of RAM to create a single-load game (?).

For more info about this level, search for “LVL2” in the main.asm.

Map and actions

  • Each level consist of 40×200 map.
  • Each level consists of:
    • Charset unique for the level: LVL0 at $C000, LVL1 at $C800, LVL3 at $D800
    • Each char in the charset contains a mask that indicates the background priority. See LVL0_CHARSET_MASK_TBL in main.asm.
    • A map: LVL0 is at $6000, LVL1 at $8000, LVL3 at $A000
    • List of actions: each action represents a sprite that must be created. But an action can perform non-related sprite tasks as well, like opening a door. See LVL0_ACTION_TBL in main.asm.
    • List of rows: when the master row index (seeV_SCROLL_ROW_IDX) matches this number, the associated action is executed. See LVL0_TRIGGER_ROW_TBL in main.asm.
    • Actions can receive an optional “sprite X position” argument. See LVL0_SPRITE_X_LO_TBL and LVL0_SPRITE_X_HI_TBL in main.asm

Sprites

The game supports up to 16 virtual sprites.

  • Sprite 0 is used for the hero
  • Sprites 1-3 are used for hero’s bullets
  • Sprite 4 is used for hero grenades
  • Sprites 5-15 are used for enemies, including its bullets/grenades.

Each sprite has:

  • X and Y coordinates (including X LSB and X MSB)
  • Sprite frame (which sprite to render). $FF is an empty frame.
  • Sprite color
  • Background priority (e.g: should it be rendered behind a tree?)
  • Animation type (see below). If it is 0, it means it is an empty sprite.
  • Extra variables that are used for different things. Varies from anim type to anim type.

Some enemies, like the motorcycle, take two sprites.

Animation type

An animation represents what the sprite should do during the game. For example, the animation type TYPE_ANIM_SOLDIER_BULLET, animates the bullet. See TYPE_ANIM_TBL in main.asm for the complete list of animation types.

An sprite can change its animation in runtime. For example, the TYPE_ANIM_SOLIDER_BEHIND_SMTH has certain logic. But when the hero is at the same Y position as it is, then it changes its animation to TYPE_ANIM_SOLDIER. Similar, the TYPE_ANIM_SOLDIER_JUMPING animates the “jumping” solider. But when the solider lands, it changes its animation to TYPE_ANIM_SOLDIER. Those are only two examples, but most animations change its animation type in runtime.

Animation type 0

When a sprite goes out of bounds, or an enemy dies, or an animation ends, that sprite is set with animation type 0, which is the TYPE_ANIM_SPAWN_SOLIDER.

What this animation does, is to create random enemies. And when an enemy is created, it changes in animation type to something different than 0.

That means, that when there map is “full” of enemies (all animation types are different than 0), the TYPE_ANIM_SPAWN_SOLDIER is not called. And when there many empty sprites, it gets called more often.

Collision detection

Collision detection is done in software (no hardware collision detection is used).

There is a routine to check whether the hero is hit (see CHECK_COLLISION) and another for enemies (see TYPE_ANIM_HERO_BULLET, TYPE_ANIM_HERO_GRENADE_END).

Each animation type has contains a mask (see f2544) that indicates whether it can collide with bullet, grenades, both or nothing. For example, when the soldier is in the trench, it can only be killed with a grenade.

Personal thoughts

From a high-level (architecture) point of view, the code is very well designed. It is pretty easy to add new types of actions, or create new levels, or modify existing ones with little change in the code/data.

From lower-level point of view, it seems that parts of the code could be improved (see FIXME in main.asm), specially regarding performance and flickers. Seeing many Level-2 traces, plus seeing certain bugs makes me think that the development team was under pressure to release the game ASAP (something fairly common in the gaming industry).

Additionally, it seems that the assembler used didn’t optimize the code to use zero page. For example, calls to:

    STY $FB,Y

are assembled to:

   STY $00FB,Y      ;3 byte variation, instead of the two-one.

 

7 thoughts on “Commando disassembled – fully commented code

  1. The removal of level 2 was documented in a Zzap!64 magazine’s interview with, IIRC, the musician, Rob Hubbard. The music and SFX code was 5KB so the programmer (Chris Butler) had to hurredly rip out Level 2 to fit in the music. He’d had just 6 weeks to write the game in order to have it released in time for Christmas 1985.

  2. Isn’t the part where you said “FIXME: Loop tried twice, probably a bug. Remove” a sorting routine? I think it’s like when loop is open, you sort twice. Or maybe I got it wrong. It’s been many years since I haven’t interacted any code like this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s