From bd2b13871d876d76aa05ff85870eb63c12c2821d Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Thu, 26 Jan 2023 21:58:16 -0400 Subject: [PATCH] add loads of features from ckosmic fork * set action * set action with arg * set animation ID (added an include in libsm64.h) * set anim frame * set state (to instantly change caps for example) * set position * set angle and faceangle * set velocity and forward velocity * set water level * take damage * heal mario * kill mario instantly * give mario a cap and play animation * attack --- src/fake_interaction.c | 301 +++++++++++++++++++++++++++++++++++++++++ src/fake_interaction.h | 8 ++ src/libsm64.c | 275 +++++++++++++++++++++++++++++++++++++ src/libsm64.h | 22 +++ 4 files changed, 606 insertions(+) create mode 100644 src/fake_interaction.c create mode 100644 src/fake_interaction.h diff --git a/src/fake_interaction.c b/src/fake_interaction.c new file mode 100644 index 0000000..606d990 --- /dev/null +++ b/src/fake_interaction.c @@ -0,0 +1,301 @@ +#include "decomp/global_state.h" + +#include "debug_print.h" +#include "load_surfaces.h" +#include "gfx_adapter.h" +#include "load_anim_data.h" +#include "load_tex_data.h" +#include "obj_pool.h" + +#include "decomp/game/interaction.h" +#include "decomp/include/object_fields.h" +#include "decomp/include/sm64.h" +#include "decomp/shim.h" +#include "decomp/game/mario.h" +#include "decomp/engine/math_util.h" +#include "fake_interaction.h" + +#define INT_GROUND_POUND_OR_TWIRL (1 << 0) // 0x01 +#define INT_PUNCH (1 << 1) // 0x02 +#define INT_KICK (1 << 2) // 0x04 +#define INT_TRIP (1 << 3) // 0x08 +#define INT_SLIDE_KICK (1 << 4) // 0x10 +#define INT_FAST_ATTACK_OR_SHELL (1 << 5) // 0x20 +#define INT_HIT_FROM_ABOVE (1 << 6) // 0x40 +#define INT_HIT_FROM_BELOW (1 << 7) // 0x80 + +#define INT_ATTACK_NOT_FROM_BELOW \ + (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK \ + | INT_FAST_ATTACK_OR_SHELL | INT_HIT_FROM_ABOVE) + +#define INT_ANY_ATTACK \ + (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK \ + | INT_FAST_ATTACK_OR_SHELL | INT_HIT_FROM_ABOVE | INT_HIT_FROM_BELOW) + +#define INT_ATTACK_NOT_WEAK_FROM_ABOVE \ + (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_HIT_FROM_BELOW) + +#define sDelayInvincTimer (g_state->msDelayInvincTimer) +#define sInvulnerable (g_state->msInvulnerable) + +static u32 sForwardKnockbackActions[][3] = { + { ACT_SOFT_FORWARD_GROUND_KB, ACT_FORWARD_GROUND_KB, ACT_HARD_FORWARD_GROUND_KB }, + { ACT_FORWARD_AIR_KB, ACT_FORWARD_AIR_KB, ACT_HARD_FORWARD_AIR_KB }, + { ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB, ACT_FORWARD_WATER_KB }, +}; + +static u32 sBackwardKnockbackActions[][3] = { + { ACT_SOFT_BACKWARD_GROUND_KB, ACT_BACKWARD_GROUND_KB, ACT_HARD_BACKWARD_GROUND_KB }, + { ACT_BACKWARD_AIR_KB, ACT_BACKWARD_AIR_KB, ACT_HARD_BACKWARD_AIR_KB }, + { ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB, ACT_BACKWARD_WATER_KB }, +}; + +uint32_t fake_damage_knock_back(struct MarioState *m, uint32_t damage,uint32_t interactionSubtype,float xSrc,float ySrc,float zSrc) { + + if (!sInvulnerable && !(m->flags & MARIO_VANISH_CAP) + && !(interactionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { + //o->oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_ATTACKED_MARIO; + //m->interactObj = o; + + // calculate damage, substitute for take_damage_from_interact_object + if (!(m->flags & MARIO_CAP_ON_HEAD)) { + damage += (damage + 1) / 2; + } + + if (m->flags & MARIO_METAL_CAP) { + damage = 0; + } + + m->hurtCounter += 4 * damage; // apply hurt counter + + if (interactionSubtype & INT_SUBTYPE_BIG_KNOCKBACK) { + m->forwardVel = 40.0f; + } + + if (damage > 0) { + play_sound(SOUND_MARIO_ATTACKED, m->marioObj->header.gfx.cameraToObject); + } + + //update_mario_sound_and_camera(m); + return drop_and_set_mario_action(m, fake_determine_knockback_action(m, damage,xSrc,ySrc,zSrc), + damage); + } + + return FALSE; +} + +s16 fake_mario_obj_angle_to_object(struct MarioState *m, float xSrc,float zSrc) { + f32 dx = xSrc - m->pos[0]; + f32 dz = zSrc - m->pos[2]; + + return atan2s(dz, dx); +} + +u32 fake_determine_knockback_action(struct MarioState *m, s32 damage,float xSrc,float ySrc,float zSrc) { + u32 bonkAction; + + s16 terrainIndex = 0; // 1 = air, 2 = water, 0 = default + s16 strengthIndex = 0; + + s16 angleToObject = fake_mario_obj_angle_to_object(m, xSrc,zSrc); + s16 facingDYaw = angleToObject - m->faceAngle[1]; + s16 remainingHealth = m->health - 0x40 * m->hurtCounter; + + if (m->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) { + terrainIndex = 2; + } else if (m->action & (ACT_FLAG_AIR | ACT_FLAG_ON_POLE | ACT_FLAG_HANGING)) { + terrainIndex = 1; + } + + if (remainingHealth < 0x100) { + strengthIndex = 2; + } else if (damage >= 4) { + strengthIndex = 2; + } else if (damage >= 2) { + strengthIndex = 1; + } + + m->faceAngle[1] = angleToObject; + + if (terrainIndex == 2) { + if (m->forwardVel < 28.0f) { + mario_set_forward_vel(m, 28.0f); + } + + if (m->pos[1] >= ySrc) { + if (m->vel[1] < 20.0f) { + m->vel[1] = 20.0f; + } + } else { + if (m->vel[1] > 0.0f) { + m->vel[1] = 0.0f; + } + } + } else { + if (m->forwardVel < 16.0f) { + mario_set_forward_vel(m, 16.0f); + } + } + + if (-0x4000 <= facingDYaw && facingDYaw <= 0x4000) { + m->forwardVel *= -1.0f; + bonkAction = sBackwardKnockbackActions[terrainIndex][strengthIndex]; + } else { + m->faceAngle[1] += 0x8000; + bonkAction = sForwardKnockbackActions[terrainIndex][strengthIndex]; + } + + return bonkAction; +} + +s16 fake_mario_obj_angle_to_pos(struct MarioState *m, float x, float z) { + f32 dx = x - m->pos[0]; + f32 dz = z - m->pos[2]; + + return atan2s(dz, dx); +} + +void fake_bounce_back_from_attack(struct MarioState *m, u32 interaction) { + if (interaction & (INT_PUNCH | INT_KICK | INT_TRIP)) { + if (m->action == ACT_PUNCHING) { + m->action = ACT_MOVE_PUNCHING; + } + + if (m->action & ACT_FLAG_AIR) { + mario_set_forward_vel(m, -16.0f); + } else { + mario_set_forward_vel(m, -48.0f); + } + + //set_camera_shake_from_hit(SHAKE_ATTACK); + m->particleFlags |= PARTICLE_TRIANGLE; + } + + if (interaction & (INT_PUNCH | INT_KICK | INT_TRIP | INT_FAST_ATTACK_OR_SHELL)) { + play_sound(SOUND_ACTION_HIT_2, m->marioObj->header.gfx.cameraToObject); + } +} + +u32 fake_determine_interaction(struct MarioState *m, float x, float y, float z) { + u32 interaction = 0; + u32 action = m->action; + + s16 dYawToObject = fake_mario_obj_angle_to_pos(m, x, z) - m->faceAngle[1]; + if (action & ACT_FLAG_ATTACKING) { + if (action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING || action == ACT_JUMP_KICK) { + + + if (m->flags & MARIO_PUNCHING) { + // 120 degrees total, or 60 each way + if (-0x2AAA <= dYawToObject && dYawToObject <= 0x2AAA) { + interaction = INT_PUNCH; + } + } + if (m->flags & MARIO_KICKING) { + // 120 degrees total, or 60 each way + if (-0x2AAA <= dYawToObject && dYawToObject <= 0x2AAA) { + interaction = INT_KICK; + } + } + if (m->flags & MARIO_TRIPPING) { + // 180 degrees total, or 90 each way + if (-0x4000 <= dYawToObject && dYawToObject <= 0x4000) { + interaction = INT_TRIP; + } + } + } else if (action == ACT_GROUND_POUND || action == ACT_TWIRLING) { + if (m->vel[1] < 0.0f) { + interaction = INT_GROUND_POUND_OR_TWIRL; + } + } else if (action == ACT_GROUND_POUND_LAND || action == ACT_TWIRL_LAND) { + // Neither ground pounding nor twirling change Mario's vertical speed on landing., + // so the speed check is nearly always true (perhaps not if you land while going upwards?) + // Additionally, actionState it set on each first thing in their action, so this is + // only true prior to the very first frame (i.e. active 1 frame prior to it run). + if (m->vel[1] < 0.0f && m->actionState == 0) { + interaction = INT_GROUND_POUND_OR_TWIRL; + } + } else if (action == ACT_SLIDE_KICK || action == ACT_SLIDE_KICK_SLIDE) { + interaction = INT_SLIDE_KICK; + } else if (action & ACT_FLAG_RIDING_SHELL) { + interaction = INT_FAST_ATTACK_OR_SHELL; + } else if (m->forwardVel <= -26.0f || 26.0f <= m->forwardVel) { + interaction = INT_FAST_ATTACK_OR_SHELL; + } + } + + // Prior to this, the interaction type could be overwritten. This requires, however, + // that the interaction not be set prior. This specifically overrides turning a ground + // pound into just a bounce. + if (interaction == 0 && (action & ACT_FLAG_AIR)) { + if (m->vel[1] < 0.0f) { + if (m->pos[1] > y) { + interaction = INT_HIT_FROM_ABOVE; + } + } else { + if (m->pos[1] < y) { + interaction = INT_HIT_FROM_BELOW; + } + } + } + + return interaction; +} + +void fake_bounce_off_object(struct MarioState *m, float x, float y, float z, float hitboxHeight, f32 velY) { + //m->pos[1] = y + hitboxHeight; + m->vel[1] = velY; + + m->flags &= ~MARIO_UNKNOWN_08; + + play_sound(SOUND_ACTION_BOUNCE_OFF_OBJECT, m->marioObj->header.gfx.cameraToObject); +} + +u32 fake_interact_hit_from_below(struct MarioState *m, float x, float y, float z, float hitboxHeight) { + + u32 interaction; + if (m->flags & MARIO_METAL_CAP) { + interaction = INT_FAST_ATTACK_OR_SHELL; + } else { + interaction = fake_determine_interaction(m, x, y, z); + } + + if (interaction & INT_ANY_ATTACK) { + fake_bounce_back_from_attack(m, interaction); + + if (interaction & INT_HIT_FROM_BELOW) { + m->vel[1] = 0.0f; + } + + if (interaction & INT_HIT_FROM_ABOVE) { + fake_bounce_off_object(m, x, y, z, hitboxHeight, 30.0f); + } + return TRUE; + } else/* if (fake_damage_knock_back(m, 0, 0, x, y, z))*/ { + return FALSE; + } + + return FALSE; +} + +u32 fake_interact_bounce_top(struct MarioState *m, float x, float y, float z, float hitboxHeight) { + u32 interaction; + if (m->flags & MARIO_METAL_CAP) { + interaction = INT_FAST_ATTACK_OR_SHELL; + } else { + interaction = fake_determine_interaction(m, x, y, z); + } + + if (interaction & INT_ATTACK_NOT_FROM_BELOW) { + fake_bounce_back_from_attack(m, interaction); + + if (interaction & INT_HIT_FROM_ABOVE) { + fake_bounce_off_object(m, x, y, z, hitboxHeight, 30.0f); + } + return TRUE; + } else/* if (fake_damage_knock_back(m, 0, 0, x, y, z))*/ { + return FALSE; + } + + return FALSE; +} \ No newline at end of file diff --git a/src/fake_interaction.h b/src/fake_interaction.h new file mode 100644 index 0000000..a6277ee --- /dev/null +++ b/src/fake_interaction.h @@ -0,0 +1,8 @@ +#pragma once +#include "decomp/include/types.h" + +u32 fake_determine_knockback_action(struct MarioState *m, s32 damage,float xSrc,float ySrc,float zSrc); +s16 fake_mario_obj_angle_to_object(struct MarioState *m, float xSrc,float zSrc); +uint32_t fake_damage_knock_back(struct MarioState *m, uint32_t damage,uint32_t interactionSubtype,float xSrc,float ySrc,float zSrc); +u32 fake_interact_hit_from_below(struct MarioState *m, float x, float y, float z, float hitboxHeight); +u32 fake_interact_bounce_top(struct MarioState *m, float x, float y, float z, float hitboxHeight); \ No newline at end of file diff --git a/src/libsm64.c b/src/libsm64.c index f4504f6..9fe3fb3 100644 --- a/src/libsm64.c +++ b/src/libsm64.c @@ -33,6 +33,7 @@ #include "load_audio_data.h" #include "load_tex_data.h" #include "obj_pool.h" +#include "fake_interaction.h" static struct AllocOnlyPool *s_mario_geo_pool = NULL; static struct GraphNode *s_mario_graph_node = NULL; @@ -252,6 +253,10 @@ SM64_LIB_FN void sm64_mario_tick( int32_t marioId, const struct SM64MarioInputs vec3f_copy( outState->position, gMarioState->pos ); vec3f_copy( outState->velocity, gMarioState->vel ); outState->faceAngle = (float)gMarioState->faceAngle[1] / 32768.0f * 3.14159f; + outState->action = gMarioState->action; + outState->flags = gMarioState->flags; + outState->particleFlags = gMarioState->particleFlags; + outState->invincTimer = gMarioState->invincTimer; } SM64_LIB_FN void sm64_mario_delete( int32_t marioId ) @@ -274,6 +279,276 @@ SM64_LIB_FN void sm64_mario_delete( int32_t marioId ) obj_pool_free_index( &s_mario_instance_pool, marioId ); } +SM64_LIB_FN void sm64_set_mario_action(int32_t marioId, uint32_t action) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + set_mario_action(gMarioState, action, 0); +} + +SM64_LIB_FN void sm64_set_mario_action_arg(int32_t marioId, uint32_t action, uint32_t actionArg) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + set_mario_action(gMarioState, action, actionArg); +} + +SM64_LIB_FN void sm64_set_mario_animation(int32_t marioId, int32_t animID) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + set_mario_animation(gMarioState, animID); +} + +SM64_LIB_FN void sm64_set_mario_anim_frame(int32_t marioId, int16_t animFrame) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->marioObj->header.gfx.animInfo.animFrame = animFrame; +} + +SM64_LIB_FN void sm64_set_mario_state(int32_t marioId, uint32_t flags) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->flags = flags; +} + +SM64_LIB_FN void sm64_set_mario_position(int32_t marioId, float x, float y, float z) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->pos[0] = x; + gMarioState->pos[1] = y; + gMarioState->pos[2] = z; + vec3f_copy(gMarioState->marioObj->header.gfx.pos, gMarioState->pos); +} + +SM64_LIB_FN void sm64_set_mario_angle(int32_t marioId, float x, float y, float z) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + vec3s_set(gMarioState->faceAngle, (int16_t)(x / 3.14159f * 32768.f), (int16_t)(y / 3.14159f * 32768.f), (int16_t)(z / 3.14159f * 32768.f)); + vec3s_copy(gMarioState->marioObj->header.gfx.angle, gMarioState->faceAngle); +} + +SM64_LIB_FN void sm64_set_mario_faceangle(int32_t marioId, float y) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->faceAngle[1] = (int16_t)(y / 3.14159f * 32768.f); + vec3s_set(gMarioState->marioObj->header.gfx.angle, 0, gMarioState->faceAngle[1], 0); +} + +SM64_LIB_FN void sm64_set_mario_velocity(int32_t marioId, float x, float y, float z) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->vel[0] = x; + gMarioState->vel[1] = y; + gMarioState->vel[2] = z; +} + +SM64_LIB_FN void sm64_set_mario_forward_velocity(int32_t marioId, float vel) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->forwardVel = vel; +} + +SM64_LIB_FN void sm64_set_mario_water_level(int32_t marioId, signed int level) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->waterLevel = level; +} + +SM64_LIB_FN void sm64_mario_take_damage(int32_t marioId, uint32_t damage, uint32_t subtype, float x, float y, float z) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + fake_damage_knock_back(gMarioState, damage, subtype, x, y, z); +} + +SM64_LIB_FN void sm64_mario_heal(int32_t marioId, uint8_t healCounter) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->healCounter += healCounter; +} + +SM64_LIB_FN void sm64_mario_kill(int32_t marioId) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + gMarioState->health = 0xff; +} + +SM64_LIB_FN void sm64_mario_interact_cap(int32_t marioId, uint32_t capFlag, uint16_t capTime, uint8_t playMusic) +{ + if( marioId >= s_mario_instance_pool.size || s_mario_instance_pool.objects[marioId] == NULL ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + uint16_t capMusic = 0; + if(gMarioState->action != ACT_GETTING_BLOWN && capFlag != 0) + { + gMarioState->flags &= ~MARIO_CAP_ON_HEAD & ~MARIO_CAP_IN_HAND; + gMarioState->flags |= capFlag; + + switch(capFlag) + { + case MARIO_VANISH_CAP: + if(capTime == 0) capTime = 600; + capMusic = SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP); + break; + case MARIO_METAL_CAP: + if(capTime == 0) capTime = 600; + capMusic = SEQUENCE_ARGS(4, SEQ_EVENT_METAL_CAP); + break; + case MARIO_WING_CAP: + if(capTime == 0) capTime = 1800; + capMusic = SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP); + break; + } + + if (capTime > gMarioState->capTimer) { + gMarioState->capTimer = capTime; + } + + if ((gMarioState->action & ACT_FLAG_IDLE) || gMarioState->action == ACT_WALKING) { + gMarioState->flags |= MARIO_CAP_IN_HAND; + set_mario_action(gMarioState, ACT_PUTTING_ON_CAP, 0); + } else { + gMarioState->flags |= MARIO_CAP_ON_HEAD; + } + + play_sound(SOUND_MENU_STAR_SOUND, gMarioState->marioObj->header.gfx.cameraToObject); + play_sound(SOUND_MARIO_HERE_WE_GO, gMarioState->marioObj->header.gfx.cameraToObject); + + if (playMusic != 0 && capMusic != 0) { + play_cap_music(capMusic); + } + } +} + +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 ) + { + DEBUG_PRINT("Tried to use non-existant Mario with ID: %d", marioId); + return false; + } + + struct GlobalState *globalState = ((struct MarioInstance *)s_mario_instance_pool.objects[ marioId ])->globalState; + global_state_bind( globalState ); + + return fake_interact_bounce_top(gMarioState, x, y, z, hitboxHeight); +} + SM64_LIB_FN uint32_t sm64_surface_object_create( const struct SM64SurfaceObject *surfaceObject ) { uint32_t id = surfaces_load_object( surfaceObject ); diff --git a/src/libsm64.h b/src/libsm64.h index 0b03e13..73d2842 100644 --- a/src/libsm64.h +++ b/src/libsm64.h @@ -5,6 +5,7 @@ #include #include +#include "decomp/include/mario_animation_ids.h" #include "decomp/include/audio_defines.h" #include "decomp/include/seq_ids.h" @@ -52,6 +53,10 @@ struct SM64MarioState float velocity[3]; float faceAngle; int16_t health; + uint32_t action; + uint32_t flags; + uint32_t particleFlags; + int16_t invincTimer; }; struct SM64MarioGeometryBuffers @@ -145,6 +150,23 @@ extern SM64_LIB_FN int32_t sm64_mario_create( float x, float y, float z ); extern SM64_LIB_FN void sm64_mario_tick( int32_t marioId, const struct SM64MarioInputs *inputs, struct SM64MarioState *outState, struct SM64MarioGeometryBuffers *outBuffers ); extern SM64_LIB_FN void sm64_mario_delete( int32_t marioId ); +extern SM64_LIB_FN void sm64_set_mario_action(int32_t marioId, uint32_t action); +extern SM64_LIB_FN void sm64_set_mario_action_arg(int32_t marioId, uint32_t action, uint32_t actionArg); +extern SM64_LIB_FN void sm64_set_mario_animation(int32_t marioId, int32_t animID); +extern SM64_LIB_FN void sm64_set_mario_anim_frame(int32_t marioId, int16_t animFrame); +extern SM64_LIB_FN void sm64_set_mario_state(int32_t marioId, uint32_t flags); +extern SM64_LIB_FN void sm64_set_mario_position(int32_t marioId, float x, float y, float z); +extern SM64_LIB_FN void sm64_set_mario_angle(int32_t marioId, float x, float y, float z); +extern SM64_LIB_FN void sm64_set_mario_faceangle(int32_t marioId, float y); +extern SM64_LIB_FN void sm64_set_mario_velocity(int32_t marioId, float x, float y, float z); +extern SM64_LIB_FN void sm64_set_mario_forward_velocity(int32_t marioId, float vel); +extern SM64_LIB_FN void sm64_set_mario_water_level(int32_t marioId, signed int level); +extern SM64_LIB_FN void sm64_mario_take_damage(int32_t marioId, uint32_t damage, uint32_t subtype, float x, float y, float z); +extern SM64_LIB_FN void sm64_mario_heal(int32_t marioId, uint8_t healCounter); +extern SM64_LIB_FN void sm64_mario_kill(int32_t marioId); +extern SM64_LIB_FN void sm64_mario_interact_cap(int32_t marioId, uint32_t capFlag, uint16_t capTime, uint8_t playMusic); +extern SM64_LIB_FN bool sm64_mario_attack(int32_t marioId, float x, float y, float z, float hitboxHeight); + extern SM64_LIB_FN uint32_t sm64_surface_object_create( const struct SM64SurfaceObject *surfaceObject ); extern SM64_LIB_FN void sm64_surface_object_move( uint32_t objectId, const struct SM64ObjectTransform *transform ); extern SM64_LIB_FN void sm64_surface_object_delete( uint32_t objectId );