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