Assembly 101: Lookup tables

Lookup tables, or LUTs for short, are a quick and easy way to reference indexed data. This post will try to explain how to use them in your game, using a general example.

Let’s say your player has an arsenal of eight weapons, and you want the player to be able to cycle through them. You will use a variable weaponChoice (with a value from 0 to 7) to determine which weapon currently is chosen. The currently chosen weapon will be shown in your HUD as a sprite. The eight available weapons each have a unique sprite in your spritesheet: the first weapon uses the sprite at position #$2C in the spritesheet, the second weapon uses #$29, et cetera. For the code to show the correct sprite on screen, you could create a long list of compares – which may look something like this:

  LDY weaponChoice  ; load the value of the chosen weapon in the y-register

  CPY #$00          ; check if the value of the y-register is #0
  BNE +             ; if not, branch out to the next + label
    LDA #$2C        ; Load value #$2C (sprite of first weapon) into the accumulator
  +                 ; this is where the above BNE + will branch out to

  CPY #$01          ; check if the value of the y-register is #1
  BNE +             ; if not, branch out to the next + label
    LDA #$29        ; Load value #$29 (sprite of second weapon) into the accumulator
  +                 ; this is where the above BNE + will branch out to

  CPY #$02          ; et cetera, et cetera... repeat this for all eight weapons
  ; ...

  STA temp          ; store the value of the accumulator (the correct weapon sprite) in a temp variable

Using a real life analogy: let’s say the eight weapons are people in a line, and you need to speak to the third person in said line. This script would go to the first person and asks him: “are you the third person in line?” That person tells you that no, in fact they’re not. Then the script moves to the next person asking the same question, and the next, up until it has found the person it is looking for.

While this may perfectly work for your game, the code will get messy if there are many weapons to select from. Also, it’ll eat away precious bytes and may put your rom size over the limit, resulting in your game not compiling. This is where a lookup table comes in handy.

A lookup table is an indexed list of data which the code can read from. Instead of checking every single possible weapon until it’s equal to the weaponChoice, it’s more efficient to use the weaponChoice variable as the index, then pluck the right value from the lookup table. This results in faster and better code, which also is easier to extend later on. A lookup table in this example will look something like this:

weaponChoiceTable:                            ; the label to reference the weapon choice table
  .db $2C, $29, $39, $74, $04, $05, $06, $07  ; the values inside the table

In this table, weaponSpriteTable is the label where the table starts; this label will be referenced in the code where you retrieve the correct value for your weapon, based on the weaponChoice value. To load the appropriate sprite value based on weaponChoice, the code will look something like this:

  LDY weaponChoice         ; Load the current weapon in the y-register
  LDA weaponChoiceTable,y  ; take the y'th value from the weaponChoiceTable
  STA temp                 ; store the value from the table in a temp variable

Applying the same real life analogy as earlier, this script knows directly to pick the third person in line.

Please note that these indexed lookup tables start with a value of 0 – so #0 is the first item in the table, #1 is the second, et cetera. Also it’s important to make sure your lookup table is not present in the executable main game loop, or the game will try to execute raw data as code, which will result in unexpected behavior and most likely will crash your game. A safe place to put your table is the ExtraTables.asm file in your Routines\BASE_4_5\Game folder.

The above example can be found in NESmaker’s source code, in Game\ExtraTables.asm and Game\MOD_AdventureBase\Common\doSpritePreDraw_AdventureBase.asm files.