Comparisons to first Pitfall game
When I first learned about this game, I was still using an Atari 2600 console before I even had the experience of owning my very first personal computer. I was already used to the joystick controller and style of the Atari VCS games in that era. I was blown away by how much more they added to the game, including some scrolling screens when Pitfall Harry descended further below into the caverns.
Some of the same game enemies remained the same such as the scorpion. Newer adversaries such as a bat, vulture, frogs, and electric eel added to the fun and gameplay.
It also remained true to the original version and the rewards were still gold bars. However, there was also a stolen Raj diamond in this episode that would kept you on your toes as you searched deeper into the caverns, swimming in rivers, and climbing to extreme heights with the end in sight. You were also supposed to capture the rat (seen at the game’s beginning) . A perfect score is reached at 199,000. This is taken into account that you don’t lose any points along the way with enemy conflicts.
I also decided to include the full source code for Pitfall II in this section. It can be found in the PDFs menu at the top, but I wanted to be sure that my visitors would have immediate access to the decompiled assembly listing below. Just click on the image in this section and you will get access to. It will open up in a separate menu a PDF document that can be viewed from top to bottom. I hope this encourages many readers to start their own series on reverse engineering. I have found few websites out here that even attempt to tackle this.
Feel free to use the VICE C64 Emulator below to load up Basic programs or files that were downloaded on this page.
To load a file, click on the menu C64/Attach D64 or you can also drop and drag a .D64 image onto the VICE window and it will load.
Learning how the game works
One of the most important things you can do before you start to reverse engineer any game is play it. Learn how it works, who are the game characters, goal of the game, etc. This will help you keep a perspective as you begin to explore the strange code known as assembly language. Also it wouldn’t hurt to have some skills in programming already.
Please understand this is no perfect solution to the game, will obviously contain errors since I do not own the original source code. Rather I am deriving my facts on what I know about the game, my experience with assembly language, and just learning what the code may be doing.
There are also going to be a lot of unanswered questions, since once again I am no master at this. Rather it has always been my curiosity that drives me deeper into code to explore strange worlds where no man has gone before. Sorry I couldn’t resist that statement. Seriously though, it will be fun as we start to unravel mysteries that went down in a sinking ship after the game designers pitched most of their code to the trash. This was common for many game companies, usually after a liquidation to prevent anyone from reproducing their work.
The Pitfall II C64 Source Code
For this series since my website is centered on the Commodore 64, we are going to be analyzing the assembly language code on this machine. The Commodore 64 version was not bad, compared to the Atari 2600 predecessor. This one obviously could take better advantage of multi-color graphics due to the VIC chip that managed 4 colors per square.
So what I’d like to do first is present my discovery finding when I disassembled this code. A lot of things I arrived at by tweaking values and then running the game afterward. Some of this logic is based on my experience with how the Commodore 64 works, such as the loading of the game sprites, and other cool things.
Reviewing the disassembly
So exploring the code from top to bottom, I was able to pinpoint where the interrupts existed, the sprite colors, the sprite loader, the screen drawings, and some other game evaluations as listed below:
Memory and code review
This game appears be using Bank 1 to relocate an empty area for sprites, the game screens, and program code. A bank is required since the Commodore 64 can only access 16K of memory for its graphics. By moving memory to start at register $4000 through $7FFF (decimal 16384 – 32767), there is plenty of room for design and the map graphics. Many commercial video games for the Commodore 64 followed this same style.
The following code below breaks the game down into the memory registers and assumed functionality of the game segments. The complete disassembly is still under construction, so your patience is appreciated as this extraction continues forward. Also taking tips from the YouTube spotlight at the GameSpot channel for David Crane is helping me learn how he created the original Pitfall.
C64 Sprites defined
The game sprites locations were revealed when I loaded the Vice snapshot file into a Windows tool called Infiltrator. This also helped me understand much later that it was necessary to move memory to accommodate so many sprites and graphics. You will notice that these sprites are seen in black and white. This is a default setting for the tool when the multi-color is not turned on. Besides I figured it would be easier to make out some of the pixels this way. I will later convert this to PDF to save scrolling through long pages. 🙂
Game Maps and Screens
When I loaded up the Pitfall II game in the tool Infiltrator for the Commodore 64, after some time searching through memory locations, I finally came across screens that fit together. Therefore I was able to see that a specific map that starts the game (likely replicated throughout the game) started at $7C00 – $7fE7 (31744 – 32743) and the character set read from $7000 – $77FF (28672 – 30719). Seen here is a screenshot of that starting map. This is helping to know when you are beginning to disassemble a game at the machine level.
Another thing I found interesting upon close observation when looking at this in memory here was to see the screen that controls the levels that scroll down. When Pitfall Harry begins to descend down a screen a similar screenshot is seen like in this example. I’m not completely convinced yet, but I believe David Crane (Tim Shotter for the C64 version), may be reusing a screen over and over to save RAM. Also being under tight timeframes and restrictions they had to churn out games pretty fast while staying as accurate as possible. The memory locations here read the screen between $7800 – $7BE7 (30720 – 31719) and the character set range is $7000 – $77FF (28672 – 30719).
Game Source Disassembly
- Perceived labels:
SPRITE_X_POS = 25
SPRITE_Y_POS = 26
GAME_DEMO_TIMER = 7
JOYSTICK_STORED = $48
SPRITE4_SPEED = $68 ; Pitfall Harry
SPRITE4_ANIM_FRAME_SPEED = $0A - SPRITE4_ANIM_FRAME_INWATER_LEFT = $a7
SPRITE4_ANIM_FRAME_INWATER_RIGHT = $a8
* = $8009 (32777 – program counter start)
- $800A – Interrupt 1: Reset Vector LDA #$<318, LDA #$>319
$801F – Sprites X Position cleared (starting address), $D000,X
$8028 – Joystick bit values cleared, $DC00
$802E – Setup the VIC bank, $DD02
$803D – Appears to be capturing joystick bits, $D011
$8048 – Raster scan line interrupts, $D011
$8057 – Raster Position (current raster line), $D012
$808A – Background colors 0 – 2, $D021 – $D023
$8099 – Begin loading the sprite designs and shape data, LDA #<$4000, LDA #>$4000
$8172 – Game title screen – Activision presents… Adapated by Tim Shotter
$81C0 – Points to hi/lo bytes of screen memory at 1798 – likely to store screen data for use in the game, <$0706, >$0706
$8206 – Sprite data for walls at the left/right far edges
$83F1 – Sprite 0 and 2 X position, $D000,$D004
$83FE – Sprite 1 Color, $D028
$8403 – Sprite 7 Horizontal Expansion, $D01D
$8415 – Sprite Multicolor Color Registers 0-1, $D025 – $D026
$8421 – Sprite Multicolor Mode (activation), $D01C
$8426 – Sprites 3, 4-5 Colors, $D02B – $D02C
$8430 – Sprite 3 X position, $D006
$8435 – Sprite 3 Color, $D02A
$843F – Set Voice 1-3 Attack / Decay Cycle Control, $D405, $D40C, $D413
$844A – Set Voice 1-3 Sustain / Release Cycle Control, $D406,$D40D,$D414
$8453 – Select Filter Mode and Volume, $D418
$8458 – Interrupt 2: Unknown, LDA #<$9CBF, LDA #>$9CBF
$8464 – Raster scan line interrupts, $D012
$8469 – Turn off Interrupts (Interrupt Mask Register), $D01A
$846C – Interrupt Request Register, $D019
$8475 – Current raster position, $D012
$8482 – JSR $9448 (Subroutine)
$848E – JSR $943D (Subroutine)
$8491 – JSR $92EO (Subroutine) – Screen pixel shifting (scrolling)
$8494 – JSR $9300 (Subroutine) – Screen pixel shifting (scrolling)
$84A6 – JSR $9300 (Subroutine)
$84BC – JSR $9448 (Subroutine)
$84C1 – JSR $9448 (Subroutine)
$84CB – JSR $9448 (Subroutine)
$84D0 – JSR $9448 (Subroutine)
$84DE – Data for “Designed by David Crane” (title screen)
$851B – Data for “Adapted by” (title screen)
$8523 – CIA1: Data Direction Register A, $DC02
$8528 – CIA1: Data Port Register A, $DC00 (keyboard/joystick 2)
$852C – CIA1: Data Direction Register B, $DC03
$852F – CIA1: Data Port Register B, $DC01 (read joystick 1)
$8534 – Store Joystick 1 in register $0A (10)
$853A – Store other joystick values $48 (72)
$8585 – CIA1: Data Direction Register B, $DC03
$8589 – CIA1: Data Direction Register A, $DC02
$858E – CIA1: Data Port Register B, $DC01 (save joystick 1 value)
$8591 – CIA1: Data Port Register A, $DC00 (keyboard/joystick 2) – Beginning routine to read keyboard (CMP #$FE) – Reads keyboard column 1
$85AF – Game demo timer (counts down time until Pitfall Harry moves during the game demo). Set to mask to 0 to start with no delay (otherwise it is 7 cycles to launch the demo).
$85BF – JSR $87F9 (Subroutine)
$85C2 – JSR $9C6E (Subroutine)
$85DE – CIA1: Data Port Register B, $DC01 (save joystick 1 value)
$85E1 – CIA1: Data Port Register A, $DC00 (Read keyboard/joystick 2). Here the keyboard/joystick 2 is idle (not moving).
$85E8 – Joystick 2 is pushed DOWN
$8608 JSR $9B9D (Subroutine)
$860B JSR $94D5 (Subroutine)
$860E JSR $87F9 (Subroutine)
$8611 JSR $99BA (Subroutine)
$861E JSR $8800 (Subroutine)
$8621 JSR $9ACD (Subroutine)
$8626 Sprite 4 Y Position
$8629 Position of Player X when entering a new room. Try LDX #32 as an example.
$865C JSR $981E (Subroutine)
$865F JSR $989D (Subroutine)
$8662 JSR $86F8 (Subroutine)
$8668 Sprite 4 X Position, $D008
$866F Sprites 0-7 MSB of X coordinate (cross over 256th position), $D010
$8677 Sprites 0-7 MSB of X coordinate (set bit), $D010
$867A Sprites 0-7 MSB of X coordinate (save value), $D010
$8684 Clear balloon when it breaks
$868F Sprite 4 Y Position, $D009
$8695 Sprite 5 Y Position (saved), $D00B
$8698 Sprite 4 X Position (read), $D008 – Pitfall Harry character
$869B Sprite 5 X Position (saved), $D00A – Balloon
$869E Sprites 0-7 MSB of X coordinate (read), $D010
$86AE Sprites 0-7 MSB of X coordinate (saved), $D010
$86DB Read low byte ($FB – 251), ZEROPAGE_POINTER_1
$86DF Store in high byte ($FD – 253), ZEROPAGE_POINTER_3
$86E4 Read low/hi bytes, LDA #<$9000, LDA #>$9000 (36864)
$86F4 JSR $0FE8 (Subroutine), RTS ($86F7)
$87D2 Starting address for a subroutine call. Ends with RTS.
$87F9 Starting address for timer routine. Can change the INC 127 to slow the game demo start or set INC 00 to speed it up.
$8824 JSR $9B2D (Subroutine)
$8827 JSR $9B49 (Subroutine)
$8833 JSR $87CB (Subroutine)
$8872 JSR $959A (Subroutine)
$8897 JSR $9B49 (Subroutine)
$88A3 JSR $87CB (Subroutine)
$8911 JSR $87CB (Subroutine)
$8914 JSR $9B70 (Subroutine)
$8934 JSR $9B7A (Subroutine)
$8983 JSR $87CB (Subroutine)
$8986 JSR $9B70 (Subroutine)
$89A6 JSR $9B7A (Subroutine)
$89EE JSR $87CB (Subroutine)
$8A2A Controls Pitfall Harry’s timed movement speed to the right. Change to AND #$7f to slow down the character timing movement. Interesting tweak on the game mechanics. Set to AND #$00 to speed up the movement.
$8A32 JSR $9B2D (Subroutine)
$8A35 JSR $9B49 (Subroutine)
$8A4D JSR $940F (Subroutine)
$8A5F JSR $959A (Subroutine)
$8A6F Controls animation speed of Pitfall Harry’s left movement. Changed to LDA $01 to bypass the read from LDA $44
$8A79 JSR $87CB (Subroutine)
$8AA6 Controls movement to the left. Set AND #$7f to slow down the left animation frames, which produces the smooth animation.
$8AB5 Controls Pitfall Harry’s timed movement speed to the left. Change to AND #$7f to slow down the character timing movement. Set to AND #$00 to speed up the movement.
$8ABD JSR $9B2D (Subroutine)
$8AC0 JSR $9B49 (Subroutine)
$8AD8 JSR $9423 (Subroutine)
$8AEA JSR $959A (Subroutine)
$8AFC JSR $87CB (Subroutine)
$8AFF JSR $9B70 (Subroutine)
$8B04 Load lo/hi bytes, LDA #<$000F, LDA #>$000F
$8B0C Jumping speed for Pitfall Harry when moving to the right. Change to AND #$00 to get a bigger jump.
$8B29 JSR $940F (Subroutine)
$8B40 JSR $982D (Subroutine)
$8B43 JSR $9B49 (Subroutine)
$8B64 JSR $87CB (Subroutine)
$8B67 JSR $9B70 (Subroutine)
$8B6C Load lo/hi bytes, LDA #<$000F, LDA #>$000F
$8B74 Jumping speed for Pitfall Harry when moving to the left. Change to AND #$00 to get a bigger jump.
$8B91 JSR $9423 (Subroutine)
$8B9D JSR $9B7A (Subroutine)
$8BA4 Controls the up movement when Pitfall Harry dies. Changing to a different register forces Harry back to the previous saved (cross object) position. Funny things happen here.
$8BA8 JSR $9B2D (Subroutine)
$8BAB JSR $9B49 (Subroutine)
$8BD7 Controls animation when swimming in the water to the right. If you change the line to ADC #$01 the scorpion and bat frames alternate. This could be used to switch a character’s animation frames.
$8BDF JSR $87CB (Subroutine)
$8BF1 Controls Pitfall Harry’s swimming movement to the right. Use AND #$00 to speed up the swimming movement.
$8CB9 Controls Pitfall Harry’s swimming movement to the left Use AND #$00 to speed up the swimming movement.
$8CF2 JSR $9423 (Subroutine)
$8D33 JSR $9B2D (Subroutine)
$8D41 JSR $9B7A (Subroutine)
$8D51 JSR $9B2D (Subroutine)
$8D54 JSR $9B49 (Subroutine)
$8D59 Controls the swimming height that Pitfall Harry can ascend to. Set to LDA #$01 to turn off the height of his swimming. Does strange things though since moving to the right makes him fall again.
$8D5B JSR $9B7A (Subroutine)
$8D63 JSR $87CB (Subroutine)
$8D66 JSR $9B70 (Subroutine)
$8D71 JSR $9B7A (Subroutine)
$8D95 JSR $87CB (Subroutine)
$8D98 JSR $9B70 (Subroutine)
$8DA3 JSR $9B7A (Subroutine) *
$8DC7 JSR $87CB (Subroutine)
$8DCC JSR $9B7A (Subroutine)
$8DDA JSR $87CB (Subroutine)
$8DDF JSR $9B7A (Subroutine)
$8DF5 JSR $87CB (Subroutine)
$8DFE JSR $87CB (Subroutine)
$8E03 Change to INC $1A to slow down the fall movement. Likely this register controls the rate of descent.
$8E1A JSR $9B2D (Subroutine)
$8E1D JSR $9B49 (Subroutine)
$8E22 Sets limits a specific height Pitfall Harry can swim when in the water. Set to DEC $1A increased his swim height (above water).
$8E30 JSR $959A (Subroutine)
$8E33 JSR $9C1C (Subroutine)
$8E6B JSR $87CB (Subroutine)
$8E74 JSR $87CB (Subroutine)
$8E90 JSR $9B2D (Subroutine)
$8E93 JSR $9B49 (Subroutine)
$8EA6 JSR $959A (Subroutine)
$8EA9 JSR $9C1C (Subroutine)
Leave A Comment