#include "common.h" #include "world/partners.h" extern f32 GravityParamsStartJump[]; extern f32 D_8010C928; extern f32 JumpedOnSwitchX; extern f32 JumpedOnSwitchZ; extern f32 D_8010C984; s32 collision_check_player_intersecting_world(s32 mode, s32 arg1, f32 yaw); s32 phys_check_interactable_collision(void); void phys_save_ground_pos(void); void record_jump_apex(void) { gPlayerStatus.jumpApexHeight = gPlayerStatus.position.y; } s32 can_trigger_loading_zone(void) { PlayerData* playerData = &gPlayerData; s32 actionState = gPlayerStatusPtr->actionState; PartnerActionStatus* partnerActionStatus = &gPartnerActionStatus; if (actionState == ACTION_STATE_IDLE || actionState == ACTION_STATE_WALK || actionState == ACTION_STATE_RUN || actionState == ACTION_STATE_USE_TWEESTER || actionState == ACTION_STATE_SPIN ) { return TRUE; } if (actionState == ACTION_STATE_RIDE) { if (playerData->currentPartner == PARTNER_LAKILESTER || playerData->currentPartner == PARTNER_BOW) { if (partnerActionStatus->partnerActionState != PARTNER_ACTION_NONE) { return TRUE; } else { gPlayerStatusPtr->animFlags |= PA_FLAG_INTERRUPT_USE_PARTNER; return FALSE; } } else { if (partnerActionStatus->actingPartner == PARTNER_WATT || partnerActionStatus->actingPartner == PARTNER_SUSHIE) { return partnerActionStatus->partnerActionState != PARTNER_ACTION_NONE; } if (partnerActionStatus->actingPartner == PARTNER_PARAKARRY) { gPlayerStatusPtr->animFlags |= PA_FLAG_INTERRUPT_USE_PARTNER; return FALSE; } } } return FALSE; } void move_player(s32 duration, f32 heading, f32 speed) { gPlayerStatus.flags |= PS_FLAG_CUTSCENE_MOVEMENT; gPlayerStatus.heading = heading; gPlayerStatus.moveFrames = duration; gPlayerStatus.currentSpeed = speed; if (!(gPlayerStatus.animFlags & PA_FLAG_RIDING_PARTNER)) { set_action_state(speed > gPlayerStatus.walkSpeed ? ACTION_STATE_RUN : ACTION_STATE_WALK); } } s32 collision_main_above(void) { PlayerStatus* playerStatus = &gPlayerStatus; CollisionStatus* collisionStatus = &gCollisionStatus; f32 x, y, z; f32 new_var; f32 moveAngle; f32 moveMagnitude; f32 sp2C; s32 hitResult; f32 phi_f2; new_var = sp2C = playerStatus->colliderHeight * 0.5f; x = playerStatus->position.x; y = playerStatus->position.y + new_var; z = playerStatus->position.z; player_input_to_move_vector(&moveAngle, &moveMagnitude); if (moveMagnitude != 0.0f) { phi_f2 = playerStatus->targetYaw; } else { phi_f2 = playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw; } moveAngle = phi_f2; hitResult = player_raycast_up_corners(playerStatus, &x, &y, &z, &sp2C, moveAngle); collisionStatus->currentCeiling = hitResult; if (hitResult >= 0) { if (playerStatus->actionState != ACTION_STATE_FALLING && playerStatus->actionState != ACTION_STATE_STEP_DOWN && collisionStatus->currentFloor < 0 ) { if (sp2C <= fabsf(new_var + playerStatus->gravityIntegrator[0])) { do { if ((hitResult & COLLISION_WITH_ENTITY_BIT) && get_entity_type(hitResult) == ENTITY_TYPE_BRICK_BLOCK) { return hitResult; } } while (0); playerStatus->position.y = y - ((playerStatus->colliderHeight / 5.0f) * 3.0f); if (playerStatus->actionState != ACTION_STATE_TORNADO_JUMP && playerStatus->actionState != ACTION_STATE_SPIN_JUMP ) { playerStatus->gravityIntegrator[0] = 0.0f; playerStatus->gravityIntegrator[1] = 0.0f; playerStatus->gravityIntegrator[2] = 0.0f; playerStatus->gravityIntegrator[3] = 0.0f; } } } } return hitResult; } void handle_switch_hit(void) { PlayerStatus* playerStatus = &gPlayerStatus; s32 colliderID; f32 groundPosY; AnimID anim; if (playerStatus->flags & PS_FLAG_ACTION_STATE_CHANGED) { playerStatus->flags &= ~PS_FLAG_ACTION_STATE_CHANGED; playerStatus->actionSubstate = LANDING_ON_SWITCH_SUBSTATE_0; } if (playerStatus->actionSubstate == LANDING_ON_SWITCH_SUBSTATE_0) { if (dist2D(JumpedOnSwitchX, JumpedOnSwitchZ, playerStatus->position.x, playerStatus->position.z) <= 22.0f) { add_vec2D_polar(&playerStatus->position.x, &playerStatus->position.z, 5.0f, playerStatus->targetYaw); } integrate_gravity(); if (playerStatus->gravityIntegrator[0] <= 0.0f) { record_jump_apex(); gravity_use_fall_parms(); integrate_gravity(); playerStatus->actionSubstate = LANDING_ON_SWITCH_SUBSTATE_1; } if (playerStatus->gravityIntegrator[0] > playerStatus->maxJumpSpeed) { playerStatus->gravityIntegrator[0] = playerStatus->maxJumpSpeed; } playerStatus->position.y += playerStatus->gravityIntegrator[0]; } else if (playerStatus->actionSubstate == LANDING_ON_SWITCH_SUBSTATE_2) { if (dist2D(JumpedOnSwitchX, JumpedOnSwitchZ, playerStatus->position.x, playerStatus->position.z) <= 22.0f) { add_vec2D_polar(&playerStatus->position.x, &playerStatus->position.z, 5.0f, playerStatus->targetYaw); } groundPosY = player_check_collision_below(player_fall_distance(), &colliderID); player_handle_floor_collider_type(colliderID); playerStatus->position.y = groundPosY; if (colliderID >= 0) { if (!(playerStatus->animFlags & PA_FLAG_USING_WATT)) { anim = ANIM_Mario1_Land; } else { anim = ANIM_MarioW1_LandWatt; } suggest_player_anim_allow_backward(anim); enable_player_input(); phys_player_land(); } } } void func_800E2BB0(void) { PlayerStatus* playerStatus = &gPlayerStatus; s32 cond = FALSE; if (playerStatus->position.y < playerStatus->gravityIntegrator[3] + playerStatus->gravityIntegrator[2]) { f32 phi_f6 = (playerStatus->gravityIntegrator[3] - playerStatus->position.y) / 777.0f; if (phi_f6 < -0.47) { phi_f6 = -0.47f; } if (phi_f6 > 0.001) { phi_f6 = 0.001f; } playerStatus->gravityIntegrator[0] += phi_f6; playerStatus->position.y += playerStatus->gravityIntegrator[0]; if (playerStatus->gravityIntegrator[0] <= 0.0f) { cond = TRUE; } } else { playerStatus->gravityIntegrator[0] += -1.2; if (playerStatus->gravityIntegrator[0] <= 0.0f) { cond = TRUE; } playerStatus->position.y += playerStatus->gravityIntegrator[0]; } if (cond) { record_jump_apex(); LOAD_INTEGRATOR_FALL(playerStatus->gravityIntegrator); set_action_state(ACTION_STATE_FALLING); } } void phys_update_jump(void) { PlayerStatus* playerStatus = &gPlayerStatus; if (playerStatus->timeInAir != 0) { switch (playerStatus->actionState) { case ACTION_STATE_LAUNCH: func_800E2BB0(); return; case ACTION_STATE_LANDING_ON_SWITCH: handle_switch_hit(); return; case ACTION_STATE_BOUNCE: integrate_gravity(); playerStatus->position.y += playerStatus->gravityIntegrator[0]; if (playerStatus->gravityIntegrator[0] <= 0.0f) { record_jump_apex(); if (is_starting_conversation()) { playerStatus->gravityIntegrator[0] = 0.154343f; playerStatus->gravityIntegrator[1] = -0.35008f; playerStatus->gravityIntegrator[2] = 0.0f; playerStatus->gravityIntegrator[3] = 0.0f; } else { gravity_use_fall_parms(); } integrate_gravity(); set_action_state(ACTION_STATE_FALLING); } return; case ACTION_STATE_HOP: playerStatus->gravityIntegrator[0] -= 4.5; playerStatus->position.y += playerStatus->gravityIntegrator[0]; if (playerStatus->gravityIntegrator[0] <= 0.0f) { record_jump_apex(); gravity_use_fall_parms(); integrate_gravity(); set_action_state(ACTION_STATE_FALLING); } return; case ACTION_STATE_HIT_FIRE: case ACTION_STATE_HIT_LAVA: return; default: if (!(playerStatus->currentButtons & BUTTON_A)) { record_jump_apex(); set_action_state(ACTION_STATE_HOP); integrate_gravity(); if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) { playerStatus->gravityIntegrator[1] *= 0.5f; playerStatus->gravityIntegrator[2] *= 0.5f; playerStatus->gravityIntegrator[3] *= 0.5f; } } break; } } integrate_gravity(); if (playerStatus->gravityIntegrator[0] <= 0.0f) { record_jump_apex(); gravity_use_fall_parms(); integrate_gravity(); set_action_state(ACTION_STATE_FALLING); } if (playerStatus->gravityIntegrator[0] > playerStatus->maxJumpSpeed) { playerStatus->gravityIntegrator[0] = playerStatus->maxJumpSpeed; } playerStatus->position.y += playerStatus->gravityIntegrator[0]; } void phys_init_integrator_for_current_state(void) { PlayerStatus* playerStatus = &gPlayerStatus; f32* params; switch (playerStatus->actionState) { case ACTION_STATE_LANDING_ON_SWITCH: playerStatus->gravityIntegrator[0] = 10.0f; playerStatus->gravityIntegrator[1] = -5.0f; playerStatus->gravityIntegrator[2] = 1.5f; playerStatus->gravityIntegrator[3] = -0.3f; break; case ACTION_STATE_JUMP: case ACTION_STATE_SPIN_JUMP: case ACTION_STATE_SPIN_POUND: case ACTION_STATE_TORNADO_JUMP: case ACTION_STATE_TORNADO_POUND: case ACTION_STATE_HIT_FIRE: case ACTION_STATE_HIT_LAVA: params = GravityParamsStartJump; if (!(playerStatus->flags & PS_FLAG_ENTERING_BATTLE)) { playerStatus->gravityIntegrator[0] = *params++; playerStatus->gravityIntegrator[1] = *params++; playerStatus->gravityIntegrator[2] = *params++; playerStatus->gravityIntegrator[3] = *params++; } else { playerStatus->gravityIntegrator[0] = *params++ * 0.5f; playerStatus->gravityIntegrator[1] = *params++ * 0.5f; playerStatus->gravityIntegrator[2] = *params++ * 0.5f; playerStatus->gravityIntegrator[3] = *params++ * 0.5f; } break; } } static const f32 padding = 0.0f; // This function is wack. This weird stuff is needed to match void gravity_use_fall_parms(void) { f32* params = GravityParamsStartFall; PlayerStatus* playerStatus; do {} while (0); playerStatus = &gPlayerStatus; if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) { playerStatus->gravityIntegrator[0] = *params++ / 12.0f; playerStatus->gravityIntegrator[1] = *params++ / 12.0f; playerStatus->gravityIntegrator[2] = *params++ / 12.0f; playerStatus->gravityIntegrator[3] = *params++ / 12.0f; } else { playerStatus->gravityIntegrator[0] = *params++; playerStatus->gravityIntegrator[1] = *params++; playerStatus->gravityIntegrator[2] = *params++; playerStatus->gravityIntegrator[3] = *params++; } } void phys_update_falling(void) { if (gPlayerStatus.actionState != ACTION_STATE_LANDING_ON_SWITCH && gPlayerStatus.actionState != ACTION_STATE_BOUNCE ) { s32 colliderID; gPlayerStatus.position.y = player_check_collision_below(player_fall_distance(), &colliderID); player_handle_floor_collider_type(colliderID); } } void player_handle_floor_collider_type(s32 colliderID) { PlayerStatus* playerStatus = &gPlayerStatus; PartnerActionStatus* partnerActionStatus = &gPartnerActionStatus; if (colliderID >= 0) { s32 surfaceType = get_collider_flags(colliderID) & COLLIDER_FLAGS_SURFACE_TYPE_MASK; switch (surfaceType) { case SURFACE_TYPE_WATER: case SURFACE_TYPE_DOCK_WALL: case SURFACE_TYPE_SLIDE: set_action_state(ACTION_STATE_LAND); break; case SURFACE_TYPE_LAVA: if ((*(s32*)(&partnerActionStatus->partnerActionState) & 0xFF0000FF) != 0x01000009) { if (playerStatus->blinkTimer == 0) { if (playerStatus->actionState != ACTION_STATE_HIT_LAVA) { playerStatus->hazardType = HAZARD_TYPE_LAVA; set_action_state(ACTION_STATE_HIT_LAVA); } } else { set_action_state(ACTION_STATE_KNOCKBACK); } } break; case SURFACE_TYPE_SPIKES: if ((*(s32*)(&partnerActionStatus->partnerActionState) & 0xFF0000FF) != 0x01000009) { if (playerStatus->blinkTimer == 0) { if (playerStatus->actionState != ACTION_STATE_HIT_FIRE) { playerStatus->hazardType = HAZARD_TYPE_SPIKES; set_action_state(ACTION_STATE_HIT_LAVA); } break; } set_action_state(ACTION_STATE_KNOCKBACK); } break; default: phys_player_land(); break; } } } void phys_player_land(void) { PlayerStatus* playerStatus = &gPlayerStatus; CollisionStatus* collisionStatus = &gCollisionStatus; f32 moveAngle; f32 moveMagnitude; playerStatus->timeInAir = 0; playerStatus->peakJumpTime = 0; playerStatus->flags &= ~PS_FLAG_SCRIPTED_FALL; playerStatus->landPos.x = playerStatus->position.x; playerStatus->landPos.z = playerStatus->position.z; playerStatus->flags &= ~PS_FLAG_AIRBORNE; sfx_play_sound_at_player(SOUND_SOFT_LAND, SOUND_SPACE_MODE_0); if (!(collisionStatus->currentFloor & COLLISION_WITH_ENTITY_BIT)) { phys_adjust_cam_on_landing(); } collisionStatus->lastTouchedFloor = -1; if (collisionStatus->currentFloor & COLLISION_WITH_ENTITY_BIT) { s32 entityType = get_entity_type(collisionStatus->currentFloor); if (entityType <= ACTION_STATE_FALLING) { if (entityType >= ACTION_STATE_LANDING_ON_SWITCH) { Entity* entity = get_entity_by_index(collisionStatus->currentFloor); entity->collisionFlags |= ENTITY_COLLISION_PLAYER_TOUCH_FLOOR; if (playerStatus->actionState != ACTION_STATE_TORNADO_JUMP && playerStatus->actionState != ACTION_STATE_TORNADO_POUND && playerStatus->actionState != ACTION_STATE_SPIN_JUMP && playerStatus->actionState != ACTION_STATE_SPIN_POUND ) { set_action_state(ACTION_STATE_LANDING_ON_SWITCH); } else { disable_player_input(); playerStatus->actionSubstate = 11; } return; } } } if (playerStatus->flags & PS_FLAG_CUTSCENE_MOVEMENT) { set_action_state(ACTION_STATE_RUN); return; } if (playerStatus->actionState == ACTION_STATE_LANDING_ON_SWITCH) { set_action_state(ACTION_STATE_BOUNCE_OFF_SWITCH); return; } player_input_to_move_vector(&moveAngle, &moveMagnitude); if (moveMagnitude == 0.0f) { if (playerStatus->actionState != ACTION_STATE_STEP_DOWN) { set_action_state(ACTION_STATE_LAND); } else { set_action_state(ACTION_STATE_STEP_DOWN_LAND); } return; } if (moveMagnitude != 0.0f) { playerStatus->targetYaw = moveAngle; } update_locomotion_state(); } f32 integrate_gravity(void) { PlayerStatus* playerStatus = &gPlayerStatus; if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) { playerStatus->gravityIntegrator[2] += playerStatus->gravityIntegrator[3] / 1.7f; playerStatus->gravityIntegrator[1] += playerStatus->gravityIntegrator[2] / 1.7f; playerStatus->gravityIntegrator[0] += playerStatus->gravityIntegrator[1] / 1.7f; } else { playerStatus->gravityIntegrator[2] += playerStatus->gravityIntegrator[3]; playerStatus->gravityIntegrator[1] += playerStatus->gravityIntegrator[2]; playerStatus->gravityIntegrator[0] += playerStatus->gravityIntegrator[1]; } return playerStatus->gravityIntegrator[0]; } f32 player_fall_distance(void) { f32 velocity = integrate_gravity(); if (game_scripts_disabled()) { velocity = 0.0f; } return velocity; } f32 player_check_collision_below(f32 offset, s32* colliderID) { PlayerStatus* playerStatus = &gPlayerStatus; CollisionStatus* collisionStatus = &gCollisionStatus; f32 temp_f4 = playerStatus->colliderHeight * 0.5f; f32 outLength = fabsf(offset) + temp_f4; f32 x = playerStatus->position.x; f32 y = playerStatus->position.y + temp_f4; f32 z = playerStatus->position.z; f32 sp38, sp3C, sp40, sp44; s32 hit = *colliderID = player_raycast_below_cam_relative(&gPlayerStatus, &x, &y, &z, &outLength, &sp38, &sp3C, &sp40, &sp44); if (hit < 0) { if (offset >= 0.0f && collisionStatus->currentCeiling >= 0) { return playerStatus->position.y; } y = playerStatus->position.y + offset; } else { collisionStatus->currentFloor = hit; collisionStatus->lastTouchedFloor = -1; } return y; } void collision_main_lateral(void) { PlayerStatus* playerStatus = &gPlayerStatus; CollisionStatus* collisionStatus = &gCollisionStatus; f32 playerX, playerY, playerZ; f32 test1X, test1Y, test1Z; f32 test2X, test2Y, test2Z; f32 yaw; f32 yaw2; f32 speed; f32 sinTheta; f32 cosTheta; s32 result; s32 test1; s32 test2; f32 xBump; f32 zBump; gCollisionStatus.pushingAgainstWall = NO_COLLIDER; if (playerStatus->flags & PS_FLAG_CUTSCENE_MOVEMENT) { speed = playerStatus->currentSpeed; if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) { speed *= 0.5f; } add_vec2D_polar(&playerStatus->position.x, &playerStatus->position.z, speed, playerStatus->heading); return; } switch (playerStatus->actionState) { case ACTION_STATE_STEP_UP: collision_check_player_intersecting_world(0, 0, playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw); break; case ACTION_STATE_RIDE: if (get_current_partner_id() == PARTNER_BOW) { playerStatus->position.x += playerStatus->pushVelocity.x; playerStatus->position.y += playerStatus->pushVelocity.y; playerStatus->position.z += playerStatus->pushVelocity.z; if (playerStatus->pushVelocity.x != 0.0f || playerStatus->pushVelocity.y != 0.0f || playerStatus->pushVelocity.z != 0.0f) { gCameras[CAM_DEFAULT].targetPos.x = playerStatus->position.x; gCameras[CAM_DEFAULT].targetPos.y = playerStatus->position.y; gCameras[CAM_DEFAULT].targetPos.z = playerStatus->position.z; if (playerStatus->alpha1 != 128) { collision_check_player_intersecting_world(0, 0, atan2(0.0f, 0.0f, playerStatus->pushVelocity.x, playerStatus->pushVelocity.z)); } } } break; case ACTION_STATE_SPIN_POUND: case ACTION_STATE_TORNADO_POUND: playerStatus->position.x += playerStatus->pushVelocity.x; playerStatus->position.y += playerStatus->pushVelocity.y; playerStatus->position.z += playerStatus->pushVelocity.z; if (playerStatus->pushVelocity.x != 0.0f || playerStatus->pushVelocity.y != 0.0f || playerStatus->pushVelocity.z != 0.0f) { gCameras[CAM_DEFAULT].targetPos.x = playerStatus->position.x; gCameras[CAM_DEFAULT].targetPos.y = playerStatus->position.y; gCameras[CAM_DEFAULT].targetPos.z = playerStatus->position.z; } if (playerStatus->pushVelocity.x != 0.0f || playerStatus->pushVelocity.y != 0.0f || playerStatus->pushVelocity.z != 0.0f) { collision_check_player_intersecting_world(0, 0, playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw); } break; case ACTION_STATE_HAMMER: playerStatus->position.x += playerStatus->pushVelocity.x; playerStatus->position.y += playerStatus->pushVelocity.y; playerStatus->position.z += playerStatus->pushVelocity.z; if (playerStatus->pushVelocity.x != 0.0f || playerStatus->pushVelocity.y != 0.0f || playerStatus->pushVelocity.z != 0.0f) { gCameras[CAM_DEFAULT].targetPos.x = playerStatus->position.x; gCameras[CAM_DEFAULT].targetPos.y = playerStatus->position.y; gCameras[CAM_DEFAULT].targetPos.z = playerStatus->position.z; } playerX = playerStatus->position.x; playerY = playerStatus->position.y; playerZ = playerStatus->position.z; if (playerStatus->currentSpeed != 0.0f) { yaw = playerStatus->targetYaw; } else { yaw = playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw; } collisionStatus->currentWall = player_test_move_with_slipping(playerStatus, &playerX, &playerY, &playerZ, playerStatus->colliderDiameter * 0.5f, yaw); if (playerStatus->pushVelocity.x != 0.0f || playerStatus->pushVelocity.y != 0.0f || playerStatus->pushVelocity.z != 0.0f) { collision_check_player_intersecting_world(0, 0, playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw); } break; default: if (!(playerStatus->flags & PS_FLAG_FLYING)) { f32 new_var; speed = 0.0f; if (!(playerStatus->flags & (PS_FLAG_SCRIPTED_FALL | PS_FLAG_INPUT_DISABLED))) { player_input_to_move_vector(&yaw, &speed); if (!(playerStatus->animFlags & PA_FLAG_SPINNING)) { speed *= 0.03125f; if (!(playerStatus->flags & (PS_FLAG_FALLING | PS_FLAG_JUMPING))) { speed *= 0.25; } if (playerStatus->actionState == ACTION_STATE_LAUNCH) { speed *= 1.5; } if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) { speed *= 0.5f; } } sin_cos_rad(DEG_TO_RAD(yaw), &sinTheta, &cosTheta); if (playerStatus->actionState == ACTION_STATE_PUSHING_BLOCK) { if (fabsf(sinTheta) > fabsf(cosTheta)) { xBump = speed * sinTheta; zBump = 0.0f; } else { xBump = 0.0f; zBump = -speed * cosTheta; } } else if (!(playerStatus->animFlags & PA_FLAG_SPINNING)) { xBump = speed * sinTheta; zBump = -speed * cosTheta; } else { xBump = 0.0f; zBump = 0.0f; } sin_cos_rad(DEG_TO_RAD(playerStatus->targetYaw), &sinTheta, &cosTheta); speed = playerStatus->currentSpeed; if (playerStatus->flags & PS_FLAG_ENTERING_BATTLE) { speed *= 0.5f; } playerX = xBump + (speed * sinTheta); playerZ = zBump - (speed * cosTheta); yaw = atan2(0.0f, 0.0f, playerX, playerZ); speed = sqrtf(SQ(playerX) + SQ(playerZ)); if (playerStatus->flags & (PS_FLAG_FALLING | PS_FLAG_JUMPING)) { if (speed > playerStatus->runSpeed) { speed = playerStatus->runSpeed; } } } playerStatus->position.x += playerStatus->pushVelocity.x; playerStatus->position.z += playerStatus->pushVelocity.z; if (playerStatus->timeInAir == 0) { playerStatus->position.y += playerStatus->pushVelocity.y; } if ( playerStatus->pushVelocity.x != 0.0f || playerStatus->pushVelocity.y != 0.0f || playerStatus->pushVelocity.z != 0.0f) { gCameras[CAM_DEFAULT].targetPos.x = playerStatus->position.x; gCameras[CAM_DEFAULT].targetPos.y = playerStatus->position.y; gCameras[CAM_DEFAULT].targetPos.z = playerStatus->position.z; } playerX = playerStatus->position.x; playerY = playerStatus->position.y; playerZ = playerStatus->position.z; result = player_test_move_with_slipping(playerStatus, &playerX, &playerY, &playerZ, playerStatus->colliderDiameter * 0.5f, playerStatus->targetYaw); if (speed == 0.0f && result < 0) { yaw2 = playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw; sin_cos_rad(DEG_TO_RAD(yaw2 + 180.0f), &sinTheta, &cosTheta); playerX = playerStatus->position.x + (sinTheta * playerStatus->colliderDiameter * 0.5f); playerY = playerStatus->position.y; playerZ = playerStatus->position.z - (cosTheta * playerStatus->colliderDiameter * 0.5f); result = player_test_move_with_slipping(playerStatus, &playerX, &playerY, &playerZ, playerStatus->colliderDiameter, yaw2); } collisionStatus->currentWall = result; if (!(playerStatus->flags & PS_FLAG_MOVEMENT_LOCKED) && playerStatus->actionState != ACTION_STATE_HAMMER) { if (speed == 0.0f) { collision_check_player_intersecting_world(0, 0, playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw); break; } playerX = playerStatus->position.x; playerZ = playerStatus->position.z; playerY = playerStatus->position.y; yaw2 = yaw; if (speed > 4.0f) { result = player_test_move_with_slipping(playerStatus, &playerX, &playerY, &playerZ, 4.0f, yaw2); if (result < 0) { result = player_test_move_with_slipping(playerStatus, &playerX, &playerY, &playerZ, speed - 4.0f, yaw2); } collisionStatus->pushingAgainstWall = result; } else { collisionStatus->pushingAgainstWall = player_test_move_with_slipping(playerStatus, &playerX, &playerY, &playerZ, speed, yaw2); } test1X = playerX; test1Y = playerY; test1Z = playerZ; yaw = clamp_angle(yaw2 - 35.0); test1 = player_test_lateral_overlap(0, playerStatus, &test1X, &test1Y, &test1Z, 0.0f, yaw); test2X = playerX; test2Z = playerY; test2Y = playerZ; yaw = clamp_angle(yaw2 + 35.0); test2 = player_test_lateral_overlap(0, playerStatus, &test2X, &test2Z, &test2Y, 0.0f, yaw); if (test1 < 0) { if (test2 < 0) { playerStatus->position.x = playerX; playerStatus->position.z = playerZ; } else { playerStatus->position.x = test1X; playerStatus->position.z = test1Z; } } else if (test2 < 0) { playerStatus->position.x = test2X; playerStatus->position.z = test2Y; } if (playerStatus->enableCollisionOverlapsCheck == 0) { if (playerStatus->animFlags & PA_FLAG_SPINNING) { yaw2 = playerStatus->targetYaw; } else { yaw2 = playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw; } if (collision_check_player_intersecting_world(0, 0, yaw2) < 0) { collision_check_player_intersecting_world(1, playerStatus->colliderHeight * 0.75f, yaw2); } } } } break; case ACTION_STATE_LANDING_ON_SWITCH: case ACTION_STATE_LAND: case ACTION_STATE_STEP_DOWN_LAND: case ACTION_STATE_TORNADO_JUMP: case ACTION_STATE_SLIDING: case ACTION_STATE_HIT_FIRE: case ACTION_STATE_HIT_LAVA: case ACTION_STATE_USE_SNEAKY_PARASOL: case ACTION_STATE_USE_SPRING: break; } } s32 collision_check_player_intersecting_world(s32 mode, s32 arg1, f32 yaw) { f32 angle = 0.0f; s32 ret = -1; s32 i; for (i = 0; i < 4; i++) { f32 x = gPlayerStatusPtr->position.x; f32 y = gPlayerStatusPtr->position.y + arg1; f32 z = gPlayerStatusPtr->position.z; s32 hitID, hitID2; hitID = player_test_lateral_overlap(mode, gPlayerStatusPtr, &x, &y, &z, 0.0f, angle); // required to match if (hitID > 0 || hitID == 0) { hitID2 = hitID; } else if (hitID == -1) { hitID2 = hitID; } else { hitID2 = hitID; } if (hitID2 >= 0) { ret = hitID2; } gPlayerStatusPtr = gPlayerStatusPtr; gPlayerStatusPtr->position.x = x; gPlayerStatusPtr->position.z = z; angle += 90.0f; } return ret; } s32 func_800E4404(s32 mode, s32 arg1, f32 arg2, f32* outX, f32* outY, f32* outZ) { f32 angle = 0.0f; s32 ret = -1; s32 i; for (i = 0; i < 4; i++) { f32 x = *outX; f32 y = *outY + arg1; f32 z = *outZ; s32 hitID = player_test_lateral_overlap(mode, gPlayerStatusPtr, &x, &y, &z, 0, angle); if (hitID >= 0) { ret = hitID; } *outX = x; *outZ = z; angle += 90.0f; } return ret; } void collision_check_player_overlaps(void) { PlayerStatus* playerStatus = &gPlayerStatus; f32 overlapPush = playerStatus->overlapPushAmount; if (overlapPush != 0.0f) { f32 x = playerStatus->position.x; f32 y = playerStatus->position.y; f32 z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, overlapPush, playerStatus->overlapPushYaw); overlapPush -= playerStatus->runSpeed / 10.0f; playerStatus->position.x = x; playerStatus->position.y = y; playerStatus->position.z = z; if (overlapPush < 0.0f) { overlapPush = 0.0f; } playerStatus->overlapPushAmount = overlapPush; } } s32 phys_should_player_be_sliding(void) { PlayerStatus* playerStatus = &gPlayerStatus; Shadow* shadow = get_shadow_by_index(playerStatus->shadowID); s32 ret = FALSE; if (gGameStatusPtr->areaID == AREA_IWA) { f32 temp_f0 = shadow->rotation.z + 180.0; if (temp_f0 != 0.0f) { ret = TRUE; switch (gGameStatusPtr->mapID) { case 0: if (fabsf(temp_f0) < 20.0f) { ret = FALSE; } break; case 1: if (playerStatus->position.x >= -300.0f && playerStatus->position.x <= -140.0f) { ret = FALSE; } break; } } } return ret; } s32 phys_is_on_sloped_ground(void) { Shadow* playerShadow = get_shadow_by_index(gPlayerStatus.shadowID); f32 rotZ = playerShadow->rotation.z + 180.0; f32 rotX = playerShadow->rotation.x + 180.0; s32 ret = TRUE; if (fabsf(rotZ) < 20.0f && fabsf(rotX) < 20.0f) { ret = FALSE; } return ret; } void phys_main_collision_below(void) { PlayerStatus* playerStatus = &gPlayerStatus; PartnerActionStatus* partnerActionStatus = &gPartnerActionStatus; CollisionStatus* collisionStatus = &gCollisionStatus; f32 collHeightHalf = playerStatus->colliderHeight * 0.5f; f32 playerX = playerStatus->position.x; f32 playerY = playerStatus->position.y + collHeightHalf; f32 playerZ = playerStatus->position.z; f32 outLength = playerStatus->colliderHeight; f32 temp_f24 = (2.0f * playerStatus->colliderHeight) / 7.0f; f32 hitRx, hitRz; f32 hitDirX, hitDirZ; s32 colliderID; s32 cond; colliderID = player_raycast_below_cam_relative(playerStatus, &playerX, &playerY, &playerZ, &outLength, &hitRx, &hitRz, &hitDirX, &hitDirZ); playerStatus->groundNormalPitch = get_player_normal_pitch(); if (collHeightHalf + (temp_f24 * 0.5f) < outLength) { colliderID = NO_COLLIDER; } if (playerStatus->timeInAir == 0) { collisionStatus->currentFloor = colliderID; } if (colliderID >= 0) { playerStatus->groundAnglesXZ.x = hitDirX; playerStatus->groundAnglesXZ.y = hitDirZ; } if (game_scripts_disabled()) { return; } if (playerStatus->flags & PS_FLAG_AIRBORNE) { return; } if (playerStatus->actionState == ACTION_STATE_SLIDING) { return; } if ((!(playerStatus->flags & PS_FLAG_SLIDING) || (phys_adjust_cam_on_landing(), !phys_should_player_be_sliding()) || (set_action_state(ACTION_STATE_SLIDING), (playerStatus->actionState != ACTION_STATE_SLIDING)))) { if (colliderID >= 0) { s32 surfaceType = get_collider_flags(colliderID) & COLLIDER_FLAGS_SURFACE_TYPE_MASK; switch (surfaceType) { case SURFACE_TYPE_SPIKES: if (partnerActionStatus->partnerActionState == PARTNER_ACTION_NONE || partnerActionStatus->actingPartner != PARTNER_BOW) { if (playerStatus->blinkTimer == 0) { if (playerStatus->actionState != ACTION_STATE_HIT_LAVA) { playerStatus->hazardType = HAZARD_TYPE_SPIKES; set_action_state(ACTION_STATE_HIT_LAVA); } } else { set_action_state(ACTION_STATE_KNOCKBACK); } } break; case SURFACE_TYPE_LAVA: if (partnerActionStatus->partnerActionState == PARTNER_ACTION_NONE || partnerActionStatus->actingPartner != PARTNER_BOW) { if (playerStatus->blinkTimer == 0) { if (playerStatus->actionState != ACTION_STATE_HIT_LAVA) { playerStatus->hazardType = HAZARD_TYPE_LAVA; set_action_state(ACTION_STATE_HIT_LAVA); } } else { set_action_state(ACTION_STATE_KNOCKBACK); } } break; default: cond = FALSE; if (collisionStatus->currentFloor & COLLISION_WITH_ENTITY_BIT) { cond = get_entity_type(collisionStatus->currentFloor) == ENTITY_TYPE_HIDDEN_PANEL; } if (playerStatus->actionState != ACTION_STATE_STEP_UP && !cond) { if (!(playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS)) { if (playerY - playerStatus->position.y < 6.0f) { playerStatus->position.y = playerY; } else { set_action_state(ACTION_STATE_STEP_UP); D_8010C928 = playerY; D_8010C984 = playerStatus->targetYaw; } } else { playerStatus->position.y = playerY; } phys_save_ground_pos(); } break; } } else if (!(playerStatus->flags & PS_FLAG_FLYING) && playerStatus->actionState != ACTION_STATE_USE_SPINNING_FLOWER ) { if (outLength <= collHeightHalf + temp_f24 && hitDirX == 0.0f && hitDirZ == 0.0f) { set_action_state(ACTION_STATE_STEP_DOWN); } else { set_action_state(ACTION_STATE_FALLING); } gravity_use_fall_parms(); } } } void func_800E4AD8(s32 mode) { Camera* currentCamera = &gCameras[gCurrentCameraID]; collision_check_player_intersecting_world(mode, 0, gPlayerStatus.spriteFacingAngle - 90.0f + currentCamera->currentYaw); } void func_800E4B40(s32 mode, f32* arg1, f32* arg2, f32* arg3) { Camera* currentCamera = &gCameras[gCurrentCameraID]; func_800E4404(mode, 0, gPlayerStatus.spriteFacingAngle - 90.0f + currentCamera->currentYaw, arg1, arg2, arg3); } void collision_lava_reset_check_additional_overlaps(void) { PlayerStatus* playerStatus = &gPlayerStatus; f32 x, y, z; f32 temp_f0; if (playerStatus->animFlags & PA_FLAG_USING_PEACH_PHYSICS) { collision_lateral_peach(); return; } temp_f0 = clamp_angle(playerStatus->targetYaw - 30.0); y = playerStatus->position.y + (playerStatus->colliderHeight * 0.75f); x = playerStatus->position.x; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; temp_f0 = clamp_angle(playerStatus->targetYaw + 30.0); y = playerStatus->position.y + (playerStatus->colliderHeight * 0.75f); x = playerStatus->position.x; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; temp_f0 = clamp_angle(playerStatus->targetYaw - 30.0); x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; temp_f0 = clamp_angle(playerStatus->targetYaw + 30.0); x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; temp_f0 = clamp_angle(playerStatus->targetYaw + 90.0); x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; temp_f0 = clamp_angle(playerStatus->targetYaw - 90.0); x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; temp_f0 = clamp_angle(playerStatus->targetYaw + 180.0); x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; player_test_lateral_overlap(0, &gPlayerStatus, &x, &y, &z, 0.0f, temp_f0); playerStatus->position.x = x; playerStatus->position.z = z; } void collision_lateral_peach(void) { PlayerStatus* playerStatus = &gPlayerStatus; s32 climbableStep = FALSE; f32 yaw = playerStatus->targetYaw; f32 x = playerStatus->position.x; f32 y = playerStatus->position.y; f32 z = playerStatus->position.z; s32 wall = player_test_move_without_slipping(&gPlayerStatus, &x, &y, &z, 0, yaw, &climbableStep); playerStatus->position.x = x; playerStatus->position.z = z; // If there was a climbable step in this direction, but no wall, we can climb up it if (climbableStep && wall < 0 && playerStatus->actionState != ACTION_STATE_STEP_UP_PEACH && playerStatus->currentSpeed != 0.0f ) { set_action_state(ACTION_STATE_STEP_UP_PEACH); } } void check_input_midair_jump(void) { if (!(gPlayerStatus.flags & (PS_FLAG_SCRIPTED_FALL | PS_FLAG_SLIDING | PS_FLAG_FLYING)) && !(gPlayerStatus.animFlags & (PA_FLAG_8BIT_MARIO | PA_FLAG_USING_WATT)) && gPlayerStatus.peakJumpTime >= 6 && gPlayerStatus.timeInAir < 18 && gPlayerStatus.pressedButtons & BUTTON_A ) { switch (gPlayerData.bootsLevel) { case 0: break; case 1: set_action_state(ACTION_STATE_SPIN_JUMP); gPlayerStatus.flags |= PS_FLAG_FLYING; break; case 2: set_action_state(ACTION_STATE_TORNADO_JUMP); gPlayerStatus.flags |= PS_FLAG_FLYING; break; } } } s8 get_current_partner_id(void) { return gPlayerData.currentPartner; } void try_player_footstep_sounds(s32 interval) { if (gGameStatusPtr->frameCounter % interval == 0) { s32 surfaceType = get_collider_flags(gCollisionStatus.currentFloor) & COLLIDER_FLAGS_SURFACE_TYPE_MASK; s32 soundID, altSoundID; if (surfaceType == SURFACE_TYPE_FLOWERS || surfaceType == SURFACE_TYPE_HEDGES) { soundID = SOUND_STEP_CRUNCHY1; altSoundID = SOUND_STEP_CRUNCHY2; } else { soundID = SOUND_STEP_NORMAL1; altSoundID = SOUND_STEP_NORMAL2; } if (FootstepSoundSelector == 0) { soundID = altSoundID; } sfx_play_sound_at_player(soundID, SOUND_SPACE_MODE_0); FootstepSoundSelector ^= 1; } } void phys_update_interact_collider(void) { gCollisionStatus.currentInspect = phys_check_interactable_collision(); } s32 phys_check_interactable_collision(void) { PlayerStatus* playerStatus = &gPlayerStatus; f32 x, y, z, yaw; s32 ret = -1; if (playerStatus->flags & PS_FLAG_INPUT_DISABLED) { return ret; } if (playerStatus->pressedButtons & BUTTON_A) { yaw = playerStatus->targetYaw; x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; ret = player_test_move_with_slipping(playerStatus, &x, &y, &z, playerStatus->colliderDiameter * 0.5f, yaw); if (ret < 0 && playerStatus->currentSpeed == 0.0f) { yaw = playerStatus->spriteFacingAngle - 90.0f + gCameras[gCurrentCameraID].currentYaw; x = playerStatus->position.x; y = playerStatus->position.y; z = playerStatus->position.z; ret = player_test_move_with_slipping(playerStatus, &x, &y, &z, playerStatus->colliderDiameter * 0.5f, yaw); } } return ret; } s32 phys_can_player_interact(void) { PartnerActionStatus* partnerActionStatus = &gPartnerActionStatus; PlayerStatus* playerStatus = &gPlayerStatus; s32 ret = TRUE; if (gPartnerActionStatus.partnerActionState != PARTNER_ACTION_NONE) { if (gPartnerActionStatus.actingPartner == PARTNER_BOMBETTE) { if (gPartnerActionStatus.partnerActionState <= PARTNER_ACTION_BOMBETTE_2) { ret = FALSE; } } else { ret = FALSE; } } else if (!(gPlayerStatus.actionState == ACTION_STATE_IDLE || gPlayerStatus.actionState == ACTION_STATE_WALK || gPlayerStatus.actionState == ACTION_STATE_RUN)) { ret = FALSE; } return ret; } f32 func_800E5348(void) { f32 deltaYaw = get_clamped_angle_diff(gCameras[gCurrentCameraID].currentYaw, gPlayerStatus.currentYaw); if (deltaYaw < -5.0f && deltaYaw > -175.0f) { deltaYaw = 0.0f; } else if (deltaYaw > 5.0f && deltaYaw < 175.0f) { deltaYaw = 180.0f; } else { deltaYaw = PrevPlayerCamRelativeYaw; } return clamp_angle(deltaYaw - 90.0f + gCameras[gCurrentCameraID].currentYaw); } f32 player_get_camera_facing_angle(void) { f32 angle = 0.0f; if (gPlayerStatus.spriteFacingAngle >= 90.0f && gPlayerStatus.spriteFacingAngle < 270.0f) { angle = 180.0f; } angle = angle + gCameras[CAM_DEFAULT].currentYaw + 90.0f; return clamp_angle(angle); } void phys_save_ground_pos(void) { PlayerStatus* playerStatus = &gPlayerStatus; playerStatus->lastGoodPosition.x = playerStatus->position.x; playerStatus->lastGoodPosition.y = playerStatus->position.y; playerStatus->lastGoodPosition.z = playerStatus->position.z; }