Home > Books > Amstrad CPC > The Further Adventures of Fred

Hacking The Further Adventures of Fred

Discover how I hacked my own Amstrad CPC game to tweak the difficulty, get rid of an annoying sequence, and change the default keys. Follow me on a journey into the code of The Further Adventures of Fred. By Sean McManus.

I wrote The Further Adventures of Fred between 1989 and 1990. The game is a simple dodge-the-baddies, collect the tokens game, without gravity. Looking back, it was probably influenced in part by Mutant Monty, which was a game I'd enjoyed a few years earlier.

Future Publishing paid me to include The Further Adventures of Fred on the Amstrad Action cover tape, but it never got that far. I heard it was scheduled to appear on issue 118, which was cancelled as the magazine ceased publication. There was a long time between the game being licensed and AA closing, so in between I released the game myself and AA reviewed it and gave it 75%.

The game is like a time capsule for me, containing lots of cultural references that were significant to me at the time. The final level is inspired by Jean-Michel Jarre's Destination Docklands concert, which I had attended the year before. There are several references to Pink Floyd in there, and lots of in-jokes. The square Fred character is based on the smiley face character in the Amstrad character set, which had featured in my first game on the machine, written on Boxing Day in 1984. I wrote it again a few days later, because we didn't have a blank tape to save it on first time around.

Here's a video of the game:

Remastering The Further Adventures of Fred

There were several things that always bothered me about The Further Adventures of Fred:

  • The difficulty was too hard. The first level has a monster hurtling straight towards you, so you can die almost instantly. My reasoning was that the stakes are really low at the start of the game and so it could start with a bit of drama. Now, I think it's probably just annoying and offputting. Creating games in a vacuum, as many of us did pre-internet, made it hard to get the difficulty right.
  • There's a practical joke at the end of Level 1 where the game pretends to crash and shows the Amstrad start-up screen. It seemed funny at the time, but again, it's probably just annoying. In an early version of the game there were little story sequences and animations between all the levels, but that was dropped when I stopped using BASIC to patch the levels together and went 100% machine code. This was the only one left.
  • The default keys were set to joystick, which means nearly everyone needs to redefine the keys before they can play, especially on an emulator. That's not a great user experience. In 1989 I'd never heard the phrase "user experience" if indeed it existed.

So, in 2020, I decided to fix the game. The question was: could I do it, thirty years on, and without much documentation to go on?

Understanding how the code is structured

At one point, I had the source code for the game running from ceiling to floor in my room, printed on continuous printer paper. I'd stare at the code for ages trying to find bugs in it. When I came back to this in 2020, I did find a print out that I could tell had been stuck to the ceiling, but it looked like quite an early version. I couldn't remember enough about Z80 assembly language to make sense of it, either.

Going through my old development discs, I found a BASIC program I wrote that compiled the game from separate files. This was a big help, because it gave me a clue as to where I'd find different parts of the game code. On the offchance anyone else wants to nose around in the code or I come back to it another day for some reason, this is what I found:

AddressContents
4500 (&1194) Squid sprite. This was a big one, added quite late, so it looks like I just dropped it down here. It takes up a huge amount of screen space and memory for an image that is, fundamentally, not very good.
8731 (&221B)

Text content. This includes a lot of control codes used for formatting, including to make it look like the machine has reset at the end of level 1. Looking back, that's quite an efficient solution because the machine code only needs to print the characters. The formatting is built in. I think at least some of the mode changes are executed using control codes, even when no text needs to be displayed. There is some padding at the start of this section that was used for hidden greetings at one time, but they're not in there now.

Here's a little program to view this data. If you make line 3 always print the character, you'll see all the mode and pen changes too.

1 for g=8731 to 10088
2 a=peek(g)
3 if a>31 then print chr$(a);
4 next

10089 (&2769)Levels data. More details below on that.
13900 (&364C) Digitized scream sound effect. CALL 13900 to hear it.
16640 (&4100) Sprites, glorious sprites! The sprites were created using my Sprite Definer, which was on an AA covertape.
33841 (&8431) Music. The music was created using Micro Music Creator. If you CALL 33841 you can use |MUSICON to hear the game completion tune. The game just goes straight to the code that plays the music when it's required, rather than using the RSXs. I think there are several tunes from Micro Music Creator in this block of code. I don't know where the others begin.
39319 (&9997)Game code. To run the game use CALL 39319.
41623 (&A297) Sprite addresses. I think this is a lookup table that converts sprite numbers into sprite addresses.

