Are we hitting or being hit?

In the previous post, we saw that a set carrier flag is what communicates back to the calling code that the hit character has died. So we can greatly simplify the damage infliction method by just setting that flag and returning. But we want to have a better cheat and only have the hit character killed if it is a monster. But how do we determine whether it is a monster?

We see an instruction which determines this on address #6807 bit 2, (iy+00) what this method does is comparing bit number 2 (numbers will start counting from 0 and from the right) of the value of memory address iy+00 and setting the a register to 0 if this bit is 0 and to 1 if this bit is 1. The value of memory address iy+00 is the index of the character, as we have seen before. It will have a value of 0,1,2 or 3 for our party members, and a value of 4,5,6 or 7 for enemies. Now look at the binary representation of these numbers. The rightmost bit is bit number 0, then number 1 and the third bit is bit 2. So the third bit from the right is the one that is being checked in the instruction. You will see that it is 0 for all our friends, and 1 for the enemies. Did you ever wonder why in old games the size of the party is often 4 max? This might be one of the reasons! Now let’s have a look at a greatly simplified damage infliction method that discriminates between enemies and friends.

Simplified invincibility code infliction method

If you look at the method, you will see first the 3rd bit is checked, which indicates whether the character hit is an enemy or friend. Then we have a jump if the check result is 0, indicating friend. We just return, so nothing happens. If we are hitting an enemy, we will set the carrier flag, indicating death, and return. The rest of the method is now obsolete, and all memory up until #682A can be set to 00. This is not needed, but will give more clarity on it being memory not used.

Checking implications

Running the game indeed seems to do what we want it to. But it is wise at this moment to think about possible implications. What things are different when we return than before the change? How can these impact program execution?

  1. The enemy HP is not set to 00.
  2. We did not end up with HP in DE and damage in HL.
  3. We outputted a less text to the screen, we might get graphical issues.

Now if you are changing code to release to public, you should really debug beyond your change in multiple scenario’s to see whether the values that are different are used anywhere beyond your change. Also, intensive testing is needed to make sure the change did not break anything else. For now, we can just fight a few battles, and see whether the cheat works. Try damaging the enemies in different ways (hit, magic, item).

Now we have freed up a bit of memory, so there is space for some more logic. I want you to make the cheat a bit more sophisticated. We now just see the enemy die or we see nothing happening to us, but there is no information. I want to see the text: [HP] DMGE! when we are hitting an enemy. So if the enemy has, for example, 225 HP, the text should be 225 DMGE!. If we are hit, the text should be 0 DMGE! I want you to use as little memory as possible for this, because we will need all the bytes we can get for the assignment in the next post. It is advised that you first write down the statements as you want them on paper and then translate them all to the needed ‘opt-codes’.

It is good to mention that the program developers did not manually look up the codes for the statements that they needed. Also, they did not have to write the correct addresses into jump and call statements. They would write the instructions in a text file. Also, each line could have an extra label that they could address in a call or jump statement. Then they would use an ‘assembler’ to create the needed opt-codes, with all the right addresses in place. If you are a developer, it is a nice assignment to write your own Z80 machine code assembler in your program language of choice.

The cheat might work as we intended to, there is a big downside to this, however. The game will be unbeatable with the cheat in place. Think about it for a minute, why is this? Well, there are several moments in the game where you are intended to die. If you don’t, the game won’t advance. Very early in the game, for example, the owls are meant to kill you in the game, but if you are invincible, they won’t. So we need to think of a way around our invincibility. Maybe you can think of a way to have the enemies kill us in certain circumstances which can be programmed into our damage infliction method with relatively little code. I will explain one way I came up with in the next post and we will try to implement it.