Untitled Document

Lethal Weapon
? Ocean
How to train it

You will need following:

1. Copy of original game
2. An Amiga or WINUAE
3. Action Replay or ROM image
4. Pencil and paper
5. Double Action ? find at amiga-stuff.com
6. DiskFiller ? find at http://wuarchive.wustl.edu/aminet/disk/misc/DiskFiller11.lha
7. Asmone

Source, bin file & boot block can be downloaded in top of this tutorial.
You just need to write the bin file to copy of original disk (block 1700) and install
supplied boot block.($ 0-400)

In this txt we will make a trainer for Lethal Weapon, using Alpha 1 / Siriax trainer menu.
Following options will be included:

  • Unlimited lives
  • Unlimited energy
  • Unlimited ammo
  • No collision detection
  • In-game keys

Note! This game take advantage expansion memory, so addresses may differ on your computer!

We will of course make the trainer compatible with all memory configs.
Boot up original game and start mission one.
We have three lives to start with. Enter AR and start trainer: TS 3. Exit and loose ONE life. Enter AR, continue trainer: T 2. still no result. Exit loose one more life and enter AR again. Continue trainer: T 1. Still nothing, repeat again. When reaching 0 lives, you get a bunch of addresses.

Guess one 🙂
By using the very fine and well-proved method ? trail and error ? I found that lives is stored at address C1A1C9.
Some instruction must subtract #1 from it, each time you die.
Find the instruction by setting a memory write watch point: ? MS C1A1C9 ?. Exit AR and loos a life more. Amiga will go real slow, just so you know. When you die, AR will pop up:

Game is halted around the instruction that decreases address C1A1C9. Disassemble memory and get a overview:

Address C148A4 subtracts 1 from address C1A1C9. By inserting two NOP?s, we will have unlimited lives.
Now for energy. Start by removing the watch point: MD C1A1C9.
This one can be a little harder to find, because it?s not a fixed value that are subtracted each time.
We know the nr. of remaining lives was stored at address C1A1C9, let?s have a look at the hex values: M C1A1C9.
We now have a string of values on the screen. Exit and loose some energy and enter AR again.

See the address again: M C1A1C9. Some values have changed. Red 2A has changed to 15, perhaps the energy?.???
Set a memory watch point to address C1A1CD (C1A1C9+4): MS C1A1CD. Exit and loose energy.

When AR activated, disassemble again and get overview:

Address C0D57A & C0D57E are interesting. The sub instruction can be killed with two NOP?s and the BGT must be changed to a BRA, done by inserting the value #60 at address C0D57E, or the next instruction will clear the energy counter. Remember to delete watch point: MD C1A1CD.
Next must be pistol clips. Use up one clip, so you have nine left, enter AR and start
trainer: TS 09. Continue the trainer cycle like with lives.

You should end up with two addresses. Set a memory watch point to the first and use a pistol clip more:

When AR pops up, press D to disassemble and get a overview:

Address C0C02A subtracts 1 from the nr. of remaining pistol clips. It can be removed with 2 NOP?s.
A no collision feature would also be nice. To find this, let?s see what calls the routine that count down on the energy.
The energy count down routine started at address C0D562, see what calls the address: FA C0D562 C00000.

Let?s have a look at the last returned address. Disassemble address C12004, hold enter down and scroll up to get an overview of the routine:

The routine starts at address C11FCA by testing if address C1B2A0 is #0, if NOT, then it just returns. If it IS, then rest of the routine is run and the energy count down routine is called by address C12004. If we change the BNE at address C11FD0 to BRA, the count down will never be called. Let?s check if there are more of these routines: FA C1B2A0:

