Level Script Engine Commands & Info « 1 2
Users browsing this thread: 1 Guest(s)

Nice finds, especially the dialog. I always thought it sucked not to have it for all levels
Gone for a while.

While looking into what it would take to relocate the general memory pool (0x8005C000-0x801C1000) to expansion RAM, I noticed something odd with Level script 0x16 that caused the game to crash. From shygoo's notes:

0x16 (8037EC54): Load raw data from ROM to absolute RAM address
16 10 00 00 [XX XX XX XX] [YY YY YY YY] [ZZ ZZ ZZ ZZ]
X = RAM address
Y = ROM address start
Z = ROM address end
Call 0x802786F0 (A0 = X, A1 = Y, A2 = Z)

This is 100% correct. However, the function it calls (FixedCopy/802786F0) makes a large assumption that the destination RAM address is within the memory pool range. SM64 only uses this level script for copying the main menu asm code to RAM. I spent some time decompiling the FixedCopy routine, which you can find below. There are two problems with the code for general use: 1. it calls _pool_alloc() and 2. it computes the length to copy from pool_tail - ram instead of rom_end - rom_start. Without some modifications, this makes it practically unusable for anything but what SM64 already uses it for.

I'm also attaching an updated decompiled level scripts C file which includes some more level scripts and all the _pool_alloc(), _pool_free() and related data structures.

Code:

pool_t *pool_tail; // 0x8033B490
u32 FixedCopy(u32 ram, u32 rom_start, u32 rom_end) // begin 802786F0/0336F0
{
  (void)ram;        // 0x28($sp)
  (void)rom_start;  // 0x2c($sp)
  (void)rom_end;    // 0x30($sp)
  u32 ret_addr = 0; // 0x24($sp)
  u32 len;          // 0x20($sp)
  u32 pool_len;     // 0x1c($sp)

  len = ((rom_end - rom_start) + 0xF) & 0xFFFFFFF0);
  pool_len = (pool_tail - ram) + 0xF) & 0xFFFFFFF0);

  if (pool_len >= len) {
     ret_addr = _pool_alloc(pool_len, 1);
     if (ret_addr != NULL) {
        bzero(ret_addr, pool_len);
        osWriteBackDCacheAll();
        DmaCopy(ret_addr, rom_start, rom_end);
        osInvalCache(ret_addr, pool_len);
        osInvalDCache(ret_addr, pool_len);
     }
  }

  return ret_addr;
}


Attached Files
Size: 20.64 KB / Downloads: 73 .c   sm64_level_scripts_decompiled.c


For what it's worth, here's that decoder I said I would release a millennium ago
https://github.com/shygoo/sm64-lsdec
https://github.com/shygoo/sm64-lsdec/releases/download/v0/lsdec.zip
(This post was last modified: 05-02-2017, 01:49 AM by shygoo.)


Attached Files
Size: 36.9 KB / Downloads: 66 .zip   level-scripts-decoded.zip

My threads are now being maintained here

Today I learned that you can actually load data directly from the ROM cartridge and put it into a register. I had always just assumed that you needed to use the DMACopy function if you wanted to use any data that is stored on the cartridge. This means that we can have jump tables inside the ROM file itself and not have to worry about where to put them in RAM. This makes it trivial to add in new custom level script commands into the game. 

I've written some example code for creating a new custom levelscript command. This simple code does 3 main things:
  1. ​Modifies function 0x803805C8 to read from a jump table at 0xB07E0000 instead of 0x8038B8B8.
  2. ​I overwrote the unused function 0x8024B940 to be the code for my new levelscript command.
  3. ​I copied the table data from ROM address 0x108638 to 0x7E0000, and then added a new entry at the end of the list. I chose 0x7E0000 since that region is not being used by the original 8MB ROM or the extended ROM.
The new levelscript command I created doesn't do anything important. My new 4-byte levelscript 0x3D command takes the value located at 0x80370000 and adds it with the signed halfword in the 0x3D command. Basically, [ 3D 04 01 00 ] is the same as: (*80370000) += 0x100. The region around 0x80370000 is empty and not being used by anything, so it will have no effect in-game.

