Notes about Gameshark codes - kfkaplan/nintendo64_hacking GitHub Wiki

Notes about Gameshark conditional statements

Equal to conditional codes (e.g., D0XXXXXX YYYY) can stack. This includes the 1 byte D0 and 2 byte D1 versions.

You can make codes that look like this where all the conditions must be met before the RAM write (80 or 81) code executes. This is the same as a logical AND.

D0XXXXXX YYYY
D0XXXXXX YYYY
D1XXXXXX YYYY
8XYYYYYY ZZZZ

Unfortunately, it seems that the not equal versions of these conditionals D2 and D3 are not stackable. You can only include one of these before the RAM write 80 or 81 code that executes when a condition is not met.

Notes about Gameshark code injection and looping

Gameshark codes execute in an infinite loop. Somehow, the Gameshark injects its own executable code into the N64 that picks off a few CPU cycles periodically to do its own thing (like a retrovirus). The entire sequence of code in a block appears to execute one line after another before letting the N64 do its own thing for a while and then looping back to the top of the code block to execute again.

N64 processor does stuff and updates all the memory
Gameshark code block starts executing
Gameshark block line 1 checks or updates memory address
Gameshark block line 2 checks or updates memory address
ect……
Gameshark code block ends
Go back to top….

This means that lines that check the RAM (D0, D1, D2, D3) or write to the RAM (80, 81, 88, 89) affect all subsequent lines below themselves inside a Gameshark code block. The order of the lines in a code block matters. Especially for complicated Gameshark codes with multiple lines that check and/or update the same memory address.

In the example below, the byte at AAAAAA is set to CC so the conditional following it never execute the line after that.

80AAAAAA 00CC
D0AAAAAA 00BB //This conditional will never execute the next line since byte AAAAAA will always equal CC
80DDDDDD 00EE

You can string conditional statements together such that if the first one executes, the subsequent conditionals can check the memory address modified by the previous conditional and then execute an additional line. This is equivalent to having a single if statement executing multiple lines.

D0AAAAAA 00BB //If AAAAAA == BB
80CCCCCC 00DD //set CCCCCC to DD
D0CCCCCC 00DD //if CCCCCC == DD
80EEEEEE 00FF //set EEEEEE to FF (this only occurs if AAAAAA == BB)

You can force a memory address to some default value and then modify it temporarily when some condition is met. When the Gameshark code block loops back around again, the memory address goes back to the default value you set if the condition is no longer met.

80AAAAAA 00BB  //Normally AAAAAA is set to BB by default
D0CCCCCC 00DD //But if CCCCCC == DD
80AAAAAA 00EE  //Temporarily change AAAAAA to EE

Bitwise logic examples with the Gameshark

NOT

D2AAAAAA 00XX //If NOT AAAAAA == XX 
80CCCCCC 00ZZ //Set CCCCCC to ZZ

AND:

D0AAAAAA 00XX //If AAAAAA == XX
D0BBBBBB 00YY //AND if BBBBBB == YY
80CCCCCC 00ZZ //Set CCCCCC to ZZ

OR:

D0AAAAAA 00XX //If AAAAAA == XX 
80CCCCCC 00ZZ //Set CCCCCC to ZZ
D0BBBBBB 00YY //OR if BBBBBB == YY
80CCCCCC 00ZZ //Set CCCCCC to ZZ

By setting a single memory address with a logic statement, you can then use conditionals on that memory address to execute subsequent lines of code. The single memory address can also be an empty memory address unused by the game, which can be used to make the Gameshark do even more complex bitwise operations such as XOR.

AND EXECUTING MULTIPLE LINES:

D0AAAAAA 00XX //If AAAAAA == XX
D0BBBBBB 00YY //AND if BBBBBB == YY
80CCCCCC 00ZZ //Set CCCCCC to ZZ
D0CCCCCC 00ZZ //If CCCCCC == ZZ
Do something…
D0CCCCCC 00ZZ //If CCCCCC == ZZ
Do something else…
D0CCCCCC 00ZZ //If CCCCCC == ZZ
And so on and so forth…