AR returns five addresses, where four of them checks if address C1B2A0 is #0. These four addresses are all followed by a BNE that needs to be changed to BRA, this is done by moving value #60 into the addresses marked with red.
When all these have been changed, you can?t get hurt by shots, bombs, sharks, etc.
It would be nice with some in-game keys. For this purpose we need to take over the games keyboard routine.
Before we do this, some toggle values must be calculated. To toggle between ex. SUBQ.W #1,1000 and NOP NOP, the EOR command is perfect. Lets start by finding EOR value for lives. This counter was located at address C148A4.
Have a look at it: M C148A4. Original opcodes is marked with red. Assemble address 100 and insert the little piece of code in the picture beneath:

This will EOR.L opcodes for NOP NOP (4e714e71) with the subi instruction. The resulting opcodes (marked with green) can be used to toggle with. If you EOR.L #1D1C4E2B with the original subi instruction, it will turn into NOP NOP.
If you do it again, the NOP NOP will turn back to the subi instruction 🙂 ? we toggle between two instructions.
Now for energy. Instruction was located at address C0D57A, assemble address 100 and EOR.L #4E714E71 with address C0D57A:

Original opcodes marked with red, new EOR values with green. We must also remember the BGT at address C0D57E. We wanted this to change to a BRA, where the hex value was 60. Assemble address 100 and EOR.B #60,C0D57E.

Again, original values marked with red and new EOR value with green.
Now for pistol clips. Routine was located at address C0C02A. This routine was also NOP?ed out, so EOR.L it:

Again new EOR value marked with green.
Then we had four addresses for collision. There we wanted to change a BNE to a BRA. The BNE is hex 66 and BRA is 60, therefore, the four EOR.B values must be 06 at address C11F48, C11F8C, C11FD0 & C12022.
Restart game, to get out of our code at address 100.
All this is not much worth, if have no keys in-game to toggle with. We must find the keyboard routine. It often appears around a RTE (hex 4E 73), so search for it: F 4E 73,C00000.

Disassemble the first address AR returns and hit enter a few times. Interesting address is C01FF4, which moves input into D2. This must be changed to JSR patch.S and code at address C01FF4 is restored in patch. Then a check for input in D2 can be checked. I want to use the function keys to for toggle options, but don?t know their hex values.
Set a breakpoint at address C01FF8, exit AR and press F1.

When AR pops up, we have the hex value for F1 in register D2 – #5F, marked with red above. F2 is 2 smaller – #5D, etc.
We need a place to locate patch in memory, depending on how game uses memory. See memory from address 0:

Hmm, looks like low chip used until around address 480. Let?s check other end, 7A000:

Use copy of original game from now!
Seems to be free. We could locate main patch here and then copy toggle options down to low chip, at address 500. Let?s have a little look at the boot block. File that needs to be patched is packed, so we have to take over the game when it?s decrunched. Read boot block intro memory, starting at address 70000: RT 0 1 70000. Disassemble start of boot code and stop when this appears:

Above looks like part of a copy routine, where it copies data from offset FE on disk. Lets look at address 700FE:

We have a jump at address 7010C. Change address 7010A to JMP 7A000, first step in taking over the game.
The code at 7010A & 7010C must of course be restored in patch.
Reboot game and enter AR when screen turns black. Assemble 7A000 and make a loop:

Exit AR and continue loading. When game hangs, enter AR and press R to see registers. Game wanted to jump to A6, it points to start of expansion memory. Files are packed with ProPack and I found end of the decruncher at address C00178. When game reaches this address, game is ready to be trained, cause main file is decrunched. We will insert a JMP 7A012 at address C00178. To ensure it can run on other memory cfgs., it will be at address 178(A6).
In the trainer patch, we also include a crack patch, which removes the copylock protection. This is done by inserting a JSR 7A030 (patch) just before copylock is run. At the same time, we can run the trainer code, cause main file is decrunched. For more details, see the comments in source code.
We are now ready to make the actual trainer. I will only go through a few of the options, read comments for more info.
Start ASMONE or your favourite txt editor. Load in source and setup following parameters:

PATCHADR, here will patch be located. CMPBYTES is where the check bytes are located. PAGEADR, notice the red line, I removed DC.L TXT3, so txt page 3 will not appear.

