PATCH: Save one city in Keen 2 to finish (2 patches)
PATCH: Save one city in Keen 2 to finish (2 patches)
Hi,
I would desperately need this patch. So, as we know, Keen can save a city by just walking on those purple things instead of shooting them. I'd need a patch that would go to the end game sequence if Keen saves the machine in level 16 -- and he doesn't have any other cities saved. So, he would need to finish the game by just saving one city, and finishing the level. Hopefully it's possible!
Oh, and it doesn't need to be level 16, and level is find, at least as Keen can finish by saving one machine.
I would desperately need this patch. So, as we know, Keen can save a city by just walking on those purple things instead of shooting them. I'd need a patch that would go to the end game sequence if Keen saves the machine in level 16 -- and he doesn't have any other cities saved. So, he would need to finish the game by just saving one city, and finishing the level. Hopefully it's possible!
Oh, and it doesn't need to be level 16, and level is find, at least as Keen can finish by saving one machine.
- adurdin
- Site Founder
- Posts: 549
- Joined: Fri Aug 29, 2003 11:27 pm
- Location: Edinburgh, Scotland
- Contact:
Finding the patch:
I started by looking at the addresses of the city names in the data segment (by looking at the disassembly):
The first one is at $222B. So I now search for this address "222B", as the code that displays 'London' if it's saved will have to get the text from this address, as well as checking if it's saved or not. The first instance is what I'm looking for:
This code examines the word at ds:$9AF4, and if it's nonzero, displays the text 'London'. Immediately following is near-identical code that examines ds:$9AF6, and displays 'Cairo' if it's nonzero.
So I surmise then that the 8 words at ds:$9AF4 to ds:$9B02 store the 8 flags indicating which cities have been saved. Now we need to find where these are checked to see if Keen has won or not. Searching for "9AF4" again reveals this:
This is a for loop -- it looks at the 8 words starting at ds:$9AF4, and adds their values to a local variable. After the loop ends, this local variable is checked to see if it is equal to 8 -- sounds like what we want. This line at $834B turns out to be the one we need to patch, so I'll post the patch following this.
Anyway, the pattern shown in this last block of code is worth remembering -- it corresponds exactly to a C "for" loop, and it'll be found throughout the disassembled Keen code:
I started by looking at the addresses of the city names in the data segment (by looking at the disassembly):
Code: Select all
511C:222B 4C 6F 6E 64 6F 6E db 'London', 0
511C:2231 00
511C:2232 43 61 69 72 6F 00 db 'Cairo', 0
511C:2238 53 79 64 6E 65 79 db 'Sydney', 0
511C:223E 00
511C:223F 4E 65 77 20 59 6F db 'New York', 0
511C:2245 72 6B 00
etc...
Code: Select all
39A4:1090 l_39A4_1090::
39A4:1090 83 3E 9AF4 00 cmp word ptr ds:d_5AE2_9AF4_e, 0 ; (=0)
39A4:1095 74 15 je l_39A4_10AC ; Jump if equal
39A4:1097 89 36 7FC6 mov ds:d_5AE2_7FC6_e, si ; (=0)
39A4:109B 8B C7 mov ax, di
39A4:109D 05 0007 add ax, 7
39A4:10A0 A3 8036 mov ds:d_5AE2_8036_e, ax ; (=0)
39A4:10A3 B8 222B mov ax, 222Bh
39A4:10A6 ú50 push ax ; PARAMETER_1
39A4:10A7 E8 17FB call s_39A4_28A5
39A4:10AA 44 inc sp
39A4:10AB 44 inc sp
39A4:10AC l_39A4_10AC::
39A4:10AC 83 3E 9AF6 00 cmp word ptr ds:d_5AE2_9AF6_e, 0 ; (=0)
39A4:10B1 74 15 je l_39A4_10C8 ; Jump if equal
etc...
So I surmise then that the 8 words at ds:$9AF4 to ds:$9B02 store the 8 flags indicating which cities have been saved. Now we need to find where these are checked to see if Keen has won or not. Searching for "9AF4" again reveals this:
Code: Select all
39A4:8421 C7 46 FA 0000 mov word ptr [bp+LOCAL_3], 0
39A4:8426 33 F6 xor si, si ; Zero register
39A4:8428 EB 0C jmp short l_39A4_8436
39A4:842A l_39A4_842A::
39A4:842A 8B DE mov bx, si
39A4:842C D1 E3 shl bx, 1 ; Shift w/zeros fill
39A4:842E 8B 87 9AF4 mov ax, ds:d_5AE2_9AF4_e[bx] ; (=0)
39A4:8432 01 46 FA add [bp+LOCAL_3], ax
39A4:8435 46 inc si
39A4:8436 l_39A4_8436::
39A4:8436 83 FE 08 cmp si, 8
39A4:8439 7C EF jl l_39A4_842A ; Jump if <
39A4:843B 83 7E FA 08 cmp word ptr [bp+LOCAL_3], 8
39A4:843F 75 09 jne l_39A4_844A ; Jump if not equal
Anyway, the pattern shown in this last block of code is worth remembering -- it corresponds exactly to a C "for" loop, and it'll be found throughout the disassembled Keen code:
Code: Select all
mov word ptr [bp+LOCAL_3], 0 # sum = 0
# Here's how a for loop is compiled:
# for(i = 0; i < 8; i++)
xor si, si # //The loop initialisation (i = 0)
jmp short l_39A4_8436 # //Jump to the loop test to start with
l_39A4_842A:: # { //The loop body begins here
mov bx, si # //These four lines correspond to
shl bx, 1 # // the line of C code:
mov ax, ds:d_5AE2_9AF4_e[bx] ; (=0) # sum += saved_cities[i]
add [bp+LOCAL_3], ax # // where saved_cities is an array of words.
inc si # //Here is the loop increment (i++)
l_39A4_8436:: # } //The loop body ends here
cmp si, 8 # //And here is the loop test (i < 8);
jl l_39A4_842A # // if the test fails, then we execute the body again
- adurdin
- Site Founder
- Posts: 549
- Joined: Fri Aug 29, 2003 11:27 pm
- Location: Edinburgh, Scotland
- Contact:
And here is the patch, which changes the '8' in line 843B to a '1':
Code: Select all
%ext ck2
%version 1.31
# Keen only needs to save 1 city
%patch $843E $01
%end
Set the patch to one machine completion. Make sure Keen touches the tantalus ray sprite [it can be hidden behind a tile and Keen can walk over it.] You'd never even know you'd passed it.
And here is that level, when placed into keen2 with the 1 city patch, you can't possibly fail to finnish the game.
http://www.freewebs.com/gannalev/LEVEL16.zip
And here is that level, when placed into keen2 with the 1 city patch, you can't possibly fail to finnish the game.
http://www.freewebs.com/gannalev/LEVEL16.zip