Saturday 4 March 2017

Impossible Mission, Epyx 1984

I talked about the synthesised speech in Impossible Mission provided by ESS in a previous post.  Now let's have a look at this great game itself.

Published in 1984 by Epyx and written by Dennis Caswell.  There are various write-ups in the retro gaming media so I doubt I can add anything new.  In short, it's a great game and a must-play if you've never played it before.

Let's hack it... (assume using .d64 image from well-known C64 site)

Summary of POKEs:

POKE 33697,96    - Stop the clock (1s tick)

POKE 33731,165  - Stop the clock on falling, touching a robot, using the modem, etc.

POKE 13369,137   - Add maximum (9) Snooze passwords
POKE 13382,137   - Add maximum (9) Lift passwords

POKE 41422,234 - Prevent snooze/lift passwords from decrementing on use
POKE 41423,234
POKE 41424,234 (must enter all 3 pokes)

POKE 36809,234 - Disable robot laser beams
POKE 36810,234
POKE 36811,234 (must enter all 3 pokes)

POKE 39075,234 - Remove object "Searching" delay
POKE 39076,234
POKE 39077,234 (must enter all 3 pokes)


The Long Version:

CIA2 Port A
$DD00 = $C6    1100 0110

VIC-II Bank (10) = 1  $4000-$7fff

VIC-II Mode
$d011 = $1b    0001 1011    Text Mode, Extended background off
$d016 = $d8    1101 1000    Multicolour mode on   

Lift Shaft Screen:
$d018 = $03    0000 0011    Character memory    001 = $0800-$0fff
                                              Screen memory        0000 = $0000-$03ff

 VIC-II is running in text mode.
    Screen Memory        = $4000-$43ff
    Colour Memory         = $d800-$dbe7
    Character Memory    = $4800-$4fff (Lift)
    Character Memory    = $5000-$57ff (Room)


1. Hack the clock.  Clock starts at 12:00:00 and stops as 06:00:00 when game ends.  It's displayed on the "Computer" screen when in the lift shaft screen.

Let's find the screen memory where clock is displayed.  Without doing maths, let's freeze and fill the lower half of the screen with a known value, unfreeze and let the game update the clock, then re-freeze and see what changed.

f 4300 43ff ff
m 4300 43ff

>C:4390  ff ff ff ff  ff ff ff ff  ff ff ff ff   ............
>C:439c  ff ff ff ff  ff ff ff ff  ff ff ff ff   ............
>C:43a8  ff ff ff ff  81 82 ff 80  80 ff 81 85   ............
>C:43b4  ff ff ff ff  ff ff ff ff  ff ff ff ff   ............
>C:43c0  ff ff ff ff  ff ff ff ff  ff ff ff ff   ............

Clock characters are drawn at...

(C:$dd03) m 43ac 43b3
>C:43ac  81 82 f6 80  80 f6 82 83                ........

Trace code where these characters are updated:
 watch store 43b3
#1 (Stop on store 43b3)  259 029
.C:851d  8D B3 43    STA $43B3      - A:83 X:88 Y:D1 SP:fc N.-.....  137569034
.C:8520  A5 D2       LDA $D2        - A:83 X:88 Y:D1 SP:fc N.-.....  137569034

Looks like it's the routine at $8516


Time is in zero page $d2(ss) $d3(mm) $d4(hh)

m d2 d4
>C:00d2  25 00 12                                %..

Time reads = 12:00:25

Lets test it:
> d2 30 15 05

Yes, time now displayed as 5:15:30 on computer.

We can slow down the time by altering the time delay at $83a8, e.g. with:
 a 83a8
.83a8  cmp #$ff
.83a8

Or we can stop the clock completely with:

(C:$83cb) a 83a1
.83a1  nop
.83a2  nop
.83a3 

(POKE 33697,96)


2. Stop the clock decrementing on falling, touching a robot, using the modem, etc.

watch store d3
WATCH: 1  C:$00d3  (Stop on store)
(C:$dd03) x
#1 (Stop on store 00d3)  266 036
.C:83c5  85 D3       STA $D3        - A:10 X:FF Y:5A SP:f9 ..-.DI..  872526978
.C:83c7  C9 60       CMP #$60       - A:10 X:FF Y:5A SP:f9 ..-.DI..  872526978
(C:$83c7) bt
(0) 96f2
(2) 860d
(4) 7288

Looks like routine at 83c2 adds minutes to clock from A register.
Fix for all cases, stop $83c2 routine from adding to minutes counter $d3.

a 83c3
.83c3  lda $d3
.83c5 

(POKE 33731,165)

2. Change the number of Snooze and Lift passwords.

We already know from earlier that the ':' character is $f6 and zero is $80, so we're looking for f6 80 in the previous line of screen memory.

(C:$4425) m 437d
>C:437d  f6 80 53 71  6e 6b 79 53  6e 73 6e 79   ..SqnkySnsny
>C:4389  78 f6 80 2b  2c 62 63 2d  62 63 2d 62   x..+,bc-bc-b

Snoozes = $437e, Lifts = $438b

Trace where this gets written when computer display is opened...

(C:$4425) watch store 437e

