Notes for Mario Kart 64 - kfkaplan/nintendo64_hacking GitHub Wiki

Offset between RAM and ROM

RAM = ROM - 0xC00
ROM = RAM + 0xC00

Hex calculator: https://www.calculator.net/hex-calculator.html

Cup courses

The following memory locations store what four courses make up each cup. They are 16 bits. Modify them to make your own cups!

Source: Cup order notes by Rena (HyperHacker?) found in the Mario Kart 64 Hacking Data document. Ask me if you want to see it.

Course Mushroom Cup Flower Cup Star Cup Special Cup
1 810F2BB4 810F2BBC 810F2BC4 810F2BCC
2 810F2BB6 810F2BBE 810F2BC6 810F2BCE
3 810F2BB8 810F2BC0 810F2BC8 810F2BD0
4 810F2BBA 810F2BC2 810F2BCA 810F2BD2

Set the memory locations above to the following values to create your own cups:

Source: http://origami64.net/showthread.php?tid=47

Course Value
Mario Raceway 0000
Choco Mountain 0001
Bowser's Castle 0002
Banshee Boardwalk 0003
Yoshi Valley 0004
Frappe Snowland 0005
Koopa Troopa Beach 0006
Royal Raceway 0007
Luigi Raceway 0008
Moo Moo Farm 0009
Toad's Turnpike 000A
Kalimari Desert 000B
Sherbert Land 000C
Rainbow Road 000D
Wario Stadium 000E
Block Fort 000F
Skyscraper 0010
Double Deck 0011
DK's Jungle Parkway 0012
Big Donut 0013

In game timers and the “heartbeat” of Mario Kart 64

An 8 bit clock through 0-255 every few seconds is stored at 8018D3FF. A 32 bit clock appears to be stored at 800DC598. Either clock can be queried with conditional codes for making something happen every so often.

A unique timer is the byte 8018D3FB is a counter that counts from 00, 01, 02, 03, 04, 05 and then loops back around to 00 a few times a second. In other words, the byte constantly counts from zero to five, then resets, so I call it the “heartbeat”. You have six possible values constantly repeating regularly. It appears to be related to the timer 8018D3FF nearby in the RAM, but I can’t figure out exactly the game is using it for. It might be used for the timing and display of short animations like wheel smoke.

This is very useful because you can execute repeated events that turn on/off using a Gameshark conditional code (here I have chosen 05 but 00 -> 04 also should work). A few times a second, 1/6 of the time the conditional will be true and the RAM write code (80 or 81) will be on, and 5/6 of the time the conditional will be false:

D018D3FB 0005
8XYYYYYY ZZZZ

You can also combine it with other equal to (D0 or D1) conditionals like so:

DABBBBBB CCCC
D018D3FB 0005
8XYYYYYY ZZZZ

As an example, you can make player 1 hop repeatedly with the following code:

D018D3FB 0005 //If heartbeat == 05
80196505 0010 //Set button activator 2 for player 1 to press R to hop

Querying the random number generator to trigger random events

Mario Kart 64 has a 2 byte unsigned int random number generator (RNG) that constantly updates every frame in the game. This can be queried by Gameshark conditional (D) codes to cause the codes to execute memory writes to trigger events probabilisticly.

Mario Kart 64's RNG is the same as Super Mario 64's RNG. This video explains how the RNG works https://www.youtube.com/watch?v=MiuLeTE2MeQ

The RNG memory address:

802BA290

The 1 byte version RNG activation code triggers a random event about once every 10 seconds:

D02BA290 00??
8??????? ????

The 2 byte version RNG activation code triggers a random event about 1-2 times per hour:

D12BA290 ????
8??????? ????

Multiple activators with the same 80 or 81 memory write but pointing to different RNG values with the D0 or D1 conditional will increase the chance of an event occurring.

Note that the RNG initializes to the value of the selected character (Mario = 0x0000) at the start of a Grand Prix cup.

Querying if game is in menu/paused or if race/battle is happening (in multiplayer only)

