Kuribo64 Wiki
Home | ForumsLogin

WIKI BACKUP

Back to listing

Objects

Contents
1. Base Object Class
    1.1. 80237320 - object_ctor
    1.2. 806952D8 - object_vtable
    1.3. 8000C340 - object_init
2. SMG Objects
    2.1. SMG Object Constructors
    2.2. SMG Object Vtables
    2.3. SMG Object Init Functions
3. Reading Object Properties
4. Loading Objects From BCSV Files
5. Object Creation Functions
6. Importing SMG1 Object Classes to SMG2

Objects are level objects that contain code. Enemies and items are both examples of objects.

1. Base Object Class


All objects are represented in the game's code as C++ classes, which all inherit from the base object class.

1.1. 80237320 - object_ctor


The first function in the base object class is the constructor.

80237320 object_ctor: # CODE XREF: .text1:8008A664p
80237320 # sub_8008D920+30p ...
80237320
80237320 .set var_8, -8
80237320 .set var_4, -4
80237320 .set arg_4, 4
80237320
80237320 stwu r1, -0x10(r1)
80237324 mflr r0
80237328 stw r0, 0x10+arg_4(r1)
8023732C stw r31, 0x10+var_4(r1)
80237330 stw r30, 0x10+var_8(r1)
80237334 mr r30, r3
80237338 bl sub_80339610
8023733C lfs f2, -0x281C(r2)
80237340 lis r3, object_vtable@h
80237344 li r31, 0
80237348 lfs f1, -0x2820(r2)
8023734C lfs f0, -0x2818(r2)
80237350 addi r3, r3, object_vtable@l
80237354 stw r3, 0(r30)
80237358 addi r3, r30, 0x70
8023735C stfs f2, 0x14(r30)
80237360 stfs f2, 0x18(r30)
80237364 stfs f2, 0x1C(r30)
80237368 stfs f2, 0x20(r30)
8023736C stfs f2, 0x24(r30)
80237370 stfs f2, 0x28(r30)
80237374 stfs f1, 0x2C(r30)
80237378 stfs f1, 0x30(r30)
8023737C stfs f1, 0x34(r30)
80237380 stfs f2, 0x38(r30)
80237384 stfs f2, 0x3C(r30)
80237388 stfs f2, 0x40(r30)
8023738C stfs f2, 0x44(r30)
80237390 stfs f0, 0x48(r30)
80237394 stfs f2, 0x4C(r30)
80237398 stw r31, 0x50(r30)
8023739C stw r31, 0x54(r30)
802373A0 stw r31, 0x58(r30)
802373A4 stw r31, 0x5C(r30)
802373A8 stw r31, 0x60(r30)
802373AC stw r31, 0x64(r30)
802373B0 stw r31, 0x68(r30)
802373B4 stw r31, 0x6C(r30)
802373B8 bl sub_80238220
802373BC stw r31, 0x7C(r30)
802373C0 stw r31, 0x80(r30)
802373C4 stw r31, 0x84(r30)
802373C8 stw r31, 0x88(r30)
802373CC stw r31, 0x8C(r30)
802373D0 bl sub_8022D950
802373D4 mr r4, r30
802373D8 bl sub_80238290
802373DC bl sub_802307B0
802373E0 mr r4, r30
802373E4 bl sub_80230700
802373E8 mr r3, r30
802373EC lwz r31, 0x10+var_4(r1)
802373F0 lwz r30, 0x10+var_8(r1)
802373F4 lwz r0, 0x10+arg_4(r1)
802373F8 mtlr r0
802373FC addi r1, r1, 0x10
80237400 blr
80237400 # End of function object_ctor
80237400
80237400 # ---------------------------------------------------------------------------

This function is the constructor of the object class. It loads the address of the object vtable into *(this + 0) in memory. After this, it initializes many of the class variables.

1.2. 806952D8 - object_vtable


The object vtable contains a pointer to every function in the object class.

