mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
205 lines
7.9 KiB
C
205 lines
7.9 KiB
C
#include "first_person_cam.h"
|
|
|
|
#include "sm64.h"
|
|
#include "behavior_data.h"
|
|
#include "camera.h"
|
|
#include "level_update.h"
|
|
#include "object_list_processor.h"
|
|
#include "object_helpers.h"
|
|
#include "mario.h"
|
|
#include "hardcoded.h"
|
|
#include "save_file.h"
|
|
|
|
#include "engine/math_util.h"
|
|
|
|
#include "pc/controller/controller_mouse.h"
|
|
#include "pc/djui/djui.h"
|
|
#include "pc/djui/djui_hud_utils.h"
|
|
#include "pc/lua/utils/smlua_camera_utils.h"
|
|
#include "pc/lua/smlua_hooks.h"
|
|
|
|
struct FirstPersonCamera gFirstPersonCamera = {
|
|
.enabled = false,
|
|
.forcePitch = false,
|
|
.forceYaw = false,
|
|
.forceRoll = true,
|
|
.centerL = true,
|
|
.pitch = 0,
|
|
.yaw = 0,
|
|
.crouch = 0,
|
|
.fov = FIRST_PERSON_DEFAULT_FOV,
|
|
.offset = { 0, 0, 0 }
|
|
};
|
|
|
|
extern s16 gMenuMode;
|
|
|
|
bool first_person_check_cancels(struct MarioState *m) {
|
|
if (m->action == ACT_FIRST_PERSON || m->action == ACT_IN_CANNON || m->action == ACT_READING_NPC_DIALOG || m->action == ACT_DISAPPEARED || m->action == ACT_FLYING) {
|
|
return true;
|
|
}
|
|
if (find_object_with_behavior(smlua_override_behavior(bhvActSelector)) != NULL) { return true; }
|
|
|
|
if (gLuaLoadingMod != NULL) { return false; }
|
|
|
|
struct Object *bowser = find_object_with_behavior(smlua_override_behavior(bhvBowser));
|
|
if ((gCurrLevelNum == LEVEL_BOWSER_1 || gCurrLevelNum == LEVEL_BOWSER_2 || gCurrLevelNum == LEVEL_BOWSER_3) &&
|
|
bowser != NULL &&
|
|
(bowser->oAction == 5 || bowser->oAction == 6)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool get_first_person_enabled(void) {
|
|
return gFirstPersonCamera.enabled && !first_person_check_cancels(&gMarioStates[0]);
|
|
}
|
|
|
|
void set_first_person_enabled(bool enable) {
|
|
gFirstPersonCamera.enabled = enable;
|
|
}
|
|
|
|
static void first_person_camera_update(void) {
|
|
struct MarioState *m = &gMarioStates[0];
|
|
f32 sensX = 0.3f * camera_config_get_x_sensitivity();
|
|
f32 sensY = 0.4f * camera_config_get_y_sensitivity();
|
|
s16 invX = camera_config_is_x_inverted() ? 1 : -1;
|
|
s16 invY = camera_config_is_y_inverted() ? 1 : -1;
|
|
|
|
if (mouse_relative_enabled) {
|
|
// hack: make c buttons work for moving the camera
|
|
s16 extStickX = m->controller->extStickX;
|
|
s16 extStickY = m->controller->extStickY;
|
|
if (extStickX == 0) {
|
|
extStickX = (clamp(m->controller->buttonDown & R_CBUTTONS, 0, 1) - clamp(m->controller->buttonDown & L_CBUTTONS, 0, 1)) * 32;
|
|
}
|
|
if (extStickY == 0) {
|
|
extStickY = (clamp(m->controller->buttonDown & U_CBUTTONS, 0, 1) - clamp(m->controller->buttonDown & D_CBUTTONS, 0, 1)) * 24;
|
|
}
|
|
|
|
// update pitch
|
|
if (!gFirstPersonCamera.forcePitch) {
|
|
gFirstPersonCamera.pitch -= sensY * (invY * extStickY - 1.5f * mouse_y);
|
|
gFirstPersonCamera.pitch = clamp(gFirstPersonCamera.pitch, -0x3F00, 0x3F00);
|
|
}
|
|
|
|
// update yaw
|
|
if (!gFirstPersonCamera.forceYaw) {
|
|
if (m->controller->buttonDown & L_TRIG && gFirstPersonCamera.centerL) {
|
|
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
|
|
} else {
|
|
gFirstPersonCamera.yaw += sensX * (invX * extStickX - 1.5f * mouse_x);
|
|
}
|
|
}
|
|
}
|
|
|
|
// fix yaw for some specific actions
|
|
// if the left stick is held, use Mario's yaw to set the camera's yaw
|
|
// otherwise, set Mario's yaw to the camera's yaw
|
|
u32 actions[] = { ACT_FLYING, ACT_HOLDING_BOWSER, ACT_TORNADO_TWIRLING, ACT_FLAG_ON_POLE, ACT_FLAG_SWIMMING, ACT_FLAG_SWIMMING_OR_FLYING };
|
|
for (s32 i = 0; i < 6; i++) {
|
|
u32 flag = actions[i];
|
|
if ((m->action & flag) == flag) {
|
|
if (ABS(m->controller->stickX) > 4) {
|
|
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
|
|
} else {
|
|
m->faceAngle[1] = gFirstPersonCamera.yaw - 0x8000;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (m->action == ACT_LEDGE_GRAB) {
|
|
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
|
|
}
|
|
|
|
gLakituState.yaw = gFirstPersonCamera.yaw;
|
|
m->area->camera->yaw = gFirstPersonCamera.yaw;
|
|
|
|
// update crouch
|
|
if (mario_is_crouching(m) || m->action == ACT_LEDGE_GRAB) {
|
|
bool up = (m->controller->buttonDown & Z_TRIG) != 0 || m->action == ACT_CROUCH_SLIDE || m->action == ACT_LEDGE_GRAB;
|
|
f32 inc = 10 * (up ? 1 : -1);
|
|
gFirstPersonCamera.crouch = clamp(gFirstPersonCamera.crouch + inc, 0, FIRST_PERSON_MARIO_HEAD_POS - FIRST_PERSON_MARIO_HEAD_POS_SHORT);
|
|
} else {
|
|
gFirstPersonCamera.crouch = clamp(gFirstPersonCamera.crouch - 10, 0, FIRST_PERSON_MARIO_HEAD_POS - FIRST_PERSON_MARIO_HEAD_POS_SHORT);
|
|
}
|
|
|
|
if (m->action == ACT_LEDGE_GRAB) {
|
|
gFirstPersonCamera.crouch = FIRST_PERSON_MARIO_HEAD_POS - FIRST_PERSON_MARIO_HEAD_POS_SHORT;
|
|
}
|
|
|
|
// update pos
|
|
gLakituState.pos[0] = (m->pos[0] + gFirstPersonCamera.offset[0]) + coss(gFirstPersonCamera.pitch) * sins(gFirstPersonCamera.yaw);
|
|
gLakituState.pos[1] = (m->pos[1] + gFirstPersonCamera.offset[1]) + sins(gFirstPersonCamera.pitch) + (FIRST_PERSON_MARIO_HEAD_POS - gFirstPersonCamera.crouch);
|
|
gLakituState.pos[2] = (m->pos[2] + gFirstPersonCamera.offset[2]) + coss(gFirstPersonCamera.pitch) * coss(gFirstPersonCamera.yaw);
|
|
vec3f_copy(m->area->camera->pos, gLakituState.pos);
|
|
vec3f_copy(gLakituState.curPos, gLakituState.pos);
|
|
vec3f_copy(gLakituState.goalPos, gLakituState.pos);
|
|
|
|
// update focus
|
|
gLakituState.focus[0] = (m->pos[0] + gFirstPersonCamera.offset[0]) - 100 * coss(gFirstPersonCamera.pitch) * sins(gFirstPersonCamera.yaw);
|
|
gLakituState.focus[1] = (m->pos[1] + gFirstPersonCamera.offset[1]) - 100 * sins(gFirstPersonCamera.pitch) + (FIRST_PERSON_MARIO_HEAD_POS - gFirstPersonCamera.crouch);
|
|
gLakituState.focus[2] = (m->pos[2] + gFirstPersonCamera.offset[2]) - 100 * coss(gFirstPersonCamera.pitch) * coss(gFirstPersonCamera.yaw);
|
|
vec3f_copy(m->area->camera->focus, gLakituState.focus);
|
|
vec3f_copy(gLakituState.curFocus, gLakituState.focus);
|
|
vec3f_copy(gLakituState.goalFocus, gLakituState.focus);
|
|
|
|
// set other values
|
|
if (gFirstPersonCamera.forceRoll) {
|
|
gLakituState.roll = 0;
|
|
}
|
|
gLakituState.posHSpeed = 0;
|
|
gLakituState.posVSpeed = 0;
|
|
gLakituState.focHSpeed = 0;
|
|
gLakituState.focVSpeed = 0;
|
|
vec3s_set(gLakituState.shakeMagnitude, 0, 0, 0);
|
|
}
|
|
|
|
void first_person_update(void) {
|
|
if (gFirstPersonCamera.enabled && !gDjuiInMainMenu) {
|
|
struct MarioState *m = &gMarioStates[0];
|
|
|
|
// check cancels
|
|
bool cancel = first_person_check_cancels(m);
|
|
if (cancel) { return; }
|
|
|
|
if (m->action == ACT_SHOT_FROM_CANNON && m->area->camera->mode == CAMERA_MODE_INSIDE_CANNON) {
|
|
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
|
|
m->area->camera->mode = CAMERA_MODE_FREE_ROAM;
|
|
}
|
|
|
|
if (gFirstPersonCamera.pitch <= -0x3F00 &&
|
|
m->floor && m->floor->type == SURFACE_LOOK_UP_WARP &&
|
|
save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1) >= gLevelValues.wingCapLookUpReq &&
|
|
m->forwardVel == 0 &&
|
|
sCurrPlayMode != PLAY_MODE_PAUSED) {
|
|
level_trigger_warp(m, WARP_OP_LOOK_UP);
|
|
}
|
|
|
|
m->marioBodyState->modelState = 0x100;
|
|
if (m->heldObj) {
|
|
Vec3f camDir = {
|
|
m->area->camera->focus[0] - m->area->camera->pos[0],
|
|
m->area->camera->focus[1] - m->area->camera->pos[1],
|
|
m->area->camera->focus[2] - m->area->camera->pos[2]
|
|
};
|
|
vec3f_normalize(camDir);
|
|
vec3f_mul(camDir, 100);
|
|
vec3f_sum(m->marioObj->header.gfx.pos, m->pos, camDir);
|
|
}
|
|
|
|
first_person_camera_update();
|
|
}
|
|
}
|
|
|
|
void first_person_reset(void) {
|
|
gFirstPersonCamera.forceRoll = false;
|
|
gFirstPersonCamera.centerL = true;
|
|
gFirstPersonCamera.pitch = 0;
|
|
gFirstPersonCamera.yaw = 0;
|
|
gFirstPersonCamera.crouch = 0;
|
|
gFirstPersonCamera.fov = FIRST_PERSON_DEFAULT_FOV;
|
|
gFirstPersonCamera.offset[0] = 0;
|
|
gFirstPersonCamera.offset[1] = 0;
|
|
gFirstPersonCamera.offset[2] = 0;
|
|
}
|