I've included the addresses in both decimal and hexadecimal above. My original code used decimal, mostly. Over the course of this update project, I drifted towards using hex more because that's what the Winape debugger uses. You can find a simple hexadecimal to decimal converter in my book chapter about using machine code with BASIC programs.

Decoding the levels data for The Further Adventures of Fred

With no real documentation to go on, I was in the strange position of "hacking" my own game to try to work out how the data was structured.

It was all about finding patterns. I started by looking at the levels data starting at 10089 and looking for numbers in the ASCII range (for the name of the level) and for repeating patterns that might represent the walls and the tokens you have to collect. Level 1 (in the original game) only had bricks, tokens, and monsters, so it wasn't too hard to spot the pattern.

Offset from start of levelContents
0 Title of the level. Fixed, 20 characters. Start address + 19 is the last one. Spaces (ASCII 32) are used for padding to centre the text.
200. Don't know why this is here. I suspect I miscalculated and left an extra byte by mistake.
21 Screen map starts. There are 10 rows, each made up of 20 columns. The screen map goes from left to right, top to bottom. A 0 means a sprite isn't drawn at that position, but big images can spill over into 0 spaces. A 7 is a token to collect.
221 5 bytes. I think this is the colour data? If I recall correctly, some of the inks are fixed, but some of them can be defined. I suspect blinking colours, which are used in a few places, including for colour swapping animation, are defined in code and not in the levels data. It's possible they're defined in the text data using control codes..
226The movement pattern for this level. All enemies follow the same movement pattern. The direction numbers are (I think):
  • 1 - Up
  • 2 - Right
  • 3 - Down
  • 4 - Left
When an enemy hits something, it bounces. These four bytes say which direction to bounce in. For example, the second byte in this sequence says which direction to go if the enemy hits something moving right (direction 2). A pattern of 4123 is clockwise. A pattern of 0402 means only left-right movement. A pattern of 3412 means that sprites either go up and down, or they go left and right. I used a similar idea for the movement of sprites in my book Mission Python. It gives you quite a lot of potential for different movement patterns without requiring bespoke coding for different patterns.
230The number of enemies on this level.
232Enemy data begins. I think this takes this form:
  • Sprite number
  • Starting x position
  • Starting y position
  • direction of movement (1, 2, 3, 4)
253 The number of tokens on this level.

Viewing the levels data

There's a great feature in the Winape emulator that enables you to copy and paste code into the emulator, that then gets typed into the virtual Amstrad. Find it under File > Auto Type or use Ctrl + F5. You can use it to copy and paste the code here so you can explore the data. First load the game into memory. You'll need to give this a moment to load. Don't add more commands after it in the F5 window, because they won't run correctly.

memory &1194
load"faf20.bin"

I'm assuming you're using the latest version of my Amstrad games disc. If not, use the filename faf91.bin instead.

Now use the Auto Type feature to enter this listing:

1 mem=10089:for level=1 to 15:print string$(60,"-");:print:print"LEVEL:";level
2 print"MEM:",mem:for char=1 to 20:print chr$(peek(mem));:mem=mem+1
3 next:print peek(mem):mem=mem+1
4 for rows=1 to 10:for cols=1 to 20:a$=hex$(peek(mem),2):if peek(mem)=0 then a$=".." else if peek(mem)=7 then a$="##"
5 print a$;" ";
6 mem=mem+1:next:print:next:print:print"MEM:",mem:print
7 for g=1 to 33:print peek(mem);:mem=mem+1:next:print:next level

Here's an example of what the output looks like, with The Starting Gun screen. This is a particularly good one to look at because it's just bricks around the edge, and tokens in the middle. The dots represent 0 spaces and the ## are tokens. This screengrab is from after I'd already modified this level by moving one of the tokens, but before I changed level 1 to a different design.

Screenshot of level data from Further Adventures of Fred

A poke for The Further Adventures of Fred