Spoiler: Source code
// Assemble with Armips v0.9

​// This function is modified to get the function pointer for a command from the table at 0xB07E0000.
​.orga 0x0FD348
LevelScriptLoad: // begin 803805C8 (0FD348)
​addiu sp, sp, -0x18
​sw ra, 0x14(sp)
​sw a0, 0x18(sp)
​addiu t6, r0, 0x1
​lui at, 0x8039
​sh t6, -0x41e0(at)
​lw t7, 0x18(sp)
​lui at, 0x8039
​sw t7, -0x41d8(at)
​lh t8, 0x8038be20 ; lui t8, 0x8039/lh t8, -0x41e0t8
​addiu at, r0, 0x1
​bne t8, at, LevelScriptLoad_70
​nop
LevelScriptLoad_38: ; 80380600
​lw t9, 0x8038be28 ; lui t9, 0x8039/lw t9, -0x41d8t9
​lbu t0, 0x00(t9)
​lui t9, 0xB07E
​sll t1, t0, 0x2
​addu t9, t9, t1
​lw t9, 0x00(t9) ; Get address from new jump table at 0xB07E0000 (ROM address 0x7E0000)
​jalr t9
​nop
​lh t2, 0x8038be20 ; lui t2, 0x8039/lh t2, -0x41e0t2
​addiu at, r0, 0x1
​beq t2, at, LevelScriptLoad_38
​nop
LevelScriptLoad_70: ; 80380638
​jal 0x8027E3E0
​addiu a0, r0, 0x1
​jal 0x80247CCC
​nop
​jal 0x8027B3B4
​nop
​jal 0x80247D14 ; CleanupDisplayList
​nop
​jal 0x80278F2C
​move a0, r0
​lui v0, 0x8039
​b LevelScriptLoad_AC
​lw v0, -0x41d8(v0)
​b LevelScriptLoad_AC
​nop
LevelScriptLoad_AC: ; 80380674
​lw ra, 0x14(sp)
​jr ra
​addiu sp, sp, 0x18

​// New levelscript command 0x3D
​.orga 0x6940 ; Overwrite the unused function 0x8024B940
​.area 0x64 ; Set data import limit to 0x64 bytes
LevelScript3D:
​addiu sp, sp, -0x18
​sw ra, 0x14(sp)
​lw t0, 0x8038be28 ; lui t0, 0x8039/lw t0, -0x41d8t0
​lh t1, 0x02(t0)
​lui t2, 0x8037
​lw t3, 0x00(t2)
​add t3, t3, t1
​sw t3, 0x00(t2)
LevelScript3D_increment: ; You NEED to include this increment code in every levelscript command
​lui at, 0x8039
​lbu t8, 0x1(t0)
​addu t9, t0, t8
​sw t9, -0x41d8(at)
LevelScript3D_end:
​lw ra, 0x14(sp)
​jr ra
​addiu sp, sp, 0x18
​.endarea

​// new levelscript jump table, original is at ROM address 0x108638
​.orga 0x007E0000
​.word 0x8037E2C4
​.word 0x8037E388
​.word 0x8037E404
​.word 0x8037E47C
​.word 0x8037E4FC
​.word 0x8037E580
​.word 0x8037E5B8
​.word 0x8037E620
​.word 0x8037E650
​.word 0x8037E6D4
​.word 0x8037E780
​.word 0x8037E7F8
​.word 0x8037E878
​.word 0x8037E8E8
​.word 0x8037E988
​.word 0x8037EA18
​.word 0x8037EA70
​.word 0x8037EA98
​.word 0x8037EB04
​.word 0x8037EB98
​.word 0x8037EBD4
​.word 0x8037EC14
​.word 0x8037EC54
​.word 0x8037ECA4
​.word 0x8037ECF8
​.word 0x8037ED48
​.word 0x8037EDF8
​.word 0x8037EE48
​.word 0x8037EEA8
​.word 0x8037EF00
​.word 0x8037EF70
​.word 0x8037F010
​.word 0x8037F130
​.word 0x8037F164
​.word 0x8037F214
​.word 0x8037F2A4
​.word 0x8037F45C
​.word 0x8037F36C
​.word 0x8037F67C
​.word 0x8037F994
​.word 0x8037F790
​.word 0x80380014
​.word 0x8038007C
​.word 0x803800BC
​.word 0x80380160
​.word 0x803801A0
​.word 0x8037FE94
​.word 0x8037FF14
​.word 0x80380274
​.word 0x8037F920
​.word 0x8038024C
​.word 0x803801E0
​.word 0x8037FDE4
​.word 0x8037FE2C
​.word 0x80380300
​.word 0x8038039C
​.word 0x803803EC
​.word 0x8037FF94
​.word 0x8037FB18
​.word 0x8037FC38
​.word 0x80380434
​.word 0x8024B940 ; Custom levelscript command 0x3D
​.word 0x00000000
(This post was last modified: 22-05-2017, 10:49 AM by David.)

