[ASM] Sweet Dreams (Spawn a 1-UP mushroom while Mario is sleeping)
Users browsing this thread: 1 Guest(s)

This tutorial will cover how to run code while Mario is doing a specific action (like sleeping). 

[Image: 6JTG6P7.png]

You will need the following: * 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.

​.org 0x861C0
​ADDIU SP, SP, 0xFFE8
​SW RA, 0x14 (SP)
​LUI T0, 0x8034
​LW T2, 0xB17C(T0)
// T2 = current action

​LUI T1, 0x0C00
​ORI T1, T1, 0x0203
// T1 = 0x0C000203, Sleeping action value
​BNE T2, T1, 802CB1C0_end
// Branch to end if Mario is not sleeping.
​NOP

​LW T3, 0xB1D0(T0)
// Load word at 0x8033B1D0 (For this example it's a timer)
​ORI T4, R0, 0x20
​BNE T3, T4, 802CB1C0_incrementTimer
​NOP

​LUI A0, 0x8036
​LW A0, 0x1158(A0)
// A0 = Pointer to Mario object.
​LUI A2, 0x1300
​ORI A2, A2, 0x40EC
// A2 = 0x130040EC, 1-UP behavior.
​JAL @SpawnObj
// 0x8029EDCC
​ORI A1, R0, 0xD4
// 1-UP Model ID.
​// V0 = pointer to newly spawned 1-UP object.

​LUI T4, 0x41A0
// 0x41A00000 = (float) 20.0
​MTC1 T4, F0
// Move value at T4 to float register F0
​LWC1 F2, 0xA4(V0)
// Get Y position of 1-UP
​ADD.S F2, F2, F0
// Add 20.0 to Y position
​SWC1 F2, 0xA4(V0)
// Store new Y position

802CB1C0_incrementTimer:
​ADDIU T3, T3, 0x01
​LUI T0, 0x8034
​SW T3, 0xB1D0(T0)

802CB1C0_end:
​LW RA, 0x14 (SP)
​JR RA
​ADDIU SP, SP, 0x18 
Mario's Actions

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.
  1. ​The function calls on a useless debug menu (according to Kaze), meaning we can change it without affecting the game in any way
  2. ​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.
  3. ​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.

.org 0x861C0
​ADDIU SP, SP, 0xFFE8
​SW RA, 0x14 (SP)

​LUI T0, 0x8034
​LW T2, 0xB17C(T0)
// T2 = current action
​LUI T1, 0x0C00
​ORI T1, T1, 0x0203
// T1 = 0x0C000203, Sleeping action value
​BNE T2, 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.

LW T3, 0xB1D0(T0) // Load word at 0x8033B1D0 (For this example it's a delay timer)
​ORI T4, R0, 0x20
// T4 = 0x20 (Decimal value 32)
​BNE T3, 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.

LUI A0, 0x8036
​LW A0, 0x1158(A0)
// A0 = Pointer to Mario object.
​LUI A2, 0x1300
​ORI A2, A2, 0x40EC
// A2 = 0x130040EC, 1-UP behavior.
​JAL @SpawnObj
// 0x8029EDCC
​ORI A1, R0, 0xD4
// 1-UP Model ID.
​// V0 = pointer to newly spawned 1-UP object.

​LUI T4, 0x41A0
// 0x41A00000 = (float) 20.0
​MTC1 T4, F0
// Move value at T4 to float register F0
​LWC1 F2, 0xA4(V0)
// Get Y position of 1-UP
​ADD.S F2, F2, F0
// Add 20.0 to Y position
​SWC1 F2, 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_incrementTimer:
​ADDIU T3, T3, 0x01
​LUI T0, 0x8034
​SW T3, 0xB1D0(T0)

802CB1C0_end:
​LW RA, 0x14 (SP)
​JR RA
​ADDIU SP, 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 )


Attached Files
Size: 1.1 KB / Downloads: 149 .txt   SleepTest.txt


[ASM] Sweet Dreams (Spawn a 1-UP mushroom while Mario is sleeping)
Users browsing this thread: 1 Guest(s)