* You don't need this file to run the code, but I find it to be more convenient as it allows you to write function names instead of addresses. I'll write out the address in a comment to the side for those who don't want to use it.
Spoiler: ASM Source Code
.include"SM64Functions.txt"
// Custom loop function 0x802CB1C0, 0x2C bytes (11 instructions) of free data left. .org0x861C0 ADDIUSP, SP, 0xFFE8 SWRA, 0x14(SP) LUIT0, 0x8034 LWT2, 0xB17C(T0)// T2 = current action
LUIT1, 0x0C00 ORIT1, T1, 0x0203// T1 = 0x0C000203, Sleeping action value BNET2, T1, 802CB1C0_end // Branch to end if Mario is not sleeping. NOP
LWT3, 0xB1D0(T0)// Load word at 0x8033B1D0 (For this example it's a timer) ORIT4, R0, 0x20 BNET3, T4, 802CB1C0_incrementTimer NOP
LUIA0, 0x8036 LWA0, 0x1158(A0)// A0 = Pointer to Mario object. LUIA2, 0x1300 ORIA2, A2, 0x40EC// A2 = 0x130040EC, 1-UP behavior. JAL@SpawnObj // 0x8029EDCC ORIA1, R0, 0xD4// 1-UP Model ID. // V0 = pointer to newly spawned 1-UP object.
LUIT4, 0x41A0// 0x41A00000 = (float) 20.0 MTC1T4, F0// Move value at T4 to float register F0 LWC1F2, 0xA4(V0)// Get Y position of 1-UP ADD.SF2, F2, F0// Add 20.0 to Y position SWC1F2, 0xA4(V0)// Store new Y position
We all know that Mario can do a lot of different moves within Super Mario 64. He can run, jump, side-flip, swim, swing Bowser's tail, grab boxes, and many different other things. All of these different actions that Mario can do have a corresponding u32 word value to them. Mario's current action is stored at 0x8033B17C (Mario→0x0C), while his previous action is stored at 0x8033B180 (Mario→0x10). For this tutorial we only want to know if Mario is currently sleeping, so we need to check if the value at 0x8033B17C equals 0x0C000203. See this wiki page for the list of Mario's actions.
Action
Description
0x04000440
Moving around
0x03000880
Jump
0x03000881
Double-jump
0x03000882
Triple-jump
0x008008A9
Ground-pounding
0x0C008220
Crouching
0x0C400201
Idle
0x0C400202
Yawning
0x0C000203
Sleeping
Hooking the code (Function 0x802CB1C0)
Most ASM tutorials overwrite the 0x802CB1C0 function to get custom code to run. Here are 3 specific reasons to why we use this function.
The function calls on a useless debug menu (according to Kaze), meaning we can change it without affecting the game in any way
It is called within Mario's behavior loop, so we know that it will be called every frame. We can change Mario's behavior script if we only want the function to run once.
The function is 0xA4 bytes long, which gives us 41 ASM instructions to play around with. This is more than enough space for most basic tutorials. If more space is needed, then we can turn this function into one that can call the dmaCopy function.
Checking the current action
First we must check if the current action (value at 0x8033B17C) equals 0x0C000203. To do this we first load the word at 0x8033B17C into register T2, then set the value of register T1 to 0x0C000203. Once we do that, we can compare the two values using the BNE (Branch Not Equal) OpCode. If the two values are not equal, then the game logic will move down to the "802CB1C0_end" label I set near the end of the function.
.org0x861C0 ADDIUSP, SP, 0xFFE8 SWRA, 0x14(SP)
LUIT0, 0x8034 LWT2, 0xB17C(T0)// T2 = current action LUIT1, 0x0C00 ORIT1, T1, 0x0203// T1 = 0x0C000203, Sleeping action value BNET2, T1, 802CB1C0_end // Branch to end if Mario is not sleeping. NOP Setting up a delay
We don't want to spawn the 1-UP as soon as Mario falls asleep, because that doesn't look very good. Mario needs to sleep for a little bit before he gets a mushroom, so we want to setup a little delay for when Mario goes to sleep and when the 1-UP mushroom spawns. While Mario is running around or Idle the value at the address 0x8033B1D0 is set to zero, but not when he is sleeping. This means we can change that value while Mario is sleeping, and it will reset when Mario wakes up. The delay time will be 32 frames (0x20), which is just a little over a second. If the timer does not equal 0x20, then the value will increment by 1. If both values are equal, then the 1-up mushroom will spawn above Mario's head.
LWT3, 0xB1D0(T0)// Load word at 0x8033B1D0 (For this example it's a delay timer) ORIT4, R0, 0x20// T4 = 0x20 (Decimal value 32) BNET3, T4, 802CB1C0_incrementTimer // Branch if T3 != T4 NOP Spawning the 1-UP mushroom
To spawn the 1-UP we must use the @SpawnObj (0x8029EDCC) function which we will use to spawn it at Mario's location. It takes 3 arguments: A0 = Object to spawn to, A1 = Model ID, A2 = Behavior segmented address. Mario's object pointer to located at 0x80361158, so we will load the word at that address for A0. The model ID for the 1-up mushroom is 0xD4. There are a few different behaviors for the 1-UP mushroom, but the one we want is 0x130040EC which will spin around above Mario's head before landing on Mario.
After we spawned the 1-UP mushroom we need to move it's Y-position up so that it can appear above Mario's head. The @SpawnObj function returns a pointer to the 1-UP object in register V0. So we are going to add to the value of offset 0xA4 (y-position) of the 1-UP object. Now every object's XYZ position are stored as floating point numbers, which are different values than regular integers. You can use this helpful webpage to convert decimal to a floating point hex value: http://www.h-schmidt.net/FloatConverter/IEEE754.html
Note: It's good practice to only use the even-numbered floating point registers (F0, F2, F4, etc). Using odd-numbered FP registers in Wii VC will crash the game, so keep this in mind when creating ROM hacks.
LUIA0, 0x8036 LWA0, 0x1158(A0)// A0 = Pointer to Mario object. LUIA2, 0x1300 ORIA2, A2, 0x40EC// A2 = 0x130040EC, 1-UP behavior. JAL@SpawnObj // 0x8029EDCC ORIA1, R0, 0xD4// 1-UP Model ID. // V0 = pointer to newly spawned 1-UP object.
LUIT4, 0x41A0// 0x41A00000 = (float) 20.0 MTC1T4, F0// Move value at T4 to float register F0 LWC1F2, 0xA4(V0)// Get Y position of 1-UP ADD.SF2, F2, F0// Add 20.0 to Y position SWC1F2, 0xA4(V0)// Store new Y position Finishing up the code
To finish up the code we have our 2 branch labels. The incrementTimer label will increase the value at 0x8033B1D0 by 1, and the end label will jump back to where the function was called from.
802CB1C0_end: LWRA, 0x14(SP) JRRA ADDIUSP, SP, 0x18
Now assemble the code and a 1-UP mushroom should appear when Mario falls asleep. If you have any questions, please leave a reply below and I'll try to answer it the best I can.
(This post was last modified: 23-06-2017, 08:03 PM by queueRAM.
Edit Reason: wiki links
)
[ASM] Sweet Dreams (Spawn a 1-UP mushroom while Mario is sleeping)