Wow that's revolutional!
Gone for a while.

I've basically figured out what the commands 0x1E & 0x1C do. Nothing exciting though, sadly.




Command 0x1E is used to allocate data from the pool and reset a couple variables:
  • ​Reallocates memory for the geometry layout node system.
  • ​Allocates 0xDAC0 bytes and stores pointer to 0x8038EE98. Not sure what this is, but it is related to collision.
  • ​Allocates memory for collision data. Vanilla SM64 allocates enough space for only 2,300 collision triangles. Newer versions of Skelux's SM64 editor allocate enough space for 32,767 triangles.
  • ​Sets halfword at address 0x8036125C to 0. (0x8036125C seems to be just a flag that is set when Mario enters into area #2 of any level)
  • ​Sets byte at address 0x803613FE to 0. (0x803613FE seems to be a read-only byte that tells you how many red coins Mario has collected so far)
Decompiled C notes of cmd 0x1E: https://pastebin.com/raw/XkCfkFyT

0x1E should come before the last 0x11 command that is above the main level loop (command 0x12)




Command 0x1C is used for level & memory cleanup:
  • ​Frees data in pool allocated from level script
  • ​Cleanups level related stuff (level objects, pointers, etc)
  • ​Cleanups geometry layout data
  • ​Cleanups all 8 area structs
Decompiled C notes of cmd 0x1C: https://pastebin.com/raw/GjDsJYqq

0x1C should come after the main level loop (command 0x12)
(This post was last modified: 03-12-2017, 03:05 AM by David.)

A couple days ago I looked into how the inside castle did its room culling, and I discovered how it worked. Its a fairly simple process that involves the level script command 0x2F, and the geometry layout switch command (0xE).

The levels "Inside Castle", "Big Boo's Haunt", and "Hazy Maze Cave" contain a switch command in their geometry layouts that uses the ASM function 0x8029DBD4.

Spoiler: Geometry Layout for Inside Castle area 1
[0E001400] 08 00 00 0A 00A0 0078 00A0 0078 // Set screen rendering area (center X = 160, center Y = 120, Width = 320, Height = 240)
[0E00140C]​ 04 00 00 00 // Open New Node
[0E001410]​    0C 00 00 00 // Disable Z-Buffer
[0E001414]​    04 00 00 00 // Open New Node
[0E001418]​       09 00 00 64 // Unknown command
[0E00141C]​       04 00 00 00 // Open New Node
[0E001420]​          19 00 0001 00000000 // Draw solid color background. Color = (0,0,0)
[0E001428]​          05 00 00 00 // Close Node
[0E00142C]​       05 00 00 00 // Close Node
[0E001430]​    0C 01 00 00 // Enable Z-Buffer
[0E001434]​    04 00 00 00 // Open New Node
[0E001438]​       0A 01 0040 0032 1B58 8029AA3C // Set camera frustum (FOV = 64, Near = 50, Far = 7000)
[0E001444]​       04 00 00 00 // Open New Node
[0E001448]​          0F 00 000D 0000 07D0 1770 0000 0000 0000 80287D30 // Unknown command
[0E00145C]​          04 00 00 00 // Open New Node
​[0E001460]             0E 00 00 11 8029DBD4 // Switch case with following display lists using ASM function 0x8029DBD4
[0E001468]​             04 00 00 00 // Open New Node
[0E00146C]​                02 01 00 00 0E000F30 // Branch geometry layout to address 0x0E000F30
[0E000F30]​                   0B 00 00 00 // Start geometry layout
[0E000F34]​                   04 00 00 00 // Open New Node
[0E000F38]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E000F40]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E000F48]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E000F50]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E000F58]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E000F60]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E000F68]​                      05 00 00 00 // Close Node
[0E000F6C]​                   03 00 00 00 // Return from branch
[0E001474]​                02 01 00 00 0E000F70 // Branch geometry layout to address 0x0E000F70
[0E000F70]​                   0B 00 00 00 // Start geometry layout
[0E000F74]​                   04 00 00 00 // Open New Node
[0E000F78]​                      15 01 00 00 0702E408 // Load display list 0x0702E408 into layer 1
[0E000F80]​                      05 00 00 00 // Close Node
[0E000F84]​                   03 00 00 00 // Return from branch
[0E00147C]​                02 01 00 00 0E000F88 // Branch geometry layout to address 0x0E000F88
[0E000F88]​                   0B 00 00 00 // Start geometry layout
[0E000F8C]​                   04 00 00 00 // Open New Node
[0E000F90]​                      15 01 00 00 0702FD30 // Load display list 0x0702FD30 into layer 1
[0E000F98]​                      15 01 00 00 07023DB0 // Load display list 0x07023DB0 into layer 1
[0E000FA0]​                      05 00 00 00 // Close Node
[0E000FA4]​                   03 00 00 00 // Return from branch
[0E001484]​                02 01 00 00 0E000FA8 // Branch geometry layout to address 0x0E000FA8
[0E000FA8]​                   0B 00 00 00 // Start geometry layout
[0E000FAC]​                   04 00 00 00 // Open New Node
[0E000FB0]​                      15 01 00 00 07031588 // Load display list 0x07031588 into layer 1
[0E000FB8]​                      15 04 00 00 07031720 // Load display list 0x07031720 into layer 4
[0E000FC0]​                      15 04 00 00 07031830 // Load display list 0x07031830 into layer 4
[0E000FC8]​                      05 00 00 00 // Close Node
[0E000FCC]​                   03 00 00 00 // Return from branch
[0E00148C]​                02 01 00 00 0E000FD0 // Branch geometry layout to address 0x0E000FD0
[0E000FD0]​                   0B 00 00 00 // Start geometry layout
[0E000FD4]​                   04 00 00 00 // Open New Node
[0E000FD8]​                      15 01 00 00 07032FC0 // Load display list 0x07032FC0 into layer 1
[0E000FE0]​                      15 04 00 00 07033158 // Load display list 0x07033158 into layer 4
[0E000FE8]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E000FF0]​                      18 00 0100 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 256)
[0E000FF8]​                      05 00 00 00 // Close Node
[0E000FFC]​                   03 00 00 00 // Return from branch
[0E001494]​                02 01 00 00 0E001000 // Branch geometry layout to address 0x0E001000
[0E001000]​                   0B 00 00 00 // Start geometry layout
[0E001004]​                   04 00 00 00 // Open New Node
[0E001008]​                      15 01 00 00 07034D88 // Load display list 0x07034D88 into layer 1
[0E001010]​                      15 04 00 00 07035178 // Load display list 0x07035178 into layer 4
[0E001018]​                      15 04 00 00 07035288 // Load display list 0x07035288 into layer 4
[0E001020]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E001028]​                      18 00 0102 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 258)
[0E001030]​                      05 00 00 00 // Close Node
[0E001034]​                   03 00 00 00 // Return from branch
[0E00149C]​                02 01 00 00 0E001038 // Branch geometry layout to address 0x0E001038
[0E001038]​                   0B 00 00 00 // Start geometry layout
[0E00103C]​                   04 00 00 00 // Open New Node
[0E001040]​                      15 01 00 00 07036D88 // Load display list 0x07036D88 into layer 1
[0E001048]​                      15 01 00 00 07037988 // Load display list 0x07037988 into layer 1
[0E001050]​                      15 01 00 00 07037BF8 // Load display list 0x07037BF8 into layer 1
[0E001058]​                      15 05 00 00 07037DE8 // Load display list 0x07037DE8 into layer 5
[0E001060]​                      15 05 00 00 07038240 // Load display list 0x07038240 into layer 5
[0E001068]​                      15 04 00 00 07038350 // Load display list 0x07038350 into layer 4
[0E001070]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E001078]​                      18 00 0103 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 259)
[0E001080]​                      05 00 00 00 // Close Node
[0E001084]​                   03 00 00 00 // Return from branch
[0E0014A4]​                02 01 00 00 0E001088 // Branch geometry layout to address 0x0E001088
[0E001088]​                   0B 00 00 00 // Start geometry layout
[0E00108C]​                   04 00 00 00 // Open New Node
[0E001090]​                      15 01 00 00 0703A6C8 // Load display list 0x0703A6C8 into layer 1
[0E001098]​                      15 04 00 00 0703A808 // Load display list 0x0703A808 into layer 4
[0E0010A0]​                      15 01 00 00 070234C0 // Load display list 0x070234C0 into layer 1
[0E0010A8]​                      15 01 00 00 07023520 // Load display list 0x07023520 into layer 1
[0E0010B0]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E0010B8]​                      18 00 0101 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 257)
[0E0010C0]​                      05 00 00 00 // Close Node
[0E0010C4]​                   03 00 00 00 // Return from branch
[0E0014AC]​                02 01 00 00 0E0010C8 // Branch geometry layout to address 0x0E0010C8
[0E0010C8]​                   0B 00 00 00 // Start geometry layout
[0E0010CC]​                   04 00 00 00 // Open New Node
[0E0010D0]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E0010D8]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E0010E0]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E0010E8]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E0010F0]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E0010F8]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001100]​                      15 01 00 00 0703BA08 // Load display list 0x0703BA08 into layer 1
[0E001108]​                      05 00 00 00 // Close Node
[0E00110C]​                   03 00 00 00 // Return from branch
[0E0014B4]​                02 01 00 00 0E001110 // Branch geometry layout to address 0x0E001110
[0E001110]​                   0B 00 00 00 // Start geometry layout
[0E001114]​                   04 00 00 00 // Open New Node
[0E001118]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E001120]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E001128]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E001130]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E001138]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E001140]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001148]​                      15 01 00 00 0702E408 // Load display list 0x0702E408 into layer 1
[0E001150]​                      05 00 00 00 // Close Node
[0E001154]​                   03 00 00 00 // Return from branch
[0E0014BC]​                02 01 00 00 0E001158 // Branch geometry layout to address 0x0E001158
[0E001158]​                   0B 00 00 00 // Start geometry layout
[0E00115C]​                   04 00 00 00 // Open New Node
[0E001160]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E001168]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E001170]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E001178]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E001180]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E001188]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001190]​                      15 01 00 00 0702FD30 // Load display list 0x0702FD30 into layer 1
[0E001198]​                      15 01 00 00 07023DB0 // Load display list 0x07023DB0 into layer 1
[0E0011A0]​                      05 00 00 00 // Close Node
[0E0011A4]​                   03 00 00 00 // Return from branch
[0E0014C4]​                02 01 00 00 0E0011A8 // Branch geometry layout to address 0x0E0011A8
[0E0011A8]​                   0B 00 00 00 // Start geometry layout
[0E0011AC]​                   04 00 00 00 // Open New Node
[0E0011B0]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E0011B8]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E0011C0]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E0011C8]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E0011D0]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E0011D8]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E0011E0]​                      15 01 00 00 07031588 // Load display list 0x07031588 into layer 1
[0E0011E8]​                      15 04 00 00 07031720 // Load display list 0x07031720 into layer 4
[0E0011F0]​                      15 04 00 00 07031830 // Load display list 0x07031830 into layer 4
[0E0011F8]​                      05 00 00 00 // Close Node
[0E0011FC]​                   03 00 00 00 // Return from branch
[0E0014CC]​                02 01 00 00 0E001200 // Branch geometry layout to address 0x0E001200
[0E001200]​                   0B 00 00 00 // Start geometry layout
[0E001204]​                   04 00 00 00 // Open New Node
[0E001208]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E001210]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E001218]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E001220]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E001228]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E001230]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001238]​                      15 01 00 00 07032FC0 // Load display list 0x07032FC0 into layer 1
[0E001240]​                      15 04 00 00 07033158 // Load display list 0x07033158 into layer 4
[0E001248]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E001250]​                      18 00 0100 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 256)
[0E001258]​                      05 00 00 00 // Close Node
[0E00125C]​                   03 00 00 00 // Return from branch
[0E0014D4]​                02 01 00 00 0E001260 // Branch geometry layout to address 0x0E001260
[0E001260]​                   0B 00 00 00 // Start geometry layout
[0E001264]​                   04 00 00 00 // Open New Node
[0E001268]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E001270]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E001278]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E001280]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E001288]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E001290]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001298]​                      15 01 00 00 07034D88 // Load display list 0x07034D88 into layer 1
[0E0012A0]​                      15 04 00 00 07035178 // Load display list 0x07035178 into layer 4
[0E0012A8]​                      15 04 00 00 07035288 // Load display list 0x07035288 into layer 4
[0E0012B0]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E0012B8]​                      18 00 0102 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 258)
[0E0012C0]​                      05 00 00 00 // Close Node
[0E0012C4]​                   03 00 00 00 // Return from branch
[0E0014DC]​                02 01 00 00 0E0012C8 // Branch geometry layout to address 0x0E0012C8
[0E0012C8]​                   0B 00 00 00 // Start geometry layout
[0E0012CC]​                   04 00 00 00 // Open New Node
[0E0012D0]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E0012D8]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E0012E0]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E0012E8]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E0012F0]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E0012F8]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001300]​                      15 01 00 00 07036D88 // Load display list 0x07036D88 into layer 1
[0E001308]​                      15 01 00 00 07037988 // Load display list 0x07037988 into layer 1
[0E001310]​                      15 01 00 00 07037BF8 // Load display list 0x07037BF8 into layer 1
[0E001318]​                      15 05 00 00 07037DE8 // Load display list 0x07037DE8 into layer 5
[0E001320]​                      15 05 00 00 07038240 // Load display list 0x07038240 into layer 5
[0E001328]​                      15 04 00 00 07038350 // Load display list 0x07038350 into layer 4
[0E001330]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E001338]​                      18 00 0103 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 259)
[0E001340]​                      05 00 00 00 // Close Node
[0E001344]​                   03 00 00 00 // Return from branch
[0E0014E4]​                02 01 00 00 0E001348 // Branch geometry layout to address 0x0E001348
[0E001348]​                   0B 00 00 00 // Start geometry layout
[0E00134C]​                   04 00 00 00 // Open New Node
[0E001350]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E001358]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E001360]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E001368]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E001370]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E001378]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E001380]​                      15 01 00 00 0703A6C8 // Load display list 0x0703A6C8 into layer 1
[0E001388]​                      15 04 00 00 0703A808 // Load display list 0x0703A808 into layer 4
[0E001390]​                      15 01 00 00 070234C0 // Load display list 0x070234C0 into layer 1
[0E001398]​                      15 01 00 00 07023520 // Load display list 0x07023520 into layer 1
[0E0013A0]​                      18 00 0000 802D5D0C // Create display list(s) from the ASM function 0x802D5D0C (a0 = 0)
[0E0013A8]​                      18 00 0101 802D5B98 // Create display list(s) from the ASM function 0x802D5B98 (a0 = 257)
[0E0013B0]​                      05 00 00 00 // Close Node
[0E0013B4]​                   03 00 00 00 // Return from branch
[0E0014EC]​                02 01 00 00 0E0013B8 // Branch geometry layout to address 0x0E0013B8
[0E0013B8]​                   0B 00 00 00 // Start geometry layout
[0E0013BC]​                   04 00 00 00 // Open New Node
[0E0013C0]​                      15 01 00 00 07028FD0 // Load display list 0x07028FD0 into layer 1
[0E0013C8]​                      15 04 00 00 07029578 // Load display list 0x07029578 into layer 4
[0E0013D0]​                      15 01 00 00 0702A650 // Load display list 0x0702A650 into layer 1
[0E0013D8]​                      15 06 00 00 0702AA10 // Load display list 0x0702AA10 into layer 6
[0E0013E0]​                      15 04 00 00 0702AB20 // Load display list 0x0702AB20 into layer 4
[0E0013E8]​                      18 00 0000 802D2360 // Create display list(s) from the ASM function 0x802D2360 (a0 = 0)
[0E0013F0]​                      15 01 00 00 0703BA08 // Load display list 0x0703BA08 into layer 1
[0E0013F8]​                      05 00 00 00 // Close Node
[0E0013FC]​                   03 00 00 00 // Return from branch
[0E0014F4]​                05 00 00 00 // Close Node
[0E0014F8]​             17 00 00 00 // Setup display lists for level objects
[0E0014FC]​             18 00 0000 802761D0 // Create display list(s) from the ASM function 0x802761D0 (a0 = 0)
[0E001504]​             05 00 00 00 // Close Node
[0E001508]​          05 00 00 00 // Close Node
[0E00150C]​       05 00 00 00 // Close Node
[0E001510]​    05 00 00 00 // Close Node
[0E001514]​ 01 00 00 00 // End geometry layout
The function 0x8029DBD4 will find the collision triangle below Mario, and use the byte at offset 0x5 in the collision triangle structure to determine which switch case to use.

