diff --git a/.idea/editor.xml b/.idea/editor.xml
index 3361f21..e9b29f0 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -279,6 +279,7 @@
+
@@ -330,7 +331,6 @@
-
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 8287001..35eb1dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,5 @@
-
\ No newline at end of file
diff --git a/src/FakeObject.c b/src/FakeObject.c
new file mode 100644
index 0000000..e23b023
--- /dev/null
+++ b/src/FakeObject.c
@@ -0,0 +1,169 @@
+//
+// Created by nepushiro on 5/29/26.
+//
+
+#include "FakeObject.h"
+
+#include
+
+#include "decomp/global_state.h"
+#include "decomp/engine/math_util.h"
+#include "decomp/game/interaction.h"
+#include "decomp/game/object_stuff.h"
+#include "decomp/include/object_fields.h"
+#include "libsm64.h"
+#include
+
+void fake_object_init(struct FakeObject *fake, float x, float y, float z)
+{
+ memset(fake, 0, sizeof(*fake));
+
+ struct Object *obj = &fake->object;
+ obj->activeFlags = ACTIVE_FLAG_ACTIVE | ACTIVE_FLAG_UNK8;
+ obj->parentObj = NULL;
+ obj->prevObj = NULL;
+ obj->collidedObjInteractTypes = 0;
+ obj->numCollidedObjs = 0;
+
+ for (s32 i = 0; i < 0x50; i++)
+ {
+ #ifdef _WIN32
+ obj->rawData.asS32[i] = 0;
+ #endif
+ #ifdef _WIN64
+ obj->ptrData.asVoidPtr[i] = NULL;
+ #endif
+ }
+
+ obj->unused1 = 0;
+ obj->bhvStackIndex = 0;
+ obj->bhvDelayTimer = 0;
+
+ obj->hitboxRadius = 50.0f;
+ obj->hitboxHeight = 100.0f;
+ obj->hurtboxRadius = 0.0f;
+ obj->hurtboxHeight = 0.0f;
+ obj->hitboxDownOffset = 0.0f;
+ obj->unused2 = 0;
+
+ obj->platform = NULL;
+ obj->collisionData = NULL;
+ obj->oIntangibleTimer = -1;
+ obj->oDamageOrCoinValue = 0;
+ obj->oHealth = 2048;
+
+ obj->oCollisionDistance = 1000.0f;
+ obj->oDrawingDistance = 4000.0f;
+
+ mtxf_identity(obj->transform);
+
+ obj->respawnInfoType = RESPAWN_INFO_TYPE_NULL;
+ obj->respawnInfo = NULL;
+
+ obj->oDistanceToMario = 19000.0f;
+ obj->oRoom = -1;
+ obj->oInteractType = 0;
+ obj->oInteractionSubtype = 0;
+ obj->oHeldState = 0;
+ obj->oAction = 0;
+
+ obj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
+ obj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
+ obj->header.gfx.node.flags &= ~GRAPH_RENDER_BILLBOARD;
+ obj->header.gfx.pos[0] = x;
+ obj->header.gfx.pos[1] = y;
+ obj->header.gfx.pos[2] = z;
+ obj->header.gfx.angle[0] = 0;
+ obj->header.gfx.angle[1] = 0;
+ obj->header.gfx.angle[2] = 0;
+ obj->header.gfx.throwMatrix = NULL;
+ obj->header.gfx.sharedChild = NULL;
+ obj->header.gfx.animInfo.curAnim = NULL;
+ obj->header.gfx.animInfo.animID = 0;
+ obj->header.gfx.animInfo.animFrame = 0;
+ obj->header.gfx.animInfo.animTimer = 0;
+
+ obj->oPosX = x;
+ obj->oPosY = y;
+ obj->oPosZ = z;
+ obj->oMoveAnglePitch = 0;
+ obj->oMoveAngleYaw = 0;
+ obj->oMoveAngleRoll = 0;
+ obj->oFaceAnglePitch = 0;
+ obj->oFaceAngleYaw = 0;
+ obj->oFaceAngleRoll = 0;
+}
+
+void fake_object_sync_position(struct FakeObject *fake)
+{
+ struct Object *obj = &fake->object;
+ obj->header.gfx.pos[0] = obj->oPosX;
+ obj->header.gfx.pos[1] = obj->oPosY;
+ obj->header.gfx.pos[2] = obj->oPosZ;
+}
+
+bool fake_object_overlaps_mario(struct FakeObject *fake, struct MarioState *m)
+{
+ struct Object *obj = &fake->object;
+ float dx = obj->oPosX - m->pos[0];
+ float dz = obj->oPosZ - m->pos[2];
+ float radius = obj->hitboxRadius;
+ float top = obj->oPosY + obj->hitboxHeight;
+ float bottom = obj->oPosY - obj->hitboxDownOffset;
+
+ if ((dx * dx) + (dz * dz) > radius * radius)
+ {
+ return false;
+ }
+
+ if (m->pos[1] < bottom || m->pos[1] > top)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void fake_object_add_collision(struct FakeObject *fake, struct MarioState *m)
+{
+ struct Object *obj = &fake->object;
+
+ if (obj->oHeldState != 0)
+ {
+ return;
+ }
+
+ m->marioObj->collidedObjInteractTypes |= obj->oInteractType;
+ if (m->marioObj->numCollidedObjs < 4)
+ {
+ m->marioObj->collidedObjs[m->marioObj->numCollidedObjs++] = obj;
+ }
+}
+
+void fake_object_apply_pole(struct FakeObject *fake)
+{
+ (void)fake;
+}
+
+void fake_object_set_preset(struct FakeObject *fake, uint32_t preset)
+{
+ struct Object *obj = &fake->object;
+
+ switch (preset)
+ {
+ case 1:
+ obj->oInteractType = INTERACT_POLE;
+ obj->oInteractionSubtype = 0;
+ obj->hitboxRadius = 60.0f;
+ obj->hitboxHeight = 1000.0f;
+ obj->hitboxDownOffset = 0.0f;
+ break;
+ case 0: default:
+ obj->oInteractType = 0;
+ obj->oInteractionSubtype = 0;
+ obj->hitboxRadius = 50.0f;
+ obj->hitboxHeight = 100.0f;
+ obj->hitboxDownOffset = 0.0f;
+ break;
+ }
+}
diff --git a/src/FakeObject.h b/src/FakeObject.h
new file mode 100644
index 0000000..94adabf
--- /dev/null
+++ b/src/FakeObject.h
@@ -0,0 +1,24 @@
+//
+// Created by nepushiro on 5/29/26.
+//
+
+#ifndef LIBSM64_FAKEOBJECT_H
+#define LIBSM64_FAKEOBJECT_H
+
+#endif //LIBSM64_FAKEOBJECT_H
+
+#include
+#include
+
+struct FakeObject
+{
+ struct Object object;
+};
+
+void fake_object_init(struct FakeObject *fake, float x, float y, float z);
+void fake_object_sync_position(struct FakeObject *fake);
+
+bool fake_object_overlaps_mario(struct FakeObject *fake, struct MarioState *m);
+void fake_object_add_collision(struct FakeObject *fake, struct MarioState *m);
+void fake_object_apply_pole(struct FakeObject *fake);
+void fake_object_set_preset(struct FakeObject *fake, uint32_t preset);
\ No newline at end of file
diff --git a/src/decomp/game/interaction.c b/src/decomp/game/interaction.c
index 4f28b0f..85d792e 100644
--- a/src/decomp/game/interaction.c
+++ b/src/decomp/game/interaction.c
@@ -71,6 +71,62 @@ static u32 interact_noop(struct MarioState *m, u32 interactType, struct Object *
return FALSE;
}
+void push_mario_out_of_object(struct MarioState *m, struct Object *o, f32 padding);
+void reset_mario_pitch(struct MarioState *m);
+
+static u32 interact_pole(struct MarioState *m, u32 interactType, struct Object *o)
+{
+ s32 actionId = m->action & ACT_ID_MASK;
+
+ if (actionId >= 0x080 && actionId < 0x0A0)
+ {
+#if defined(VERSION_SH) || defined(VERSION_CN)
+ f32 velConv = m->forwardVel; // conserve the velocity.
+ struct Object *marioObj = m->marioObj;
+ u32 lowSpeed;
+#else
+ u32 lowSpeed = (m->forwardVel <= 10.0f);
+ struct Object *marioObj = m->marioObj;
+#endif
+
+ if (!(m->prevAction & ACT_FLAG_ON_POLE) || m->usedObj != o)
+ {
+#if defined(VERSION_SH) || defined(VERSION_CN)
+ lowSpeed = (velConv <= 10.0f);
+#endif
+
+ mario_stop_riding_and_holding(m);
+
+ m->interactObj = o;
+ m->usedObj = o;
+ m->vel[1] = 0.0f;
+ m->forwardVel = 0.0f;
+
+ marioObj->oMarioPoleUnk108 = 0;
+ marioObj->oMarioPoleYawVel = 0;
+ marioObj->oMarioPolePos = m->pos[1] - o->oPosY;
+
+ if (lowSpeed)
+ {
+ return set_mario_action(m, ACT_GRAB_POLE_SLOW, 0);
+ }
+
+#if defined(VERSION_SH) || defined(VERSION_CN)
+ marioObj->oMarioPoleYawVel = (s32)(velConv * 0x100 + 0x1000);
+#else
+ marioObj->oMarioPoleYawVel = (s32)(m->forwardVel * 0x100 + 0x1000);
+#endif
+ reset_mario_pitch(m);
+#if ENABLE_RUMBLE
+ queue_rumble_data(5, 80);
+#endif
+ return set_mario_action(m, ACT_GRAB_POLE_FAST, 0);
+ }
+ }
+
+ return FALSE;
+}
+
static struct InteractionHandler sInteractionHandlers[] = {
{INTERACT_COIN, interact_noop},
{INTERACT_WATER_RING, interact_noop},
@@ -94,7 +150,7 @@ static struct InteractionHandler sInteractionHandlers[] = {
{INTERACT_HIT_FROM_BELOW, interact_noop},
{INTERACT_BOUNCE_TOP, interact_noop},
{INTERACT_DAMAGE, interact_noop},
- {INTERACT_POLE, interact_noop},
+ {INTERACT_POLE, interact_pole},
{INTERACT_HOOT, interact_noop},
{INTERACT_BREAKABLE, interact_noop},
{INTERACT_KOOPA, interact_noop},
diff --git a/src/decomp/game/mario_actions_automatic.c b/src/decomp/game/mario_actions_automatic.c
index 5823730..93effd8 100644
--- a/src/decomp/game/mario_actions_automatic.c
+++ b/src/decomp/game/mario_actions_automatic.c
@@ -123,8 +123,7 @@ s32 set_pole_position(struct MarioState *m, f32 offsetY)
}
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
- vec3s_set(m->marioObj->header.gfx.angle, m->usedObj->oMoveAnglePitch, m->faceAngle[1],
- m->usedObj->oMoveAngleRoll);
+ vec3s_set(m->marioObj->header.gfx.angle, m->usedObj->oMoveAnglePitch, m->faceAngle[1], m->usedObj->oMoveAngleRoll);
return result;
}
@@ -132,6 +131,7 @@ s32 set_pole_position(struct MarioState *m, f32 offsetY)
s32 act_holding_pole(struct MarioState *m)
{
struct Object *marioObj = m->marioObj;
+ f32 poleStickY = -m->controller->stickY;
#ifdef VERSION_JP
if (m->input & INPUT_A_PRESSED)
@@ -163,7 +163,7 @@ s32 act_holding_pole(struct MarioState *m)
}
#endif
- if (m->controller->stickY > 16.0f)
+ if (poleStickY > 16.0f)
{
f32 poleTop = m->usedObj->hitboxHeight - 100.0f;
// const BehaviorScript *poleBehavior = virtual_to_segmented(0x13, m->usedObj->behavior);
@@ -174,15 +174,15 @@ s32 act_holding_pole(struct MarioState *m)
}
// if (poleBehavior != bhvGiantPole && m->controller->stickY > 50.0f) {
- if (m->controller->stickY > 50.0f)
+ if (poleStickY > 50.0f)
{
return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 0);
}
}
- if (m->controller->stickY < -16.0f)
+ if (poleStickY < -16.0f)
{
- marioObj->oMarioPoleYawVel -= m->controller->stickY * 2;
+ marioObj->oMarioPoleYawVel -= poleStickY * 2;
if (marioObj->oMarioPoleYawVel > 0x1000)
{
marioObj->oMarioPoleYawVel = 0x1000;
@@ -223,6 +223,7 @@ s32 act_climbing_pole(struct MarioState *m)
s32 sp24;
struct Object *marioObj = m->marioObj;
s16 cameraAngle = m->area->camera->yaw;
+ f32 poleStickY = -m->controller->stickY;
#ifndef VERSION_JP
if (m->health < 0x100)
@@ -240,18 +241,18 @@ s32 act_climbing_pole(struct MarioState *m)
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
}
- if (m->controller->stickY < 8.0f)
+ if (poleStickY < 8.0f)
{
return set_mario_action(m, ACT_HOLDING_POLE, 0);
}
- marioObj->oMarioPolePos += m->controller->stickY / 8.0f;
+ marioObj->oMarioPolePos += poleStickY / 8.0f;
marioObj->oMarioPoleYawVel = 0;
m->faceAngle[1] = cameraAngle - approach_s32((s16)(cameraAngle - m->faceAngle[1]), 0, 0x400, 0x400);
if (set_pole_position(m, 0.0f) == POLE_NONE)
{
- sp24 = m->controller->stickY / 4.0f * 0x10000;
+ sp24 = poleStickY / 4.0f * 0x10000;
set_mario_anim_with_accel(m, MARIO_ANIM_CLIMB_UP_POLE, sp24);
add_tree_leaf_particles(m);
play_climbing_sounds(m, 1);
@@ -336,12 +337,13 @@ s32 act_top_of_pole(struct MarioState *m)
{
UNUSED
struct Object *marioObj = m->marioObj;
+ f32 poleStickY = -m->controller->stickY;
if (m->input & INPUT_A_PRESSED)
{
return set_mario_action(m, ACT_TOP_OF_POLE_JUMP, 0);
}
- if (m->controller->stickY < -16.0f)
+ if (poleStickY < -16.0f)
{
return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 1);
}
diff --git a/src/decomp/global_state.c b/src/decomp/global_state.c
index 20fdeee..63e44dd 100644
--- a/src/decomp/global_state.c
+++ b/src/decomp/global_state.c
@@ -3,6 +3,8 @@
#include
#include
+#include "../obj_pool.h"
+
struct GlobalState *g_state = 0;
struct GlobalState *global_state_create(void)
@@ -21,5 +23,6 @@ void global_state_bind(struct GlobalState *state)
void global_state_delete(struct GlobalState *state)
{
+ obj_pool_free_all(&state->mgFakeObjects);
free(state);
}
\ No newline at end of file
diff --git a/src/decomp/global_state.h b/src/decomp/global_state.h
index 2ae3667..3a97f87 100644
--- a/src/decomp/global_state.h
+++ b/src/decomp/global_state.h
@@ -2,6 +2,7 @@
#include "include/types.h"
#include "game/area.h"
+#include "../obj_pool.h"
struct GlobalState
{
@@ -41,6 +42,7 @@ struct GlobalState
struct Area *mgCurrentArea;
struct Object *mgCurrentObject;
struct Object *mgMarioObject;
+ struct ObjPool mgFakeObjects;
struct MarioAnimation mD_80339D10;
struct MarioState mgMarioStateVal;
};
@@ -54,4 +56,4 @@ extern struct GlobalState *global_state_create(void);
extern void global_state_bind(struct GlobalState *state);
-extern void global_state_delete(struct GlobalState *state);
\ No newline at end of file
+extern void global_state_delete(struct GlobalState *state);
diff --git a/src/libsm64.c b/src/libsm64.c
index 538e5fd..920de43 100644
--- a/src/libsm64.c
+++ b/src/libsm64.c
@@ -38,6 +38,8 @@
#include "load_tex_data.h"
#include "obj_pool.h"
#include "fake_interaction.h"
+#include "object_fields.h"
+#include "FakeObject.h"
static struct AllocOnlyPool *s_mario_geo_pool = NULL;
static struct GraphNode *s_mario_graph_node = NULL;
@@ -51,6 +53,7 @@ struct MarioInstance
};
struct ObjPool s_mario_instance_pool = {0, 0};
+struct ObjPool s_fakeobj_instance_pool = {0, 0};
static void update_button(bool on, u16 button)
{
@@ -109,8 +112,7 @@ SM64_LIB_FN void sm64_register_play_sound_function(SM64PlaySoundFunctionPtr play
SM64_LIB_FN void sm64_global_init(const uint8_t *rom, uint8_t *outTexture)
{
- if (s_init_global)
- sm64_global_terminate();
+ if (s_init_global) sm64_global_terminate();
s_init_global = true;
@@ -128,9 +130,8 @@ SM64_LIB_FN void sm64_global_terminate(void)
if (s_init_one_mario)
{
- for (int i = 0; i < s_mario_instance_pool.size; ++i)
- if (s_mario_instance_pool.objects[i] != NULL)
- sm64_mario_delete(i);
+ for (int i = 0; i < s_mario_instance_pool.size; ++i) if (s_mario_instance_pool.objects[i] != NULL) sm64_mario_delete(i);
+ for (int i = 0; i < s_fakeobj_instance_pool.size; ++i) if (s_fakeobj_instance_pool.objects[i] != NULL) sm64_fake_object_delete(i);
obj_pool_free_all(&s_mario_instance_pool);
}
@@ -257,6 +258,10 @@ SM64_LIB_FN void sm64_mario_tick(int32_t marioId, const struct SM64MarioInputs *
apply_mario_platform_displacement();
bhv_mario_update();
+
+ gMarioState->marioObj->collidedObjInteractTypes = 0;
+ gMarioState->marioObj->numCollidedObjs = 0;
+
update_mario_platform(); // TODO platform grabbed here and used next tick could be a use-after-free
gfx_adapter_bind_output_buffers(outBuffers);
@@ -623,6 +628,119 @@ SM64_LIB_FN void sm64_mario_extend_cap(int32_t marioId, uint16_t capTime)
gMarioState->capTimer += capTime;
}
+SM64_LIB_FN int32_t sm64_fake_object_create(float x, float y, float z, int32_t preset)
+{
+ struct GlobalState *state = g_state;
+ if (state == NULL)
+ {
+ DEBUG_PRINT("Tried to create fake object without an active Mario state.");
+ return -1;
+ }
+
+ int32_t objectIndex = obj_pool_alloc_index(&s_fakeobj_instance_pool, sizeof(struct FakeObject));
+ struct FakeObject *fake = (struct FakeObject *)s_fakeobj_instance_pool.objects[objectIndex];
+
+ fake_object_init(fake, x, y, z);
+ fake_object_set_preset(fake, preset);
+ return objectIndex;
+}
+
+SM64_LIB_FN void sm64_fake_object_delete(int32_t objectId)
+{
+ if (objectId >= s_fakeobj_instance_pool.size || s_fakeobj_instance_pool.objects[objectId] == NULL)
+ {
+ DEBUG_PRINT("Tried to use non-existant Object with ID: %d", objectId);
+ return;
+ }
+ struct FakeObject *fake = s_fakeobj_instance_pool.objects[objectId];
+
+ struct MarioState *m = &g_state->mgMarioStateVal;
+ uint32_t action = m->action;
+
+ if (m->interactObj == &fake->object || m->usedObj == &fake->object || m->heldObj == &fake->object)
+ {
+ m->interactObj = NULL;
+ m->usedObj = NULL;
+ m->heldObj = NULL;
+
+ switch (action)
+ {
+ case ACT_HOLDING_POLE:
+ case ACT_CLIMBING_POLE:
+ case ACT_TOP_OF_POLE:
+ m->action = ACT_FREEFALL;
+ break;
+
+ default:
+ m->action = ACT_IDLE;
+ break;
+ }
+
+ m->actionState = 0;
+ }
+ if (m->marioBodyState != NULL && m->heldObj == NULL)
+ {
+ vec3f_set(m->marioBodyState->heldObjLastPosition, 0.0f, 0.0f, 0.0f);
+ }
+
+ obj_pool_free_index(&s_fakeobj_instance_pool, (uint32_t)objectId);
+}
+
+SM64_LIB_FN void sm64_fake_object_set_position(int32_t objectId, float x, float y, float z)
+{
+ if (objectId >= s_fakeobj_instance_pool.size || s_fakeobj_instance_pool.objects[objectId] == NULL)
+ {
+ DEBUG_PRINT("Tried to use non-existant Object with ID: %d", objectId);
+ return;
+ }
+ struct FakeObject *fake = s_fakeobj_instance_pool.objects[objectId];
+
+ fake->object.oPosX = x;
+ fake->object.oPosY = y;
+ fake->object.oPosZ = z;
+ fake_object_sync_position(fake);
+}
+
+SM64_LIB_FN void sm64_fake_object_set_hitbox(int32_t objectId, float radius, float height, float downOffset)
+{
+ if (objectId >= s_fakeobj_instance_pool.size || s_fakeobj_instance_pool.objects[objectId] == NULL)
+ {
+ DEBUG_PRINT("Tried to use non-existant Object with ID: %d", objectId);
+ return;
+ }
+ struct FakeObject *fake = s_fakeobj_instance_pool.objects[objectId];
+
+ fake->object.hitboxRadius = radius;
+ fake->object.hitboxHeight = height;
+ fake->object.hitboxDownOffset = downOffset;
+}
+
+SM64_LIB_FN void sm64_fake_object_tick(int32_t objectId)
+{
+ if (objectId >= s_fakeobj_instance_pool.size || s_fakeobj_instance_pool.objects[objectId] == NULL)
+ {
+ DEBUG_PRINT("Tried to use non-existant Object with ID: %d", objectId);
+ return;
+ }
+ struct FakeObject *fake = s_fakeobj_instance_pool.objects[objectId];
+
+ struct GlobalState *state = g_state;
+ struct MarioState *m = state != NULL ? &state->mgMarioStateVal : NULL;
+ struct Object *obj = &fake->object;
+
+ obj->oInteractStatus = 0;
+
+ if (m == NULL)
+ {
+ return;
+ }
+
+ if (fake_object_overlaps_mario(fake, m))
+ {
+ fake_object_add_collision(fake, m);
+ }
+}
+
SM64_LIB_FN bool sm64_mario_attack(int32_t marioId, float x, float y, float z, float hitboxHeight)
{
if (marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL)
@@ -653,12 +771,10 @@ SM64_LIB_FN void sm64_surface_object_delete(uint32_t objectId)
// A mario standing on the platform that is being destroyed will have a pointer to freed memory if we don't clear it.
for (int i = 0; i < s_mario_instance_pool.size; ++i)
{
- if (s_mario_instance_pool.objects[i] == NULL)
- continue;
+ if (s_mario_instance_pool.objects[i] == NULL) continue;
struct GlobalState *state = ((struct MarioInstance *)s_mario_instance_pool.objects[i])->globalState;
- if (state->mgMarioObject->platform == surfaces_object_get_transform_ptr(objectId))
- state->mgMarioObject->platform = NULL;
+ if (state->mgMarioObject->platform == surfaces_object_get_transform_ptr(objectId)) state->mgMarioObject->platform = NULL;
}
surfaces_unload_object(objectId);
diff --git a/src/libsm64.h b/src/libsm64.h
index 1f2c940..0ed9c7c 100644
--- a/src/libsm64.h
+++ b/src/libsm64.h
@@ -1,9 +1,7 @@
#ifndef LIB_SM64_H
#define LIB_SM64_H
-#include
#include
-#include
#if defined(_WIN32)
#ifdef SM64_LIB_EXPORT
@@ -146,7 +144,9 @@ struct SM64SurfaceCollisionData
enum
{
- SM64_TEXTURE_WIDTH = 64 * 11, SM64_TEXTURE_HEIGHT = 64, SM64_GEO_MAX_TRIANGLES = 1024,
+ SM64_TEXTURE_WIDTH = 64 * 11,
+ SM64_TEXTURE_HEIGHT = 64,
+ SM64_GEO_MAX_TRIANGLES = 1024,
};
typedef void (*SM64RumbleCallbackFunctionPtr)(int32_t marioId, int16_t level, int16_t time);
@@ -259,6 +259,16 @@ extern SM64_LIB_FN uint16_t sm64_get_current_background_music();
extern SM64_LIB_FN void sm64_play_sound(int32_t soundBits, float *pos);
+extern SM64_LIB_FN int32_t sm64_fake_object_create(float x, float y, float z, int32_t preset);
+
+extern SM64_LIB_FN void sm64_fake_object_delete(int32_t objectId);
+
+extern SM64_LIB_FN void sm64_fake_object_set_position(int32_t objectId, float x, float y, float z);
+
+extern SM64_LIB_FN void sm64_fake_object_set_hitbox(int32_t objectId, float radius, float height, float downOffset);
+
+extern SM64_LIB_FN void sm64_fake_object_tick(int32_t objectId);
+
extern SM64_LIB_FN void sm64_play_sound_global(int32_t soundBits);
extern SM64_LIB_FN void sm64_set_sound_volume(float vol);
diff --git a/test/main.cpp b/test/main.cpp
index 09ac1e8..7402050 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -800,6 +800,9 @@ int main(void)
sm64_static_surfaces_load(surfaces, surfaces_count);
int32_t marioId = sm64_mario_create(-6558, 0, 6464);
+ int thing = sm64_fake_object_create(-6558.0f, 0.0f, 6200.0f, 1);
+ sm64_fake_object_set_hitbox(thing, 32.0f, 800.0f * 2, 800);
+
printf("MarioID: %i\n", marioId);
free(rom);
@@ -958,6 +961,7 @@ int main(void)
tick -= 1.f / 30;
sm64_mario_tick(marioId, &marioInputs, &marioState, &marioGeometry);
+ sm64_fake_object_tick(thing);
memcpy(currPos, marioState.position, sizeof(currPos));
memcpy(currGeoPos, marioGeometry.position, sizeof(currGeoPos));