.C:801d  99 76 43    STA $4376,Y    - A:80 X:FF Y:08 SP:fd N.-..... 1283098714
.C:8020  B9 C1 35    LDA $35C1,Y    - A:80 X:FF Y:08 SP:fd N.-..... 1283098714
(must be this one... it's writing char $80 ('0') to screen mem.

(C:$3b12) d 8018
.C:8018  A0 3D       LDY #$3D
.C:801a  B9 31 34    LDA $3431,Y
.C:801d  99 76 43    STA $4376,Y    ; When Y=$08 (A=$80)
.C:8020  B9 C1 35    LDA $35C1,Y
.C:8023  99 76 DB    STA $DB76,Y
.C:8026  88          DEY
.C:8027  10 F1       BPL $801A
.C:8029  60          RTS

Above routine copies bytes to screen mem from offset $3d downwards, including snoozes and lifts at offset $08 and snoozes at offset $15.  Looks like simple copy from $3431 + offset.

(C:$8043) m $3431
>C:3431  78 73 74 74  7f 6a 78 f6  80 53 71 6e   xstt.jx..Sqn
>C:343d  6b 79 53 6e  73 6e 79 78  f6 80 2b 2c   kySnsnyx..+,

Snoozes = 3439, Lifts = 3446

Let's watch 3439 and try and find the routine that updates the Snooze password count.

(C:$8606) watch store 3439
WATCH: 13  C:$3439  (Stop on store)
(C:$8606) x
#13 (Stop on store 3439)  014 039
.C:9953  FE 39 34    INC $3439,X    - A:80 X:00 Y:FF SP:fb N.-..... 1337277225
.C:9956  20 83 9B    JSR $9B83      - A:80 X:00 Y:FF SP:fb N.-..... 1337277225


.C:9940  50 88       BVC $98CA
.C:9942  C0 FF       CPY #$FF
.C:9944  D0 F6       BNE $993C
.C:9946  E6 D7       INC $D7        ; High Score passwords found total
.C:9948  BD 1A A2    LDA $A21A,X
.C:994b  AA          TAX
.C:994c  BD 39 34    LDA $3439,X
.C:994f  C9 89       CMP #$89        ; Maximum of 9 passwords
.C:9951  B0 03       BCS $9956
.C:9953  FE 39 34    INC $3439,X    ; Increment char (80-89)
.C:9956  20 83 9B    JSR $9B83
.C:9959  4C B4 99    JMP $99B4

Game appears to keep track of passwords by storing character in screen mem backing store only.  Lets test it:
> 3439 89
> 3446 89

(POKE 13369,137)
(POKE 13382,137)

Yes, we now have 9 of each password.

Decrement occurs at:
#13 (Stop on store 3439)  178 000
.C:a1ce  DE 39 34    DEC $3439,X    - A:89 X:00 Y:25 SP:cf N.-..I.C 1820510622
.C:a1d1  08          PHP            - A:89 X:00 Y:25 SP:cf N.-..I.C 1820510622

Prevent passwords from decrementing with:
(C:$a1e2) a a1ce
.a1ce  nop
.a1cf  nop
.a1d0  nop
.a1d1
(C:$a1d1) x

(POKE 41422,234)
(POKE 41423,234)
(POKE 41424,234)

3. Disable robot laser beam sprites:

Sprites:
1 = Robot laser
2 = Character
3 = Character
4 = Character
5 = Robot 1        (top down)
6 = Robot 2
7 = Robot 3
8 = Robot 4

Sprite 5 (robot 1) X, Y updates:

(C:$8f82) watch store d00a
WATCH: 2  C:$d00a  (Stop on store)
(C:$8f82) x
#2 (Stop on store d00a)  268 041
.C:91b1  99 08 D0    STA $D008,Y    - A:7D X:06 Y:02 SP:ee ..-..I.. 1541342165
.C:91b4  90 0C       BCC $91C2      - A:7D X:06 Y:02 SP:ee ..-..I.. 1541342165
(C:$91b4) bt
(0) 8340
(13) 871e
(15) 7288

JSR $8ECA Robot movement and lasers
JSR $92C1 "Rover" ball movement


Disable laser beam sprite mux:
Trace sprite control register $d015

#3 (Stop on store d015)  269 022
.C:8fc9  8D 15 D0    STA $D015      - A:0F X:06 Y:01 SP:ee ..-B.I.. 1723415737
.C:8fcc  AD 1C D0    LDA $D01C      - A:0F X:06 Y:01 SP:ee ..-B.I.. 1723415737
(C:$8fcc) bt
(0) 8340
(13) 7f70
(15) 7249

(C:$8fcc) a 8fc9
.8fc9  nop
.8fca  nop
.8fcb  nop
.8fcc 
(C:$8fcc) x

(POKE 36809,234)
(POKE 36810,234)
(POKE 36811,234)


4. Remove variable delay when "Searching" an object.

Find where "Searching" box is drawn from....
Put a trace on screen memory where Searching box is going to appear next.

#7 (Stop on store 4180)  286 022
.C:9ba6  91 10       STA ($10),Y    - A:52 X:1B Y:04 SP:f9 ..-..... 1819790176
.C:9ba8  A9 01       LDA #$01       - A:52 X:1B Y:04 SP:f9 ..-..... 1819790176
(C:$9ba8) bt
(0) 98a0
(2) 92bd
(4) 726f

.C:98a0  20 96 9B    JSR $9B96        ; Overlay Searching box

.C:98a3  20 6B 7F    JSR $7F6B        ; Searching delay

 Remove delay entirely:
(Note that delay routine at $7f6b) is used elsewhere, e.g. when riding elevator platforms, so can't be sped up/removed globally without side effects.)

(C:$8606) a 98a3
.98a3  nop
.98a4  nop
.98a5  nop
.98a6 

(POKE 39075,234)
(POKE 39076,234)
(POKE 39077,234)

All puzzles solved, password to control room found.
Elvin Atombender (No, No, Nooooo!)
I went ahead and completed the game with a couple of minor pokes enabled.  I used the 'fast searching' hack and switched off robot lasers.  Even so, I was still down to less than 1 hour to go at game completion.  Room 00 used up a lot of time by falling or touching robots whilst attempting to get the jumps timed just right.

A quick cheat is to disable sprite collisions with a freeze cartridge but that takes all the fun out of the game.

No comments:

Post a Comment