So here is an example of a poke we can create using this information. You'll need to load the game code first using the code snippet above. The code won't load if there's a BASIC program in memory, so load the game code and then enter this program. This program changes the number of tokens on each level to 1, so that you complete the level if you collect a single token.

1 for levels=1 to 15
2 poke 10088+(levels*254),1
3 next
4 call 39319

That's maybe not the most useful poke. If you want to see all the levels, there's a cheat mode you can use: Shift+1 completes the level.

Reconfiguring the starting screen

You could use the information above to change the screen layouts too. I made two changes in the updated version of the game, which is available on the new version of my games disc:

  • I placed a token between you and the enemy that charges towards you on The Starting Gun. Enemies can't walk through tokens. This solves the problem of that level being too hard, and stops you dying immediately if you don't move fast enough when the level begins. I moved a token rather than adding one to avoid having to check for or fix any side effects of adding a token to the game. I don't know, for example, whether there are checks at any point on how many tokens you have. I doubt it, but it was safer not to raise the question.

  • I swapped the data for two levels around, so the first level is now Toot-And-Come-In (that's how you operate an Egyptian doorbell, incidentally). The Starting Gun has moved back a couple of levels. I think that provides a softer start to the game, and more clearly establishes a pattern in the game before The Starting Gun subverts it by not having any interior walls. The Starting Gun is a fairly difficult level, even without the monster racing towards you at the start. Here's the code I used to swap those levels over. I got the address numbers using the program above that shows the level data.

1 for mem=10089 to 10342
2 oldstart=peek(mem)
3 poke mem, peek(mem+508)
4 poke mem+508, oldstart
5 next

Screenshot from The Further Adventures of Fred

The new starting screen in The Further Adventures of Fred

Removing the game reset joke

Screenshot showing CPC reset screen with "Ha Ha Only Joking" on itI was really keen to get rid of the sequence that fakes a machine crash at the end of the first level.

Here's how I went about that:

  1. Find the text for the screen reset sequence in the screen data. It starts at &22BF. It looks like the message you see when you turn the Amstrad on.

  2. Search for where &22BF is referenced in the machine code. Pressing F7 in Winape opens the debugger which has a tool for searching for bytes in memory. I found &22BF referenced at &A275. Remember that data is stored low byte first, so I actually had to search for "BF 22" to find references to memory address &22BF.

  3. My Z80 knowledge is rusty, and this code probably isn't the cleanest either. Using the disassembler in the debugger, I identified addresses to try to poke 0 (NOP) and &C9 (RET) into. I tried disabling the call to the text display firmware, but this disabled all mode changes, so I think what I've found here is the text display routine. I think the code is using control codes to effect all mode changes. After poking around here, I decided this wasn't the best place to address this problem. I tried several ideas, and the game crashed each time.

  4. Searched instead for "joking" because this routine says "Ha Ha! Only joking!" after a short delay. This uses the double-height text rather than the normal text display routine, so I was happy this would lead me somewhere different.

  5. Found that text begins at &9E23. Used the disassembler in Winape to find where that address is referenced, which is at &9E1A.

  6. Used the disassembler to identify where the routine containing this reference begins and tried POKE &9E14,&C9 to make this routine return immediately. It got rid of the reset sequence, but not the "Ha Ha!..." message and the delay around it.

  7. Searched for references to &9E14 to see where this code routine is called. Couldn't find anything useful.

  8. Took another look at the code starting at &9E14. Worked out that CALL &9E39 is the delay, CALL &A274 displays the reset screen (although without the mode change, strangely). I think CALL &A20D is the double-height text routine. Decided to zero the whole lot of it, and then poke a return instruction at the end with:

for mem=&9e14 to &9e1d:poke mem,0:next:poke &9e20,&c9

That worked! The pace of the game is much better flowing smoothly from level 1 to level 2, without the distraction of the fake reset in between.

Screenshot of the Winape debugger

Press F7 in Winape to access the built-in debugger and disassembler. It's worth remembering that the disassembler doesn't know what's data and what's code. Here you can see it provides disassembly for the text, which doesn't make sense as machine code.

Changing the default keys

The default keys in the game are joystick, which means pretty much everyone nowadays has to start by redefining them. It's friction nobody needs. I wanted to make the default keys something more sensible.

Here's the process I went through:

  1. Searched for references to CALL &BB09. This is the firmware routine for reading a keyboard character from the buffer if available. I had a hunch I'd probably used this rather than something more sophisticated. I was investigating this before I found the built-in debugger in Winape, so I wrote a short program to carry out the search. Remember that the address in memory is stored least significant byte first, so to find &BB09 you have to search for &09 and &BB in that order. The op code &CD is the CALL instruction. 5 ' Find a CALL instruction
    10 for mem=39319 to 41623
    20 if peek(mem)=&cd and peek(mem+1)=&09 and peek(mem+2)=&bb then print mem
    30 next

  2. Found that address &9F88 is where CALL &BB09 is used. It's the only place in the code. I did also search for CALL &BB1B which reads a key from the keyboard. It's referenced in two places, but I didn't need to go down this route. It's possible it's being used in the section that redefines the keys.

  3. Studied the code starting at this memory address and found a sequence that had five CP and JP Z instructions in a row. These instructions could be used to see whether a particular key was pressed, and jump to a particular part of the game code if so. The CP instruction compares what's in the accumulator with a particular number. The JP Z instruction jumps to an address if the comparison matches. This sequence starts at &9FAD. There is one pair of CP/JP Z instructions for each of the gameplay keys (including the quit key). There is another CP/JP Z pair before it. I'm not sure what that's doing. I left it alone. [UPDATE: Come to think of it, this is probably the cheat mode. You press SHIFT + 1 to move to the next level.]

  4. Took a note of the values in the CP instructions. Then started the game, redefined the keys, and took another look. The values had changed!

  5. Tried poking the values I'd redefined into the game code and running it to see if it worked. It did!

    The code to change the default keys to cursor keys with Q to quit is: POKE &9FAE,&F0
    POKE &9FB3,&F1
    POKE &9FB8,&F2
    POKE &9FBD,&F3
    POKE &9FC2,&71

    Saving the modified game

    Another great feature in Winape is the File Properties. Find it using File > Disc A > Edit disc and then right-click a file and select Properties. It gave me a good start working out how to save the game once I'd finished tinkering with it.

    Screenshot of File Properties menu in Winape

    After making any customizations, you can save your game file using:

    save"custom",B,4500,37710,39319

    Play the updated Further Adventures of Fred

    The new version of the game is much easier to get started with, so I hope you'll consider giving it a go. You can find The Further Adventures of Fred on my Amstrad CPC games disc, which also includes updates to my other programs too. Find my other Amstrad CPC resources and tutorials here.

Credits

© Sean McManus. All rights reserved.

Visit www.sean.co.uk for free chapters from Sean's coding books (including Mission Python, Scratch Programming in Easy Steps and Coder Academy) and more!

Discover my latest books

100 Top Tips: Microsoft Excel

100 Top Tips: Microsoft Excel

Power up your Microsoft Excel skills with this powerful pocket-sized book of tips that will save you time and help you learn more from your spreadsheets.

Scratch Programming in Easy Steps

Scratch Programming IES

This book, now fully updated for Scratch 3, will take you from the basics of the Scratch language into the depths of its more advanced features. A great way to start programming.

Mission Python book

Mission Python

Code a space adventure game in this Python programming book published by No Starch Press.

Cool Scratch Projects in Easy Steps book

Cool Scratch Projects in Easy Steps

Discover how to make 3D games, create mazes, build a drum machine, make a game with cartoon animals and more!

Raspberry Pi For Dummies

Raspberry Pi For Dummies

Set up your Raspberry Pi, then learn how to use the Linux command line, Scratch, Python, Sonic Pi, Minecraft and electronics projects with it.

Earworm

Earworm

In this entertaining techno-thriller, Sean McManus takes a slice through the music industry: from the boardroom to the stage; from the studio to the record fair.

Scratch Homeschooling resources

Scratch cat with balloons invites you to visit my Scratch resources

Sean's Scratch Resources

Tips, tutorials and free book chapters for Scratch, a coding language widely used in schools.

Walking astronaut from Mission Python book Top | Search | Help | Privacy | Access Keys | Contact me
Home | Blog | Copywriting Services | Books | Free book chapters | Articles | Music | Photos | Games | Shop | About