B_squo
1st Place Fanfare - Mario Kart 7 Music
updated
This video showcases the details on said system and its quirks, but in summary, if during the last three days you've been playing Mario Kart Wii online you disconnect a total of 15 times or more, then the next time you connect, you will be forced to only play with other players who've also been disconnecting a lot from online matches (i.e. penalised players), which means that finding matches will take much longer, or even not being able to find players at all, plus not being able to join friends in public online rooms.
This system is also known as "Suspend Status", or just being "suspended" by the community.
Besides people with poor connections, other players back in the day, such as hackers or players doing the "low VR / 1 VR" challenge, have been more likely to get this status due to them often disconnecting or freezing their consoles. You can find other mentions of this phenomenon in the links below.
The penalty is automatically removed from the license after a few days (assuming you don't start disconnecting again a lot).
This wasn't mentioned in the video, but it is possible to clear the "disconnected" counters faster by simply changing to a different date in the Wii's calendar and then going into MKWii and saving the game in the penalized player's license. Do this three times (one per counter) and those counters should all go back to 0, removing the penalisation for that license.
* License penalty check algorithms: https ://decomp.me/scratch/pxaLr
* This video's soundtrack: youtube.com/watch?v=VCXGTlnPByY
* Penalty system mentions (aka "Suspend" status):
- https ://forum.wii-homebrew.com/index.php/Thread/55270-Mario-Kart-Wii-suspend-status
- https ://4drclanforum.com/threads/suspended-on-mkw-what-should-i-do-to-solve-this.1974
- youtube.com/watch?v=nw7--wiu-Cs
* You can use the following Gecko code to trigger the penalisation system on or off at will: https ://mariokartwii.com/showthread.php?tid=2502
In this video, I demonstrate this by creating a new Mii and then storing it in the Wii remote (I then removed that Mii from the Wii console to demonstrate that this data is indeed coming only from the remote). Afterwards, you can see that the Mii indeed gets loaded from the remote in Mario Kart Wii.
In the Mii selection page, an extra button exists, named "TabRemote", that would've shown the list of Miis from the Wii remote, but got scrapped. In this video, I've replaced the button normally used for the Guest Mii list with the unused "TabRemote" one. This unused button is placed on the far right of the screen, and has empty text.
== Code ==
You can try this for yourself by using the following Gecko code. This code replaces the Guest Mii button in the Mii selection screen with the "TabRemote" one, and will load the first Mii saved in your first Wii controller.
Note that this is just a experimental proof of concept for demonstration purposes, and needs more work in order to properly support all remotes + loading all the Miis in the controller and not just one. Because of this, please ensure that you have backups of your savegame, Wii NAND, etc, before trying this code.
(PAL)
C2527D44 00000005
3C60809C 8063D710
38800000 38A00000
7FE6FB78 3CE08052
60E79420 7CE903A6
4E800421 00000000
C28487C4 00000004
98030265 38800000
3CA08052 60A59530
7CA903A6 4E800421
60000000 00000000
040ca820 38600000
040ca824 4e800020
04849068 38000001
048490bc 4bdb16f5
068ad99f 00000006
52656D6F 74650000
== Code documentation (PAL) ==
## Inside the function that loads either a Mii from the console or a guest Mii, replace the "find Guest Mii" function call with a call to find the first Mii from the first Wii remote instead.
C2527D44 00000005
3C60809C 8063D710
38800000 38A00000
7FE6FB78 3CE08052
60E79420 7CE903A6
4E800421 00000000
# Inject at 0x80527d44 (PAL)
.set MiiManager_insertMiiFromController, 0x80529420 # (PAL)
.set ptr_MiiManager, 0x809bd710 # (PAL)
lis r3, ptr_MiiManager@ha
lwz r3, ptr_MiiManager@l(r3)
li r4, 0 # Mii index (first Mii on the list)
li r5, 0 # Wii controller index (first Wii remote)
mr r6, r31 # heap
lis r7, MiiManager_insertMiiFromController@h
ori r7, r7, MiiManager_insertMiiFromController@l
mtctr r7
bctrl
## When loading the Mii selection screen, load the Mii list from the first Wii remote controller. Needed for the code above so that the list is available to choose Wii remote Miis from.
C28487C4 00000004
98030265 38800000
3CA08052 60A59530
7CA903A6 4E800421
60000000 00000000
# Inject at 0x808487c4 (PAL)
.set MiiManager_loadMiisFromControllerAsync, 0x80529530 # (PAL)
.set ptr_MiiManager, 0x809bd710 # (PAL)
# Original instruction
stb r0, 0x265(r3)
li r4, 0 # Wii controller index (first Wii remote)
lis r5, MiiManager_loadMiisFromControllerAsync@h
ori r5, r5, MiiManager_loadMiisFromControllerAsync@l
mtctr r5
bctrl
## Since this code replaces all of the Guest Mii loading functionality with the functionality for loading Wii remote Miis, this "is Guest Mii" function will always return "false".
040ca820 38600000
040ca824 4e800020
## Force Wii remote Mii list in the Mii selection screen to only have 1 Mii. This is a temporary solution until more code is written to load the rest of the Miis from the list.
04849068 38000001
## Replace load Guest Mii function call in the Mii selection screen with call to find Wii remote Mii function.
048490bc 4bdb16f5
## Load the unused "TabRemote" button instead of the Guest Mii one.
068ad99f 00000006
52656D6F 74650000
== More functionality documentation ==
The relevant functions are as follows (PAL):
* 0x80529530: Loads the controller data. This function must be called first to load the list of Miis from the controller into memory. Arguments: (MiiManager *this,uint controllerIdx). This function calls `RFLLoadControllerAsync` (0x800c8680)
* 0x805fa7b0: Loads a a certain Mii from a given controller. Arguments: (MiiGroup *this,int miiListIndex,int controllerIdx,uint miiIndex)
* 0x80529420: Called from the function above to load the Mii data. Arguments: (MiiManager *this,uint controllerIdx,uint miiIndex,Heap *heap). This function calls `RFLIsAvailableControllerData` (0x800c8780)
Other relevant things:
* Field 0x2E8 of `MiiManager` (instance at 809bd710) is an array of four bytes, and each byte is the amount of Miis found in the controller
* Field 0xD9C of the Mii Selection page is the source where the currently viewed Miis come from. 0 is from the console and 1 is Guest Miis. However, 2 goes unused, which represents that the Miis come from the controller (see 80848efc for an example usage)
Notably, it's a bit easier to drive in the latter, since the waves are not as steep nor strong.
By playing said competition and then going back to Battle Mode, this change is carried over, making it a bit easier to drive through the arena.
Internally, the game changes the following float parameters when entering the Big Pokey tournament, but does not change them back to their default values afterwards (the RAM addresses are for PAL):
* Sand shake wave length (0x808d5e50)
* Time until sand wave reaches the end (0x808d5e54)
* Sand push and pull strength (0x808d5e70)
Source for the meaning of each parameter: https: //szs.wiimm.de/cgi/mkw/track-ref/object/quicksand
To do it, keep your trailed items and then get a Thundercloud from an itembox. While the Thundercloud image is on-screen, the other player must use the Lightning. If done correctly, you will get hit, but will still keep your trailed items as if nothing happened.
This will only work while the Thundercloud image is displayed in your screen when getting said item, giving you a couple seconds for this to be performed correctly. Getting hit by the Lightning before or afterwards won't work.
Likewise, this will only work during online matches. This won't work in Local multiplayer, even if you get hit by the Lightning while the Thundercloud is on-screen.
The reason why this happens is because of some checks present in the beginning of function 0x80798a30 (PAL). This function will only allow you to drop your trailed items if your not online at all *or* if you are online, but a variable that we'll call "Displayed Item" is set to "None".
When using most items, the "Displayed Item" variable is always set to "None", allowing the game to drop your items. However (from what I know) this variable is set to a different value in the following circumstances:
* When using the Thundercloud, only while the icon is on-screen.
* When you use a Bullet Bill, while it's activated.
* When using a Blue Shell, only during one frame, the moment you throw it.
Since it's not possible to keep trailed items while using the Bullet Bill, it means that this oddity can only be seen when using the Thundercloud.
Credits to @Rerim47 for bringing this to my attention!
Source: youtube.com/shorts/PLoj-wvHOeo
At around 807b0b9c (PAL), the game doesn't check if you're currently in a Team match or not for trying to pass the Thundercloud, therefore it will carry over the Team settings from the previous match into non-team matches, resulting in this behaviour.
However, it's possible to restrict yourself to only selecting karts or bikes by going into a competition / tournament that has one of these restrictions, and then joining a Grand Prix via the Mario Kart Channel-specific Friend button.
Note that this will only work when joining the room via the Mario Kart Channel Friend button, and not from the Main WFC menu.
This likely happens because the kart / bike restriction is only reset during the single player menu and also when going back to the Title menu, but doesn't update when going online through the Mario Kart Channel, and therefore the game will carry over the previous restriction.
This also won't work with Battles because the vehicle restriction is only ever applied to Grand Prix-type races, and not Battles.
"%s = (%.1f, %.1f, %.1f)"
where the first three "%.1f" are the X, Y and Z position of the item, and the "%s" is the coordinates "type" being printed.
As for the "type", four possible types can be printed:
- "pos": The current item's position
- "posS": The current item's position when the player first throws the item?
- "posD": The position of the Blue Shell while it's flying towards its target?
- "????": Anything else
In PAL, this function can be found at VRAM address 0x807A34CC. It is unknown where the strings would have been printed, as the code that exists only formats the strings, but calling this function doesn't print the strings anywhere.
For this showcase, I changed the function so that the string is printed to the debugging console by calling OSReport instead. Not only that, but I also changed the string to replace the last parenthesis ")" with a newline character, so that it's more readable.
This code calls the debug function in one of the item's update functions, which means that everytime an item is actively in the course, its coordinates will be printed every frame. Again, this is just for demonstration purposes, as said function doesn't appear to be called anywhere in the code.
You can see this by yourself using this Gecko code. If using Dolphin Emulator, you can open the debug console by opening the emulator in Debug mode (-d), and then clicking on View - Show Log.
(Code, PAL)
C279F498 00000004
7FA3EB78 3C80807A
608434CC 7C8903A6
4E800421 807D007C
60000000 00000000
047a3540 4b9ff090
008a5321 0000000A
(Source, PAL)
### Injected assembly code ###
C279F498 00000004
7FA3EB78 3C80807A
608434CC 7C8903A6
4E800421 807D007C
60000000 00000000
# Inject at 8079f498 (PAL)
.set debugPrintPosition2, 0x807a34cc # PAL
mr r3, r29
lis r4, debugPrintPosition2@h
ori r4, r4, debugPrintPosition2@l
mtctr r4
bctrl
# Original instruction
lwz r3, 0x7C(r29)
### Call OSReport instead of vsnprintf in order to print the debug strings to the console ###
047a3540 4b9ff090
### Replace the last parenthesis ")" of the string with a newline character, so that it's more readable ###
008a5321 0000000A
"%d, %d, %d #%d"
where the first thre "%d" are the X, Y and Z position of the item as integers, and the "#%d" is the current course ID in decimal (in this case, SNES Mario Circuit 3 has a course ID of 24 in decimal, 0x18 in hexadecimal).
At 0:01, the live position coordinates are shown for a Green Shell, and at 0:20 the coordinates for a Blue Shell are shown as it travels the course searching for the player in 1st.
In PAL, this function can be found at VRAM address 0x807A3544. It is unknown where the strings would have been printed, as the code that exists only formats the strings to add the item position and the course ID, but calling this function doesn't print the strings anywhere.
For this showcase, I changed the function so that the string is printed to the debugging console by calling OSReport instead. Not only that, but I also changed the string to add a newline character at the end, for demonstration purposes.
This code calls the debug function in one of the item's update functions, which means that everytime an item is actively in the course, its coordinates will be printed every frame. Again, this is just for demonstration purposes, as said function doesn't appear to be called anywhere in the code.
You can see this by yourself using this Gecko code. If using Dolphin Emulator, you can open the debug console by opening the emulator in Debug mode (-d), and then clicking on View - Show Log.
(Code, PAL)
C279F498 00000004
7FA3EB78 3C80807A
60843544 7C8903A6
4E800421 807D007C
60000000 00000000
047a359c 4b9ff035
008a5345 0000000A
(Source, PAL)
### Injected assembly code ###
C279F498 00000004
7FA3EB78 3C80807A
60843544 7C8903A6
4E800421 807D007C
60000000 00000000
# Inject at 8079f498 (PAL)
.set debugPrintPosition, 0x807a3544 # PAL
mr r3, r29
lis r4, debugPrintPosition@h
ori r4, r4, debugPrintPosition@l
mtctr r4
bctrl
# Original instruction
lwz r3, 0x7C(r29)
### Call OSReport instead of vsnprintf in order to print the debug strings to the console ###
047a359c 4b9ff035
### Add newline to the string so that it's more readable ###
008a5345 0000000A
- Time: 02'38''55
- Lap 1: 00'53''20
- Lap 2: 00'52''54
- Lap 3: 00'52''81
- Course: Royal Raceway
- Character: Peach
- VRAM address of this ghost's input data (USA): 0x0F4FAD04
======= Additional information =======
- Regular gameplay was recorded in the USA version of the game, while the inputs were recorded using the Amped Up 2.9A mod, by @Litronom
- The footage was recorded using the following Gameshark code (USA).
81005672 C4BC
81005088 0000
8100508A 0000
810050EC 0000
810050EE 0000
81005154 0000
81005156 0000
810F8554 C974
810F8558 4C00
810F855C C974
Enable the code and access Time Trials, then select the same character as the staff ghost, and finally start a race in your desired course.
- Time: 01'27''16
- Lap 1: 00'28''96
- Lap 2: 00'29''04
- Lap 3: 00'29''16
- Course: Mario Raceway
- Character: Mario
- VRAM address of this ghost's input data (USA): 0x0F4F8E10
======= Additional information =======
- Regular gameplay was recorded in the USA version of the game, while the inputs were recorded using the Amped Up 2.9A mod, by @Litronom
- The footage was recorded using the following Gameshark code (USA).
81005672 C4BC
81005088 0000
8100508A 0000
810050EC 0000
810050EE 0000
81005154 0000
81005156 0000
810F8554 C974
810F8558 4C00
810F855C C974
Enable the code and access Time Trials, then select the same character as the staff ghost, and finally start a race in your desired course.
- Time: 01'48''37
- Lap 1: 00'36''25
- Lap 2: 00'36''02
- Lap 3: 00'36''10
- Course: Luigi Raceway
- Character: Luigi
- VRAM address of this ghost's input data (USA): 0x0F4F9CAC
======= Additional information =======
- Regular gameplay was recorded in the USA version of the game, while the inputs were recorded using the Amped Up 2.9A mod, by @Litronom
- The footage was recorded using the following Gameshark code (USA).
81005672 C4BC
81005088 0000
8100508A 0000
810050EC 0000
810050EE 0000
81005154 0000
81005156 0000
810F8554 C974
810F8558 4C00
810F855C C974
Enable the code and access Time Trials, then select the same character as the staff ghost, and finally start a race in your desired course.
What's interesting about this is that, much like with the unlockable characters, all the default characters have specific voice clips assigned for when they're unlocked. Said voice clips are listed below, alongside their sound ID in hex:
- Mario: VO_MR_SELECT_CHAR_02 (039C)
- Baby Peach: VO_BPC_SELECT_CHAR_01 (03B9)
- Waluigi: VO_WL_SELECT_CHAR_01 (03CE)
- Bowser: VO_KP_SELECT_CHAR_01 (03D1)
- Baby Mario: VO_BMR_SELECT_CHAR_02 (03B4)
- Luigi: VO_LG_SELECT_CHAR_02 (039F)
- Toad: VO_KO_SELECT_CHAR_END (03C4)
- Donkey Kong: VO_DK_SELECT_CHAR_01 (03D4)
- Yoshi: VO_YS_SELECT_CHAR_02 (03A2)
- Wario: VO_WR_SELECT_CHAR_02 (03CC)
- Koopa Troopa: VO_NK_SELECT_CHAR_01 (03C8)
- Peach: VO_PC_SELECT_CHAR_END (03A6)
- You can use this Gecko code to modify the unlock screen yourself:
https ://mariokartwii.com/showthread.php?tid=2446
- In PAL, 0x808b1ea0 contains the array of sound IDs to play for each character on the unlock screen.
Each vehicle has a unique horn sound associated to it, all of them are shown at 0:00.
All vehicles can play up to 4 melodies with the horn at random. 4 unique to karts and other 4 unique to bikes, all of which are shown at 0:46. For playing the melodies on this video, the horn sounds form the Wild Wing and Phantom were used.
Regarding the melodies, each melody can be found in the BRSEQ that starts at offset 0x1315460 in revo_kart.brsar (PAL). Each melody is a small sequenced (MIDI) sound, all of which are named `horn_kart_cmn` for karts, and `horn_bike_cmn` for bikes. The logic for playing each melody, as well as what random melody to play, can be found below.
This output was generated by the `diSEQt` tool, which allows you to decode / encode BRSEQ files to / from readable output.
⧼newtrack name="horn_kart_cmn" dataoffset="1851"⧽
⧼offset name="73b"/⧽ ;; Offset 73b. START
wait 10
cmp_eq 1, 1
jump::if 756
randvar 0, 5
cmp_eq 0, 0
jump::if 75f
⧼offset name="756"/⧽ ;; Offset 756.
cn4 100, 10 ;; 1st variant (Kart)
wait 10
cn4 127, 30
fin
⧼offset name="75f"/⧽ ;; Offset 75f.
randvar 0, 5
cmp_eq 0, 0
jump::if 7b5
randvar 0, 1
cmp_eq 0, 0
jump::if 799
cn4 100, 10 ;; 2nd variant (Kart)
gn4 100, 10
ds4 100, 10
gn4 100, 10
cn4 100, 10
gn4 100, 10
ds4 100, 10
gn4 100, 10
cn4 100, 10
fin
⧼offset name="799"/⧽ ;; Offset 799
cn4 100, 10 ;; 3rd variant (Kart)
gn4 100, 10
en4 100, 10
gn4 100, 10
cn4 100, 10
gn4 100, 10
en4 100, 10
gn4 100, 10
cn4 100, 10
fin
⧼offset name="7b5"/⧽ ;; Offset 7b5
en4 127, 5 ;; 4th variant (Kart)
wait 15
cn4 127, 5
wait 5
en4 127, 5
wait 5
gn4 127, 5
wait 15
cn5 127, 5
wait 5
wait 10
en5 127, 20
fin
⧼/newtrack⧽
⧼newtrack name="horn_bike_cmn" dataoffset="2004"⧽
⧼offset name="7d4"/⧽ ;; Offset 7d4
wait 10
cmp_eq 1, 1
jump::if 7ef
randvar 0, 5
cmp_eq 0, 0
jump::if 7f8
⧼offset name="7ef"/⧽ ;; Offset 7ef
cn4 100, 10 ;; 1st variant (Bike)
wait 10
cn4 127, 30
fin
⧼offset name="7f8"/⧽ ;; Offset 7f8
randvar 0, 5
cmp_eq 0, 0
jump::if 851
randvar 0, 1
cmp_eq 0, 0
jump::if 835
cn4 100, 10 ;; 2nd variant (Bike)
fs4 100, 10
dn4 100, 10
cn5 100, 10
an4 100, 10
ds4 100, 10
as3 100, 10
ds4 100, 10
gn4 100, 10
cs5 100, 10
fin
⧼offset name="835"/⧽ ;; Offset 835
cn4 100, 10 ;; 3rd variant (Bike)
en4 100, 10
gn4 100, 10
dn4 100, 10
fs4 100, 10
an4 100, 10
en4 100, 10
gs4 100, 10
bn4 100, 10
fin
⧼offset name="851"/⧽ ;; Offset 851
en4 127, 5 ;; 4th variant (Bike)
wait 5
en4 127, 5
wait 5
wait 10
en4 127, 5
wait 10
cn4 127, 5
wait 5
en4 127, 5
wait 5
wait 10
gn4 127, 5
fin
⧼/newtrack⧽
- diSEQt Tool + output documentation: https ://github.com/killaketa/diSEQt
- All horn sound effects (8:44): youtu.be/23HT8RhOg8Q?t=524
- BRSEQ File Format: https ://wiki.tockdom.com/wiki/BRSEQ_(File_Format)
- Sound ID list. All of the sound effects start from ID 427, named using the format `SE_VCL_HORN_VEHICLE_IDENTIFIER`: https ://raw.githubusercontent.com/mkw-sp/mkw-sp/refs/heads/main/payload/game/sound/SoundId.hh
- In PAL, the function that plays the horn sounds is located at address 0x807091AC
The values are:
- XXXX: The number of frames the countdown lasts. This is gotten by adding 1 to the number of seconds you want the countdown to last, and then multiplying that with 60 (or 50 if playing in PAL 50Hz). For example, for a 100 seconds countdown, this is (100 + 1) x 60 = 6060 (put 17AC in the code).
- YYYY: The number of seconds the countdown lasts. For example, for a 100 seconds countdown, this is 100 (put 0064 in the code).
- ZZZZ: The number of seconds the countdown lasts plus 1. For example, for a 100 seconds countdown, this is 100 + 1 = 101 (put 0065 in the code).
- RRRR (optional): This is the number of frames during the countdown where the player's nametag hides. This is gotten by substracting the total countdown time in seconds + 1 with the number of seconds you want the nametag to hide, and then multiplying that with 60 (or 50 if playing in PAL 50Hz).
For example, for a 100 seconds countdown, if I want the nametag to hide after 3 seconds from the start of the countdown, we do ((100 + 1) - 3) x 60 = 5880 (put 16F8 in the code). If you don't care about this, you can remove this line, but this makes the nametag hide three seconds before the countdown ends, as usual.
- QQQQ: The BMG ID for the first number displayed by the countdown. Every second, the game adds 1 to this ID, so you get the different text that is displayed.
This means that, if you want to display a sequence of strings during the countdown, they must be put one after the other when it come to their BMG IDs.
For this video, I modified Race_E.szs to change the text there to have each number from 100 to 1 (and then GO!). Then, I noted down the BMG ID corresponding to the number 100, and put that into this code.
(PAL)
04533540 2000XXXX
045330b8 2060XXXX
0485777c 2800YYYY
04857654 2800ZZZZ
0483376c 3863QQQQ
047f138c 2c03RRRR
(USA)
0452e9f8 2000XXXX
0452e570 2060XXXX
04835cec 2800YYYY
04835bc4 2800ZZZZ
0481b86c 3863QQQQ
047e6d64 2c03RRRR
(JPN)
04532ec0 2000XXXX
04532a38 2060XXXX
04856de8 2800YYYY
04856cc0 2800ZZZZ
04832dd8 3863QQQQ
047f09f8 2c03RRRR
(KOR)
04521598 2000XXXX
04521110 2060XXXX
04845b3c 2800YYYY
04845a14 2800ZZZZ
04821b2c 3863QQQQ
047df74c 2c03RRRR
The console first displays the Special Ghost icon in the Mario Kart Channel's Home Menu banner, and once inside the Mario Kart Channel, the message "Special Ghost data is available" appears in the notification button. Clicking on it takes you to the Worldwide rankings of the course the Special Ghost was played at. Special Ghosts are stored as downloaded ghosts, nothing happens when you actually beat them.
Special Ghosts were originally sent out by Nintendo, alongside a letter, via WiiConnect24 to Wiis. The premise was to send ghosts played by people who appeared in commercials from the game.
Check out this playlist for more information: youtube.com/playlist?list=PLGxJatVKZR1VhBIbYAPYR7AgBtPuCc5tt
In this video, I inserted my own Special Ghost from scratch, which involved doing the following:
- Store a downloaded ghost RKG in the save file with the RKG type set to 5 (special ghost).
- Have a special ghost entry defined in the wc24dl.vff file. This tells the game how many special ghosts are saved, and other things such as its finish time, the course played, and its Mii data.
This all was possible thanks to a wc24dl.vff file I recently was able to obtain that included a "distmap.bin" file of the maximum size allowed (0xBC00 bytes). You can download the save file I used on the links below.
My assumption is that the game would have downloaded the current iteration of the wc24dl.vff file via WiiConnect24 (and alternatively via the "Download latest data" option in the Mario Kart Channel), and then, besides the competition data, it would have downloaded the Special Ghost list in said file. Then, the Special Ghost icon would show up in the rankings, and clicking on it would have prompted the game to connect to Nintendo WFC to download the actual ghost RKG into the save file.
Note that, in order for the game to recognise the data, it must load the wc24dl.vff file. To do so, make sure to have an active Internet connection on the Wii, parental controls disabled, read the EULA and have WiiConnefct24 enabled. If you don't want ot do any of that, you can also force the game into loading wc24dl.vff by using the following Gecko code: https: //mariokartwii.com/showthread.php?tid=2416
=== Other info ===
In the save file below, the following addresses correspond to this information:
==== wc24dl.vff ====
* 0x9050: Special Ghost list (More info: https ://wiki.tockdom.com/wiki/Distmap.bin#Special_Ghost_List)
* 0x1E10: Offset (relative to the start of distmap.bin, which in this case is offset 0x1620) to the Special Ghost list.
* 0x1E14: Size of the Special Ghost list.
==== rksys.dat ====
* 0x78000: Special Ghost RKG file
* 0x26AE0: Special Ghost ID List. In order to display the icon in the Home Menu, the special ghost ID found in its entry from wc24dl.vff must not already be on this list. Otherwise, it will be treated as "already received", and so the icon won't be displayed.
=== Links ===
- More info on Special Ghosts: https ://tcrf.net/User:B_squo#About_Mario_Kart_Wii.27s_Special_Ghosts
- rksys.dat File Format: https: //wiki.tockdom.com/wiki/Rksys.dat
- distmap.bin File Format: https ://wiki.tockdom.com/wiki/Distmap.bin
- You can download the save file I used on this video here (PAL): https ://drive.google.com/file/d/1MHfW8GhnkdZi8TFQ2olNzaukHVJQQCbx/view?usp=drive_link
You can try this out by using the following Gecko code:
(PAL)
029c41b8 00000001
(USA)
029bf968 00000001
Thanks to vabold for telling me about this + providing the code above!
CPUs don't actually steer using the joystick. Instead, the game automatically rotates their vehicles to adjust their path. CPUs only turn the stick when attempting to do a drift.
When CPUs break an itembox, they rapid-fire the item button in order to get the item as fast as possible. It also seems that, if CPUs get damaged while holding an item in their back, they will still keep the item button pressed until grabbing another item, as seen at 1:26. Also, at this state, they won't rapid-fire the item button in order to get the item faster.
CPUs will also try to performa a random trick every time they are in the air. This is why every time they hop, a trick input is pressed.
This was possible by using the Retro Rewind mod, which features a graphical input viewer, originally ported from the MKW-SP mod.
In order to make this video, I used the PAL version of the game using Dolphin Emulator's Riivolution feature, then loaded the Retro Rewind mod, and did the following on the debugger:
- After the intro cutscene fades out, set a breakpoint at 0x8052f538 (PAL). When it breaks, go to the address stored at register r30 + 0x18, and there, set the value to 00000001. This turns the first human player into a CPU.
- Set the instruction at 0x805a1e40 (PAL) to 0x3800FFFF. This prevents the camera from switching to a dynamic view automatically when playing as a CPU.
- Retro Rewind: https ://wiki.tockdom.com/wiki/Retro_Rewind
- MKW-SP: https ://wiki.tockdom.com/wiki/MKW-SP
In the game, there is some extra code not used by the rest of the penguin objects that appear to be pretty similar to the code used by the small penguin's reflection. Its associated code is (PAL):
- 80777288: constructor
- 808cfe58: vtable
- 807774e4: destructor
- 807772c8: load animations
- 80777390: update
I say "possibly" in the title because there's no direct evidence in the code that this was indeed meant to be the big penguin's reflection. However, comparing the small penguin reflection's code VS this code reveals that they're almost identical.
For example, both object's update function are empty, and both objects have an extra function in their vtables not present in any other penguin object (80777450 for small penguin reflection, and 80777388 for this object).
Not only that, but looking at the big penguin reflection closer reveals that it's using Cull Inside, instead of Cull None like with the small penguins. This makes the reflection look the way it does, making it seem like the reflection is looking back when the big penguin is looking to the front, and viceversa when looking to the back
(... just like in the prerelease screenshot!)
You can use the following code to see this in-game. The following code creates and initializes the reflection object during the big penguin's object creation:
(PAL)
04823250 386000EC
C2777138 00000015
9421FFF0 7C0802A6
90010014 7C7D1B78
386000B0 3D808022
618C9DCC 7D8903A6
4E800421 7F84E378
3D808077 618C7288
7D8903A6 4E800421
7C7B1B78 907D00E8
81830000 818C0044
7D8903A6 4E800421
7F63DB78 81830000
818C005C 7D8903A6
4E800421 7F63DB78
81830000 818C000C
7D8903A6 4E800421
7F63DB78 81830000
818C001C 7D8903A6
4E800421 7FA3EB78
7F84E378 80010014
7C0803A6 38210010
38A00000 00000000
048cfdb4 80776ecc
048cfd54 807760b0
=== Code Documentation ===
# Assembly code
# Inject at 0x80777138 (ObjPenguinL_ct) (PAL)
.set region, 'P'
.if (region == 'P')
.set new, 0x80229dcc
.set ObjPenguinLMirror_ct, 0x80777288
.else
.err
.endif
# Assumes that a copy of r4 is on r28 at this point
stwu r1, -0x10(r1)
mflr r0
stw r0, 0x14(r1)
# Store a copy of the current big penguin instance to restore it later
mr r29, r3
# Allocate and construct the big penguin reflection
li r3, 0xB0
lis r12, new@h
ori r12, r12, new@l
mtctr r12
bctrl
mr r4, r28
lis r12, ObjPenguinLMirror_ct@h
ori r12, r12, ObjPenguinLMirror_ct@l
mtctr r12
bctrl
# Big penguin reflection - Load graphics
mr r27, r3
stw r3, 0xE8(r29)
lwz r12, 0x00(r3)
lwz r12, 0x44(r12)
mtctr r12
bctrl
# Big penguin reflection - Load animations
mr r3, r27
lwz r12, 0x00(r3)
lwz r12, 0x5C(r12)
mtctr r12
bctrl
# Big penguin reflection - init
mr r3, r27
lwz r12, 0x00(r3)
lwz r12, 0x0C(r12)
mtctr r12
bctrl
# Big penguin reflection - Update model
mr r3, r27
lwz r12, 0x00(r3)
lwz r12, 0x1C(r12)
mtctr r12
bctrl
# Restore big penguin instance and its map obj data as they're used later
mr r3, r29
mr r4, r28
lwz r0, 0x14(r1)
mtlr r0
addi r1, r1, 0x10
# Original instruction
li r5, 0
# Replace big penguin's initialization and model update functions with
# the ones used by small penguin, in order to properly animate the big penguin reflection
048cfdb4 80776ecc
048cfd54 807760b0
This behaviour goes unused, since players can't normally get Thunderclouds nor the Lightning in Coin Runners, as the probability for both items to appear is set to 0 for the Coin Runners mode.
Note that the Lightning can only be obtained in Balloon Battle mode, but not Coin Runners.
- List of all item probabilities: https ://wiki.tockdom.com/wiki/Filesystem/Race/Common.szs/ItemSlot.bin/listing
Normally these special types are used in places such as competitions or some boxes in Chain Chomp Wheel, in order to give you specific items from the item box no matter your current position. Settings 1 and 2 from the itembox objects correspond to the special item type to grant to the human players and CPUs, respectively.
Three item types go unused, as no item box uses them in the regular game, nor in competitions. These are:
* 0006 - Banana (50%) or Mushroom (50%) (0:00)
* 0009 - Red Shell (0:20)
* 0006 - Thunder Cloud (Mushroom if another Thunder Cloud is in play) (0:32)
* 000D, 000E, 000F, 0010 - These are empty (i.e. all item probabilities are set to 0). In practice, it grants a Mushroom, even though the roulette shows a single Green Shell (1:01)
- List of the all item box item types: https ://wiki.tockdom.com/wiki/Item_Settings_-_Item_Boxes#values
NOTE: Item types 0001 (Banana), 0002 (Mushroom), 0003 (Triple Mushrooms), 0004 (Star), 0005 (Triple Green Shell), 0007 (Green Shell), 0008 (Bob-omb), 000A (Mega Mushroom) and 0255 (same as 0000, Default) are only found in competitions.
This code hasn't been tested very much, only on Dolphin...
You should be able to combine this with other CPU-related codes, (such as codes that change the CPU's speed) to achieve even crazier results.
I recommend using an item delimiter code such as this one for the best experience: https ://mariokartwii.com/showthread.php?tid=259
=== Code ===
(PAL)
04731ffc 4bffd805
04731cb0 4bffdb51
02731fea 000000d4
02731c9e 000000d4
0472fb7c 38600001
0472fb80 4e800020
0472fcd8 60000000
C272FDAC 00000004
38600006 3C808074
6084B7F4 7C8903A6
4E800421 7C641B78
60000000 00000000
0472fdb4 60000000
0472fed0 60000000
04726ed4 38800000
048c98fc 462BE000
04726f70 4800000c
04727220 60000000
04727228 60000000
(NTSC-U)
04727e44 48018d81
04727af8 480190cd
02727e32 000000d4
02727ae6 000000d4
04740f40 38600001
04740f44 4e800020
0474109c 60000000
C2741170 00000004
38600006 3C808073
6084b928 7C8903A6
4E800421 7C641B78
60000000 00000000
04741178 60000000
04741294 60000000
0473cf3c 38800000
048c67cc 462BE000
0473cfd8 4800000c
0473d288 60000000
0473d290 60000000
Alternative version. Just like above, except that you can choose what item CPUs will throw. XX is the item ID (see "Item Box number" here: https ://wiki.tockdom.com/wiki/List_of_Identifiers#Items)
(PAL)
04731ffc 4bffd805
04731cb0 4bffdb51
02731fea 000000d4
02731c9e 000000d4
0472fb7c 38600001
0472fb80 4e800020
0472fcd8 60000000
0472fda4 38600001
0072fdb7 000000XX
0472fed0 60000000
04726ed4 38800000
048c98fc 462BE000
04726f70 4800000c
04727220 60000000
04727228 60000000
(NTSC-U)
04727e44 48018d81
04727af8 480190cd
02727e32 000000d4
02727ae6 000000d4
04740f40 38600001
04740f44 4e800020
0474109c 60000000
04741168 38600001
0074117b 000000XX
04741178 60000000
0473cf3c 38800000
048c67cc 462BE000
0473cfd8 4800000c
0473d288 60000000
0473d290 60000000
=== Documentation ===
This code switches the regular CPU race "control" by the one used in the N64 DK's Jungle Parkway competition, which allow them to equip an item without touching item boxes, nor requiring any item hack.
Normally, this control only allows CPUs to throw single bananas when near enough the player, and at certain semi-random intervals. This code modifies that so that the item equipped by the CPU is randomized every frame, and to remove the delay in-between each item throw.
As for the "CPUs following the exact path of the player" part, it was made by forcing the game into calling the function responsible for following the player when they have a Mega Mushroom or Thundercloud, with a modified, larger radius.
---------------
- When initializing the match, create the N64 DK's Jungle Parkway competition CPU control instead of the race one. This is done for both the race control and the battle control.
04731ffc 4bffd805
04731cb0 4bffdb51
02731fea 000000d4
02731c9e 000000d4
- Makes the "isNearPlayer" function associated to the N64 DKJP competition CPU control always return true, in order to allow CPUs to throw items no matter where they are.
0472fb7c 38600001
0472fb80 4e800020
- Remove the delay time in between item throws
0472fcd8 60000000
0472fed0 60000000
- Small function that randomizes the item given to the player from items ID 0 to 6. The hook overwrites a call to a "item limit not reached" function, which we won't need for the mod.
C272FDAC 00000004
38600006 3C808074
6084B7F4 7C8903A6
4E800421 7C641B78
60000000 00000000
0472fdb4 60000000
# Inject at 0x8072fdac (PAL)
.set rand, 0x8074b7f4 # (PAL)
li r3, 0x06
lis r4, rand@h
ori r4, r4, rand@l
mtctr r4
bctrl
mr r4, r3 # r4 is the item ID argument in the "set item to player" function
- Force always calling the "CPU follows player" function
04727220 60000000
04727228 60000000
- CPUs will only follow player 0 (the first human player)
04726ed4 38800000
- Set the XZ size of the CPU follow radius. If the player is inside the radius limited by the CPU's position and this value, then the CPU will start chasing the human player.
048c98fc 462BE000
- Ignore Y component of the CPU follow radius
04726f70 4800000c
Due to the speed of the itembox, as well as the length of its path, it takes some time for it to appear (usually around 2 minutes). When it shows up, it wiggles up and down slightly before going back to the water.
At 0:30, the full path is shown in-game, and at 1:34, it's shown using Lorenzi's KMP Editor.
- You can use this code to display this itembox in-game: https ://tcrf.net/Mario_Kart_Wii/Unused_Course_Elements
- The Tournament Museum mod allows you to play all official competitions offline: https ://wiki.tockdom.com/wiki/Tournament_Museum
While CPUs are technically able to reach a few larger soft speed limits, such as 108.5, (see youtube.com/watch?v=kxdrfZlMF30), that's on Mirror mode (which uses 150cc speeds)...
This competition takes place in *100cc*, which means that a soft speed limit of 106.5 is the equivalent of around 117.15 in 150cc (very close the 120 hard speed limit, and all of this without the needs additional boosts like wheelies, mushrooms, etc).
For this video, I am about to end the race, just behind the finish line on lap 3, while CPUs start from lap 1, in order to see how fast they are with the most human advantage possible.
This video was possible by using some cheat codes that allowed me to attach the camera to a CPU without removing the human player from the match. See the description of this video for more info: youtube.com/watch?v=zf5soaNkClQ
AIParam transcription per competition (rubberbanding and action parameters found on each competition that has those): https: //docs.google.com/spreadsheets/d/14MrTFf-WrXytfXwU6pr5j8C-u2Zanml33xVhUFLt1UI/edit?pli=1&gid=737924637#gid=737924637
Note that I also used the following code to avoid CPUs from hopping and taking drifts. The reason why I did that is because CPUs will briefly return to their vehicle's max speeds if they're on the air (so in this case, Bowser would go from like 100 back to 78.71 when hopping, and then from 78.71 back to 100 upon reaching the ground). Basically, I just did it so that it's easier for you to see the rubberbanding speeds without interruption:
(PAL)
0473efa8 38600000
0473efac 4e800020
For this video, I am about to end the race, just behind the finish line on lap 3, while CPUs start from lap 1, in order to see how fast they are with the most human advantage possible.
This video was possible by using some cheat codes that allowed me to attach the camera to a CPU without removing the human player from the match. See the description of this video for more info: youtube.com/watch?v=zf5soaNkClQ
AIParam transcription per competition (rubberbanding and action parameters found on each competition that has those): https: //docs.google.com/spreadsheets/d/14MrTFf-WrXytfXwU6pr5j8C-u2Zanml33xVhUFLt1UI/edit?pli=1&gid=737924637#gid=737924637
For this video, I am about to end the race, just behind the finish line on lap 3, while CPUs start from lap 1, in order to see how they look like with the most human advantage possible.
We can see that at one point, they reach a whopping max speed of 108.5 when driving normally on the ground (see 0:46)
Coconut Mall in a Mirror GP appears to have the highest combination of CPU rubberbanding parameters, as specified in kartAISpdParam.bin: https: //docs.google.com/spreadsheets/d/1Jku0s4jPhJ4dAVcD1UhY7AYyAaxfORD6VTXmVvu026Y/edit?pli=1&gid=1790094554#gid=1790094554
This video was possible by using some cheat codes that allowed me to attach the camera to a CPU without removing the human player from the match. See the description of this video for more info: youtube.com/watch?v=zf5soaNkClQ
Note that I also used the following code to avoid CPUs from hopping and taking drifts. The reason why I did that is because CPUs will briefly return to their vehicle's max speeds if they're on the air (so in this case, Baby Daisy would go from like 100 back to 76.06 when hopping, and then from 76.06 back to 100 upon reaching the ground). Basically, I just did it so that it's easier for you to see the rubberbanding speeds without interruption:
(PAL)
0473efa8 38600000
0473efac 4e800020
We know this is the absolute lowest limit as it's defined like so in kartAISpdParam.bin, which control various CPU rubberbanding parameters: https: //docs.google.com/spreadsheets/d/1Jku0s4jPhJ4dAVcD1UhY7AYyAaxfORD6VTXmVvu026Y/edit?pli=1&gid=1790094554#gid=1790094554
This video was possible by using some cheat codes that allowed me to attach the camera to a CPU without removing the human player from the match. See the description of this video for more info: youtube.com/watch?v=zf5soaNkClQ
This better exposes the AI's particular behaviour, including rubberbanding, incredible steering as well as being able to pass through course objects.
For example, Koopa Troopa, despite being in one of the slowest vehicles, can reach speeds that easily surpass mine (I'm using the Spear, one of the fastest vehicles). This is mostly true when I'm far ahead from the CPU - if I am far behind him, the CPU will slow down considerably to make it easier for me to catch up. CPUs will vary their maximum speed throughout the race depending on this and a few other conditions, such as the current lap.
Likewise, CPUs are able to pass through course objects, such as the Moonview Highway cars (4:37), if they are far behind the human player (i.e. more than 5000 units behind). This is handled by function 0x807308dc (PAL), known as "Enemy::AIControlRace::watchPlayerAndSwitchCollision" in Mario Kart 7.
Note that despite the camera being attached to the CPU, the HUD as well as some camera effects (including going out of bounds) are still targetting the human player. This is just a side effects from the code I used.
-------------------------------
This was possible by using the cheat code below, which is a combination of various other codes by several creators. More specifically:
* Racer Count Modifier (456) https ://mariokartwii.com/showthread.php?tid=2369 : Modifies the total racer count to 2 (me + the CPU)
* Pretty Speedometer (stebler) https ://mariokartwii.com/showthread.php?tid=1730 : Allows you to view the speed on screen. I modified a line of this code to force it into displaying racer 1 (the CPU)'s speed.
* Steer / Drift like CPUs (me) https ://mariokartwii.com/showthread.php?tid=2218 : Allows human players to steer like the CPUs would. I used this to make navigation for myself easier, as I the camera is attached to the CPU the whole time
* Attach the camera to player ID (me) : This code forces the camera to be attached to the specified player ID (in this case, player 1, the CPU)
If you want to use the specific code I used in the video, here it is (again, this is a combination of the above codes, credits go to the respective creators). Note that this was only tested in Grand Prix / VS Race for this showcase, and may not work properly or crash the game if used under other conditions.
(PAL)
C252F914 00000002
3900000X 99040000
60000000 00000000
048ca7f8 807332a0
048ca850 807332a0
C267DE94 00000002
3800000Y 9803009C
8803009C 00000000
C2857CA0 00000002
7C63F214 83E1001C
60000000 00000000
04857EDC 56B50630
C25E88F0 00000006
4E800421 80930000
3CA0636F 60A5696E
7C042800 40820014
3C804370 90830190
38800020 B0830198
60000000 00000000
C2857F4C 0000001A
72A00001 408200BC
7CA802A6 4800003D
4358C30C C30CC365
436CC365 436CC336
41D0C343 42DC42DC
C2D2C2D2 4398C366
C366C3A6 43ACC3A6
43ACC33E 41C8C347
42E642E6 C2E6C2E6
7C6802A6 88810016
3884FFCF 7C848A14
5484083C 7C632214
3C808038 80846000
80840058 1C84001C
7C632214 A0830000
B094001C A083000E
B0940020 807400BC
80630014 80630010
3C803E80 90830040
90830044 38800002
988300FC 3865006C
2C150000 4182000C
3865FF94 62B50001
7C6803A6 4E800020
98140081 38600208
60000000 00000000
C27ED1D8 00000021
887E0081 2C030000
408200F8 8BFE0190
3C60809C 8063D728
7C63FA14 3880000Z
3C60809C 806318F8
80630020 5484103A
7C63202E 80630000
80630028 C0230020
38610008 3880000D
48000019 001A0800
00010030 0025002E
00320066 00000000
7CA802A6 4CC63242
3D808001 618C7814
7D8903A6 4E800421
38810010 387F0030
3CA0809C 80A5D728
1CDF00F0 7CA53214
80A500F4 2C050002
41820008 38650020
B064FFFE A0640000
2C030000 41820038
2C03002D 40820008
3860246D 2C03002E
40820008 3860246B
38A3FFD0 28050009
41810008 38652460
B0640000 38840001
4BFFFFC4 7FC3F378
38810008 38A00000
3D808063 618CDDB4
7D8903A6 4E800421
800100E4 00000000
C25F8C88 00000003
2C040000 4080000C
7C832378 4E800020
80A30010 00000000
045F8D08 7C832378
045F8D44 386DBFC4
045CDDAC 2C14FFFF
045CDDB0 4082000C
Where
* X: Racer count (2)
* Y: Player ID from the player you want to attach the camera to (1)
* Z: Player ID from the player you wanna see their speed (1) (this is the line that was modified from the original speedometer code)
You can also use the following code alongside a button activator to temporarily stop CPUs from driving, in case you want to take some advantage (JoshuaMK): https ://mariokartwii.com/showthread.php?tid=1282
The codes above may have a side effect where, if you as a human don't keep driving or go very slow, you may get respawned. Use this to avoid such scenario from happening. This will prevent CPU racers from getting respawned if stuck:
(PAL)
04744ba4 4e800020
However, flag 0x20 (called Eflag3 in course.0) is also defined in the code, and it makes the racer forcefully throw an item forwards during a cutscene. Since players are unable to get items during the award or ending cutscenes, this goes unused.
In this video, I modified the code to make the game think all ENPT points in the award ceremony course have Eflag3, forcing them to use an item if they have it every time (note that this flag is intended to be used in a few ENPT points, not all of them like I'm showing on this video. This is why the players just spam the items constantly).
I demonstrate this by manually giving the players an item in their inventory, such as the Mega Mushroom, or the POW block.
- More info on the ENPT settings: https ://wiki.tockdom.com/wiki/ENPT_Settings
- In PAL, functions 0x8073ed30, 0x8073ed3c and 0x8073ed48 return "true" if the Eflag2, Eflag3 and Eflag4 of the CPU's current ENPT is set.
- Source 1 (6:20): youtu.be/8RoLkIwhGi0?t=380
- Source 2 (5:39): youtu.be/xe6WZ2nvitk?t=339
- Mirror download: https ://drive.google.com/file/d/14GiXgOuKnMVzCz982HDTAH58AW3Zzn8_/view?usp=drive_link
This video first shows the original behavior, where they won't throw it near the end, VS a mod that removes this oddity and lets them throw it.
Here is the code snippet responsible for this behaviour, rewritten from a portion of function "Enemy::AIItemRace::useItemCommon_": https: //imgur.com/a/32fV7Bu
Thanks to @PabloMK7 for informing me about this + for providing the screenshot!
(Note: in the video, a mod was used to make players be able to only pull Blue Shells from item boxes, for demonstration purposes)
Check out the Tournament Museum mod for being able to play competitions / tournaments offline: https ://wiki.tockdom.com/wiki/Tournament_Museum
This parameter forces the default CPU max speed to be what's set in the "speed advantage" field of the BAS file + 70. This means that if a BAS file has a large speed advantage value set, CPUs will drive very fast, and they will drive slow if said value is low. This mode also appears to override the engine class speed multiplier (so for example, a 50cc race won't necessarily make CPUs slower).
To demonstrate this, I modified two competitions:
- The N64 DK's Jungle Parkway competition has the speed advantage set to 45, which results in CPUs having a default max speed of 115.
- The DS Twilight House competition has the speed advantage set to -8, which results in CPUs having a default max speed of 62.
You can use the following code to test this for yourself during a competition / tournament:
(PAL)
04731D10 38600001
04731D28 38000001
On the bottom you can see the current maximum soft speed limit for the player, the first and the second CPU. This was displayed using Dolphin Memory's Engine and a MKW watchfile provided by the Kinoko team: https ://github.com/vabold/Kinoko
- More info on BAS files: https ://wiki.tockdom.com/wiki/BAS_(File_Format)
- You can see the values set for the AIParam files per competition here: https: //docs.google.com/spreadsheets/d/14MrTFf-WrXytfXwU6pr5j8C-u2Zanml33xVhUFLt1UI/edit?pli=1&gid=737924637#gid=737924637
- Check out the Tournament Museum mod for being able to play competitions / tournaments offline: https ://wiki.tockdom.com/wiki/Tournament_Museum
This version restores the content that was not copied in the original version, and also removes anything not implicitly mentioned in the course.0 file (including the minimap, skybox, various decorative objects and effects, cameras, etc).
-- The changes are as follows --
- The parameters (KMP) were remade from scratch to match course.0's specifications, which include porting back the checkpoints, respawn points, removing all cameras, AREAs, and item points, and port back Bowser's figure (defined in the TagObj section of course.0).
- Removed minimap (in reality it was replaced with a very small 3D model to make it invisible)
- Remove any unnecessary assets from the course file.
-- Notes --
As mentioned in the linked video, the 3D model was created from the collision model defined from the course.0 file and fake textures were added to represent each collision type.
The collision types assigned in the restoration are guesses made from the "mapCGI_00" entry in the "Polygon" section of the course.0 file (which defines all collision triangles), as well as from comparing the early and the final collision models.
The collision types (alongside the fake texture in the BRRES corresponding to each) are as follows:
- ATTACH (Red, Texture.002): Sticky Road (0x16)
- DASH / DASHJ (Yellow, Texture.007): Boost (0x06) and Boost Ramp (0x07), respectively
- DIRT (Brown, Texture.004): Off-road (assumed to be the default off-road type, 0x03)
- HPIPE (Blue, Texture.005): Half-pipe Ramp (0x13)
- OUTF (Light Blue, Texture.006): Invisible Wall (0x0D) (could also be "Half-Pipe Invisible Wall (0x1C)")
- ROAD (Red, Texture): Road (0x00)
- ROAD_MH (Purple, Texture.008): Road (0x00) (with collision effect = reject road)
- ROAD_SJ (Orange, Texture.009): Road (0x00) (with collision effect = trickable)
- VALLEY (Dark black and white, Texture.003): Fall Boundary (0x10)
- WALL (Black and white, Texture): Wall (0x0C)
On this restoration specifically, the "mapCGI_01" entry on each collision triangle is assumed to be the collision type's "variant". While this is speculation from my part, there are a few things that make me think that "mapCGI_01" could be related to the collision type's variant in some way or other:
Almost all collision types have the "mapCGI_01" set as 0 (default variant). However, two of them have 1 instead: OUTF (invisible wall) and DASHJ (boost ramp).
- For the boost ramp, variant 1 makes the character only spin once when doing a trick instead of two times, which matches the same ramp from the final version.
- For the invisible wall, variant 1 creates a spark effect + the character plays its "collided with wall" voice clip. This is similar to the behaviour seen in this prerelease video of the game: youtu.be/p9i_9D7kNlQ?t=10
* Due to the lack of item points, the game will crash if any player uses an item that follows a route, like the Red Shell, Blue Shell or the Bullet Bill.
* The off-road section creates a black smoke effect when driving on it. This is a property of the Bowser's Castle slot, and does not have anything to do with the restoration itself.
* At 5:51, the collision type for the boost ramp was changed to act as a cannon trigger in order to be able to showcase the location of the cannon destination point. In the actual course.0 file, only the cannon point is defined, but no triggers or similar are defined, so we don't know where the devs intended to put the start of the cannon.
* For all sections with more than one point in course.0 (i.e. with pnt0_?, pnt1_? and pnt2_?), only the pnt0_? coordinates are taken into account. For checkpoints, the XZ position of the first point were obtained from its pnt0_X and pnt0_Z, while the XZ position of the second point were obtained from the pnt0_X and pnt0_Z of the checkpoint definition immediatly below it.
* It is assumed that only one key checkpoint exists (the lap counter), and that the rest are regular checkpoints.
* The Bowser figure's fireball has its first setting set to 100, but said object doesn't use any of the settings in the final game, so it's unknown what it meant.
(Remove the spaces from the links below)
- Download: https: //drive.google.com/file/d/1sYauN9wbJzeV0Bs32eVRkk3uOPBeD_-4/view?usp=drive_link
- More info at TCRF: https: //tcrf.net/Mario_Kart_Wii/Unused_Courses#course.0
-- Timestamps --
0:00 VS. Race
3:47 CPU Points
5:03 Start Position
5:08 Respawn Points
5:50 Cannon Point (Unused)
5:57 Paths (only a single path is defined, used for the trajectory of Bowser figure's fireball)
6:20 Checkpoints
Since this course was only meant to be used as a boss stage (and thus was not supposed to have the player completing races), the only reason why checkpoints are present is so that players are able to respawn at different locations in the stage.
This way, the devs made it so that when you fall at a certain part of the stage, you will respawn on the *opposite* side (see 0:50), likely so that you don't fall right above the Topmen (which will usually be nearby the location where you fell off). In order for this to work, checkpoints have to be defined in order to determine which respawn point will the player go when they fall on a certain area.
At 1:25, all checkpoints defined are shown. The recovered competition data for this and many other competitions can be found here (remove the spaces from the link): https:// github.com/mkwcat/mkw-tournament-museum/tree/master/data/mkwtm/Comp
NOTE: Battle Mode uses different logic to determine what respawn point to go to, which doesn't need checkpoints at all, hence why players are able to respawn at different positions in battle mode, despite battle arenas not having checkpoints defined.
In the final game, they don't emit a voice when they're hit.
It's referred to as "SE_CC_DOSSUN_V_DMG" internally (ID 0x246).
Thanks to DBlaze for letting me know about this!
This code is offline-only, at least temporarily, in order to prevent situations where the player's Mii name would not match the Mii name seen by the Wiimmfi server, which according to that server's rules, it's banworthy.
The Gecko code itself won't work as is. You have to copy some specific files from MenuMulti.szs to MenuSingle.szs and Event.szs (otherwise the game will crash)
The following BRCTRs must be present in those files:
* /button/ctrl/MiiSelectArrowLeft.brctr
* /button/ctrl/MiiSelectArrowRight.brctr
* /button/ctrl/MiiSelectMii.brctr
* /button/ctrl/Back.brctr
* /control/ctrl/MiiBlackBack.brctr
* /control/ctrl/MiiSelectName.brctr
* /control/ctrl/TabControlMiiSelect.brctr
* /bg/ctrl/MenuObiBottom.brctr
* /bg/ctrl/MenuObiTop.brctr
Their associated BRLYTs and TPLs must also be present, in the respective /blyt and /timg folders.
If you don't want to be copying the exact files over, you can just copy the entire /bg , /button and /control folders from MenuMulti.szs to the other files, *without* overwriting the files with the same name, *with the exception* of Back.brctr, MenuObiBottom.brctr and MenuObiTop.brctr .
Those three files must be replaced with the ones from MenuMulti.szs.
Here you have example patches for patching both files so that they're compatible with the Gecko code: https ://drive.google.com/file/d/1EnKjtz6fXCPac_xs3M55Suh-xGOpLI4O/view?usp=drive_link
*** CODE ***
(PAL)
0462D32C 4B9D3485
0462D470 4B9D3341
0462D5B4 4B9D31FD
0462D800 4B9D2FB1
0462D86C 4B9D2F45
0462D8D8 4B9D2ED9
0462D944 4B9D2E6D
0462F684 4B9D112D
0462F768 4B9D1049
0462F840 4B9D0F71
0462FC3C 4B9D0B75
0462FCB4 4B9D0AFD
060007B0 0000002C
9421FFF0 7C0802A6
90010014 7FE3FB78
38800060 48622545
7FE3FB78 80010014
7C0803A6 38210010
4E800020 00000000
C2847E84 00000003
2C000045 41820010
2C000046 41820008
2C000047 00000000
04847E88 41820020
04847ED4 60000000
048315B8 60000000
04848858 48000044
04848950 480000F4
0459E3B0 60000000
047E3BB0 60000000
047E3928 60000000
0483E354 38600000
(USA)
045fc478 4ba04339
045fc5bc 4ba041f5
045fc700 4ba040b1
045fc94c 4ba03e65
045fc9b8 4ba03df9
045fca24 4ba03d8d
045fca90 4BA03D21
045fe7d0 4BA01fe1
045fe8b4 4BA01efd
045fe98c 4BA01e25
045fed88 4BA01a29
045fee00 4BA019b1
060007B0 0000002C
9421FFF0 7C0802A6
90010014 7FE3FB78
38800060 485f1691
7FE3FB78 80010014
7C0803A6 38210010
4E800020 00000000
C282afac 00000003
2C000045 41820010
2C000046 41820008
2C000047 00000000
0482afb0 41820020
0482affc 60000000
0484e290 60000000
0482b980 48000044
0482ba78 480000F4
045b3398 60000000
047ddb20 60000000
047dd898 60000000
048238f4 38600000
*** DOCUMENTATION (PAL) ***
# Add Mii Selection page to the sections that have the Character Select page
0462D32C 4B9D3485
0462D470 4B9D3341
0462D5B4 4B9D31FD
0462D800 4B9D2FB1
0462D86C 4B9D2F45
0462D8D8 4B9D2ED9
0462D944 4B9D2E6D
0462F684 4B9D112D
0462F768 4B9D1049
0462F840 4B9D0F71
0462FC3C 4B9D0B75
0462FCB4 4B9D0AFD
# Small function that adds the Mii Selection page. Accessed from the branches in the lines above. Uses addresses 0x800007B0 thru 0x800007E0
060007B0 0000002C
9421FFF0 7C0802A6
90010014 7FE3FB78
38800060 48622545
7FE3FB78 80010014
7C0803A6 38210010
4E800020 00000000
# Don't add extra buttons if going to the License settings / Mii Select on create / Mii Select on deleted Mii pages. This avoids a crash due to missing resources in MenuOther.szs, used by said pages.
04847E84 2C000054
C2847E84 00000003
2C000045 41820010
2C000046 41820008
2C000047 00000000
04847E88 41820020
# Remove local multiplayer-only checks so that they pass if accessing other sections.
04847ED4 60000000
048315B8 60000000
04848858 48000044
04848950 480000F4
0459E3B0 60000000
# The game crashes when selecting a Mii here because of a missing pane named ok_text_Xp (where X is a local player number). I wasn't able to fix this on time, so at the moment I skip this to avoid the crash, but has the side effect of not displaying the small "OK" text in in front of the Mii icon
047E3BB0 60000000
# Allow loading the Mii Selection page instead of simply choosing the Mii when in single player modes
047E3928 60000000
# Fixes an issue where selecting a Mii would then load the License's Mii data back
0483E354 38600000
KNOWN BUGS
- When going back to the Time Trial course selection screen (by clicking on Change Course during gameplay), your selected Mii will revert back to your License's Mii, and sometimes the vehicle model will become invisible.
If you selected a Mii with different weight class than your License's Mii, you will be able to select their vehicles if you go back to the vehicle selection screen, and play with them just fine.
This is temporarily though, when you go back to the character selection screen, select your desired Mii again and it will be fixed, or just exit to the main menu.
"There is an entry in memory that is connected to Link learning Saria's Song. The instrument used is the Giant's voice from the cutscene where Tatl interprets the Oath to Order for Link. The message is "ワタクシのあとに 吹いてください", or "Follow along after me.""
What I'm showing on this video is what the article is referring to. Function 0x80152CAC (USA) decides what instrument to use when somebody is teaching Link a song. Curiously, one entry exists for the unused Saria's Song that will set the "teacher's" instrument to Tatl's sounds, much like when learning the Oath to Order.
The text ID for the staff is set to 0x1B61 for Saria's Song, which is just a copy of the "Follow along after me." text.
An entry also exists for learning the Sun's Song, which has the text ID assgined to 0x1B67 (also the "Follow along after me." text). Unlike the Saria's Song though, there's no specific instrument set for that, so the teacher's instrument will be set to the ocarina by default.
- More info at TCRF: tcrf.net/The_Legend_of_Zelda:_Majora%27s_Mask/Song_Data
- Function 0x80152CAC's code: github.com/zeldaret/mm/blob/1ddc836c8eb0f143255a1806087f7098b52dee90/src/code/z_message.c#L3761
This single tree is the only one with this behaviour in the whole game, plus this behaviour is unique to the 3DS version of the game. The way this is done is by skipping most of the code from the tree's draw function (at VRAM address 0x001E0F00 in USA) if the game sees that the tree is placed in the exact XYZ coordinates of (3935, -116, 6279).
You can see the checks I mentioned above here (courtesy of Hylian Freddy): cdn.discordapp.com/attachments/915273929369731173/1287853027960557681/image.png?ex=66f30e19&is=66f1bc99&hm=7c79580c06c70aea70355955da7091bbbb7a8f38e42d71582f7443bcd6b80305&
While many of them don't have their icons anymore, they still retain the same functionality and quirks, and you can even see their "Get Item" models in the pause menu!
You can try these out by using the following Gateway code (EUR v1.0). This will assign any item you want to the X button (with XX = Item index; shown in the video):
2077532C 000000XX
For anybody who hasn't seen the unused MM64 items before, here's a video showcasing a bunch of them: youtube.com/watch?v=XjttYsoIeqY
One interesting thing is that various registers allow the user to change various properties of the shadow, such as scale, angle, transparency, distance away from the player, etc, which is shown on this video using the "B" registers (which can be opened by pressing Start + R a few times on the second controller in debug versions of the game).
Ocarina of Time's implementation can be found here, although it's pretty much identical in Majora's Mask: github.com/zeldaret/oot/blob/main/src/overlays/actors/ovl_En_Sda/z_en_sda.c
The actor actually has two variables: 0, which loads Link's shadow, and also 1, which appears to have been intended to indicate the game to draw shadows of parent actors instead.
This suggests that this actor was intended to function alongside any actor, not just Link (note that other actors that have dynamic shadows in the game, like signs, Ganondorf, etc, have their own shadow drawing code, and thus don't use En_Sda at all)
However, much of the code in the final game is written to only make it function properly with Link, so using it alongside other actors most likely won't work properly.
The code for this actor was dummied out in both game's 3DS remakes. In OoT 3D in particular, the initialization function for this actor is found at VRAM address 0x0018EA04
However, there are actually jump sounds for up to 8 jumps, which go unused. These being NA_SE_PL_DEKUNUTS_JUMP6 to NA_SE_PL_DEKUNUTS_JUMP8, which are play on higher pitch than the other sounds.
The code responsible for playing the water jump sounds for Deku Link can be seen here: github.com/zeldaret/mm/blob/98d9571f51aa85279ae501707793848b1c3f6256/src/overlays/actors/ovl_player_actor/z_player.c#L6887
However, a third unused variant exists, named "ObjectRrWaveWay1" in the code, and whose object ID is 0x0186. It behaves similarly to 0x188, but doesn't have any holes and moves a bit faster. Not only that, but its collision seems to have a few boost pads that don't appear on the 3D model.
More specifically, it uses:
- RB33: Choose a SFX from a preset of sounds.
- RB32: Play the SFX from RB33
- RB35: Choose a background music
- RB34: Play the song from RB35
If using debug builds, like shown in the video, the registers page containing the registers above can be opened by pressing Start + R a couple of times in the second controller, and then using the D-Pad on said controller to navigate.
More info at TCRF: tcrf.net/Proto:The_Legend_of_Zelda:_Ocarina_of_Time_Master_Quest#Morpha_Sound_Test
You can see the code that handles this sound test here: github.com/zeldaret/oot/blob/1f2e82c39e910d45f3ac4e06c95e662c9978477a/src/overlays/actors/ovl_Boss_Mo/z_boss_mo.c#L3055
Here is how it looks like when the code is changed so that this screen doesn't get skipped in the Master Quest (Debug) version of the game.
The code associated to this screen can be seen here: github.com/zeldaret/oot/blob/main/src/overlays/gamestates/ovl_title/z_title.c
All three effects are unused, and the snow effect is instead loaded from Common.szs/Effect/RKRace.breff/rk_snow
While the course's rk_snow and rk_snowDemo are very similar to the used rk_snow from Common.szs, rk_snowTest is quite different, as it renders the snowflakes in a line and very close together.
Interestingly, there's code that's supposed to execute if the game fails to load any of those BCP files, but it's never executed in practice because of a nullptr check that prevents to go to the code I mentioned above anyways (see the code at around VRAM address 0x805a1f68 in PAL).
If we force said code to be executed, we can see that it assigns default hardcoded parameters to the starting camera in case the game can't find any BCP. These look quite different than any starting camera parameters used by the game, and kinda look like the starting camera from Super Mario Kart.
You can see this unused camera for yourself using the following Gecko code:
(PAL)
045A1F5C 38800000
(USA)
04596F24 38800000
(JPN)
045A18DC 38800000
(KOR)
0458FFB4 38800000
"start_camera.bcp" is very similar to "race_camera.bcp" (which is used in most instances, such as at the start of VS Races or time Trials). The only notable difference I could find is that, halfway through, the camera is very slightly further away from the character in "start_camera.bcp". At 0:10 a comparison between both BCPs are shown.
More info on BCP files: wiki.tockdom.com/wiki/BCP
The second one is a method to select what damage effect to display when they're hit. This can be done by setting specific values at register kReg 17 (which can be opened by pressing Start + B on the 2nd controller), which will correspond to their "damage effect ID", and then pressing the R button, also on the 4th controller. Unfortunately I don't think I've been able to do this correctly, even after doing the previously mentioned steps, so I didn't show it in the video.
These features are enabled by default in debug builds of the game (shown in the video is footage of me doing it in the debug version of the European v1.1 version of the game). They're also present in retail builds, but it's not possible to trigger them because retails builds clear the data for all controllers but controller 1 on every frame, so the game ignores controller 4 completely.
The following Gameshark code ignores that and makes it so that all controllers are read, enabling these features back:
(USA)
81175CE4 0000
81175CE6 0000
You can read the code associated to these features in the decompilation project:
github.com/zeldaret/mm/blob/2a12eca52b1e5706c404f41705e51b30d73bc92e/src/overlays/actors/ovl_En_Knight/z_en_knight.c#L3783
0:00 Besides not being able to save, you're also unable to access online play, the Mario Kart Channel, or Time Trials, since those modes require data taken / saved to the save file in order to work.
0:50 When getting to the ending picture, the game won't allow you to save it to the Wii Message Board, so pressing A on this screen just fades out and goes back to the Title Screen.
0:58 Booting up the Mario Kart Channel from the Home Menu forces the player to initialize the disc to try to create a save file, making the channel unable to be accessed until the player can successfully create one.
Note that it should still be possible to unlock all characters / vehicles / modes. The ones that are normally unlocked via Time Trials must be unlocked using the alternative method (if possible), or by doing the "Play X number of races" method.
The Goron Tunic allows the player to not get killed in hot rooms, while the Zora Tunic makes the player able to swim underwater infinitely.
Shown on this video is the Zora Tunic. Normally, a countdown appears stating the time left before drowning. Then, at 0:18, I "equip" the Zora Tunic, which makes the countdown disappear, allowing me to breath underwater infinitely.
The code that handles this in Majora's Mask is part of the source code file "z_parameter.c", as part of a function known as "Interface_Update".
- You can see it here in the original version: github.com/zeldaret/mm/blob/34e326bc344b2a7be9d40cbbdf6367e0956a99f6/src/code/z_parameter.c#L6786
- In the 3DS version (EUR v1.0) the code that handles this starts at around 0x00170B80 in RAM.
You can use this code to equip any of those tunics on the EUR v1.0 version:
10775352 00000X00
where X:
2 = Goron Tunic
3 = Zora Tunic


