In the Deep Dive series, we’ll take apart a NESmaker assembly script and see what it does and how it works. In this first episode, we’ll take a look at the GetActionStep macro.
Inside your game code, you might have come across the following lines of code once or twice:
TXA
STA temp ;; assumes the object we want to move is in x.
GetActionStep temp
CMP #$07
What this code does, line by line, is this:
- Transfer the value of the X-register to the accumulator.
- Save the accumulator in a temporary variable, named temp.
- Get the current action step number from the object with number temp.
- Check if this action step number has a value of #$07.
Lines 1, 2 and 4 are pretty basic Assembly code. Line 3 though, is a bit more than that: it references a macro by the name of GetActionStep. This macro consists of a few lines of assembly, which I will further dissect now.
The code for the GetActionStep macro can be found in your NESmaker installation folder, in the following file:
GameEngineData\Routines\BASE_4_5\System\Macros\GetActionStep.asm
The code looks like this:
MACRO GetActionStep arg0 ;; arg0 = player LDX arg0 LDA Object_frame,x LSR LSR LSR AND #%00000111 ;;; this is the action step, loaded now into accumulator. ENDM
Line by line, it does the following:
MACRO GetActionStep arg0
Start a new macro, name it GetActionStep and accept one argument by the name of arg0. This way, the assembler/compiler knows that whatever code comes next won’t directly be part of the game’s code, but might be inserted later on if the macro gets referenced. The line “GetActionStep temp” is an example of such a reference.
;; arg0 = player
A semicolon inside the code indicates that it is followed by a comment instead of executable code. This semicolon will tell the assembler/compiler that whatever is written after should be ignored, up until a new line starts. So this line is here to tell the developer that the value of the arg0 value corresponds with the player’s object number value.
LDX arg0
Transfer the value of arg0 (which is actually temp, which according to the previous comment is the player) to the X-register.
LDA Object_frame,x
Object_frame is a reference label used for a memory location in the code. At this location, the frame data for all current objects is stored in a row of variables. This line of code tells the script to look at the location of Object_frame in memory, move over x positions to the right, read the value of that location in memory and write that value in the accumulator. So, for instance, if the player object number is 5, we go to the first Object_frame variable, look five places ahead and we will find the player’s object frame value there.
The Object_frame variable is stored in the form of #%aabbbccc, where bbb is the current action step (0-7).
LSR LSR LSR
The LSR command stands for Logical Shift Right. What this command does, is shift all bits of the accumulator one position to the right, and adds a zero in front of it. By repeating this command three times, it shifts the bits to the right three times as well, and additionally, it adds three zeroes in front.
As stated above the Object_frame variable has a format of #%aabbbccc. Shifting this over three times and adding leading zeroes will turn the value into #%000aabbb.
AND #%00000111
The AND command does an AND logical operation on each bit of the accumulator value, and changes each bit accordingly. Each bit will become 1 if and only if both the original bit and the bit that is passed as the AND argument are 1. In all other cases, the bit will become 0. So what this script actually does, is set the leftmost five bits to zero, and keeps the last three bits the way they are.
;;; this is the action step, loaded now into accumulator.
Another commented line which has no code and will not be compiled.
ENDM
This line tells the compiler that this is the end of the GetActionStep macro. So whenever the macro gets referenced, it will be replaced with the macro code up until this point. From here on, code will be compiled as usual again.
Putting it all together
MACRO GetActionStep arg0 ;; Define GetActionStep macro, take one argument ;; arg0 = player LDX arg0 ;; Load the argument into the X-register LDA Object_frame,x ;; Take the x'th variable from Object_Frame, value #%aabbbccc, and load it into the accumulator LSR ;; Shift right: #%0aabbbcc LSR ;; Shift right: #%00aabbbc LSR ;; Shift right: #%000aabbb AND #%00000111 ;; #%000aabbb AND #%00000111 = #%00000bbb ;;; this is the action step, loaded now into accumulator. ENDM ;; End of macro ; usage: TXA ;; Move the X-register value to the accumulator STA temp ;; Store the accumulator's value in a variable named temp GetActionStep temp ;; Reference the GetActionStep macro; see below CMP #$07 ;; Check if its value is #$07