Calling Functions
Pre-baked code for sound, NPC spawning, etc.

Let's say you want to do something interesting. Like call a TSC event using assembly code. How would you do that?

Well, no fears. Pixel already has "pre-built" functions that are easy to use via the CALL instruction. Functions work like this:
  1. You put in some numbers (to the stack) in order to tell the function what to do.
  2. You CALL the function you want to use.
  3. You fix the stack.
Functions
Let's look at a function. These 3 instructions will call a TSC event on the map:
Instruction            Comments
PUSH (event number)    ;The number of the TSC event you want to call. THIS MUST BE CONVERTED TO HEX FIRST.
CALL 00421990          ;This is the specific CALL that will cause the TSC event to be run.
ADD ESP,4              ;Fix the stack.
Pixel already wrote the code that's been compiled and now located at address 421990, so we can just use the CALL immediately.
Instruction      Comments
PUSH 11          ;11 (hex) = 17 (dec). This will run event 17.
CALL 00421990
ADD ESP,4
Event 17 is the "refill health and missiles" event by default. So if you run this piece of code, Quote's health/missiles will be refilled along with a dialog box to tell you that it happened.

There are many more functions that do useful things. Like the following:
Add some weapon energy:
Instruction                      Comments
PUSH (amount of weapon energy)   ;Numbers must be in hex.
CALL 004196F0
ADD ESP,4
Play a song:
Instruction              Comments
PUSH (music ID number)   ;This is the TSC number of the song. Translate it to hex first.
CALL 00420EE0
ADD ESP,4
You can find more of these functions in the Assembly Compendium.

Fix the Stack?
This has probably confused you more than it has helped you. The "fix the stack" part is just the ADD ESP,(number) command that's at the bottom of any call to a function. The ADD ESP,(number) part removes the need for POP after calling a function.

Here's some more info:
Instruction              Comments
PUSH (music ID number)
CALL 00420EE0
ADD ESP,4               ;We PUSHed only once, so we use ADD ESP,4
Play a sound effect:
Instruction              Comments
PUSH (channel number)
PUSH (Sound ID number)
CALL 00420640
ADD ESP,8               ;We PUSHed twice, so we use ADD ESP,8
Notice that for playing a sound, we need to PUSH two numbers instead of one. These numbers tell the function two things: the channel number, and the # of the sound to play.

So, back to the "fix the stack part". In order to fix the stack after a function, you multiply the (number of times you PUSHed) by 4, then use ADD, ESP (that number). If you pushed one time before CALLing the function, it's ADD ESP,4. If you push 2 times, it's ADD ESP,8.

Also, be careful when multiplying by 4. It's obvious that 1*4 = 4, and 2*4 = 8. However, 4*4 is not 16. We are using hexadecimal, so 4*4 = 10 in hex. (Hopefully studying assembly will not cause you to fail at basic multiplication in real life)

Here's a super-sized function that requires 8 PUSHes!
Spawn an NPC:[1]
Instruction                           Comments
PUSH 0
PUSH 0
PUSH (direction)                      ;direction of NPC. 0 = left, 2 = right.
PUSH (Y velocity)                     ;y-velocity of NPC
PUSH (X velocity)                     ;x-velocity of NPC
PUSH (Y)                              ;y-position of NPC
PUSH (X)                              ;x-position of NPC
PUSH (NPC ID)                         ;TSC NPC number, in hex
CALL 0046EFD0                         ;perform create NPC function.
ADD ESP,20                            ;4*8 = 32 (dec) = 20 (hex)
Also, don't be under the impression that EAX, ECX, and EDX are somehow magically saved before and after you use a function. Keep in mind that registers are not supposed to be permanent storage locations. If you call a function, that function will probably use EDX, EAX, and ECX during its calculations. Therefore, the values of the registers will be different after you call a function (unless you made the function yourself and you know exactly what it does).

Saving Register Values
Preserving the value of a register during a function CALL is easy. Just PUSH whichever register you want to save and then do POP (register) after the function is done. Here I save and load the number located in EAX so that it is preserved after we CALL the "play a sound" function.
Address   Instruction
004937F4  MOV EAX,1300
004937F9  PUSH EAX        ;Save the value of EAX.
004937FA  PUSH 1          ;Push 1 (channel number)
004937FC  PUSH 1D         ;Push 1D (hex) = 29 (dec)
004937FE  CALL 00420640   ;Play a sound (29 is the teleport sound)
00493803  ADD ESP,8       ;Fix the stack.
00493806  POP EAX         ;Load the value of EAX. Now EAX holds 1300 just like before.
It seems as if CALLing a function would screw up the stack because of all the PUSHes and then the CALL and the modifying ESP part. In reality - the structure of an ASM function is carefully designed so that it doesn't screw up the stack. The PUSH EAX and POP EAX parts (highlighted in green) actually work correctly.

What if you wanted to save the value of multiple registers instead of just one? This is also easy.

Just do:
PUSH EAX
PUSH ECX
PUSH EDX
right before the function. After the function, just do:
POP EDX
POP ECX
POP EAX
And that's it.

Navigation
Previous Lesson: Math Instructions
Next Lesson: Valentine Nemesis
Table of Contents

[1]For the Spawn NPC function, the first two PUSHes do not have to be PUSH 0. The first PUSH actually determines which entity slot the game starts checking at for this NPC. There are 0x200 slots total. The next PUSH is more complicated. You're supposed to do PUSH DWORD [EBP+8] if you want to create a parent/child system between NPCs. The parent can communicate information to its children and vice versa. These are both more complex topics, so if you feel overwhelmed, just know that using those two PUSH 0 commands will work just fine.