Code:
​#define MARIO_OBJ_POINTER 0x80361158
typedef char s8;
int proc_8029DBD4(int a0, Node* a1) // function 0x8029DBD4
{
   if(a0 == 1 && *(MARIO_OBJ_POINTER) != NULL) 
   {
       *((short*)0x80361182) = 1;

       collisionTriangle* triangle;
       Object* mario_obj = *(MARIO_OBJ_POINTER);

       // Function that finds triangle underneath XYZ position.
       proc_80381900(mario_obj->x_pos, mario_obj->y_pos, mario_obj->z_pos, &triangle);

       if((*triangle) != NULL)
       {
           *((short*)0x80361250) = (s8)(triangle->_0x5);
           short sp_26 = (s8)(triangle->_0x5) - 1;

           // Some printing function that calls PrintInt. 0x803377B0 = "areainfo %d"
           proc_802CA5B8((char*)0x803377B0, (s8)(triangle->_0x5));

           if(sp_26 >= 0)
           {
               a1->_0x1E = sp_26; // Switch value = sp_26
           }
       } 
       else 
       {
           a1->_0x1E = 0; // Switch value = 0
       }
   }

   return 0;
}

The purpose of the level script command 0x2F is to setup the pointer of an array of byte values that will populate the collision triangles. This pointer will be stored at offset 0x0C in the structure of the current area being processed. The length of this byte array is the same as the number of collision triangles inside the current area. If the level script doesn't have a 0x2F command, then each collision triangle will have zero as their offset 0x5.

Code:
​typedef char s8;
void LevelScript2F()
{
    // 0x8038B8AC = current area index being processed in the level scripts
    if(*((short*)0x8038B8AC) != -1)
    {
        Area* t8 = *((Area**)0x8032DDC8); // 0x8032DDC8 = pointer to start of area struct array.
        int t0 = (*((short*)0x8038B8AC) * 0x3C);
        Area* area_struct = (Area*)(t8 + t0);
        area_struct->_0xC = SegmentedToVirtual(*((int*)(*((int*)0x8038BE28) + 4)));
    }

    *((int*)0x8038BE28) += *((s8*)(*((int*)0x8038BE28) + 1)); // Go to the next level script command
}

The collision triangle's offset 0x05 is populated from a loop in the function 0x80383068, which is eventually called from the level initialize command ([ 11 08 0000 8024BCD8 ]) before the main level loop command starts ([ 12 08 0001 8024BCD8 ]).

Here's a video showing me editing the switch byte in the collision triangle underneath where Mario is standing:

(This post was last modified: 21-01-2018, 07:27 AM by David.)

Level Script Engine Commands & Info « 1 2
Users browsing this thread: 1 Guest(s)