Everyone's a Wally (C64) - Town square |
Looking at the game now, it was certainly very well-featured for the budget price. There are 5 playable characters you can switch between and they continue to roam the map and pick up/drop objects as they go around. There's several interesting puzzles to complete and the aim of the game is to collect several letters (B-R-E-A-K) and take them to the Bank to finish. If all this wasn't enough, the graphics are bright and colourful, there's a back story for all the characters and there's a music single on the B side of the tape.
The first puzzle game I really got into in a big way was Adventure for the Atari 2600 and this game is similar in some respects, e.g. objects being moved around randomly by other characters (The Bat), nasties roaming the map (Dragons), puzzles (Keys/Castles/Bridge/Magnet), collecting items and taking them to a special location to finish the game (Chalice and Yellow Castle).
This YouTube video has the Mike Berry song from the tape B side and shows the C64 gameplay. Note the character inventory in the top left and the energy/lives at top right.
Back in the day I found the game difficult to complete because I ran out of lives quickly and it's often time consuming to track down specific items as they could either be carried by another character or in one of the many locations. The longer you roam the map looking for items, the greater the likelihood of running into a nasty. I didn't have any pokes for the game and my early Datel Action Replay Mk IV couldn't locate the lives counter.
Looking at the game today, the newer Action Replay Mk VI correctly finds the code for decrementing the lives counter (for all characters) as follows:
Infinite lives poke:
POKE 36317,189 (Switches STA to LDA instruction)
However, that's way too easy. Let's hack this the hard way for fun and get a better understanding of the Commodore 64 memory map and play with some 6502.
I used the following cracked .d64 for this (I do own the physical tape so don't judge me!).
006980209167de90736f18fd032e059b Everyone's a wally.DC.d64
Infinite Lives
The game sets up the 64's VIC-II graphics as follows:
CIA2 Port A
$DD00 = $C4 (1100 0100)
VIC-II Bank = 3 (00), memory mapped $c000-$ffff
VIC-II Mode
$d011 = $bb (1011 1011) Bitmap Mode, Extended bg mode off
$d016 = $c8 (1100 1000) Multicolour mode off
$d018 = $39 (0011 1001) Char memory 1xx = $2000-$3fff
Screen memory 0011 = $0c00-$0fff
So we're running in VIC-II bitmap mode at 320x200.
Screen memory (colour) = $cc00-cfff
Bitmap/Character memory = $e000-$efff
Let's find the character memory location where the lives (heart symbols) are drawn on screen. We can do this with maths or by trial and error writing to $e000 onwards.
$e3a0-$e3a7
We can overwrite the character with FF to prove this is the correct location:
> f e3a0 e3a7 ff
Let's watch this memory location for updates.
watch e3a0
Now touch a nasty and/or lose a life. Note how both the energy bar and the lives remaining are always redrawn every time energy is decremented even if a life isn't actually lost.
#4 (Stop on load e3a0) 098 037
.C:3c2d 91 0A STA ($0A),Y - A:6C X:24 Y:00 SP:78 ..-..I.. 171937243
.C:3c2f C8 INY - A:6C X:24 Y:00 SP:78 ..-..I.. 171937243
Add breakpoint on 3c2d where bitmap memory update occurs.
break $3c2d
#6 (Stop on exec 3c2d) 106 049
.C:3c2d 91 0A STA ($0A),Y - A:6C X:24 Y:00 SP:78 ..-..I.. 125117167
(C:$3c2d) bt
(0) 8e0f
(2) 9acc
(4) 4f07
(6) 4edb
(118) 0b77
(131) a677
$3bd5 subroutine updates the lives bitmap (decrement happens before this)
.C:8de2 4C 51 43 JMP $4351
.C:8de5 84 42 STY $42
.C:8de7 A9 70 LDA #$70
.C:8de9 85 0C STA $0C
.C:8deb A9 92 LDA #$92
.C:8ded 8D EE 3B STA $3BEE
.C:8df0 A9 83 LDA #$83
.C:8df2 8D F5 3B STA $3BF5
.C:8df5 A6 0F LDX $0F
.C:8df7 BD 18 5C LDA $5C18,X ; Probably lives?
.C:8dfa 85 23 STA $23
.C:8dfc C6 23 DEC $23
.C:8dfe A2 24 LDX #$24
.C:8e00 A0 02 LDY #$02
.C:8e02 84 24 STY $24
.C:8e04 A5 23 LDA $23
.C:8e06 D0 05 BNE $8E0D
.C:8e08 A9 20 LDA #$20
.C:8e0a 4C 0F 8E JMP $8E0F
.C:8e0d A9 1F LDA #$1F
.C:8e0f 20 D5 3B JSR $3BD5
Looks like lives are probably stored in memory at $5c18 onwards:
The offset is for the character being played (5 different characters).
>C:5c18 03 03 03 03 03 00 08 10 18 20 00 00 ......... ..
Lose a life (Wally)...
>C:5c18 02 03 03 03 03 04 0c 14 1c 20 00 00 ......... ..
Yep, this is it. Let's prove it by restoring the starting number of lives (Wally):
> 5c18 3
Watch this memory location for writes...
watch store 5c18
WATCH: 10 C:$5c18 (Stop on store)
#10 (Stop on store 5c18) 033 050
.C:8ddd DE 18 5C DEC $5C18,X - A:80 X:00 Y:01 SP:7a ..-..I.C 215883977
.C:8de0 D0 03 BNE $8DE5 - A:80 X:00 Y:01 SP:7a ..-..I.C 215883977
Found it! Remaining lives counters are decremented by the DEC instruction at $8ddd
Remove the 3 byte DEC instruction and test it:
a 8ddd
nop
nop
nop
x
Yes, we now have unlimited lives. Let's make this an Action Replay style poke by switching the STA to an LDA instruction with the same addressing mode which takes the same number of bytes in memory.
Infinite lives poke:
POKE 36317,189 (Switch STA to LDA instruction)
Note that this poke matches the poke determined by Datel's Action Replay Mk VI cartridge (see above), which demonstrates just how clever that cartridge was.
Remaining lives memory locations:
5c18 Lives Wally
5c19 Lives Wilma
5c1a Lives Tom
5c1b Lives Dick
5c1c Lives Harry
More tracing and disassembly to come in the next post...
No comments:
Post a Comment