OR EXECUTING MULTIPLE LINES:

D0AAAAAA 00XX //If AAAAAA == XX 
80CCCCCC 00ZZ //Set CCCCCC to ZZ
D0BBBBBB 00YY //OR if BBBBBB == YY
80CCCCCC 00ZZ //Set CCCCCC to ZZ
D0CCCCCC 00ZZ //If CCCCCC == ZZ
Do something…
D0CCCCCC 00ZZ //If CCCCCC == ZZ
Do something else…
D0CCCCCC 00ZZ //If CCCCCC == ZZ
And so on and so forth…

XOR:

80AAAAAA 0000 //AAAAAA is an unused mem address set to 00 by default, this acts as the value for checking if the OR is true or not
D0CCCCCC 00DD //If CCCCCC == DD
80AAAAAA 0001 //Set AAAAAA to 01
D0EEEEEE 00FF  //if EEEEEE == FF
80AAAAAA 0001 //Set AAAAAA to 01
D0CCCCCC 00DD //If CCCCCC == DD and…
D0EEEEEE 00FF  //if EEEEEE == FF
80AAAAAA 0001 //Set AAAAAA to 00
D0AAAAAA 0001 //If AAAAAA == 01 (CCCCCC == DD XOR EEEEEE == FF)
80GGGGGG 00FF //Set GGGGGG to 01
D0AAAAAA 0001 //If AAAAAA == 01….
…execute more lines if you want….

Button and control stick activation codes

Activator values source: https://doc.kodewerx.org/hacking_n64.html

Button Activators

Hex Byte 1 Hex Byte 2 Decimal Byte 1 Decimal Byte 2 Button
00 00 0 0 No buttons
01 00 1 0 D-Pad Right
02 00 2 0 D-Pad Left
04 00 4 0 D-Pad Down
08 00 8 0 D-Pad Up
10 00 16 0 Start
20 00 32 0 Z
40 00 64 0 B
80 00 128 0 A
00 01 0 1 C-Right
00 02 0 2 C-Left
00 04 0 4 C-Down
00 08 0 8 C-Up
00 10 0 16 R
00 20 0 32 L

1 Byte Control Stick Activators (Most Games)

x-axis y-axis
Minimum 80 (left) 80 (down)
Zero point 00 00
Maximum 7F (right) 7F (up)

Typical byte order in memory for activators. Sets of activators for each player are 8 bytes apart. Find player 1's activators and then add 8 bytes to the memory address location for player 2, 16 bytes for player 3, and 24 bytes for player 4. FF010401 tracks if a controller is plugged in. It is possible to search for this to easily find the activators (Hex to decimal: FF01=65281, 0401= 1025) (Source: N64 Activators - A Slightly More Techy Method ~by Viper187 http://viper.shadowflareindustries.com/?file=hackv500c.html&cat=hax0r)

Byte 0 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Bytes Offset from P1
FF 01 04 01 P1 Button 1 P1 Button 2 P1 C-stick 1 (x-axis) P1 C-stick 2 (y-axis) 0
FF 01 04 01 P2 Button 1 P2 Button 2 P2 C-stick 1 (x-axis) P2 C-stick 2 (y-axis) +8
FF 01 04 01 P3 Button 1 P3 Button 2 P3 C-stick 1 (x-axis) P3 C-stick 2 (y-axis) +16
FF 01 04 01 P4 Button 1 P4 Button 2 P4 C-stick 1 (x-axis) P4 C-stick 2 (y-axis) +24
FE 00 00 00 - - - - -

ASM (assembly) commands

2400 - NOP (No Operation) code

2400 is a NOP (No Operation) OpCode. It prevents code from running. For example 81XXXXXX 2400 will disable whatever code is running in memory address XXXXXX. This is useful for turning off various features in a game.

Source: https://macrox.gshi.org/The%20Hacking%20Text.htm#n64_asm