This is useful for codes that you only want to execute while the game is in menu/paused or if a race/battle is happening in multiplayer. I need to find a more universal code for single player and multiplayer.

If in menu or paused... D015A788 00?? D115A788 ????

If race/battle is running... D215A788 00?? D315A788 ????

States and State Activators

Players/CPUs are separated by 0DD8 or 3544 bytes in memory. I have calculated the memory locations for all Players/CPUS. States add together.

Original source: http://tasvideos.org/GameResources/N64/MarioKart64.html

States:

Player Mem. loc.
Player 1 0F69D4 0F6A4C 0F6A4D 0F6A4E 0F6A4F 0F6A5A 0F6A5B
Player 2 0F77AC 0F7824 0F7825 0F7826 0F7827 0F7832 0F7833
Player 3 0F8584 0F85FC 0F85FD 0F85FE 0F85FF 0F860A 0F860B
Player 4 0F935C 0F93D4 0F93D5 0F93D6 0F93D7 0F93E2 0F93E3
CPU 5 0FA134 0FA1AC 0FA1AD 0FA1AE 0FA1AF 0FA1BA 0FA1BB
CPU 6 0FAF0C 0FAF84 0FAF85 0FAF86 0FAF87 0FAF92 0FAF93
CPU 7 0FBCE4 0FBD5C 0FBD5D 0FBD5E 0FBD5F 0FBD6A 0FBD6B
CPU 8 0FCABC 0FCB34 0FCB35 0FCB36 0FCB37 0FCB42 0FCB43
- - - - - - - -
Value State - - - - - -
80 (128) unknown Boo active Large feather jump active Dazed (e.g. penguin hit) Spin-out (hit object) unknown Frozen
40 (64) Spin-out swerve Struck by lightning "Reverse" Stop and slowly spin out Spin-out "WHIRRR!" unknown unknown
20 (32) No kart roll Outward sliding Draft boost Shrooming AB Spinning Dripping water Defrosting
10 (16) Bonk unknown Dash Zone boost (autoboost) CPU controlled (After losing GP race) "BOING!" speed (can slide) Smoking Frost (blue tint after ice breaks)
08 (8) Freeze kart in air (activates 32) Un-flattening Small feather jump active Spin out (banana) Off Ground unknown Stuck (out of bounds)
04 (4) Spin-out bonk (activates 8) Flattened unknown Tumble rotation (momentum) Zipper boost unknown Low opacity (Lakitu fade-out)
02 (2) Ghost activation smoke Directional tumble (i.e. green shell) Slightly off ground Star power Jumped (pressed "R") unknown Lakitu holding
01 (1) Big jump landing smoke Vertical tumble (i.e. fake item box) Wall tumble MT boost active Braking Over water/ lava/ space Water (out of bounds)

State activators:

Player Mem. loc.
Player 1 0F699C 0F699D 0F699E 0F699F
Player 2 0F7774 0F7775 0F7776 0F7777
Player 3 0F854C 0F854D 0F854E 0F854F
Player 4 0F9324 0F9325 0F9326 0F9327
CPU 5 0FA0FC 0FA0FD 0FA0FE 0FA0FF
CPU 6 0FAED4 0FAED5 0FAED6 0FAED7
CPU 7 0FBCAC 0FBCAD 0FBCAE 0FBCAF
CPU 8 0FCA84 0FCA85 0FCA86 0FCA87
- - - - -
Value State Activator - - -
80 (128) unknown Dash Zone activator Weak shroom (unknown use) Spinout start (save)
40 (64) unknown Chomp/ train/ car/ bomb hit tumble activator Lightning hit unknown
20 (32) unknown Spiny/crab hit Star unknown
10 (16) Spinout unknown Small feather jump activator unknown
08 (8) unknown Boat hit Boo activator (translucent) unknown
04 (4) Boo activator (invisible) Holding item(s) zoom out unknown Green shell hit
02 (2) Start boost activator Large feather jump activator Shroom Mole hit
01 (1) Shell hit unknown Squished Spinout

AI/Player States

Source: http://origami64.net/showthread.php?tid=740&pid=7252#pid7252

