Ideas to ASM
Converting thoughts to code

Translating to ASM
For many people - especially those without significant programming experience - it can be hard to transform "this is what I want the code to do" into "this is what it should actually look like". Right now we're going to practice translating basic ideas into assembly language so that you can see how the instructions fit together to create more complex actions.

Let's step away from the world of Cave Story for a while. Pretend that you're a computer programmer who is trying to design a music player[1]. This is what part of it might look like:
if the music player is ready
then play song 1
otherwise wait for user to press a button
An if ... then statement is a very common expression used in computer programming to control how programs operate.
In assembly, the idea is exactly the same. Instead of if ... then we have CMP ... (jump), where (jump) refers to any jump instruction that checks for a condition, such as JE, JNE, JGE, JG, and so on.

If (this is true), then (do something)
if variable X is 0
then add 3 to variable X
afterwards do nothing
The 3 statements above are written in "psuedocode", which means fake code. It's not real code yet, but it's useful enough so that we have a guiding system before we decide to write some assembly.

That said, let's translate psuedocode to ASM. Here I will choose EAX to replace "variable X" in the psuedocode.
Address   Instruction
00494201  CMP EAX,0    ;Is EAX equal to 0 or not?
00494204  JNE 494209   ;If no, don't add 3 to EAX.
00494206  ADD EAX,3    ;If yes, then add 3 to EAX.
00494209  NOP          ;Do nothing.
Notice that the "then statement" is only executed if the "if statement" is true. If the "if statement" is not true, then the "then statement" is ignored. The "afterwards" statement is executed regardless of whether the last "if statement" is true or not.

What if you want two things to be true at the same time?
if (variable X is 0 and variable Y equals variable Z)
then
    store 1 to variable X
    store 0 to variable Y
otherwise
    store 2 to variable X
    calculate Z minus Y
    store answer to Z
afterwards push X, Y, and Z onto the stack.
Now that piece of psuedocode is much more complicated. We can still translate it though. I will choose EAX to replace variable X, ECX to replace variable Y, and EDX to replace variable Z.
Address   Instruction
00493801  CMP EAX,0      ;Is EAX equal to 0?
00493804  JNE 493816        ;If not, go to PART 2.
00493806  CMP ECX,EDX    ;Is ECX equal to EDX?
00493808  JNE 493816        ;If not, go to PART 2.
0049380A  MOV EAX,1      ;PART 1. Store 1 to EAX.
0049380F  MOV ECX,0         ;Store 0 to ECX.
00493814  JMP 49381D        ;Go to PART 3.
00493816  MOV EAX,2      ;PART 2. Store 2 to EAX.
0049381B  SUB EDX,ECX       ;Calculate EDX - ECX, store result to EDX.
0049381D  PUSH EAX       ;PART 3. Push EAX.
0049381E  PUSH ECX          ;Push ECX.
0049381F  PUSH EDX          ;Push EDX.
Can we do something that's not pure math?
store 0 to variable X.
if Quote's current-health is less than or equal to 5
then
    if Quote's max-health is less than 8
    then store 8 to max-health
    afterwards store 8 to current-health
otherwise store 1 to variable X.
afterwards do nothing
One of the if ... then statements is nested inside another one! This is common practice in other programming languages, and assembly is no exception.
Here you really need the Assembly Compendium. Look up CurrentHealth in the compendium and you'll find 49E6CC. Look up MaxHealth and you'll find 49E6D0.
Address   Instruction
00493915  MOV EAX,0              ;store 0 to EAX.
0049391A  CMP WORD [49E6CC],5    ;Is Quote's current health less than or equal to 5?
00493922  JG 493942                  ;If not, go to address 493942.
00493924  CMP DWORD [49E6D0],8   ;Is Quote's max health less than 8?
0049392B  JGE 493937                 ;If not, go to address 493937.
0049392D  MOV DWORD [49E6D0],8   ;Make Quote's max health equal to 8.
00493937  MOV WORD [49E6CC],8    ;Heal Quote to 8 health points.
00493940  JMP 493947             ;Skip over MOV EAX,1
00493942  MOV EAX,1              ;store 1 to EAX.
00493947  NOP                    ;do nothing.
The above piece of code will heal Quote ONLY IF Quote's current health is below or equal to 5.
If Quote does get healed, then his max health will be checked. If the max health is less than 8, it will be set to 8. Then full healing occurs after that.
If Quote's max health is greater than or equal to 8, he will only be healed to 8 health points (no more than that).
Finally, EAX will hold the number 1 if Quote did not get healed. EAX will hold 0 if he did get healed.

Also, you should notice that the player's current-health is written as WORD [49E6CC] instead of DWORD [49E6CC]. This means that the current-health can only hold 4 hexadecimal digits at maximum, but the max-health can hold 8 hexadecimal digits at maximum. Remember that a word is 16-bits (4 hex digits) and a dword is 32-bits (8 hex digits).

Why is the max-health a bigger data size than the current-health? If the max-health happens to be bigger than 4 hex digits, the current-health can't reach the same value as the max-health anyway, so what's the point?

I have absolutely no idea. Maybe Pixel had a good reason for doing this. Maybe he didn't. Maybe he forgot that the current-health had a size of 2 bytes and the max-health had a size of 4 bytes. Maybe he didn't bother to change it. I really don't know.

Backwards Translation
In order to make pre-existing ASM code more understandable to human beings, we can do backwards translation (converting ASM to ideas) in order to make better sense of assembly language.

Remember that looping code from a couple of lessons ago? Well here it is:
Address  Instruction          Comments
004937F7 MOV EAX,0            ;Store 0 to EAX.
004937FC INC EAX              ;Increase EAX by 1.
004937FD CMP EAX,50           ;Compare EAX with 50 (hex).
00493800 JGE 00450DE9         ;If EAX is greater than or equal to 50 (hex), jump to 450DE9.
00493806 PUSH 9955            ;If not, push 9955 onto the stack.
0049380B JMP SHORT 004937FC   ;Jump to address 4937FC
Now we take the code and transform it into a format that humans can more easily read and understand:
store 0 to variable X
begin cycle A
increase variable X by 1
if variable X is greater than 50 (hex)
then break cycle A (go to address 450DE9)
otherwise
    push 9955 (hex) onto stack
    repeat cycle A
*takes a breath* Whew. That was a lot of code today.

Navigation
Previous Lesson: Call and Return
Next Lesson: Math Instructions
Table of Contents

[1]The example music player code given is an oversimplification. A real music player would need thousands of lines of code, or possibly more, to make it work correctly.