Trainer patch should be located under txt ? PATCH ?. We start this patch with taking over the game till its decrunched, then we crack copylock (no further description, it?s a trainer tutorial) and then actual trainer can start. It start by moving the toggle functions down to address 500.

Our trainer options will appear like this (for logical reasons):

  • Unlimited lives
  • Unlimited energy
  • Unlimited ammo
  • No collision detection
  • In-game keys

In the trainer code, I have chosen to check for options like this:

  • Unlimited ammo
  • Unlimited energy
  • Unlimited lives
  • No collision detection
  • In-game keys

This is because all code that we need to change is located in expansion memory. The instruction for nr. of remaining pistol clips appears first, then energy counter.
A4 points to start of expansion memory. We then add the value to a4, so it points to the pistol clips instruction. After that we don?t have to subtract a value, but just add a value more, to make it point to energy instruction, etc.
Ex. first we add #c02a to a4, make it point to pistol clips. Then we check if user has chosen unlimited ammo. If not, branch to energy. If he has, then move contents of address 500 into (a4) ? NOP NOP.
The energy adds a value to a4 (which right now points to ammo), to make it point to energy, then it checks if user chosen unlimited energy, etc. The check is done by setting address 4C0-4C4 to #0 or 1 ? off or on.

The in-game keys will overwrite the keyboard routine with JSR 504.S. This will call our toggle patch, in patch we must of course restore code we removed to take over keyboard routine. At the same time we also saved a4 at address C0.
A4 points to start of expansion memory, and can be used in toggle functions, to point to the different count down ins.
To toggle ex. lives, patch checks if F1 is pressed. If not, it branches on to check if F2 for energy is pressed.
If F1 is pressed, a4 is saved at address d0, address c0 which points to start of expansion memory is fetched to a4, value to make it point to lives instruction is added to a4, calculated eor value is run with (a4) ? we toggle lives.
Then a4 is restored again, by fetching it from address d0, and next option is checked?.
When all the coding is done, it?s time to make txt for the trainer:

When you have filled in the txt that suits your needs, it can be assembled. Start ASMONE and fill in parameters marked with red:

This will give you 128kb of public work memory, and r means read source.
A file reg. appears, choose your source code and click ok:

Assemble file and write an exe file:

A file req. appears, select a save file name, I choose ? lethal ?:

Game is NDOS, so we have to relocate file. For this ex. Double Action or Tetragon can be used, and crunching the file at the same time.
Start Double Action and select ? load ? from ? file menu ?:

A file req. appears, select your newly assembled file:

A new window appear, where we select crunch offset, dest. & load address, etc.:

Press ? start crunching ? and wait for it to finish. When done, select ? Save file ? from the ? file menu ?. Choose a file name, ex. ? lethal2 ?.
Start DiskFiller, select ? get ?, a file req. appears, select your crunched file.

In first block field select ? 1700 ?. Press ? do it ?. Following will appear:

It should say ? last block used 1721 ?. If you selected a higher crunch rate, it might say ? 1720 ?. Select ok, to write file.
? Save source ? can now be selected, do this and save a file in RAM: called ? source ?. Open it in a txt editor, to see values for the track loader:

Red txt is disk offset & green is amount to read. Enter AR, read track 0 to
address 70000: RT 0 1 70000.
Follow the steps beneath, to make the boot block call a track loader for the trainer:

There is free space at offset 200 on boot, for the track loader. Assemble 70200 and make the track loader:

Line 70226 can?t be assembled with AR, insert hex values instead.
Line 70234 restores code we removed ion start of boot block.

Correct boot block checksum & write track back, see above.

Boot your new trainer & have fun.


Publication author

offline 20 years


Comments: 103Publics: 79Registration: 20-07-2004

Notify of

Inline Feedbacks
View all comments
18 years ago


aLpHa oNe
18 years ago

Nice to see you fully active again, Rob ! What about a Turrican II trainer, my all time favourite ! 😉


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Password generation

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Would love your thoughts, please comment.x