Setting to D0 turns on AI and human status for an AI that does not cheat and can be used as a bot in VS mode. Turning off bit 128 "kills" a character. Bit 1 appears to set if a player is a bomb (only loads in 3 & 4 player battle mode, otherwise player just turns invisible).

Player Mem. loc.
Player 1 0F6990
Player 2 0F7768
Player 3 0F8540
Player 4 0F9318
CPU 5 0FA0F0
CPU 6 0FAEC8
CPU 7 0FBCA0
CPU 8 0FCA78
- -
Value State
80 (128) Character exist, if 0 character doesn't exist
40 (64) Character is human controlled
20 (32) Character can't move, race has not started and waiting on Lakitu
10 (16) Character is CPU controlled
08 (8) Demo / finish line camera movement
04 (4) Unknown
02 (2) Race startup sequence drive to the starting line
01 (1) Character is invisible / a bomb

Rough notes (in progress)

800F6991 0040 turns P1 into a bomb and unable to use items. Normally 800F6991 is 0010. Not sure what that does but setting it to 0000 has it go straight back to being 0010. The bomb will not render unless in 3 or 4P VS mode. You can run into other characters to blow them up. Once you do that 800F6990 gets set to 0070 which means you are human AND CPU controlled and can't move. 800F6991 then gets set to 0000.

800F6990: C0 10 00 0E 00 06 00 00 -- During race 800F6990: D8 10 00 0A 00 01 00 00 -- Finish line camera 800F6990: D8 10 00 5B 00 01 00 00 -- Demo cam after finish line

During race startup 8018F002 0001 8018F1E1 0007 80191F8B 00FF 801920AA 0005 801920DA 0006 80192AAB 0001

During Race 8018F002 0001 8018F1E1 0007 80191F8B 0001 801920AA 0005 801920DA 0006 80192AAB 0008

During cross the finish line 8018F002 0008 8018F1E1 0000 80191F8B 0007 801920AA 00FF 801920DA 0000 80192AAB 0006

During points add up at end of race 8018F002 00FF 8018F1E1 00FF 80191F8B 00FF 801920AA 0007 801920DA 00FF 80192AAB 0007

Steering:

800F6A50 is a signed 1 byte float for player 1 that controls causes the kart to steer, with values similar to those found in the control stick activators. It might be related to "AB" spinning where you hold the breaks, gas, and turn all the same time and spin around fast. The other players presumably have the same byte separated by 0DD8 in memory like all the other state and state activators. I will make a table later. This will probably be useful for making bots that randomly turn, without the need to use control stick activators.

Character color modifiers

The color modifiers tint the color of a character. Likely used in game to make the characters flash various colors like yellow when a star is used, or to add dark or yellow tints like when going through the tunnel in Luigi's Raceway. Setting these 2 bytes to FFFF achieves a nice tinting effect. Other values can be set for all sorts of psychedelic colors. In memory, each color is separated by 10 and each player is separated by 02. Below is a table showing all the memory locations for each player's color modifier.

Player Red (10) Green (20) Blue (30) Black Tint (40) Blueish Tint (50) Yellowish Tint (60)
Player 1 81164B10 81164B20 81164B30 81164B40 81164B50 81164B60
Player 2 81164B12 81164B22 81164B32 81164B42 81164B52 81164B62
Player 3 81164B14 81164B24 81164B34 81164B44 81164B54 81164B64
Player 4 81164B16 81164B26 81164B36 81164B46 81164B56 81164B66
CPU 5 81164B18 81164B28 81164B38 81164B48 81164B58 81164B68
CPU 6 81164B1A 81164B2A 81164B3A 81164B4A 81164B5A 81164B6A
CPU 7 81164B1C 81164B2C 81164B3C 81164B4C 81164B5C 81164B6C
CPU 8 81164B1E 81164B2E 81164B3E 81164B4E 81164B5E 81164B6E

Laps

The default starting lap number and how laps are incremented when crossing the finish line can be set with the following codes. Setting the starting lap modifier to negative numbers allows more laps per race.

