diff --git a/autogen/convert_structs.py b/autogen/convert_structs.py
index b333088f..6a53e222 100644
--- a/autogen/convert_structs.py
+++ b/autogen/convert_structs.py
@@ -84,6 +84,7 @@ override_field_invisible = {
"MarioState": [ "visibleToEnemies" ],
"NetworkPlayer": [ "gag", "moderator"],
"GraphNode": [ "_guard1", "_guard2" ],
+ "Object": [ "firstSurface" ],
}
override_field_deprecated = {
@@ -98,7 +99,7 @@ override_field_immutable = {
"Character": [ "*" ],
"NetworkPlayer": [ "*" ],
"TextureInfo": [ "*" ],
- "Object": ["oSyncID", "coopFlags", "oChainChompSegments", "oWigglerSegments", "oHauntedChairUnk100", "oTTCTreadmillBigSurface", "oTTCTreadmillSmallSurface", "bhvStackIndex", "respawnInfoType" ],
+ "Object": ["oSyncID", "coopFlags", "oChainChompSegments", "oWigglerSegments", "oHauntedChairUnk100", "oTTCTreadmillBigSurface", "oTTCTreadmillSmallSurface", "bhvStackIndex", "respawnInfoType", "numSurfaces" ],
"GlobalObjectAnimations": [ "*"],
"SpawnParticlesInfo": [ "model" ],
"MarioBodyState": [ "updateTorsoTime" ],
diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua
index b6ae3887..c76fa629 100644
--- a/autogen/lua_definitions/functions.lua
+++ b/autogen/lua_definitions/functions.lua
@@ -8908,6 +8908,13 @@ function load_object_collision_model()
-- ...
end
+--- @param o Object
+--- @param index integer
+--- @return Surface
+function obj_get_surface_from_index(o, index)
+ -- ...
+end
+
--- @class Pointer_integer
--- @class Pointer_BehaviorScript
--- @class Pointer_number
diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua
index f39f25ba..39299403 100644
--- a/autogen/lua_definitions/structs.lua
+++ b/autogen/lua_definitions/structs.lua
@@ -1145,6 +1145,7 @@
--- @field public hurtboxHeight number
--- @field public hurtboxRadius number
--- @field public numCollidedObjs integer
+--- @field public numSurfaces integer
--- @field public o1UpForceSpawn integer
--- @field public o1UpHiddenUnkF4 integer
--- @field public oAction integer
diff --git a/docs/lua/functions-5.md b/docs/lua/functions-5.md
index 41330aef..33eecbd0 100644
--- a/docs/lua/functions-5.md
+++ b/docs/lua/functions-5.md
@@ -4734,6 +4734,27 @@
+## [obj_get_surface_from_index](#obj_get_surface_from_index)
+
+### Lua Example
+`local SurfaceValue = obj_get_surface_from_index(o, index)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| o | [Object](structs.md#Object) |
+| index | `integer` |
+
+### Returns
+[Surface](structs.md#Surface)
+
+### C Prototype
+`struct Surface *obj_get_surface_from_index(struct Object *o, u32 index);`
+
+[:arrow_up_small:](#)
+
+
+
---
[< prev](functions-4.md) | [1](functions.md) | [2](functions-2.md) | [3](functions-3.md) | [4](functions-4.md) | 5]
diff --git a/docs/lua/functions.md b/docs/lua/functions.md
index 9b1eb885..80abecba 100644
--- a/docs/lua/functions.md
+++ b/docs/lua/functions.md
@@ -1846,6 +1846,7 @@
- [get_area_terrain_size](functions-5.md#get_area_terrain_size)
- [load_area_terrain](functions-5.md#load_area_terrain)
- [load_object_collision_model](functions-5.md#load_object_collision_model)
+ - [obj_get_surface_from_index](functions-5.md#obj_get_surface_from_index)
diff --git a/docs/lua/structs.md b/docs/lua/structs.md
index bededb1e..39c29bd7 100644
--- a/docs/lua/structs.md
+++ b/docs/lua/structs.md
@@ -1559,6 +1559,7 @@
| hurtboxHeight | `number` | |
| hurtboxRadius | `number` | |
| numCollidedObjs | `integer` | |
+| numSurfaces | `integer` | read-only |
| parentObj | [Object](structs.md#Object) | |
| platform | [Object](structs.md#Object) | |
| prevObj | [Object](structs.md#Object) | |
diff --git a/include/types.h b/include/types.h
index 9c7efcc2..a39ec00b 100644
--- a/include/types.h
+++ b/include/types.h
@@ -251,6 +251,8 @@ struct Object
/*?????*/ u8 setHome;
/*?????*/ u8 allowRemoteInteractions;
/*?????*/ u8 ctx;
+ /*?????*/ u32 firstSurface;
+ /*?????*/ u32 numSurfaces;
};
struct ObjectHitbox
diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c
index 3015b7b7..66b2067d 100644
--- a/src/engine/surface_load.c
+++ b/src/engine/surface_load.c
@@ -595,6 +595,12 @@ void clear_dynamic_surfaces(void) {
gSurfaceNodesAllocated = gNumStaticSurfaceNodes;
clear_spatial_partition(&gDynamicSurfacePartition[0][0]);
+
+ for (u16 i = 0; i < OBJECT_POOL_CAPACITY; i++) {
+ struct Object *obj = &gObjectPool[i];
+ obj->firstSurface = 0;
+ obj->numSurfaces = 0;
+ }
}
}
@@ -674,6 +680,15 @@ void load_object_surfaces(s16** data, s16* vertexData) {
struct Surface* surface = read_surface_data(vertexData, data);
if (surface != NULL) {
+
+ // Set index of first surface
+ if (gCurrentObject->firstSurface == 0) {
+ gCurrentObject->firstSurface = gSurfacesAllocated - 1;
+ }
+
+ // Increase surface count
+ gCurrentObject->numSurfaces++;
+
surface->object = gCurrentObject;
surface->type = surfaceType;
@@ -763,3 +778,10 @@ void load_object_collision_model(void) {
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
}
}
+
+struct Surface *obj_get_surface_from_index(struct Object *o, u32 index) {
+ if (!o || o->firstSurface == 0) { return NULL; }
+ if (index >= o->numSurfaces) { return NULL; }
+ struct Surface *surf = sSurfacePool->buffer[o->firstSurface + index];
+ return surf;
+}
diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h
index 30558132..e948c2e9 100644
--- a/src/engine/surface_load.h
+++ b/src/engine/surface_load.h
@@ -34,5 +34,6 @@ u32 get_area_terrain_size(s16 *data);
void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects);
void clear_dynamic_surfaces(void);
void load_object_collision_model(void);
+struct Surface *obj_get_surface_from_index(struct Object *o, u32 index);
#endif // SURFACE_LOAD_H
diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c
index 497cfab2..23c1fb5f 100644
--- a/src/game/spawn_object.c
+++ b/src/game/spawn_object.c
@@ -233,6 +233,9 @@ void unload_object(struct Object *obj) {
smlua_call_event_hooks_object_param(HOOK_ON_SYNC_OBJECT_UNLOAD, obj);
}
+ obj->firstSurface = 0;
+ obj->numSurfaces = 0;
+
smlua_call_event_hooks_object_param(HOOK_ON_OBJECT_UNLOAD, obj);
deallocate_object(&gFreeObjectList, &obj->header);
@@ -338,6 +341,9 @@ struct Object *allocate_object(struct ObjectNode *objList) {
obj->usingObj = NULL;
+ obj->firstSurface = 0;
+ obj->numSurfaces = 0;
+
return obj;
}
diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c
index 3b9a7d61..ad533bd1 100644
--- a/src/pc/lua/smlua_cobject_autogen.c
+++ b/src/pc/lua/smlua_cobject_autogen.c
@@ -1269,7 +1269,7 @@ static struct LuaObjectField sNetworkPlayerFields[LUA_NETWORK_PLAYER_FIELD_COUNT
{ "type", LVT_U8, offsetof(struct NetworkPlayer, type), true, LOT_NONE },
};
-#define LUA_OBJECT_FIELD_COUNT 758
+#define LUA_OBJECT_FIELD_COUNT 759
static struct LuaObjectField sObjectFields[LUA_OBJECT_FIELD_COUNT] = {
{ "activeFlags", LVT_S16, offsetof(struct Object, activeFlags), false, LOT_NONE },
{ "allowRemoteInteractions", LVT_U8, offsetof(struct Object, allowRemoteInteractions), false, LOT_NONE },
@@ -1297,6 +1297,7 @@ static struct LuaObjectField sObjectFields[LUA_OBJECT_FIELD_COUNT] = {
{ "hurtboxHeight", LVT_F32, offsetof(struct Object, hurtboxHeight), false, LOT_NONE },
{ "hurtboxRadius", LVT_F32, offsetof(struct Object, hurtboxRadius), false, LOT_NONE },
{ "numCollidedObjs", LVT_S16, offsetof(struct Object, numCollidedObjs), false, LOT_NONE },
+ { "numSurfaces", LVT_U32, offsetof(struct Object, numSurfaces), true, LOT_NONE },
{ "o1UpForceSpawn", LVT_S32, offsetof(struct Object, o1UpForceSpawn), false, LOT_NONE },
{ "o1UpHiddenUnkF4", LVT_S32, offsetof(struct Object, o1UpHiddenUnkF4), false, LOT_NONE },
{ "oAction", LVT_S32, offsetof(struct Object, oAction), false, LOT_NONE },
diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c
index 200b8672..961f695c 100644
--- a/src/pc/lua/smlua_functions_autogen.c
+++ b/src/pc/lua/smlua_functions_autogen.c
@@ -32470,6 +32470,25 @@ int smlua_func_load_object_collision_model(UNUSED lua_State* L) {
return 1;
}
+int smlua_func_obj_get_surface_from_index(lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 2) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "obj_get_surface_from_index", 2, top);
+ return 0;
+ }
+
+ struct Object* o = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "obj_get_surface_from_index"); return 0; }
+ u32 index = smlua_to_integer(L, 2);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "obj_get_surface_from_index"); return 0; }
+
+ smlua_push_object(L, LOT_SURFACE, obj_get_surface_from_index(o, index));
+
+ return 1;
+}
+
void smlua_bind_functions_autogen(void) {
@@ -34235,5 +34254,6 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "get_area_terrain_size", smlua_func_get_area_terrain_size);
smlua_bind_function(L, "load_area_terrain", smlua_func_load_area_terrain);
smlua_bind_function(L, "load_object_collision_model", smlua_func_load_object_collision_model);
+ smlua_bind_function(L, "obj_get_surface_from_index", smlua_func_obj_get_surface_from_index);
}