diff --git a/src/game/puppycam2.c b/src/game/puppycam2.c index a774c239..2fb9fb9b 100644 --- a/src/game/puppycam2.c +++ b/src/game/puppycam2.c @@ -1,4 +1,4 @@ -///Puppycam 2.1 by Fazana +///Puppycam 2.2 by Fazana #include #include @@ -198,7 +198,82 @@ void puppycam_activate_cutscene(s32 *scene, s32 lockinput) gPuppyCam.sceneInput = lockinput; } -static void newcam_process_cutscene(void) +//If you've read camera.c this will look familiar. +//It takes the next 4 spline points and extrapolates a curvature based positioning of the camera vector that's passed through. +//It's a standard B spline +static void puppycam_evaluate_spline(f32 progress, Vec3s cameraPos, Vec3f spline1, Vec3f spline2, Vec3f spline3, Vec3f spline4) +{ + f32 tempP[4]; + + if (progress > 1.0f) { + progress = 1.0f; + } + + tempP[0] = (1.0f - progress) * (1.0f - progress) * (1.0f - progress) / 6.0f; + tempP[1] = progress * progress * progress / 2.0f - progress * progress + 0.6666667f; + tempP[2] = -progress * progress * progress / 2.0f + progress * progress / 2.0f + progress / 2.0f + 0.16666667f; + tempP[3] = progress * progress * progress / 6.0f; + + cameraPos[0] = tempP[0] * spline1[0] + tempP[1] * spline2[0] + tempP[2] * spline3[0] + tempP[3] * spline4[0]; + cameraPos[1] = tempP[0] * spline1[1] + tempP[1] * spline2[1] + tempP[2] * spline3[1] + tempP[3] * spline4[1]; + cameraPos[2] = tempP[0] * spline1[2] + tempP[1] * spline2[2] + tempP[2] * spline3[2] + tempP[3] * spline4[2]; +} + +s32 puppycam_move_spline(struct sPuppySpline splinePos[], struct sPuppySpline splineFocus[], s32 mode, s32 index) +{ + Vec3f tempPoints[4]; + f32 tempProgress[2] = {0.0f, 0.0f}; + f32 progChange = 0.0f; + s32 i; + Vec3f prevPos; + + if (gPuppyCam.splineIndex == 65000) + gPuppyCam.splineIndex = index; + + if (splinePos[gPuppyCam.splineIndex].index == -1 || splinePos[gPuppyCam.splineIndex + 1].index == -1 || splinePos[gPuppyCam.splineIndex + 2].index == -1) + return 1; + if (mode == PUPPYSPLINE_FOLLOW) + if (splineFocus[gPuppyCam.splineIndex].index == -1 || splineFocus[gPuppyCam.splineIndex + 1].index == -1 || splineFocus[gPuppyCam.splineIndex + 2].index == -1) + return 1; + + vec3f_set(prevPos, gPuppyCam.pos[0], gPuppyCam.pos[1], gPuppyCam.pos[2]); + + for (i = 0; i < 4; i++) + vec3f_set(tempPoints[i], splinePos[gPuppyCam.splineIndex + i].pos[0], splinePos[gPuppyCam.splineIndex + i].pos[1], splinePos[gPuppyCam.splineIndex + i].pos[2]); + puppycam_evaluate_spline(gPuppyCam.splineProgress, gPuppyCam.pos, tempPoints[0], tempPoints[1], tempPoints[2], tempPoints[3]); + if (mode == PUPPYSPLINE_FOLLOW) + { + for (i = 0; i < 4; i++) + vec3f_set(tempPoints[i], splineFocus[gPuppyCam.splineIndex + i].pos[0], splineFocus[gPuppyCam.splineIndex + i].pos[1], splineFocus[gPuppyCam.splineIndex + i].pos[2]); + puppycam_evaluate_spline(gPuppyCam.splineProgress, gPuppyCam.focus, tempPoints[0], tempPoints[1], tempPoints[2], tempPoints[3]); + } + + if (splinePos[gPuppyCam.splineIndex+1].speed != 0) { + tempProgress[0] = 1.0f / splinePos[gPuppyCam.splineIndex+1].speed; + } + if (splinePos[gPuppyCam.splineIndex+2].speed != 0) { + tempProgress[1] = 1.0f / splinePos[gPuppyCam.splineIndex+2].speed; + } + progChange = (tempProgress[1] - tempProgress[0]) * gPuppyCam.splineProgress + tempProgress[0]; + + gPuppyCam.splineProgress += progChange; + + if (gPuppyCam.splineProgress >= 1.0f) + { + gPuppyCam.splineIndex++; + if (splinePos[gPuppyCam.splineIndex+3].index == -1) + { + gPuppyCam.splineIndex = 0; + gPuppyCam.splineProgress = 0; + return 1; + } + gPuppyCam.splineProgress -=1; + } + + return 0; +} + +static void puppycam_process_cutscene(void) { if (gPuppyCam.cutscene) { @@ -446,6 +521,8 @@ void puppycam_reset_values(void) gPuppyCam.floorY[0] = 0; gPuppyCam.floorY[1] = 0; gPuppyCam.terrainPitch = 0; + gPuppyCam.splineIndex = 0; + gPuppyCam.splineProgress = 0; } //Set up values. Runs on level load. @@ -615,7 +692,7 @@ static void puppycam_input_hold_preset2(f32 ivX) } //Another alternative control scheme. This one aims to mimic the parallel camera scheme down to the last bit from the original game. -static void puppycam_input_hold_preset3(f32 ivX) +static void puppycam_input_hold_preset3(void) { f32 stickMag[2] = {gPlayer1Controller->rawStickX*0.65f, gPlayer1Controller->rawStickY*0.2f}; //Just in case it happens to be nonzero. @@ -741,7 +818,7 @@ static void puppycam_input_hold(void) { default: puppycam_input_hold_preset1(ivX); puppycam_input_pitch(); puppycam_input_zoom(); puppycam_input_centre(); break; case 1: puppycam_input_hold_preset2(ivX); puppycam_input_pitch(); puppycam_input_zoom(); puppycam_input_centre(); break; - case 2: puppycam_input_hold_preset3(ivX); puppycam_input_centre(); break; + case 2: puppycam_input_hold_preset3(); puppycam_input_centre(); break; } } else @@ -972,6 +1049,35 @@ static s32 puppycam_check_volume_bounds(struct sPuppyVolume *volume, s32 index) return FALSE; } +//Handles wall adjustment when wall kicking. +void puppycam_wall_angle(void) +{ + struct Surface *wall; + struct WallCollisionData cData; + s16 wallYaw; + + if (!(gMarioState->action & ACT_WALL_KICK_AIR) || ((gMarioState->action & ACT_FLAG_AIR) && ABS(gMarioState->forwardVel) < 16.0f) || !(gMarioState->action & ACT_FLAG_AIR)) + return; + + cData.x = gPuppyCam.targetObj->oPosX; + cData.y = gPuppyCam.targetObj->oPosY; + cData.z = gPuppyCam.targetObj->oPosZ; + cData.radius = 150.0f; + cData.offsetY = 0; + + if (find_wall_collisions(&cData)) + wall = cData.walls[cData.numWalls - 1]; + else + return; + wallYaw = atan2s(wall->normal.z, wall->normal.x) + 0x4000; + + wallYaw -= gPuppyCam.yawTarget; + if (wallYaw % 0x4000) + wallYaw += 0x4000 - wallYaw % 0x4000; + + gPuppyCam.yawTarget = approach_s32(gPuppyCam.yawTarget, wallYaw, 0x200, 0x200); +} + void puppycam_projection_behaviours(void) { f32 turnRate = 1; @@ -1081,6 +1187,9 @@ void puppycam_projection_behaviours(void) //This sets a pseudo tilt offset based on the floor heights in front and behind mario. puppycam_terrain_angle(); + + //This will shift the intended yaw when wall kicking, to align with the wall being kicked. + puppycam_wall_angle(); } else { @@ -1386,7 +1495,7 @@ void puppycam_loop(void) if (gPuppyCam.cutscene) { gPuppyCam.opacity = 255; - newcam_process_cutscene(); + puppycam_process_cutscene(); } puppycam_apply(); diff --git a/src/game/puppycam2.h b/src/game/puppycam2.h index 7f8b0e9b..e094671c 100644 --- a/src/game/puppycam2.h +++ b/src/game/puppycam2.h @@ -25,6 +25,9 @@ #define PUPPYCAM_MODE3_ZOOMED_OUT 0x4 #define PUPPYCAM_MODE3_ENTER_FIRST_PERSON 0x8 +#define PUPPYSPLINE_NONE 1 //Will not write to focus at all. +#define PUPPYSPLINE_FOLLOW 2 //Focus will follow a separate spline, but will mirror the speed and progress of the pos. + #include "include/command_macros_base.h" #define PUPPYVOLUME(x, y, z, length, height, width, yaw, functionptr, anglesptr, addflags, removeflags, flagpersistance, room, shape) \ @@ -94,6 +97,8 @@ struct gPuppyStruct s32 sceneTimer; //The cutscene timer that goes up during a cutscene. Vec3s scenePos; //Where the camera is during a cutscene Vec3s sceneFocus; //Where the camera looks during a cutscene + u16 splineIndex; //Determines which point of the spline it's at. + f32 splineProgress; //Determines how far along the index the spline is. struct gPuppyOptions options; @@ -109,6 +114,14 @@ struct sPuppyAngles s16 zoom; }; +//Structurally, it's exactly the same as CutsceneSplinePoint +struct sPuppySpline +{ + s8 index; //The index of the spline. Ends with -1 + u8 speed; //The amount of frames it takes to get through this index. + Vec3s pos; //The vector pos of the spline index itself. +}; + //A bounding volume for activating puppycamera scripts and angles. struct sPuppyVolume { @@ -172,7 +185,8 @@ extern void puppycam_set_save(void); extern void puppycam_check_pause_buttons(void); extern void puppycam_activate_cutscene(s32 *scene, s32 lockinput); extern void puppycam_render_option_text(); -void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ); +extern void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ); +extern s32 puppycam_move_spline(struct sPuppySpline splinePos[], struct sPuppySpline splineFocus[], s32 mode, s32 index); #endif