Source: HyperHacker's old website https://web.archive.org/web/20090423093334/http://hyperhacker.kicks-ass.org:55555/index.php?p=Codes/Mario_Kart_64

Starting lap modifier (default FFFF)
8100F94A ????
You can reduce this value to have more laps per race by starting on a negative lap number.

Number of laps counted when crossing finish line
81009562 ????

Number of laps counted when crossing finish line backward
810096AA ????

Endless race
81009564 2400

Messed up laps
81009564 AC48

It is possible to invert how laps are counted when crossing the finish line to create a "backwards race." This was attempted in this video: https://www.youtube.com/watch?v=fZfZkFYkEBQ&t=4s

Each player's current lap is stored as a 32 bit integer. Each player starts on lap 0, so the integer is FFFF FFFF. After immediately crosses the finish line to start lap 1, the integer increments up to 0000 0000. Lap 2 increments to 0000 0001. Lap 3 increments to 0000 0002. When the player has finished their final lap, the integer increments to 0000 0003 and the race ends for that player. In general we can ignore the first 16 bits so that the laps progress is as follows on the second 16 bits: FFFF, 0000, 0001, 0002, and 0003.

Lap First 16 bits Second 16 bits
-3 FFFF FFFC
-2 FFFF FFFD
-1 FFFF FFFE
0 (default start) FFFF FFFF
1 0000 0000
2 0000 0001
3 0000 0002
4 and above (finish race and win) 0000 0003

These bytes are stored in the following memory addresses for each player:

Player / CPU First 16 bits Second 16 bits
Player 1 81164390 81164392
Player/CPU 2 81164394 81164396
Player/CPU 3 81164398 8116439A
Player/CPU 4 8116439C 8116439E
CPU 5 811643A0 811643A2
CPU 6 811643A4 811643A6
CPU 7 811643A8 811643AA
CPU 8 811643AC 811643AE

Starting a race with negative laps will not show up on the on screen "Lap ?/3" lap counter until the final three laps. It seems that this lap counter is a series of premade textures and trying to set it above 3 results in loading a glitchy texture in place of the lap number. The lap counter modifier for player 1 is as follows:

On screen lap counter modifier for Player 1

8018CAE2 00??

?? = 00 Lap 1
?? = 01 Lap 2
?? = 02 Lap 3
?? = 03 and above, nonsense texture in place of number
?? = 80 start win sequence and freeze?
?? = 90 and above, start win sequence and not freeze, Lakitu flying around waving flag

HyperHacker made an alternate lap counter which can handle more than 3 laps (Note: does not work in mpuen64+).
See: https://www.kodewerx.org/forum/viewtopic.php?f=18&t=2763#p38213yer

Distance around track

Each player has a 32 byte signed float that tracks their progress around the track. While eight floats exist, as far as I can tell, it only tracks human players. The CPU locations might be stored elsewhere. The floats are stored in the following memory locations:

Player 1st 16 Bytes 2nd 16 Bytes
Player 1 80163288 8016328A
Player/CPU 2 8016328C 8016328E
Player/CPU 3 80163290 80163292
Player/CPU 4 80163294 80163296
CPU 5 80163298 8016329A
CPU 6 8016329C 8016329E
CPU 7 801632A0 801632A2
CPU 8 801632A4 801632A6

Original source: https://github.com/RenaKunisaki/mariokart64/issues/3

Checking the Gameshark memory editor revealed the rest of the players' memory locations.

VS mode score

The VS mode score shows how many times a player gets 1st, 2nd or 3rd place in VS mode. The scores are stored as 8 bit integers.

2 Player VS mode score memory locations:

Player 1st place
P1 8000031C
P2 8000031D

3 Player VS mode score memory locations:

Player 1st place 2nd place 3rd place
P1 8000031E 8000031F 80000320
P2 80000321 80000322 80000323
P3 80000324 80000325 80000326

4 Player VS mode score memory locations:

