diff --git a/src/d_player.h b/src/d_player.h index 1b9744efb..fff4eab9c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -465,6 +465,15 @@ typedef enum BOT_ITEM_PR__MAX } botItemPriority_e; +typedef struct { + tic_t enter_tic, exit_tic; + tic_t zoom_in_speed, zoom_out_speed; + fixed_t dist; + angle_t pan; + fixed_t pan_speed; // in degrees + tic_t pan_accel, pan_back; +} sonicloopcamvars_t; + // player_t struct for loop state typedef struct { fixed_t radius; @@ -474,6 +483,7 @@ typedef struct { vector2_t origin_shift; vector2_t shift; boolean flip; + sonicloopcamvars_t camera; } sonicloopvars_t; // player_t struct for power-ups diff --git a/src/objects/loops.cpp b/src/objects/loops.cpp index c54103f9d..9d2262848 100644 --- a/src/objects/loops.cpp +++ b/src/objects/loops.cpp @@ -295,6 +295,7 @@ Obj_LoopEndpointCollide { player_t *player = toucher->player; sonicloopvars_t *s = &player->loop; + sonicloopcamvars_t *cam = &s->camera; mobj_t *anchor = end_anchor(end); mobj_t *center = anchor ? anchor_center(anchor) : NULL; @@ -352,6 +353,17 @@ Obj_LoopEndpointCollide s->flip = center_has_flip(center); + cam->enter_tic = leveltime; + cam->exit_tic = INFTICS; + + cam->zoom_out_speed = center->thing_args[2]; + cam->zoom_in_speed = center->thing_args[3]; + cam->dist = center->thing_args[4] * FRACUNIT; + cam->pan = FixedAngle(center->thing_args[5] * FRACUNIT); + cam->pan_speed = center->thing_args[6] * FRACUNIT; + cam->pan_accel = center->thing_args[7]; + cam->pan_back = center->thing_args[8]; + player->speed = 3 * (player->speed + toucher->momz) / 2; diff --git a/src/p_loop.c b/src/p_loop.c index bc1454a5d..67ba60f02 100644 --- a/src/p_loop.c +++ b/src/p_loop.c @@ -37,6 +37,7 @@ void P_HaltPlayerOrbit(player_t *player) player->mo->flags &= ~(MF_NOCLIPHEIGHT); player->loop.radius = 0; + player->loop.camera.exit_tic = leveltime; } void P_ExitPlayerOrbit(player_t *player) diff --git a/src/p_saveg.c b/src/p_saveg.c index 4a8fd3027..097057ef7 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -682,6 +682,17 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEFIXED(save->p, players[i].loop.shift.y); WRITEUINT8(save->p, players[i].loop.flip); + // sonicloopcamvars_t + WRITEUINT32(save->p, players[i].loop.camera.enter_tic); + WRITEUINT32(save->p, players[i].loop.camera.exit_tic); + WRITEUINT32(save->p, players[i].loop.camera.zoom_in_speed); + WRITEUINT32(save->p, players[i].loop.camera.zoom_out_speed); + WRITEFIXED(save->p, players[i].loop.camera.dist); + WRITEANGLE(save->p, players[i].loop.camera.pan); + WRITEFIXED(save->p, players[i].loop.camera.pan_speed); + WRITEUINT32(save->p, players[i].loop.camera.pan_accel); + WRITEUINT32(save->p, players[i].loop.camera.pan_back); + // ACS has read access to this, so it has to be net-communicated. // It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way. WRITEUINT32(save->p, players[i].roundconditions.unlocktriggers); @@ -1208,6 +1219,17 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].loop.shift.y = READFIXED(save->p); players[i].loop.flip = READUINT8(save->p); + // sonicloopcamvars_t + players[i].loop.camera.enter_tic = READUINT32(save->p); + players[i].loop.camera.exit_tic = READUINT32(save->p); + players[i].loop.camera.zoom_in_speed = READUINT32(save->p); + players[i].loop.camera.zoom_out_speed = READUINT32(save->p); + players[i].loop.camera.dist = READFIXED(save->p); + players[i].loop.camera.pan = READANGLE(save->p); + players[i].loop.camera.pan_speed = READFIXED(save->p); + players[i].loop.camera.pan_accel = READUINT32(save->p); + players[i].loop.camera.pan_back = READUINT32(save->p); + // ACS has read access to this, so it has to be net-communicated. // It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way. players[i].roundconditions.unlocktriggers = READUINT32(save->p); diff --git a/src/p_user.c b/src/p_user.c index 17f04c76f..070cfcee8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3072,6 +3072,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall fixed_t scaleDiff; fixed_t cameraScale = mapobjectscale; + sonicloopcamvars_t *loop = &player->loop.camera; + tic_t loop_out = leveltime - loop->enter_tic; + tic_t loop_in = max(leveltime, loop->exit_tic) - loop->exit_tic; + thiscam->old_x = thiscam->x; thiscam->old_y = thiscam->y; thiscam->old_z = thiscam->z; @@ -3196,6 +3200,58 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camdist = FixedMul(cv_cam_dist[num].value, cameraScale); camheight = FixedMul(cv_cam_height[num].value, cameraScale); + if (loop_in < loop->zoom_in_speed) + { + fixed_t f = loop_out < loop->zoom_out_speed + ? (loop_out * FRACUNIT) / loop->zoom_out_speed + : FRACUNIT - ((loop_in * FRACUNIT) / loop->zoom_in_speed); + + camspeed -= FixedMul(f, camspeed - (FRACUNIT/10)); + camdist += FixedMul(f, loop->dist); + } + + if (loop_in < max(loop->pan_back, 1)) + { + fixed_t f = (loop_in * FRACUNIT) / max(loop->pan_back, 1); + + fixed_t dx = mo->x - thiscam->x; + fixed_t dy = mo->y - thiscam->y; + + angle_t th = R_PointToAngle2(0, 0, dx, dy); + fixed_t d = AngleFixed(focusangle - th); + + if (d > 180*FRACUNIT) + { + d -= (360*FRACUNIT); + } + + focusangle = th + FixedAngle(FixedMul(f, d)); + + if (loop_in == 0) + { + focusaiming = R_PointToAngle2(0, thiscam->z, FixedHypot(dx, dy), mo->z); + } + } + + if (loop_in == 0) + { + tic_t accel = max(loop->pan_accel, 1); + fixed_t f = (min(loop_out, accel) * FRACUNIT) / accel; + + INT32 turn = AngleDeltaSigned(focusangle, player->loop.yaw - loop->pan); + INT32 turnspeed = FixedAngle(FixedMul(f, loop->pan_speed)); + + if (turn > turnspeed) + { + if (turn < ANGLE_90) + { + turnspeed = -(turnspeed); + } + + focusangle += turnspeed; + } + } + if (timeover) { const INT32 timeovercam = max(0, min(180, (player->karthud[khud_timeovercam] - 2*TICRATE)*15)); @@ -3878,6 +3934,11 @@ DoABarrelRoll (player_t *player) fixed_t smoothing; + if (player->loop.radius) + { + return; + } + if (player->respawn.state != RESPAWNST_NONE) { player->tilt = 0;