806952D8 object_vtable: .long 0 # DATA XREF: object_ctor+20o
806952D8 # object_ctor+30o
806952DC .long 0
806952E0 .long sub_8004DCF0
806952E4 .long locret_80237410
806952E8 .long nullsub_28
806952EC .long sub_80237610
806952F0 .long nullsub_37
806952F4 .long sub_80237730
806952F8 .long sub_80237800
806952FC .long locret_800269F0
80695300 .long locret_800269E0
80695304 .long sub_80237420
80695308 .long sub_80237430
8069530C .long sub_80237500
80695310 .long sub_80237570
80695314 .long sub_80237830
80695318 .long sub_80237A00
8069531C .long sub_80237970
80695320 .long sub_80237A50
80695324 .long sub_80237AD0
80695328 .long locret_800738D0
8069532C .long sub_802378C0
80695330 .long locret_8004E990
80695334 .long locret_80238190
80695338 .long sub_8004E980
8069533C .long sub_800738C0
80695340 .long sub_8004E970
80695344 .long sub_800738B0

Many of these functions get replaced by functions in the classes that inherit from the object class. This is most likely why many of the functions in here are nullsubs and locrets, because Nintendo didn't bother coding functions that would end up getting replaced.

1.3. 8000C340 - object_init


object_init initializes the object class. It is responsible for loading the .arc from /ObjectData, reading InitActor.bcsv, and loading its model into memory. The function is very large, but the most important parts are below.

object_init is actually called by a stub function called call_object_init. This function does not appear to be used in SMG1, instead, object_init is called directly.

8000C1E0 call_object_init: # CODE XREF: sub_8008A730+2Cp
8000C1E0 # sub_8008F3F0+20p ...
8000C1E0 mr r8, r6
8000C1E4 li r6, 0
8000C1E8 li r7, 0
8000C1EC b object_init
8000C1EC # End of function call_object_init

8000CB5C addi r3, r1, 0x350+var_150
8000CB60 bl object_arc_load

This part of the function stores the name of the .arc from /ObjectData into r3 and calls object_arc_load.

2. SMG Objects


All of the objects in SMG inherit from the object class.

2.1. SMG Object Constructors


Just like the object class, the first function in the class is a constructor. For example, this is the constructor of the Goomba class.

801B8990 goomba_ctor: # CODE XREF: .text1:801A2CA0p
801B8990 # .text1:801E4B48p
801B8990
801B8990 .set var_8, -8
801B8990 .set var_4, -4
801B8990 .set arg_4, 4
801B8990
801B8990 stwu r1, -0x10(r1)
801B8994 mflr r0
801B8998 stw r0, 0x10+arg_4(r1)
801B899C stw r31, 0x10+var_4(r1)
801B89A0 stw r30, 0x10+var_8(r1)
801B89A4 mr r30, r3
801B89A8 bl object_ctor
801B89AC lfs f1, -0x3E9C(r2)
801B89B0 lis r3, ((goomba_vtable+0x10000)@h)
801B89B4 li r31, 0
801B89B8 lfs f0, -0x3EA0(r2)
801B89BC addi r3, r3, -0x4838 # goomba_vtable
801B89C0 stw r3, 0(r30)
801B89C4 addi r3, r30, 0xBC
801B89C8 li r4, 0
801B89CC stw r31, 0x90(r30)
801B89D0 li r5, 0
801B89D4 li r6, 1
801B89D8 stw r31, 0x94(r30)
801B89DC stw r31, 0x98(r30)
801B89E0 stw r31, 0x9C(r30)
801B89E4 stw r31, 0xA0(r30)
801B89E8 stw r31, 0xA4(r30)
801B89EC stw r31, 0xA8(r30)
801B89F0 stfs f1, 0xAC(r30)
801B89F4 stfs f1, 0xB0(r30)
801B89F8 stfs f1, 0xB4(r30)
801B89FC stfs f0, 0xB8(r30)
801B8A00 bl sub_80013990
801B8A04 li r3, -1
801B8A08 li r0, 1
801B8A0C stw r3, 0xC8(r30)
801B8A10 mr r3, r30
801B8A14 stb r31, 0xCC(r30)
801B8A18 stb r0, 0xCD(r30)
801B8A1C stb r31, 0xCE(r30)
801B8A20 lwz r31, 0x10+var_4(r1)
801B8A24 lwz r30, 0x10+var_8(r1)
801B8A28 lwz r0, 0x10+arg_4(r1)
801B8A2C mtlr r0
801B8A30 addi r1, r1, 0x10
801B8A34 blr
801B8A34 # End of function goomba_ctor
801B8A34
801B8A34 # ---------------------------------------------------------------------------