Player 1st place 2nd place 3rd place
P1 80000327 80000328 80000329
P2 8000032A 8000032B 8000032C
P3 8000032D 8000032E 8000032F
P4 80000330 80000331 80000332

Battle mode score

The battle mode scores count how many times a player has won a battle. Like the VS mode scores, they are simply 8 bit integers.

2 player battle mode score memory locations:

Player Battle ranking
P1 80000333
P2 80000334

3 player battle mode score memory locations:

Player Battle ranking
P1 80000335
P2 80000336
P3 80000337

4 Player battle mode score memory locations:

Player Battle ranking
P1 80000338
P2 80000339
P3 8000033A
P4 8000033B

Collision Detection / Surface Driving Over

How can I trigger events when a kart hits a wall? The goal is to make a bot spin when it his a barrier

Cruise Control Mushroom	800F6A6C 3250

Source code #10 on: http://viper.shadowflareindustries.com/antigsc/index.php?codes&dev=gs&system=n64&game=mariokart64/mariokart645#note5

By giving a CPU bot an automatic shroom state activator in battle mode, they will stay in a boosted state until they hit a wall. This simultaneously makes them always move forward and gives a hook to detecting a wall collision. When the shroom state is over, another activator can tell the kart to turn for a short period of time and then boost again. This way the kart will turn and boost every time it hits a wall and never get stuck for long.

See links below.

Memory address for surface currently driving over: https://github.com/RenaKunisaki/mariokart64/blob/master/old%20notes/surface%20hax.txt

Detailed notes on how game handles when you drive over stuff (ie. boost ramps): https://github.com/RenaKunisaki/mariokart64/blob/master/old%20notes/rom%20addrs.txt

Spawning Items

It is a gigantic mystery how the game code spawns items when you press z. Here I will keep my notes about what I have learned.

Weapon modifiers (Source: Code Master)

1P & 2P modes

Weapon Modifier P1
80165F5D 00??
80165F8A 00??

Weapon Modifier P2
8016603D 00??
8016606A 00??

3P & 4P Modes

Weapon Modifier P1
8016611D 00??
8016614A 00??

Weapon Modifier P2
801661FD 00??
8016622A 00??

Weapon Modifier P3
801662DD 00??
8016630A 00??

Weapon Modifier P4
801663BD 00??
801663EA 00??

