Path: blob/master/src/game/mario_actions_automatic.c
7858 views
#include <PR/ultratypes.h>12#include "sm64.h"3#include "behavior_data.h"4#include "mario_actions_automatic.h"5#include "audio/external.h"6#include "area.h"7#include "mario.h"8#include "mario_step.h"9#include "engine/math_util.h"10#include "memory.h"11#include "engine/graph_node.h"12#include "save_file.h"13#include "engine/surface_collision.h"14#include "interaction.h"15#include "camera.h"16#include "level_table.h"17#include "rumble_init.h"1819#include "settings.h"2021#define POLE_NONE 022#define POLE_TOUCHED_FLOOR 123#define POLE_FELL_OFF 22425#define HANG_NONE 026#define HANG_HIT_CEIL_OR_OOB 127#define HANG_LEFT_CEIL 22829void add_tree_leaf_particles(struct MarioState *m) {30f32 leafHeight;3132if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) {33// make leaf effect spawn higher on the Shifting Sand Land palm tree34if (gCurrLevelNum == LEVEL_SSL) {35leafHeight = 250.0f;36} else {37leafHeight = 100.0f;38}39if (m->pos[1] - m->floorHeight > leafHeight) {40m->particleFlags |= PARTICLE_LEAF;41}42}43}4445void play_climbing_sounds(struct MarioState *m, s32 b) {46s32 isOnTree = (m->usedObj->behavior == segmented_to_virtual(bhvTree));4748if (b == 1) {49if (is_anim_past_frame(m, 1)) {50play_sound(isOnTree ? SOUND_ACTION_CLIMB_UP_TREE : SOUND_ACTION_CLIMB_UP_POLE,51m->marioObj->header.gfx.cameraToObject);52}53} else {54play_sound(isOnTree ? SOUND_MOVING_SLIDE_DOWN_TREE : SOUND_MOVING_SLIDE_DOWN_POLE,55m->marioObj->header.gfx.cameraToObject);56}57}5859s32 set_pole_position(struct MarioState *m, f32 offsetY) {60UNUSED s32 unused1;61UNUSED s32 unused2;62UNUSED s32 unused3;63struct Surface *floor;64struct Surface *ceil;65f32 floorHeight;66f32 ceilHeight;67s32 collided;68s32 result = POLE_NONE;69f32 poleTop = m->usedObj->hitboxHeight - 100.0f;70struct Object *marioObj = m->marioObj;7172if (marioObj->oMarioPolePos > poleTop) {73marioObj->oMarioPolePos = poleTop;74}7576m->pos[0] = m->usedObj->oPosX;77m->pos[2] = m->usedObj->oPosZ;78m->pos[1] = m->usedObj->oPosY + marioObj->oMarioPolePos + offsetY;7980collided = f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 60.0f, 50.0f);81collided |= f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 30.0f, 24.0f);8283ceilHeight = vec3f_find_ceil(m->pos, m->pos[1], &ceil);84if (m->pos[1] > ceilHeight - 160.0f) {85m->pos[1] = ceilHeight - 160.0f;86marioObj->oMarioPolePos = m->pos[1] - m->usedObj->oPosY;87}8889floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);90if (m->pos[1] < floorHeight) {91m->pos[1] = floorHeight;92set_mario_action(m, ACT_IDLE, 0);93result = POLE_TOUCHED_FLOOR;94} else if (marioObj->oMarioPolePos < -m->usedObj->hitboxDownOffset) {95m->pos[1] = m->usedObj->oPosY - m->usedObj->hitboxDownOffset;96set_mario_action(m, ACT_FREEFALL, 0);97result = POLE_FELL_OFF;98} else if (collided) {99if (m->pos[1] > floorHeight + 20.0f) {100m->forwardVel = -2.0f;101set_mario_action(m, ACT_SOFT_BONK, 0);102result = POLE_FELL_OFF;103} else {104set_mario_action(m, ACT_IDLE, 0);105result = POLE_TOUCHED_FLOOR;106}107}108109vec3f_copy(m->marioObj->header.gfx.pos, m->pos);110vec3s_set(m->marioObj->header.gfx.angle, m->usedObj->oMoveAnglePitch, m->faceAngle[1],111m->usedObj->oMoveAngleRoll);112113return result;114}115116s32 act_holding_pole(struct MarioState *m) {117struct Object *marioObj = m->marioObj;118119#ifdef VERSION_JP120if (m->input & INPUT_A_PRESSED) {121add_tree_leaf_particles(m);122m->faceAngle[1] += 0x8000;123return set_mario_action(m, ACT_WALL_KICK_AIR, 0);124}125126if (m->input & INPUT_Z_PRESSED) {127add_tree_leaf_particles(m);128m->forwardVel = -2.0f;129return set_mario_action(m, ACT_SOFT_BONK, 0);130}131#else132if ((m->input & INPUT_Z_PRESSED) || m->health < 0x100) {133add_tree_leaf_particles(m);134m->forwardVel = -2.0f;135return set_mario_action(m, ACT_SOFT_BONK, 0);136}137138if (m->input & INPUT_A_PRESSED) {139add_tree_leaf_particles(m);140m->faceAngle[1] += 0x8000;141return set_mario_action(m, ACT_WALL_KICK_AIR, 0);142}143#endif144145if (m->controller->stickY > 16.0f) {146f32 poleTop = m->usedObj->hitboxHeight - 100.0f;147const BehaviorScript *poleBehavior = virtual_to_segmented(0x13, m->usedObj->behavior);148149if (marioObj->oMarioPolePos < poleTop - 0.4f) {150return set_mario_action(m, ACT_CLIMBING_POLE, 0);151}152153if (poleBehavior != bhvGiantPole && m->controller->stickY > 50.0f) {154return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 0);155}156}157158if (m->controller->stickY < -16.0f) {159marioObj->oMarioPoleYawVel -= m->controller->stickY * 2;160if (marioObj->oMarioPoleYawVel > 0x1000) {161marioObj->oMarioPoleYawVel = 0x1000;162}163164m->faceAngle[1] += marioObj->oMarioPoleYawVel;165marioObj->oMarioPolePos -= marioObj->oMarioPoleYawVel / 0x100;166167if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) {168//! The Shifting Sand Land palm tree check is done climbing up in169// add_tree_leaf_particles, but not here, when climbing down.170if (m->pos[1] - m->floorHeight > 100.0f) {171m->particleFlags |= PARTICLE_LEAF;172}173}174play_climbing_sounds(m, 2);175#if ENABLE_RUMBLE176reset_rumble_timers();177#endif178set_sound_moving_speed(SOUND_BANK_MOVING, marioObj->oMarioPoleYawVel / 0x100 * 2);179} else {180marioObj->oMarioPoleYawVel = 0;181m->faceAngle[1] -= m->controller->stickX * 16.0f;182}183184if (set_pole_position(m, 0.0f) == POLE_NONE) {185set_mario_animation(m, MARIO_ANIM_IDLE_ON_POLE);186}187188return FALSE;189}190191s32 act_climbing_pole(struct MarioState *m) {192s32 sp24;193struct Object *marioObj = m->marioObj;194s16 cameraAngle = m->area->camera->yaw;195196#ifndef VERSION_JP197if (m->health < 0x100) {198add_tree_leaf_particles(m);199m->forwardVel = -2.0f;200return set_mario_action(m, ACT_SOFT_BONK, 0);201}202#endif203204if (m->input & INPUT_A_PRESSED) {205add_tree_leaf_particles(m);206m->faceAngle[1] += 0x8000;207return set_mario_action(m, ACT_WALL_KICK_AIR, 0);208}209210if (m->controller->stickY < 8.0f) {211return set_mario_action(m, ACT_HOLDING_POLE, 0);212}213214marioObj->oMarioPolePos += m->controller->stickY / 8.0f;215marioObj->oMarioPoleYawVel = 0;216m->faceAngle[1] = cameraAngle - approach_s32((s16)(cameraAngle - m->faceAngle[1]), 0, 0x400, 0x400);217218if (set_pole_position(m, 0.0f) == POLE_NONE) {219sp24 = m->controller->stickY / 4.0f * 0x10000;220set_mario_anim_with_accel(m, MARIO_ANIM_CLIMB_UP_POLE, sp24);221add_tree_leaf_particles(m);222play_climbing_sounds(m, 1);223}224225return FALSE;226}227228s32 act_grab_pole_slow(struct MarioState *m) {229play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);230231if (set_pole_position(m, 0.0f) == POLE_NONE) {232set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SHORT);233if (is_anim_at_end(m)) {234set_mario_action(m, ACT_HOLDING_POLE, 0);235}236add_tree_leaf_particles(m);237}238239return FALSE;240}241242s32 act_grab_pole_fast(struct MarioState *m) {243struct Object *marioObj = m->marioObj;244245play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);246m->faceAngle[1] += marioObj->oMarioPoleYawVel;247marioObj->oMarioPoleYawVel = marioObj->oMarioPoleYawVel * 8 / 10;248249if (set_pole_position(m, 0.0f) == POLE_NONE) {250if (marioObj->oMarioPoleYawVel > 0x800) {251set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART1);252} else {253set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART2);254if (is_anim_at_end(m)) {255marioObj->oMarioPoleYawVel = 0;256set_mario_action(m, ACT_HOLDING_POLE, 0);257}258}259add_tree_leaf_particles(m);260}261262return FALSE;263}264265s32 act_top_of_pole_transition(struct MarioState *m) {266struct Object *marioObj = m->marioObj;267268marioObj->oMarioPoleYawVel = 0;269if (m->actionArg == 0) {270set_mario_animation(m, MARIO_ANIM_START_HANDSTAND);271if (is_anim_at_end(m)) {272return set_mario_action(m, ACT_TOP_OF_POLE, 0);273}274} else {275set_mario_animation(m, MARIO_ANIM_RETURN_FROM_HANDSTAND);276if (m->marioObj->header.gfx.animInfo.animFrame == 0) {277return set_mario_action(m, ACT_HOLDING_POLE, 0);278}279}280281set_pole_position(m, return_mario_anim_y_translation(m));282return FALSE;283}284285s32 act_top_of_pole(struct MarioState *m) {286UNUSED struct Object *marioObj = m->marioObj;287288if (m->input & INPUT_A_PRESSED) {289return set_mario_action(m, ACT_TOP_OF_POLE_JUMP, 0);290}291if (m->controller->stickY < -16.0f) {292return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 1);293}294295m->faceAngle[1] -= m->controller->stickX * 16.0f;296297set_mario_animation(m, MARIO_ANIM_HANDSTAND_IDLE);298set_pole_position(m, return_mario_anim_y_translation(m));299return FALSE;300}301302s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {303UNUSED s32 unused;304struct Surface *ceil;305struct Surface *floor;306f32 ceilHeight;307f32 floorHeight;308f32 ceilOffset;309310m->wall = resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f);311floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);312if (configApplyBugFixes > 1)313ceilHeight = vec3f_find_ceil(nextPos, nextPos[1], &ceil);314else315ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);316317if (floor == NULL) {318return HANG_HIT_CEIL_OR_OOB;319}320if (ceil == NULL) {321return HANG_LEFT_CEIL;322}323if (ceilHeight - floorHeight <= 160.0f) {324return HANG_HIT_CEIL_OR_OOB;325}326if (ceil->type != SURFACE_HANGABLE) {327return HANG_LEFT_CEIL;328}329330ceilOffset = ceilHeight - (nextPos[1] + 160.0f);331if (ceilOffset < -30.0f) {332return HANG_HIT_CEIL_OR_OOB;333}334if (ceilOffset > 30.0f) {335return HANG_LEFT_CEIL;336}337338nextPos[1] = m->ceilHeight - 160.0f;339vec3f_copy(m->pos, nextPos);340341m->floor = floor;342m->floorHeight = floorHeight;343m->ceil = ceil;344m->ceilHeight = ceilHeight;345346return HANG_NONE;347}348349s32 update_hang_moving(struct MarioState *m) {350s32 stepResult;351Vec3f nextPos;352f32 maxSpeed;353354if (configImprovedHanging)355maxSpeed = 8.0f;356else357maxSpeed = 4.0f;358359m->forwardVel += 1.0f;360if (m->forwardVel > maxSpeed) {361m->forwardVel = maxSpeed;362}363364m->faceAngle[1] =365m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800);366367m->slideYaw = m->faceAngle[1];368m->slideVelX = m->forwardVel * sins(m->faceAngle[1]);369m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]);370371m->vel[0] = m->slideVelX;372m->vel[1] = 0.0f;373m->vel[2] = m->slideVelZ;374375nextPos[0] = m->pos[0] - m->ceil->normal.y * m->vel[0];376nextPos[2] = m->pos[2] - m->ceil->normal.y * m->vel[2];377nextPos[1] = m->pos[1];378379stepResult = perform_hanging_step(m, nextPos);380381vec3f_copy(m->marioObj->header.gfx.pos, m->pos);382vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);383return stepResult;384}385386void update_hang_stationary(struct MarioState *m) {387m->forwardVel = 0.0f;388m->slideVelX = 0.0f;389m->slideVelZ = 0.0f;390391m->pos[1] = m->ceilHeight - 160.0f;392vec3f_copy(m->vel, gVec3fZero);393vec3f_copy(m->marioObj->header.gfx.pos, m->pos);394}395396s32 act_start_hanging(struct MarioState *m) {397#if ENABLE_RUMBLE398if (m->actionTimer++ == 0) {399queue_rumble_data(5, 80);400}401#else402m->actionTimer++;403#endif404405if ((m->input & INPUT_NONZERO_ANALOG) && m->actionTimer >= 31) {406return set_mario_action(m, ACT_HANGING, 0);407}408409if ((!(m->input & INPUT_A_DOWN) && !configImprovedHanging)410|| ((m->input & INPUT_A_PRESSED) && configImprovedHanging)) {411return set_mario_action(m, ACT_FREEFALL, 0);412}413414if (m->input & INPUT_Z_PRESSED) {415return set_mario_action(m, ACT_GROUND_POUND, 0);416}417418//! Crash if Mario's referenced ceiling is NULL (same for other hanging actions)419if (m->ceil->type != SURFACE_HANGABLE) {420return set_mario_action(m, ACT_FREEFALL, 0);421}422423set_mario_animation(m, MARIO_ANIM_HANG_ON_CEILING);424play_sound_if_no_flag(m, SOUND_ACTION_HANGING_STEP, MARIO_ACTION_SOUND_PLAYED);425update_hang_stationary(m);426427if (is_anim_at_end(m)) {428set_mario_action(m, ACT_HANGING, 0);429}430431return FALSE;432}433434s32 act_hanging(struct MarioState *m) {435if (m->input & INPUT_NONZERO_ANALOG) {436return set_mario_action(m, ACT_HANG_MOVING, m->actionArg);437}438439if ((!(m->input & INPUT_A_DOWN) && !configImprovedHanging)440|| ((m->input & INPUT_A_PRESSED) && configImprovedHanging)) {441return set_mario_action(m, ACT_FREEFALL, 0);442}443444if (m->input & INPUT_Z_PRESSED) {445return set_mario_action(m, ACT_GROUND_POUND, 0);446}447448if (m->ceil->type != SURFACE_HANGABLE) {449return set_mario_action(m, ACT_FREEFALL, 0);450}451452if (m->actionArg & 1) {453set_mario_animation(m, MARIO_ANIM_HANDSTAND_LEFT);454} else {455set_mario_animation(m, MARIO_ANIM_HANDSTAND_RIGHT);456}457458update_hang_stationary(m);459460return FALSE;461}462463s32 act_hang_moving(struct MarioState *m) {464if ((!(m->input & INPUT_A_DOWN) && !configImprovedHanging)465|| ((m->input & INPUT_A_PRESSED) && configImprovedHanging)) {466return set_mario_action(m, ACT_FREEFALL, 0);467}468469if (m->input & INPUT_Z_PRESSED) {470return set_mario_action(m, ACT_GROUND_POUND, 0);471}472473if (m->ceil->type != SURFACE_HANGABLE) {474return set_mario_action(m, ACT_FREEFALL, 0);475}476477if (m->actionArg & 1) {478set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_RIGHT);479} else {480set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_LEFT);481}482483if (m->marioObj->header.gfx.animInfo.animFrame == 12) {484play_sound(SOUND_ACTION_HANGING_STEP, m->marioObj->header.gfx.cameraToObject);485#if ENABLE_RUMBLE486queue_rumble_data(1, 30);487#endif488}489490if (is_anim_past_end(m)) {491m->actionArg ^= 1;492if (m->input & INPUT_UNKNOWN_5) {493return set_mario_action(m, ACT_HANGING, m->actionArg);494}495}496if (configImprovedHanging)497update_hang_moving(m);498else {499if (update_hang_moving(m) == HANG_LEFT_CEIL) {500set_mario_action(m, ACT_FREEFALL, 0);501}502}503504return FALSE;505}506507s32 let_go_of_ledge(struct MarioState *m) {508f32 floorHeight;509struct Surface *floor;510511m->vel[1] = 0.0f;512m->forwardVel = -8.0f;513m->pos[0] -= 60.0f * sins(m->faceAngle[1]);514m->pos[2] -= 60.0f * coss(m->faceAngle[1]);515516floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);517if (floorHeight < m->pos[1] - 100.0f) {518m->pos[1] -= 100.0f;519} else {520m->pos[1] = floorHeight;521}522523return set_mario_action(m, ACT_SOFT_BONK, 0);524}525526void climb_up_ledge(struct MarioState *m) {527set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);528m->pos[0] += 14.0f * sins(m->faceAngle[1]);529m->pos[2] += 14.0f * coss(m->faceAngle[1]);530vec3f_copy(m->marioObj->header.gfx.pos, m->pos);531}532533void update_ledge_climb_camera(struct MarioState *m) {534f32 sp4;535536if (m->actionTimer < 14) {537sp4 = m->actionTimer;538} else {539sp4 = 14.0f;540}541m->statusForCamera->pos[0] = m->pos[0] + sp4 * sins(m->faceAngle[1]);542m->statusForCamera->pos[2] = m->pos[2] + sp4 * coss(m->faceAngle[1]);543m->statusForCamera->pos[1] = m->pos[1];544m->actionTimer++;545m->flags |= MARIO_UNKNOWN_25;546}547548void update_ledge_climb(struct MarioState *m, s32 animation, u32 endAction) {549stop_and_set_height_to_floor(m);550551set_mario_animation(m, animation);552if (is_anim_at_end(m)) {553set_mario_action(m, endAction, 0);554if (endAction == ACT_IDLE) {555climb_up_ledge(m);556}557}558}559560s32 act_ledge_grab(struct MarioState *m) {561f32 heightAboveFloor;562s16 intendedDYaw = m->intendedYaw - m->faceAngle[1];563s32 hasSpaceForMario = (m->ceilHeight - m->floorHeight >= 160.0f);564565if (m->actionTimer < 10) {566m->actionTimer++;567}568569if (m->floor->normal.y < 0.9063078f) {570return let_go_of_ledge(m);571}572573if (m->input & (INPUT_Z_PRESSED | INPUT_OFF_FLOOR)) {574return let_go_of_ledge(m);575}576577if ((m->input & INPUT_A_PRESSED) && hasSpaceForMario) {578return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0);579}580581if (m->input & INPUT_STOMPED) {582if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) {583m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18;584}585return let_go_of_ledge(m);586}587#ifdef VERSION_EU588// On EU, you can't slow climb up ledges while holding A.589if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG) && !(m->input & INPUT_A_DOWN))590#else591if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG))592#endif593{594if (intendedDYaw >= -0x4000 && intendedDYaw <= 0x4000) {595if (hasSpaceForMario) {596return set_mario_action(m, ACT_LEDGE_CLIMB_SLOW_1, 0);597}598} else {599return let_go_of_ledge(m);600}601}602603heightAboveFloor = m->pos[1] - find_floor_height_relative_polar(m, -0x8000, 30.0f);604if (hasSpaceForMario && heightAboveFloor < 100.0f) {605return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0);606}607608if (m->actionArg == 0) {609play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);610}611612stop_and_set_height_to_floor(m);613set_mario_animation(m, MARIO_ANIM_IDLE_ON_LEDGE);614615return FALSE;616}617618s32 act_ledge_climb_slow(struct MarioState *m) {619if (m->input & INPUT_OFF_FLOOR) {620return let_go_of_ledge(m);621}622623if (m->actionTimer >= 28624&& (m->input625& (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE))) {626climb_up_ledge(m);627return check_common_action_exits(m);628}629630if (m->actionTimer == 10) {631play_sound_if_no_flag(m, SOUND_MARIO_EEUH, MARIO_MARIO_SOUND_PLAYED);632}633634update_ledge_climb(m, MARIO_ANIM_SLOW_LEDGE_GRAB, ACT_IDLE);635636update_ledge_climb_camera(m);637if (m->marioObj->header.gfx.animInfo.animFrame == 17) {638m->action = ACT_LEDGE_CLIMB_SLOW_2;639}640641return FALSE;642}643644s32 act_ledge_climb_down(struct MarioState *m) {645if (m->input & INPUT_OFF_FLOOR) {646return let_go_of_ledge(m);647}648649play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);650651update_ledge_climb(m, MARIO_ANIM_CLIMB_DOWN_LEDGE, ACT_LEDGE_GRAB);652m->actionArg = 1;653654return FALSE;655}656657s32 act_ledge_climb_fast(struct MarioState *m) {658if (m->input & INPUT_OFF_FLOOR) {659return let_go_of_ledge(m);660}661662play_sound_if_no_flag(m, SOUND_MARIO_UH2, MARIO_MARIO_SOUND_PLAYED);663664update_ledge_climb(m, MARIO_ANIM_FAST_LEDGE_GRAB, ACT_IDLE);665666if (m->marioObj->header.gfx.animInfo.animFrame == 8) {667play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING);668}669update_ledge_climb_camera(m);670671return FALSE;672}673674s32 act_grabbed(struct MarioState *m) {675if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK2) {676s32 thrown = (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK6) == 0;677678m->faceAngle[1] = m->usedObj->oMoveAngleYaw;679vec3f_copy(m->pos, m->marioObj->header.gfx.pos);680#if ENABLE_RUMBLE681queue_rumble_data(5, 60);682#endif683684return set_mario_action(m, (m->forwardVel >= 0.0f) ? ACT_THROWN_FORWARD : ACT_THROWN_BACKWARD,685thrown);686}687688set_mario_animation(m, MARIO_ANIM_BEING_GRABBED);689return FALSE;690}691692s32 act_in_cannon(struct MarioState *m) {693struct Object *marioObj = m->marioObj;694s16 startFacePitch = m->faceAngle[0];695s16 startFaceYaw = m->faceAngle[1];696697switch (m->actionState) {698case 0:699m->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;700m->usedObj->oInteractStatus = INT_STATUS_INTERACTED;701702m->statusForCamera->cameraEvent = CAM_EVENT_CANNON;703m->statusForCamera->usedObj = m->usedObj;704705vec3f_set(m->vel, 0.0f, 0.0f, 0.0f);706707m->pos[0] = m->usedObj->oPosX;708m->pos[1] = m->usedObj->oPosY + 350.0f;709m->pos[2] = m->usedObj->oPosZ;710711m->forwardVel = 0.0f;712713m->actionState = 1;714break;715716case 1:717if (m->usedObj->oAction == 1) {718m->faceAngle[0] = m->usedObj->oMoveAnglePitch;719m->faceAngle[1] = m->usedObj->oMoveAngleYaw;720721marioObj->oMarioCannonObjectYaw = m->usedObj->oMoveAngleYaw;722marioObj->oMarioCannonInputYaw = 0;723724m->actionState = 2;725}726break;727728case 2:729if (configImprovedControls) {730m->faceAngle[0] -= (s16)((m->controller->stickY + m->controller->stick2Y) * 6.0f);731marioObj->oMarioCannonInputYaw -= (s16)((m->controller->stickX + m->controller->stick2X) * 6.0f);732}733else {734m->faceAngle[0] -= (s16)((m->controller->stickY + m->controller->stick2Y) * 10.0f);735marioObj->oMarioCannonInputYaw -= (s16)((m->controller->stickX + m->controller->stick2X) * 10.0f);736}737738if (m->faceAngle[0] > 0x38E3) {739m->faceAngle[0] = 0x38E3;740}741if (m->faceAngle[0] < 0) {742m->faceAngle[0] = 0;743}744745if (configFlexibleCannons) {746if (marioObj->oMarioCannonInputYaw > 0x10000) {747marioObj->oMarioCannonInputYaw = 0x10000;748}749if (marioObj->oMarioCannonInputYaw < -0x10000) {750marioObj->oMarioCannonInputYaw = -0x10000;751}752}753else {754if (marioObj->oMarioCannonInputYaw > 0x4000) {755marioObj->oMarioCannonInputYaw = 0x4000;756}757if (marioObj->oMarioCannonInputYaw < -0x4000) {758marioObj->oMarioCannonInputYaw = -0x4000;759}760}761762m->faceAngle[1] = marioObj->oMarioCannonObjectYaw + marioObj->oMarioCannonInputYaw;763if (m->input & INPUT_A_PRESSED) {764m->forwardVel = 100.0f * coss(m->faceAngle[0]);765766m->vel[1] = 100.0f * sins(m->faceAngle[0]);767768m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);769m->pos[1] += 120.0f * sins(m->faceAngle[0]);770m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);771772play_sound(SOUND_ACTION_FLYING_FAST, m->marioObj->header.gfx.cameraToObject);773play_sound(SOUND_OBJ_POUNDING_CANNON, m->marioObj->header.gfx.cameraToObject);774775m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;776777set_mario_action(m, ACT_SHOT_FROM_CANNON, 0);778#if ENABLE_RUMBLE779queue_rumble_data(60, 70);780#endif781m->usedObj->oAction = 2;782return FALSE;783} else if (m->faceAngle[0] != startFacePitch || m->faceAngle[1] != startFaceYaw) {784play_sound(SOUND_MOVING_AIM_CANNON, m->marioObj->header.gfx.cameraToObject);785#if ENABLE_RUMBLE786reset_rumble_timers_2(0);787#endif788}789}790791vec3f_copy(m->marioObj->header.gfx.pos, m->pos);792vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);793set_mario_animation(m, MARIO_ANIM_DIVE);794795return FALSE;796}797798s32 act_tornado_twirling(struct MarioState *m) {799struct Surface *floor;800Vec3f nextPos;801f32 sinAngleVel;802f32 cosAngleVel;803f32 floorHeight;804struct Object *marioObj = m->marioObj;805struct Object *usedObj = m->usedObj;806s16 prevTwirlYaw = m->twirlYaw;807808f32 dx = (m->pos[0] - usedObj->oPosX) * 0.95f;809f32 dz = (m->pos[2] - usedObj->oPosZ) * 0.95f;810811if (m->vel[1] < 60.0f) {812m->vel[1] += 1.0f;813}814815if ((marioObj->oMarioTornadoPosY += m->vel[1]) < 0.0f) {816marioObj->oMarioTornadoPosY = 0.0f;817}818if (marioObj->oMarioTornadoPosY > usedObj->hitboxHeight) {819if (m->vel[1] < 20.0f) {820m->vel[1] = 20.0f;821}822return set_mario_action(m, ACT_TWIRLING, 1);823}824825if (m->angleVel[1] < 0x3000) {826m->angleVel[1] += 0x100;827}828829if (marioObj->oMarioTornadoYawVel < 0x1000) {830marioObj->oMarioTornadoYawVel += 0x100;831}832833m->twirlYaw += m->angleVel[1];834835sinAngleVel = sins(marioObj->oMarioTornadoYawVel);836cosAngleVel = coss(marioObj->oMarioTornadoYawVel);837838nextPos[0] = usedObj->oPosX + dx * cosAngleVel + dz * sinAngleVel;839nextPos[2] = usedObj->oPosZ - dx * sinAngleVel + dz * cosAngleVel;840nextPos[1] = usedObj->oPosY + marioObj->oMarioTornadoPosY;841842f32_find_wall_collision(&nextPos[0], &nextPos[1], &nextPos[2], 60.0f, 50.0f);843844floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);845if (floor != NULL) {846m->floor = floor;847m->floorHeight = floorHeight;848vec3f_copy(m->pos, nextPos);849} else {850if (nextPos[1] >= m->floorHeight) {851m->pos[1] = nextPos[1];852} else {853m->pos[1] = m->floorHeight;854}855}856857m->actionTimer++;858859set_mario_animation(m, (m->actionArg == 0) ? MARIO_ANIM_START_TWIRL : MARIO_ANIM_TWIRL);860861if (is_anim_past_end(m)) {862m->actionArg = 1;863}864865// Play sound on angle overflow866if (prevTwirlYaw > m->twirlYaw) {867play_sound(SOUND_ACTION_TWIRL, m->marioObj->header.gfx.cameraToObject);868}869870vec3f_copy(m->marioObj->header.gfx.pos, m->pos);871vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1] + m->twirlYaw, 0);872#if ENABLE_RUMBLE873reset_rumble_timers();874#endif875876return FALSE;877}878879s32 check_common_automatic_cancels(struct MarioState *m) {880if (m->pos[1] < m->waterLevel - 100) {881return set_water_plunge_action(m);882}883884return FALSE;885}886887s32 mario_execute_automatic_action(struct MarioState *m) {888s32 cancel;889890if (check_common_automatic_cancels(m)) {891return TRUE;892}893894m->quicksandDepth = 0.0f;895896/* clang-format off */897switch (m->action) {898case ACT_HOLDING_POLE: cancel = act_holding_pole(m); break;899case ACT_GRAB_POLE_SLOW: cancel = act_grab_pole_slow(m); break;900case ACT_GRAB_POLE_FAST: cancel = act_grab_pole_fast(m); break;901case ACT_CLIMBING_POLE: cancel = act_climbing_pole(m); break;902case ACT_TOP_OF_POLE_TRANSITION: cancel = act_top_of_pole_transition(m); break;903case ACT_TOP_OF_POLE: cancel = act_top_of_pole(m); break;904case ACT_START_HANGING: cancel = act_start_hanging(m); break;905case ACT_HANGING: cancel = act_hanging(m); break;906case ACT_HANG_MOVING: cancel = act_hang_moving(m); break;907case ACT_LEDGE_GRAB: cancel = act_ledge_grab(m); break;908case ACT_LEDGE_CLIMB_SLOW_1: cancel = act_ledge_climb_slow(m); break;909case ACT_LEDGE_CLIMB_SLOW_2: cancel = act_ledge_climb_slow(m); break;910case ACT_LEDGE_CLIMB_DOWN: cancel = act_ledge_climb_down(m); break;911case ACT_LEDGE_CLIMB_FAST: cancel = act_ledge_climb_fast(m); break;912case ACT_GRABBED: cancel = act_grabbed(m); break;913case ACT_IN_CANNON: cancel = act_in_cannon(m); break;914case ACT_TORNADO_TWIRLING: cancel = act_tornado_twirling(m); break;915}916/* clang-format on */917918return cancel;919}920921922