The constructor first calls object_ctor to initialize the base class. After this, it replaces the pointer to the object vtable with a pointer to the Goomba vtable. Then it initializes several of the class variables. All object class constructors follow this structure.

2.2. SMG Object Vtables


Like every the object class, the object classes in SMG contain vtables. The vtables contain pointers to each object in the individual class. For example, this is the Goomba vtable.

8068B7C8 goomba_vtable: .long 0 # DATA XREF: goomba_ctor+20o
8068B7CC .long 0
8068B7D0 .long sub_801BB030
8068B7D4 .long goomba_init
8068B7D8 .long sub_801B8BF0
8068B7DC .long sub_80237610
8068B7E0 .long nullsub_37
8068B7E4 .long sub_80237730
8068B7E8 .long sub_80237800
8068B7EC .long locret_800269F0
8068B7F0 .long locret_800269E0
8068B7F4 .long sub_80237420
8068B7F8 .long sub_801B8E30
8068B7FC .long sub_801B8E80
8068B800 .long sub_801B8E70
8068B804 .long sub_80237830
8068B808 .long sub_80237A00
8068B80C .long sub_80237970
8068B810 .long sub_80237A50
8068B814 .long sub_80237AD0
8068B818 .long sub_801B8F10
8068B81C .long sub_801B9040
8068B820 .long locret_8004E990
8068B824 .long sub_801B9080
8068B828 .long sub_801B93F0
8068B82C .long sub_801B91A0
8068B830 .long sub_801B9320
8068B834 .long sub_801B94D0

These functions are specific to the Goomba class. Each object class has their own vtable, but they all follow the same format. In all object vtables, just like this one, the second function in it is the initialization function. The other functions are usually called this way.

80237420 sub_80237420: # CODE XREF: sub_8008DC40+14p
80237420 # .text1:8008ECE4p ...
80237420 lwz r12, 0(r3) # Load the vtable pointer into r12
80237424 lwz r12, 0x30(r12) # Load the address of sub_80237430 into r12
80237428 mtctr r12
8023742C bctr # Branch to sub_80237430
8023742C # End of function sub_80237420

In this code, the vtable pointer is loaded into r3. Then the value at *(vtable + 0x30) is loaded into r12. In this case, the value is the address of sub_80237430. The code branches to this address. Code that looks like this appears many times throughout the object classes. The way that this function works means that this function can be easily replaced by subclasses without having to worry about which version of the function it's calling.

2.3. SMG Object Init Functions


Objects in SMG levels also contain init functions. These functions are responsible for loading the .arc from /ObjectData, reading InitActor.bcsv, and loading its model into memory, just like object_init, but they also do specific tasks for each object, such as reading the Obj_args. In fact, every init function calls object_init to perform the tasks required for every object. For example, this is the first part of the Goomba init function.

goomba_init: # DATA XREF: .data5:8068B7D4o
801B8A40
801B8A40 .set var_28, -0x28
801B8A40 .set var_1C, -0x1C
801B8A40 .set var_8, -8
801B8A40 .set var_4, -4
801B8A40 .set arg_4, 4
801B8A40
801B8A40 stwu r1, -0x30(r1)
801B8A44 mflr r0
801B8A48 lis r5, ((aKuribo+0x10000)@h) # "Kuribo"
801B8A4C li r6, 0
801B8A50 stw r0, 0x30+arg_4(r1)
801B8A54 addi r5, r5, -0x4930 # aKuribo
801B8A58 stw r31, 0x30+var_4(r1)
801B8A5C mr r31, r4
801B8A60 stw r30, 0x30+var_8(r1)
801B8A64 mr r30, r3
801B8A68 bl call_object_init

Goombas don't have any Obj_args, but many objects do read the Obj_args. One of the objects that does this is the power-up object.