The item values are as follows (source: http://origami64.net/showthread.php?tid=47):

Value Item
00 Nothing
01 Single Bananna Peel
02 Triple Bananna Peels
03 Single Green Shell
04 Triple Green Shell
05 Single Red Shell
06 Triple Red Shell
07 Blue Shell
08 Lightning Bolt
09 Evil Item Box
0A Star
0B Ghost
0C Single Mushroom
0D Two Mushrooms
0E Three Mushrooms
0F Super Mushroom

Player 1's item values are stored in 3 locations. These handle getting items from an item box.

80165F5B appears to actually be where the RNG dumps the item value once the item box "roll" has finished.

80165F8A defines what item is being animated in the item box "roll". Changing the value changes what item you see but not what item you actually have. This is part of the "Weapon Modifier" codes.

80165F5D stores the item you actually have. It would seem to copy its value from 80164F5B where the RNG has dumped the item chosen at random. This is part of the "Weapon Modifier" codes.

80165F5F controls the item box sequence. 00 means the item box is not being used. 01 starts the "get an item" sequence when you hit an item box, as if you hit an item box. 01-08 is the sequence of steps of the item box rolling for an item. This sequence stops at 08. 09-0B is the sequence of steps that occur when an item is used, finishing with the item box scrolling up and out of sight. Once it hits 0B, the value rolls back to 00 to await the next item.

More detailed notes at 80165F5F

80165F5F 00?? Description
?? = 01 same effect as hitting item box
?? = 02 like 01 but no beginning “slot machine” sound plays, appears to be the 2nd step in the animation of item acquisition
?? = 03 looks like the final “ding ding ding” step of the item acquisition process, although it is not displayed, you still get an item
?? = 04 same effect as 03? Probalby just the next step with 03 being a small step in the process
?? = 05 same effect as 03? Probalby just the next step with 03 being a small step in the process
?? = 06 same effect as 03? Probalby just the next step with 03 being a small step in the process
?? = 07 same effect as 03? Probalby just the next step with 03 being a small step in the process, looks like the flashing is related to this progression or is bitwise math happening?
?? = 08 no effect if manually set it seems, item should be in box and ready to use
?? = 09 item box scrolls up and out of sight, item still in inventory
?? = 0A not sure on this one??? no effect?
?? = 0B item used, item box scrolls back up and out of sight
?? = 00 looks like it zeros out after that
?? = 08 after item is used, the “final” step?
?? = 32 Item stays in place, at least for golden mushroom, appears to make box flash
?? = 28 Flashing between triple to double mushroom or double mushroom to single mushroom
?? = 14 Play animation of Boo stealing item, item still in inventory
?? = 1E Play animation of Boo stealing item and box disappears, item still in inventory
?? = 1F Box disappears, item still in inventory

Notes on 80165F8D. This memory address appears to have something to do with when an item is loaded.

| 80165F8D 00?? | Description | | ?? = 00 | When you have no item, if you had item and set this value, item will be used up but box will stay | | ?? = 01 | When you use an item, will immediately load another item | | ?? = 03 | You have an item |

But what happens when Z is pressed? I still can't figure it out. Below are some notes on my attempt to make sense of how spawning an item adds to the giant object array.

After getting item (lightning in this example but before Z is pressed:

80165F80: 00 00 01 00 00 00 00 00
80165F88: 00 00 08 00 01 00 03 00
80165F90: 00 28 20 00 00 00 00 00

After Z is pressed:

80165F80: 00 00 01 00 00 00 00 00
80165F88: 00 00 01 00 01 00 00 00
80165F90: 00 28 20 00 00 00 00 00

This block of memory controls the roll for an item animation, and does not appear to affect the actual game. 80165F8A sets the item showing up on screen but not what actually spawns when you push Z.

Player 1 3 red shells spawning. It appears objects are created dynamically for the class that spawns three shells. My guess is when an item box chooses an item, an object is created for handling the execution of that item. After that, the pointer to the object is removed and the memory block cleared for another dynamically created item class object to be created. This makes things very hard to track..... I need to find the thing that actually spawns the objects themselves.

For one example the following memory block......

Section in mem editor 8 9 A B C D E F
80160C88: 00 16 80 00 00 01 00 04

To spawn red shells first set 80160C89 = 16 and 80160C8A = 80. Then set 80160C8F = 00. This is the counter that counts up to 04 and animates the shell spawning of 3 shells. You can animate more spawning by setting 80160C8F = 00 repeatedly but you only seem to get three. Once all shells are spent you can redo this process to spawn three more shells. 80160C8B is simply a 2 byte unsigned int that counts the number of shells you currently have. It only seems to correspond to the shell spawning animation. The countdown from three is stored somewhere else in memory. Either way after you fire off all three shells, you can set this entire block of memory back to spawn three more. Very strange. Setting 80160C88 = 01 causes all your shells to despawn. 80160C8A appears to be able to be set to any value AFTER spawning shells (normally it sets itself to 80). Setting it to 00, however, turns off your ability to fire the shells apparently. They will continue to circle you but pressing Z does nothing. 80160C8A appears to be a binary flag, when it's ==00 you can't press Z to fire shells. When it's !=00, you can fire the shells.

I suspect 80160C89 and 80160C8A encode different objects that can spawn. If I can decode what those are, I might be able to figure out how to create codes that can fire weapons without the need to press Z.

If 80160C8A == 00, you can't fire your weapon.

If 80160C8A != 00 you can fire your weapon

If 80160C89 == 16, 3 red shells will spawn

If 80160C89 == 15, 3 green shells will spawn

I have also found copies of the object for the class for spawning single shells... more notes about that later. It appears to be related to the 3 shell spawning class but it's a little different.

Some notes on item spawning: https://github.com/RenaKunisaki/mariokart64/blob/master/old%20notes/item%20hax.txt