802D22C0 bl read_obj_arg0
802D22C4 stw r28, 0x90+var_70(r1)
802D22C8 mr r3, r30
802D22CC addi r4, r1, 0x90+var_70
802D22D0 bl read_obj_arg1
802D22D4 stw r28, 0x90+var_74(r1)
802D22D8 mr r3, r30
802D22DC addi r4, r1, 0x90+var_74
802D22E0 bl read_obj_arg2
802D22E4 stw r28, 0x90+var_78(r1)
802D22E8 mr r3, r30
802D22EC addi r4, r1, 0x90+var_78
802D22F0 bl read_obj_arg3
802D22F4 stw r28, 0x90+var_7C(r1)
802D22F8 mr r3, r30
802D22FC addi r4, r1, 0x90+var_7C
802D2300 bl read_obj_arg4
802D2304 stw r28, 0x90+var_80(r1)
802D2308 mr r3, r30
802D230C addi r4, r1, 0x90+var_80
802D2310 bl read_obj_arg5
802D2314 stw r28, 0x90+var_84(r1)
802D2318 mr r3, r30
802D231C addi r4, r1, 0x90+var_84
802D2320 bl read_obj_arg6
802D2324 stw r28, 0x90+var_88(r1)
802D2328 mr r3, r30
802D232C addi r4, r1, 0x90+var_88
802D2330 bl read_obj_arg7

This code reads Obj_args 0-7 and stores them on the stack (which is r1). The functions that read Obj_args are BCSV functions, and are detailed below.

3. Reading Object Properties


SMG2 has many functions that read object properties, such as Obj_args, from level BCSV entries. This is a table of all those known functions:

Address Function Prototype Description
8002C020 unsigned int Read_ShapeModelNo(); Read the ShapeModelNo field from a level BCSV entry
8002C040 unsigned int Read_AreaShapeNo(); Read the AreaShapeNo field from a level BCSV entry

4. Loading Objects From BCSV Files


Objects are created from BCSV files using their name to search a table of creation functions. These names do not often match the internal id of the actual resulting object. Currently there are 3 known tables used for creating objects:

Object Type Number of Entries Table Start Address
Planet Objects 78 80648C88
Functional Objects 47 80648EF8
Normal Objects 997 80649970

Each entry in a table is 8 bytes consisting of a name pointer and a creation function pointer. Functional objects are objects which contain certain generic behaviors such as movement or breakability. A structure stored at 8114d5b0 contains a relationship table that determines the names of objects that derive from these functional base objects.

In addition to the creation functions, there are also preload functions which are responsible for loading essential elements of certain objects. Only one preload table is currently known.

Object Type Number of Entries Table Start Address
Power-up Objects 27 8064B7F8

5. Object Creation Functions


The BCSV object tables contain pointers to object creation functions. An object creation function allocates memory for an object and then calls its constructor. Here is the object creation function for a Goomba:

.text1:8033D4B0 create_goomba: # DATA XREF: .data4:80649FFCo
.text1:8033D4B0
.text1:8033D4B0
.text1:8033D4B0 stwu r1, -0x10(r1)
.text1:8033D4B4 mfspr r0, LR
.text1:8033D4B8 stw r0, 0x14(r1)
.text1:8033D4BC stw r31, 0xC(r1)
.text1:8033D4C0 mr r31, r3
.text1:8033D4C4 li r3, 0xD0
.text1:8033D4C8 bl AllocFromHeapEx_Align4_0
.text1:8033D4CC cmpwi r3, 0
.text1:8033D4D0 beq destroy_stack_frame_8033D4DC
.text1:8033D4D4 mr r4, r31
.text1:8033D4D8 bl goomba_ctor
.text1:8033D4DC
.text1:8033D4DC destroy_stack_frame_8033D4DC: # CODE XREF: create_goomba+20j
.text1:8033D4DC lwz r0, 0x14(r1)
.text1:8033D4E0 lwz r31, 0xC(r1)
.text1:8033D4E4 mtspr LR, r0
.text1:8033D4E8 addi r1, r1, 0x10
.text1:8033D4EC blr
.text1:8033D4EC # End of function create_goomba

This particular create function creates a stack frame, allocates 0xD0 (208) bytes for the object (Goomba), and then jumps to the constructor.

6. Importing SMG1 Object Classes to SMG2


Because the object classes in SMG1 and SMG2 are both similar, it is theoretically possible to import SMG1 classes into SMG2. However, one problem is that the addresses in SMG1 are different from the ones in SMG2. To solve this problem, this is a table of all the object class functions and the addresses in both SMG1 and SMG2.

This is documented at Corresponding Object Functions.

Page rendered in 0.013 seconds. (2048KB of memory used)
MySQL - queries: 17, rows: 66/66, time: 0.010 seconds.