From 89c503135a5733a59fe465d7f89972486b3200d6 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 00:58:16 -0700 Subject: [PATCH 01/18] Tweak spectator vertical aiming - Decrease vertical aiming speed to match turning speed - Reduce software aiming bounds to 45 degrees - (Even) less distortion due to extreme angles --- src/g_build_ticcmd.cpp | 2 +- src/g_game.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 035bdc08a..4bb138d05 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -261,7 +261,7 @@ class TiccmdBuilder if (G_PlayerInputDown(forplayer(), gc_lookback, 0)) { - cmd->aiming -= joystickvector.yaxis; + cmd->aiming -= (joystickvector.yaxis * KART_FULLTURN) / JOYAXISRANGE; } else { diff --git a/src/g_game.c b/src/g_game.c index 550324341..b73dfda2f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -861,7 +861,7 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) INT32 limitangle; // note: the current software mode implementation doesn't have true perspective - limitangle = ANGLE_90 - ANG10; // Some viewing fun, but not too far down... + limitangle = ANGLE_45; // Some viewing fun, but not too far down... if (*aiming > limitangle) *aiming = limitangle; From 3320faec8cebecb124882d38c7ec0ad37b79340a Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:00:11 -0700 Subject: [PATCH 02/18] Interpolate view, even when paused Fixes slideshow movement with demo freecam while paused. Does not appear to jitter like texture scrollers do. --- src/d_main.c | 3 +++ src/r_main.c | 3 ++- src/r_main.h | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index cade52936..bc042c57c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -886,11 +886,14 @@ void D_SRB2Loop(void) { rendertimefrac = FRACUNIT; } + + rendertimefrac_unpaused = g_time.timefrac; } else { renderdeltatics = realtics * FRACUNIT; rendertimefrac = FRACUNIT; + rendertimefrac_unpaused = FRACUNIT; } if (interp || doDisplay) diff --git a/src/r_main.c b/src/r_main.c index 107e6684b..6cf539574 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -81,6 +81,7 @@ mobj_t *r_viewmobj; int r_splitscreen; fixed_t rendertimefrac; +fixed_t rendertimefrac_unpaused; fixed_t renderdeltatics; boolean renderisnewtic; @@ -1227,7 +1228,7 @@ R_SetupCommonFrame else newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; - R_InterpolateView(rendertimefrac); + R_InterpolateView(rendertimefrac_unpaused); } static void R_SetupAimingFrame(int s) diff --git a/src/r_main.h b/src/r_main.h index dcd496cfb..0f5560308 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -39,6 +39,8 @@ extern size_t validcount, linecount, loopcount, framecount; // The fraction of a tic being drawn (for interpolation between two tics) extern fixed_t rendertimefrac; +// Same as rendertimefrac but not suspended when the game is paused +extern fixed_t rendertimefrac_unpaused; // Evaluated delta tics for this frame (how many tics since the last frame) extern fixed_t renderdeltatics; // The current render is a new logical tic From bf14773b219206ef95ccb95a95d09532bc89ffa6 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:05:02 -0700 Subject: [PATCH 03/18] TiccmdBuilder: don't reset ticcmd while paused If there a short pause by mistake, this will prevent it from interrupting a drift, for instance. --- src/g_build_ticcmd.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 4bb138d05..a37af680c 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -361,14 +361,14 @@ public: explicit TiccmdBuilder(ticcmd_t* cmd_, INT32 realtics_, UINT8 ssplayer_) : cmd(cmd_), realtics(realtics_), ssplayer(ssplayer_), viewnum(G_PartyPosition(g_localplayers[forplayer()])) { - *cmd = {}; // blank ticcmd - - if (demo.playback) + if (paused || P_AutoPause()) { return; } - if (paused || P_AutoPause()) + *cmd = {}; // blank ticcmd + + if (demo.playback) { return; } From 5a973734d0c781b09ec2949f8aecfea3e81cdd2c Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:08:33 -0700 Subject: [PATCH 04/18] Move software shearing conditions from R_SetupFreelook into G_FinalClipAimingPitch --- src/g_game.c | 29 +++++++++++++++++++++++++++++ src/g_game.h | 1 + src/r_fps.c | 21 +-------------------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index b73dfda2f..e108861df 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -76,6 +76,10 @@ #include "discord.h" #endif +#ifdef HWRENDER +#include "hardware/hw_main.h" // for cv_glshearing +#endif + gameaction_t gameaction; gamestate_t gamestate = GS_NULL; UINT8 ultimatemode = false; @@ -871,6 +875,31 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) return (INT16)((*aiming)>>16); } +void G_FinalClipAimingPitch(INT32 *aiming, player_t *player, boolean skybox) +{ +#ifndef HWRENDER + (void)player; + (void)skybox; +#endif + + // clip it in the case we are looking a hardware 90 degrees full aiming + // (lmps, network and use F12...) + if (rendermode == render_soft +#ifdef HWRENDER + || (rendermode == render_opengl + && (cv_glshearing.value == 1 + || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))) +#endif + ) + { + G_SoftwareClipAimingPitch(aiming); + } + else + { + G_ClipAimingPitch(aiming); + } +} + static INT32 G_GetValueFromControlTable(INT32 deviceID, INT32 deadzone, INT32 *controltable) { INT32 i, failret = NO_BINDS_REACHABLE; diff --git a/src/g_game.h b/src/g_game.h index 71dd4ada8..72e9ce005 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -126,6 +126,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n); // clip the console player aiming to the view INT32 G_ClipAimingPitch(INT32 *aiming); INT16 G_SoftwareClipAimingPitch(INT32 *aiming); +void G_FinalClipAimingPitch(INT32 *aiming, player_t *player, boolean skybox); extern angle_t localangle[MAXSPLITSCREENPLAYERS]; extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed diff --git a/src/r_fps.c b/src/r_fps.c index 8f870abf2..f21d38943 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -22,9 +22,6 @@ #include "r_state.h" #include "z_zone.h" #include "console.h" // con_startup_loadprogress -#ifdef HWRENDER -#include "hardware/hw_main.h" // for cv_glshearing -#endif static CV_PossibleValue_t fpscap_cons_t[] = { #ifdef DEVELOP @@ -117,23 +114,7 @@ static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixe // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) static void R_SetupFreelook(player_t *player, boolean skybox) { -#ifndef HWRENDER - (void)player; - (void)skybox; -#endif - - // clip it in the case we are looking a hardware 90 degrees full aiming - // (lmps, network and use F12...) - if (rendermode == render_soft -#ifdef HWRENDER - || (rendermode == render_opengl - && (cv_glshearing.value == 1 - || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))) -#endif - ) - { - G_SoftwareClipAimingPitch((INT32 *)&aimingangle); - } + G_FinalClipAimingPitch((INT32 *)&aimingangle, player, skybox); centeryfrac = (viewheight/2)< Date: Mon, 14 Aug 2023 01:15:45 -0700 Subject: [PATCH 05/18] ST_overlayDrawer: hide VIEWPOINT text when using demo freecam --- src/st_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index dc4133089..c7166c414 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1171,7 +1171,7 @@ static void ST_overlayDrawer(void) { if (cv_showviewpointtext.value) { - if (!demo.title && !P_IsLocalPlayer(stplyr)) + if (!demo.title && !P_IsLocalPlayer(stplyr) && !demo.freecam) { if (!r_splitscreen) { From dbca307ad4c25a230dc94241dbdb00ae51deac6e Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:16:35 -0700 Subject: [PATCH 06/18] Fix sound handling in demo freecam - Object sounds are audible from the location of the camera - Certain HUD sounds should no longer be audible - For instance, lap complete sfx --- src/g_demo.c | 1 - src/p_local.h | 1 - src/p_user.c | 20 +++++++++----------- src/s_sound.c | 23 ++++++++--------------- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index d7f240f38..f0f7dca3f 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4129,7 +4129,6 @@ void G_StopDemo(void) demo.freecam = false; // reset democam shit too: democam.cam = NULL; - democam.soundmobj = NULL; democam.localangle = 0; democam.localaiming = 0; democam.keyboardlook = false; diff --git a/src/p_local.h b/src/p_local.h index 20ad1d5d2..5b46de49a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -135,7 +135,6 @@ struct camera_t struct demofreecam_s { camera_t *cam; // this is useful when the game is paused, notably - mobj_t *soundmobj; // mobj to play sound from, used in s_sound angle_t localangle; // keeps track of the cam angle for cmds angle_t localaiming; // ditto with aiming diff --git a/src/p_user.c b/src/p_user.c index d2f148283..991440d4b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1082,6 +1082,15 @@ boolean P_IsDisplayPlayer(player_t *player) return false; } + // Freecam still techically has a player in + // displayplayers. But since the camera is detached, it + // would be weird if sounds were heard from that player's + // perspective. + if (demo.freecam) + { + return false; + } + for (i = 0; i <= r_splitscreen; i++) // DON'T skip P1 { if (player == &players[displayplayers[i]]) @@ -3114,7 +3123,6 @@ void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; angle_t thrustangle; - mobj_t *awayviewmobj_hack; player_t *lastp; // update democam stuff with what we got here: @@ -3163,14 +3171,6 @@ void P_DemoCameraMovement(camera_t *cam) // besides freecam going inside walls sounds pretty cool on paper. } - // awayviewmobj hack; this is to prevent us from hearing sounds from the player's perspective - - awayviewmobj_hack = P_SpawnMobj(cam->x, cam->y, cam->z, MT_THOK); - awayviewmobj_hack->tics = 2; - awayviewmobj_hack->renderflags |= RF_DONTDRAW; - - democam.soundmobj = awayviewmobj_hack; - // update subsector to avoid crashes; cam->subsector = R_PointInSubsector(cam->x, cam->y); } @@ -3239,8 +3239,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall thiscam->old_angle = thiscam->angle; thiscam->old_aiming = thiscam->aiming; - democam.soundmobj = NULL; // reset this each frame, we don't want the game crashing for stupid reasons now do we - // We probably shouldn't move the camera if there is no player or player mobj somehow if (!player || !player->mo) return true; diff --git a/src/s_sound.c b/src/s_sound.c index a9e5a4656..eb6c9a2e1 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -540,11 +540,6 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) continue; } - if (i == 0 && democam.soundmobj) - { - continue; - } - if (player->awayview.tics) { listenmobj[i] = player->awayview.mobj; @@ -554,7 +549,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) listenmobj[i] = player->mo; } - if (origin && origin == listenmobj[i]) + if (origin && origin == listenmobj[i] && !demo.freecam) { itsUs = true; } @@ -827,11 +822,6 @@ void S_UpdateSounds(void) continue; } - if (i == 0 && democam.soundmobj) - { - continue; - } - if (player->awayview.tics) { listenmobj[i] = player->awayview.mobj; @@ -898,12 +888,15 @@ void S_UpdateSounds(void) { boolean itsUs = false; - for (i = r_splitscreen; i >= 0; i--) + if (!demo.freecam) { - if (c->origin != listenmobj[i]) - continue; + for (i = r_splitscreen; i >= 0; i--) + { + if (c->origin != listenmobj[i]) + continue; - itsUs = true; + itsUs = true; + } } if (itsUs == false) From fec0f1341988f71e12462d64a41fd4361382a6b4 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:40:25 -0700 Subject: [PATCH 07/18] P_DemoCameraMovement: use locally built ticcmd from G_BuildTiccmd --- src/d_clisrv.c | 5 ++ src/d_clisrv.h | 2 + src/g_build_ticcmd.cpp | 25 +++++- src/menus/transient/pause-replay.c | 1 - src/p_local.h | 1 - src/p_user.c | 140 +---------------------------- 6 files changed, 30 insertions(+), 144 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index eb493d55e..990f8401a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -561,6 +561,11 @@ void D_ResetTiccmds(void) D_Clearticcmd(textcmds[i]->tic); } +ticcmd_t *D_LocalTiccmd(UINT8 ss) +{ + return &localcmds[ss][0]; +} + void SendKick(UINT8 playernum, UINT8 msg) { UINT8 buf[2]; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 1d8c339e3..79d5c16cf 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -615,7 +615,9 @@ extern UINT8 playerconsole[MAXPLAYERS]; INT32 D_NumPlayers(void); boolean D_IsPlayerHumanAndGaming(INT32 player_number); + void D_ResetTiccmds(void); +ticcmd_t *D_LocalTiccmd(UINT8 ss); tic_t GetLag(INT32 node); UINT8 GetFreeXCmdSize(UINT8 playerid); diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index a37af680c..17ffcaf32 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -244,7 +244,7 @@ class TiccmdBuilder bool spectator_analog_input() { - if (!player()->spectator && !objectplacing) + if (!player()->spectator && !objectplacing && !demo.freecam) { return false; } @@ -361,6 +361,26 @@ public: explicit TiccmdBuilder(ticcmd_t* cmd_, INT32 realtics_, UINT8 ssplayer_) : cmd(cmd_), realtics(realtics_), ssplayer(ssplayer_), viewnum(G_PartyPosition(g_localplayers[forplayer()])) { + auto regular_input = [this] + { + analog_input(); + common_button_input(); + }; + + if (demo.freecam) + { + // freecam is controllable even while paused + + *cmd = {}; + + if (!typing_input()) + { + regular_input(); + } + + return; + } + if (paused || P_AutoPause()) { return; @@ -391,8 +411,7 @@ public: if (!overlay) { - analog_input(); - common_button_input(); + regular_input(); } cmd->angle = localangle[viewnum] >> TICCMD_REDUCE; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 52cc4b7e5..2032eccc2 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -236,7 +236,6 @@ void M_PlaybackToggleFreecam(INT32 choice) splitscreen = 0; R_ExecuteSetViewSize(); - P_InitCameraCmd(); // init camera controls if (!demo.freecam) // toggle on { demo.freecam = true; diff --git a/src/p_local.h b/src/p_local.h index 5b46de49a..c4a0d290a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -158,7 +158,6 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); void P_DemoCameraMovement(camera_t *cam); boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled); -void P_InitCameraCmd(void); boolean P_PlayerInPain(player_t *player); void P_ResetPlayer(player_t *player); diff --git a/src/p_user.c b/src/p_user.c index 991440d4b..a29347aa0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2979,146 +2979,8 @@ fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_height[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; -// Heavily simplified version of G_BuildTicCmd that only takes the local first player's control input and converts it to readable ticcmd_t -// we then throw that ticcmd garbage in the camera and make it move -// TODO: please just use the normal ticcmd function somehow - -static ticcmd_t cameracmd; - struct demofreecam_s democam; -// called by m_menu to reinit cam input every time it's toggled -void P_InitCameraCmd(void) -{ - memset(&cameracmd, 0, sizeof(ticcmd_t)); // initialize cmd -} - -static ticcmd_t *P_CameraCmd(camera_t *cam) -{ - /* - INT32 forward, axis; //i - // these ones used for multiple conditions - boolean turnleft, turnright, mouseaiming; - boolean invertmouse, lookaxis, usejoystick, kbl; - INT32 player_invert; - INT32 screen_invert; - */ - ticcmd_t *cmd = &cameracmd; - - (void)cam; - - if (!demo.playback) - return cmd; // empty cmd, no. - - /* - kbl = democam.keyboardlook; - - G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver - - mouseaiming = true; - invertmouse = cv_invertmouse.value; - lookaxis = cv_lookaxis[0].value; - - usejoystick = true; - turnright = PlayerInputDown(1, gc_turnright); - turnleft = PlayerInputDown(1, gc_turnleft); - - axis = PlayerJoyAxis(1, AXISTURN); - - if (encoremode) - { - turnright ^= turnleft; // swap these using three XORs - turnleft ^= turnright; - turnright ^= turnleft; - axis = -axis; - } - - if (axis != 0) - { - turnright = turnright || (axis > 0); - turnleft = turnleft || (axis < 0); - } - forward = 0; - - cmd->turning = 0; - - // let movement keys cancel each other out - if (turnright && !(turnleft)) - { - cmd->turning -= KART_FULLTURN; - } - else if (turnleft && !(turnright)) - { - cmd->turning += KART_FULLTURN; - } - - cmd->turning -= (mousex * 8) * (encoremode ? -1 : 1); - - axis = PlayerJoyAxis(1, AXISMOVE); - if (PlayerInputDown(1, gc_a) || (usejoystick && axis > 0)) - cmd->buttons |= BT_ACCELERATE; - axis = PlayerJoyAxis(1, AXISBRAKE); - if (PlayerInputDown(1, gc_brake) || (usejoystick && axis > 0)) - cmd->buttons |= BT_BRAKE; - axis = PlayerJoyAxis(1, AXISAIM); - if (PlayerInputDown(1, gc_aimforward) || (usejoystick && axis < 0)) - forward += MAXPLMOVE; - if (PlayerInputDown(1, gc_aimbackward) || (usejoystick && axis > 0)) - forward -= MAXPLMOVE; - - // fire with any button/key - axis = PlayerJoyAxis(1, AXISFIRE); - if (PlayerInputDown(1, gc_fire) || (usejoystick && axis > 0)) - cmd->buttons |= BT_ATTACK; - - // spectator aiming shit, ahhhh... - player_invert = invertmouse ? -1 : 1; - screen_invert = 1; // nope - - // mouse look stuff (mouse look is not the same as mouse aim) - kbl = false; - - // looking up/down - cmd->aiming += (mlooky<<19)*player_invert*screen_invert; - - axis = PlayerJoyAxis(1, AXISLOOK); - - // spring back if not using keyboard neither mouselookin' - if (!kbl && !lookaxis && !mouseaiming) - cmd->aiming = 0; - - if (PlayerInputDown(1, gc_lookup) || (axis < 0)) - { - cmd->aiming += KB_LOOKSPEED * screen_invert; - kbl = true; - } - else if (PlayerInputDown(1, gc_lookdown) || (axis > 0)) - { - cmd->aiming -= KB_LOOKSPEED * screen_invert; - kbl = true; - } - - if (PlayerInputDown(1, gc_centerview)) // No need to put a spectator limit on this one though :V - cmd->aiming = 0; - - cmd->forwardmove += (SINT8)forward; - - if (cmd->forwardmove > MAXPLMOVE) - cmd->forwardmove = MAXPLMOVE; - else if (cmd->forwardmove < -MAXPLMOVE) - cmd->forwardmove = -MAXPLMOVE; - - if (cmd->turning > KART_FULLTURN) - cmd->turning = KART_FULLTURN; - else if (cmd->turning < -KART_FULLTURN) - cmd->turning = -KART_FULLTURN; - - democam.keyboardlook = kbl; - */ - - return cmd; -} - void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; @@ -3131,7 +2993,7 @@ void P_DemoCameraMovement(camera_t *cam) democam.localaiming = cam->aiming; // first off we need to get button input - cmd = P_CameraCmd(cam); + cmd = D_LocalTiccmd(0); cam->aiming += cmd->aiming << TICCMD_REDUCE; cam->angle += cmd->turning << TICCMD_REDUCE; From 8809ab02fcbb3439edb32d626d22fa8581e1a174 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:47:37 -0700 Subject: [PATCH 08/18] democam: remove unnecessary fields --- src/g_demo.c | 3 --- src/menus/transient/pause-replay.c | 2 -- src/p_local.h | 5 ----- src/p_user.c | 7 ------- 4 files changed, 17 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index f0f7dca3f..ede754ee7 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4129,9 +4129,6 @@ void G_StopDemo(void) demo.freecam = false; // reset democam shit too: democam.cam = NULL; - democam.localangle = 0; - democam.localaiming = 0; - democam.keyboardlook = false; Z_Free(demo.skinlist); demo.skinlist = NULL; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 2032eccc2..6db7cee98 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -246,8 +246,6 @@ void M_PlaybackToggleFreecam(INT32 choice) demo.freecam = false; // reset democam vars: democam.cam = NULL; - //democam.turnheld = false; - democam.keyboardlook = false; // reset only these. localangle / aiming gets set before the cam does anything anyway } } diff --git a/src/p_local.h b/src/p_local.h index c4a0d290a..08b3293ed 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -135,11 +135,6 @@ struct camera_t struct demofreecam_s { camera_t *cam; // this is useful when the game is paused, notably - - angle_t localangle; // keeps track of the cam angle for cmds - angle_t localaiming; // ditto with aiming - boolean turnheld; // holding turn button for gradual turn speed - boolean keyboardlook; // keyboard look }; extern struct demofreecam_s democam; diff --git a/src/p_user.c b/src/p_user.c index a29347aa0..a6a5076b1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2989,20 +2989,13 @@ void P_DemoCameraMovement(camera_t *cam) // update democam stuff with what we got here: democam.cam = cam; - democam.localangle = cam->angle; - democam.localaiming = cam->aiming; - // first off we need to get button input cmd = D_LocalTiccmd(0); cam->aiming += cmd->aiming << TICCMD_REDUCE; cam->angle += cmd->turning << TICCMD_REDUCE; - democam.localangle += cmd->turning << TICCMD_REDUCE; - democam.localaiming += cmd->aiming << TICCMD_REDUCE; - cam->aiming = G_ClipAimingPitch((INT32 *)&cam->aiming); - democam.localaiming = G_ClipAimingPitch((INT32 *)&democam.localaiming); // camera movement: if (cmd->buttons & BT_ACCELERATE) From 83f02231e3ea11728079cae27953e7a851c373c2 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:50:34 -0700 Subject: [PATCH 09/18] Replace spectator movement with demo freecam --- src/g_build_ticcmd.cpp | 4 +-- src/g_demo.c | 2 -- src/menus/transient/pause-replay.c | 3 -- src/p_local.h | 8 ----- src/p_tick.c | 4 +-- src/p_user.c | 51 +++--------------------------- src/r_main.c | 16 ++++++---- 7 files changed, 18 insertions(+), 70 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 17ffcaf32..9ee6263f2 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -367,13 +367,13 @@ public: common_button_input(); }; - if (demo.freecam) + if (demo.freecam || player()->spectator) { // freecam is controllable even while paused *cmd = {}; - if (!typing_input()) + if (!typing_input() && !director_input()) { regular_input(); } diff --git a/src/g_demo.c b/src/g_demo.c index ede754ee7..7f58d289e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -4127,8 +4127,6 @@ void G_StopDemo(void) singletics = false; demo.freecam = false; - // reset democam shit too: - democam.cam = NULL; Z_Free(demo.skinlist); demo.skinlist = NULL; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 6db7cee98..163a2885e 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -239,13 +239,10 @@ void M_PlaybackToggleFreecam(INT32 choice) if (!demo.freecam) // toggle on { demo.freecam = true; - democam.cam = &camera[0]; // this is rather useful } else // toggle off { demo.freecam = false; - // reset democam vars: - democam.cam = NULL; } } diff --git a/src/p_local.h b/src/p_local.h index 08b3293ed..22c593c21 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -131,14 +131,6 @@ struct camera_t angle_t old_angle, old_aiming; }; -// demo freecam or something before i commit die -struct demofreecam_s { - - camera_t *cam; // this is useful when the game is paused, notably -}; - -extern struct demofreecam_s democam; - extern camera_t camera[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_dist[MAXSPLITSCREENPLAYERS], cv_cam_still[MAXSPLITSCREENPLAYERS], cv_cam_height[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_speed[MAXSPLITSCREENPLAYERS], cv_cam_rotate[MAXSPLITSCREENPLAYERS]; diff --git a/src/p_tick.c b/src/p_tick.c index b6b470ce5..8e408e92b 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -729,8 +729,8 @@ void P_Ticker(boolean run) timeinmap = (timeinmap-1) & ~3; G_PreviewRewind(leveltime); } - else if (demo.freecam && democam.cam) // special case: allow freecam to MOVE during pause! - P_DemoCameraMovement(democam.cam); + else + P_RunChaseCameras(); // special case: allow freecam to MOVE during pause! return; } diff --git a/src/p_user.c b/src/p_user.c index a6a5076b1..cec39ee8a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2359,45 +2359,6 @@ static void P_UpdatePlayerAngle(player_t *player) } } - -// -// P_SpectatorMovement -// -// Control for spectators in multiplayer -// -static void P_SpectatorMovement(player_t *player) -{ - ticcmd_t *cmd = &player->cmd; - - P_UpdatePlayerAngle(player); - - ticruned++; - if (!(cmd->flags & TICCMD_RECEIVED)) - ticmiss++; - - if (cmd->buttons & BT_ACCELERATE) - player->mo->z += 32*mapobjectscale; - else if (cmd->buttons & BT_BRAKE) - player->mo->z -= 32*mapobjectscale; - - if (!(player->mo->flags & MF_NOCLIPHEIGHT)) - { - if (player->mo->z > player->mo->ceilingz - player->mo->height) - player->mo->z = player->mo->ceilingz - player->mo->height; - if (player->mo->z < player->mo->floorz) - player->mo->z = player->mo->floorz; - } - - player->mo->momx = player->mo->momy = player->mo->momz = 0; - if (cmd->forwardmove != 0) - { - P_Thrust(player->mo, player->mo->angle, cmd->forwardmove*mapobjectscale); - - // Quake-style flying spectators :D - player->mo->momz += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(player->aiming)); - } -} - // // P_MovePlayer void P_MovePlayer(player_t *player) @@ -2424,7 +2385,6 @@ void P_MovePlayer(player_t *player) if (player->spectator) { player->mo->eflags &= ~MFE_VERTICALFLIP; // deflip... - P_SpectatorMovement(player); return; } @@ -2979,16 +2939,12 @@ fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_height[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; -struct demofreecam_s democam; - void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; angle_t thrustangle; player_t *lastp; - // update democam stuff with what we got here: - democam.cam = cam; // first off we need to get button input cmd = D_LocalTiccmd(0); @@ -3004,7 +2960,7 @@ void P_DemoCameraMovement(camera_t *cam) cam->z -= 32*mapobjectscale; // if you hold item, you will lock on to displayplayer. (The last player you were ""f12-ing"") - if (cmd->buttons & BT_ATTACK) + if (demo.freecam && cmd->buttons & BT_ATTACK) { lastp = &players[displayplayers[0]]; // Fun fact, I was trying displayplayers[0]->mo as if it was Lua like an absolute idiot. cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y); @@ -3102,12 +3058,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL) return true; - if (demo.freecam) + if (demo.freecam || player->spectator) { P_DemoCameraMovement(thiscam); return true; } + if (paused || P_AutoPause()) + return true; + playerScale = FixedDiv(player->mo->scale, mapobjectscale); scaleDiff = playerScale - FRACUNIT; diff --git a/src/r_main.c b/src/r_main.c index 6cf539574..8a9abd36c 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1266,8 +1266,12 @@ void R_SetupFrame(int s) R_SetViewContext(VIEWCONTEXT_PLAYER1 + s); - if (player->spectator) // no spectator chasecam - chasecam = false; // force chasecam off + if (player->spectator) + { + // Free flying spectator uses demo freecam. This + // requires chasecam to be enabled. + chasecam = true; + } if (chasecam && (thiscam && !thiscam->chase)) { @@ -1293,7 +1297,7 @@ void R_SetupFrame(int s) R_SetupCommonFrame(player, r_viewmobj->subsector); } - else if (!player->spectator && chasecam) + else if (chasecam) // use outside cam view { r_viewmobj = NULL; @@ -1431,10 +1435,8 @@ boolean R_ViewpointHasChasecam(player_t *player) } } - if (player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN) + if (player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || player->spectator) chasecam = true; // force chasecam on - else if (player->spectator) // no spectator chasecam - chasecam = false; // force chasecam off return chasecam; } @@ -1447,7 +1449,7 @@ boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox) if (player->awayview.tics || skybox) return chasecam; // use outside cam view - else if (!player->spectator && chasecam) + else if (chasecam) return true; // use the player's eyes view From 0f9ceab817918d6da6230c0fc70b830b06b7c5d5 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:55:00 -0700 Subject: [PATCH 10/18] P_DemoCameraMovement: don't let A button press from menu carry over to rise camera --- src/menus/transient/pause-replay.c | 1 + src/p_local.h | 8 ++++++++ src/p_user.c | 18 ++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 163a2885e..46c0a6cfb 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -239,6 +239,7 @@ void M_PlaybackToggleFreecam(INT32 choice) if (!demo.freecam) // toggle on { demo.freecam = true; + democam.button_a_held = 2; } else // toggle off { diff --git a/src/p_local.h b/src/p_local.h index 22c593c21..06f8b9d61 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -131,6 +131,14 @@ struct camera_t angle_t old_angle, old_aiming; }; +// demo freecam or something before i commit die +struct demofreecam_s { + + UINT8 button_a_held; // A button was held since entering from menu, so don't move camera +}; + +extern struct demofreecam_s democam; + extern camera_t camera[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_dist[MAXSPLITSCREENPLAYERS], cv_cam_still[MAXSPLITSCREENPLAYERS], cv_cam_height[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_cam_speed[MAXSPLITSCREENPLAYERS], cv_cam_rotate[MAXSPLITSCREENPLAYERS]; diff --git a/src/p_user.c b/src/p_user.c index cec39ee8a..46df9a0ad 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2939,6 +2939,8 @@ fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_height[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; +struct demofreecam_s democam; + void P_DemoCameraMovement(camera_t *cam) { ticcmd_t *cmd; @@ -2954,10 +2956,18 @@ void P_DemoCameraMovement(camera_t *cam) cam->aiming = G_ClipAimingPitch((INT32 *)&cam->aiming); // camera movement: - if (cmd->buttons & BT_ACCELERATE) - cam->z += 32*mapobjectscale; - else if (cmd->buttons & BT_BRAKE) - cam->z -= 32*mapobjectscale; + if (!democam.button_a_held) + { + if (cmd->buttons & BT_ACCELERATE) + cam->z += 32*mapobjectscale; + else if (cmd->buttons & BT_BRAKE) + cam->z -= 32*mapobjectscale; + } + + if (!(cmd->buttons & BT_ACCELERATE) && democam.button_a_held) + { + democam.button_a_held--; + } // if you hold item, you will lock on to displayplayer. (The last player you were ""f12-ing"") if (demo.freecam && cmd->buttons & BT_ATTACK) From ff447a212a51b37a9a2e7369c6710f3ed46684bf Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 01:58:47 -0700 Subject: [PATCH 11/18] P_DemoCameraMovement: even out vertical angle after toggling After turning on freecam, the vertical angle is tilted slightly downward (this is carried over from normal chasecam). Interpolate that angle back to normal while moving forward. This makes it so you don't need to manually adjust the vertical angle, since it would cause forward movement to send you into the ground. --- src/menus/transient/pause-replay.c | 1 + src/p_local.h | 1 + src/p_user.c | 55 +++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 46c0a6cfb..fba7ec7ed 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -240,6 +240,7 @@ void M_PlaybackToggleFreecam(INT32 choice) { demo.freecam = true; democam.button_a_held = 2; + democam.reset_aiming = true; } else // toggle off { diff --git a/src/p_local.h b/src/p_local.h index 06f8b9d61..919c73dec 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -135,6 +135,7 @@ struct camera_t struct demofreecam_s { UINT8 button_a_held; // A button was held since entering from menu, so don't move camera + boolean reset_aiming; // camera aiming needs to be reset from chase camera }; extern struct demofreecam_s democam; diff --git a/src/p_user.c b/src/p_user.c index 46df9a0ad..e13a247e7 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2947,21 +2947,33 @@ void P_DemoCameraMovement(camera_t *cam) angle_t thrustangle; player_t *lastp; + boolean moving = false; + // first off we need to get button input cmd = D_LocalTiccmd(0); - cam->aiming += cmd->aiming << TICCMD_REDUCE; - cam->angle += cmd->turning << TICCMD_REDUCE; + if (cmd->aiming != 0) + { + cam->aiming += cmd->aiming << TICCMD_REDUCE; - cam->aiming = G_ClipAimingPitch((INT32 *)&cam->aiming); + democam.reset_aiming = false; + } + + cam->angle += cmd->turning << TICCMD_REDUCE; // camera movement: if (!democam.button_a_held) { if (cmd->buttons & BT_ACCELERATE) + { cam->z += 32*mapobjectscale; + moving = true; + } else if (cmd->buttons & BT_BRAKE) + { cam->z -= 32*mapobjectscale; + moving = true; + } } if (!(cmd->buttons & BT_ACCELERATE) && democam.button_a_held) @@ -2975,8 +2987,39 @@ void P_DemoCameraMovement(camera_t *cam) lastp = &players[displayplayers[0]]; // Fun fact, I was trying displayplayers[0]->mo as if it was Lua like an absolute idiot. cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y); cam->aiming = R_PointToAngle2(0, cam->z, R_PointToDist2(cam->x, cam->y, lastp->mo->x, lastp->mo->y), lastp->mo->z + lastp->mo->scale*128*P_MobjFlip(lastp->mo)); // This is still unholy. Aim a bit above their heads. + + democam.reset_aiming = false; } + if (cmd->forwardmove != 0) + { + moving = true; + } + + // After switching to democam, the vertical angle of + // chasecam is inherited. This is intentional because it + // creates a smooth transition. However, moving + // forward/back will have a slope. So, as long as democam + // controls haven't been used to alter the vertical angle, + // slowly reset it to flat. + if (democam.reset_aiming && moving) + { + INT32 aiming = cam->aiming; + INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); + + if (abs(smooth) < abs(aiming)) + { + cam->aiming -= smooth * intsign(aiming); + } + else + { + cam->aiming = 0; + democam.reset_aiming = false; // completely smoothed out + } + } + + G_FinalClipAimingPitch((INT32 *)&cam->aiming, NULL, false); + cam->momx = cam->momy = cam->momz = 0; if (cmd->forwardmove != 0) @@ -2985,7 +3028,11 @@ void P_DemoCameraMovement(camera_t *cam) cam->x += FixedMul(cmd->forwardmove*mapobjectscale, FINECOSINE(thrustangle)); cam->y += FixedMul(cmd->forwardmove*mapobjectscale, FINESINE(thrustangle)); - cam->z += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(cam->aiming)); + + if (!democam.reset_aiming) + { + cam->z += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(cam->aiming)); + } // momentums are useless here, directly add to the coordinates // this.......... doesn't actually check for floors and walls and whatnot but the function to do that is a pure mess so fuck that. From 697e42cecd9ad35f7d8c494fe6807228541d8bc9 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 02:00:46 -0700 Subject: [PATCH 12/18] P_DemoCameraMovement: drift button resets vertical angle --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index e13a247e7..97b6aefde 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3002,7 +3002,7 @@ void P_DemoCameraMovement(camera_t *cam) // forward/back will have a slope. So, as long as democam // controls haven't been used to alter the vertical angle, // slowly reset it to flat. - if (democam.reset_aiming && moving) + if ((democam.reset_aiming && moving) || (cmd->buttons & BT_DRIFT)) { INT32 aiming = cam->aiming; INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); From fcc35c1bb1f1302fe534be7f40cd2921ad633461 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 04:17:01 -0700 Subject: [PATCH 13/18] Toggle between freecam and director using C button --- src/g_build_ticcmd.cpp | 17 ++++++++++++++++- src/k_hud.c | 10 +++++++++- src/menus/transient/pause-replay.c | 11 +---------- src/p_local.h | 1 + src/p_mobj.c | 9 +++++++++ src/p_user.c | 18 ++++++++++++++++-- 6 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 9ee6263f2..5c2abee86 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -206,9 +206,17 @@ class TiccmdBuilder return true; } + void toggle_freecam_input() + { + if (M_MenuButtonPressed(forplayer(), MBT_C)) + { + P_ToggleDemoCamera(); + } + } + bool director_input() { - if (G_IsPartyLocal(displayplayers[forplayer()]) == true) + if (demo.freecam || G_IsPartyLocal(displayplayers[forplayer()]) == true) { return false; } @@ -239,6 +247,8 @@ class TiccmdBuilder } } + toggle_freecam_input(); + return true; } @@ -376,6 +386,11 @@ public: if (!typing_input() && !director_input()) { regular_input(); + + if (demo.freecam) + { + toggle_freecam_input(); + } } return; diff --git a/src/k_hud.c b/src/k_hud.c index 0d928db0c..73caf2d96 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5192,12 +5192,15 @@ static void K_drawDirectorHUD(void) offs = 2; } + K_DrawDirectorButton(offs + 1, "Freecam", kp_button_c[0], 0); + if (p == -1 || !playeringame[p] || players[p].spectator == false) { return; } - K_DrawDirectorButton(offs + 1, "Director", kp_button_r, + // TODO: this is too close to the screen bottom + K_DrawDirectorButton(offs + 2, "Director", kp_button_r, (directorinfo.active ? V_YELLOWMAP : 0)); if (players[p].flashing) @@ -5643,6 +5646,11 @@ void K_drawKartHUD(void) if (stplyr->karthud[khud_trickcool]) K_drawTrickCool(); + if (freecam) + { + K_DrawDirectorButton(3, "Freecam", kp_button_c[0], 0); + } + if (modeattacking || freecam) // everything after here is MP and debug only return; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index fba7ec7ed..68b4859dc 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -236,16 +236,7 @@ void M_PlaybackToggleFreecam(INT32 choice) splitscreen = 0; R_ExecuteSetViewSize(); - if (!demo.freecam) // toggle on - { - demo.freecam = true; - democam.button_a_held = 2; - democam.reset_aiming = true; - } - else // toggle off - { - demo.freecam = false; - } + P_ToggleDemoCamera(); } void M_PlaybackQuit(INT32 choice) diff --git a/src/p_local.h b/src/p_local.h index 919c73dec..b4bd09c51 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -154,6 +154,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); void P_DemoCameraMovement(camera_t *cam); boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled); +void P_ToggleDemoCamera(void); boolean P_PlayerInPain(player_t *player); void P_ResetPlayer(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 47d20059b..ddcce4818 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11969,6 +11969,15 @@ void P_SpawnPlayer(INT32 playernum) { K_ToggleDirector(players[consoleplayer].spectator && pcount > 0); } + + // TODO: handle splitscreen + // Spectators can switch to freecam. This should be + // disabled when they enter the race, or when the level + // changes. + if (playernum == consoleplayer && !demo.playback) + { + demo.freecam = false; + } } void P_AfterPlayerSpawn(INT32 playernum) diff --git a/src/p_user.c b/src/p_user.c index 97b6aefde..caec26b99 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2976,7 +2976,7 @@ void P_DemoCameraMovement(camera_t *cam) } } - if (!(cmd->buttons & BT_ACCELERATE) && democam.button_a_held) + if (!(cmd->buttons & (BT_ACCELERATE | BT_DRIFT)) && democam.button_a_held) { democam.button_a_held--; } @@ -3002,7 +3002,7 @@ void P_DemoCameraMovement(camera_t *cam) // forward/back will have a slope. So, as long as democam // controls haven't been used to alter the vertical angle, // slowly reset it to flat. - if ((democam.reset_aiming && moving) || (cmd->buttons & BT_DRIFT)) + if ((democam.reset_aiming && moving) || ((cmd->buttons & BT_DRIFT) && !democam.button_a_held)) { INT32 aiming = cam->aiming; INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); @@ -3043,6 +3043,20 @@ void P_DemoCameraMovement(camera_t *cam) cam->subsector = R_PointInSubsector(cam->x, cam->y); } +void P_ToggleDemoCamera(void) +{ + if (!demo.freecam) // toggle on + { + demo.freecam = true; + democam.button_a_held = 2; + democam.reset_aiming = true; + } + else // toggle off + { + demo.freecam = false; + } +} + void P_ResetCamera(player_t *player, camera_t *thiscam) { tic_t tries = 0; From c7bd74c6613abbd4c37bccb3523b5058a80bb868 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 04:38:12 -0700 Subject: [PATCH 14/18] Let replays use director controls --- src/g_build_ticcmd.cpp | 7 +------ src/k_hud.c | 5 +++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 5c2abee86..1057595b9 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -377,7 +377,7 @@ public: common_button_input(); }; - if (demo.freecam || player()->spectator) + if (demo.playback || demo.freecam || player()->spectator) { // freecam is controllable even while paused @@ -403,11 +403,6 @@ public: *cmd = {}; // blank ticcmd - if (demo.playback) - { - return; - } - if (gamestate == GS_LEVEL && player()->playerstate == PST_REBORN) { return; diff --git a/src/k_hud.c b/src/k_hud.c index 73caf2d96..569304485 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5169,7 +5169,8 @@ static void K_DrawDirectorButton(INT32 idx, const char *label, patch_t *kp[2], I static void K_drawDirectorHUD(void) { - const INT32 p = G_PartyMember(consoleplayer, R_GetViewNumber()); + const UINT8 viewnum = R_GetViewNumber(); + const INT32 p = viewnum < G_PartySize(consoleplayer) ? G_PartyMember(consoleplayer, viewnum) : -1; const char *itemtxt = "Join"; UINT8 offs = 0; @@ -5667,7 +5668,7 @@ void K_drawKartHUD(void) K_drawKartPowerUps(); - if (G_IsPartyLocal(displayplayers[viewnum]) == false && !demo.playback) + if (G_IsPartyLocal(displayplayers[viewnum]) == false) { K_drawDirectorHUD(); } From 01e2a26689b550d86975978343ea537053e9f82e Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 14 Aug 2023 05:05:21 -0700 Subject: [PATCH 15/18] DEVELOP: let us spectate or pause the game at all times TODO: This should be available as a debugging option at release, since it would be useful for addon authors. I don't want to make more cvars, those are getting cluttered and should maybe be coalesced into a single debugging option. --- src/d_netcmd.c | 6 ++++++ src/g_game.c | 4 ++++ src/k_battle.c | 3 +++ src/p_inter.c | 8 ++++++++ src/p_mobj.c | 3 +++ 5 files changed, 24 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 68abb753f..f49647810 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3690,11 +3690,14 @@ static void Command_Pause(void) CONS_Printf(M_GetText("You can't pause here.\n")); return; } + // TODO: this would make a great debug feature for release +#ifndef DEVELOP else if (modeattacking) // in time attack, pausing restarts the map { //M_ModeAttackRetry(0); // directly call from m_menu; return; } +#endif SendNetXCmd(XD_PAUSE, &buf, 2); } @@ -3715,8 +3718,11 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) return; } + // TODO: this would make a great debug feature for release +#ifndef DEVELOP if (modeattacking && !demo.playback) return; +#endif paused = READUINT8(*cp); dedicatedpause = READUINT8(*cp); diff --git a/src/g_game.c b/src/g_game.c index e108861df..08fc60159 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3318,6 +3318,10 @@ boolean G_GametypeHasTeams(void) // boolean G_GametypeHasSpectators(void) { + // TODO: this would make a great debug feature for release +#ifdef DEVELOP + return true; +#endif return (netgame || (multiplayer && demo.netgame)); } diff --git a/src/k_battle.c b/src/k_battle.c index 66e98561c..837f173b4 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -127,7 +127,10 @@ void K_CheckBumpers(void) { if (nobumpers > 0 && nobumpers >= numingame) { + // TODO: this would make a great debug feature for release +#ifndef DEVELOP P_DoAllPlayersExit(PF_NOCONTEST, false); +#endif return; } } diff --git a/src/p_inter.c b/src/p_inter.c index fb2a7a071..918c3faca 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1998,7 +1998,15 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (!player->exiting && (specialstageinfo.valid == true || modeattacking & ATTACKING_SPB)) { + // TODO: this would make a great debug feature for release +#ifdef DEVELOP + if (type != DMG_SPECTATOR) + { + P_DoPlayerExit(player, PF_NOCONTEST); + } +#else P_DoPlayerExit(player, PF_NOCONTEST); +#endif } if (player->exiting) diff --git a/src/p_mobj.c b/src/p_mobj.c index ddcce4818..e3abdee26 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11841,7 +11841,10 @@ void P_SpawnPlayer(INT32 playernum) } else // Otherwise, never spectator. { + // TODO: this would make a great debug feature for release +#ifndef DEVELOP p->spectator = false; +#endif } } From 00360065864e5d7693107c09e29f19c98c00ca73 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 15 Aug 2023 01:15:56 -0700 Subject: [PATCH 16/18] R_ViewRollAngle: don't apply camera tilting while using freecam --- src/r_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.c b/src/r_main.c index 8a9abd36c..d50c43644 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -979,7 +979,7 @@ angle_t R_ViewRollAngle(const player_t *player) if (cv_tilting.value) { - if (!player->spectator) + if (!player->spectator && !demo.freecam) { roll += player->tilt; } From 414d6f3647ce905ff61ead9c7142b149f107f8cc Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 17:38:24 -0700 Subject: [PATCH 17/18] Don't reset camera position when spectating Fixes a software renderer crash due to hitlag VFX from the player's death (death from spectating) being too close to the camera. --- src/p_mobj.c | 11 +++++++---- src/p_setup.c | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index e3abdee26..ab0d25e5e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12014,12 +12014,15 @@ void P_AfterPlayerSpawn(INT32 playernum) p->drawangle = mobj->angle; - for (i = 0; i <= r_splitscreen; i++) + if (p->spectator == false) { - if (camera[i].chase) + for (i = 0; i <= r_splitscreen; i++) { - if (displayplayers[i] == playernum) - P_ResetCamera(p, &camera[i]); + if (camera[i].chase) + { + if (displayplayers[i] == playernum) + P_ResetCamera(p, &camera[i]); + } } } diff --git a/src/p_setup.c b/src/p_setup.c index 3f9bfcd2e..48caf293a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7735,6 +7735,8 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) cam->subsector = R_PointInSubsector(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) } } + + cam->chase = false; // tell camera to reset its position next tic } static void P_InitCamera(void) From 7a1e61d722aed94c87340a35d646fcf986a17f86 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Aug 2023 17:39:41 -0700 Subject: [PATCH 18/18] Move democam.reset_aiming to camera_t, let spectator camera even out aiming --- src/p_local.h | 4 +++- src/p_user.c | 14 ++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index b4bd09c51..a09caf896 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -126,6 +126,9 @@ struct camera_t // SRB2Kart: camera pitches on slopes angle_t pitch; + // Freecam: aiming needs to be reset after switching from chasecam + boolean reset_aiming; + // Interpolation data fixed_t old_x, old_y, old_z; angle_t old_angle, old_aiming; @@ -135,7 +138,6 @@ struct camera_t struct demofreecam_s { UINT8 button_a_held; // A button was held since entering from menu, so don't move camera - boolean reset_aiming; // camera aiming needs to be reset from chase camera }; extern struct demofreecam_s democam; diff --git a/src/p_user.c b/src/p_user.c index caec26b99..df58dc55f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2956,7 +2956,7 @@ void P_DemoCameraMovement(camera_t *cam) { cam->aiming += cmd->aiming << TICCMD_REDUCE; - democam.reset_aiming = false; + cam->reset_aiming = false; } cam->angle += cmd->turning << TICCMD_REDUCE; @@ -2988,7 +2988,7 @@ void P_DemoCameraMovement(camera_t *cam) cam->angle = R_PointToAngle2(cam->x, cam->y, lastp->mo->x, lastp->mo->y); cam->aiming = R_PointToAngle2(0, cam->z, R_PointToDist2(cam->x, cam->y, lastp->mo->x, lastp->mo->y), lastp->mo->z + lastp->mo->scale*128*P_MobjFlip(lastp->mo)); // This is still unholy. Aim a bit above their heads. - democam.reset_aiming = false; + cam->reset_aiming = false; } if (cmd->forwardmove != 0) @@ -3002,7 +3002,7 @@ void P_DemoCameraMovement(camera_t *cam) // forward/back will have a slope. So, as long as democam // controls haven't been used to alter the vertical angle, // slowly reset it to flat. - if ((democam.reset_aiming && moving) || ((cmd->buttons & BT_DRIFT) && !democam.button_a_held)) + if ((cam->reset_aiming && moving) || ((cmd->buttons & BT_DRIFT) && !democam.button_a_held)) { INT32 aiming = cam->aiming; INT32 smooth = FixedMul(ANGLE_11hh / 4, FCOS(cam->aiming)); @@ -3014,7 +3014,7 @@ void P_DemoCameraMovement(camera_t *cam) else { cam->aiming = 0; - democam.reset_aiming = false; // completely smoothed out + cam->reset_aiming = false; // completely smoothed out } } @@ -3029,7 +3029,7 @@ void P_DemoCameraMovement(camera_t *cam) cam->x += FixedMul(cmd->forwardmove*mapobjectscale, FINECOSINE(thrustangle)); cam->y += FixedMul(cmd->forwardmove*mapobjectscale, FINESINE(thrustangle)); - if (!democam.reset_aiming) + if (!cam->reset_aiming) { cam->z += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(cam->aiming)); } @@ -3049,7 +3049,7 @@ void P_ToggleDemoCamera(void) { demo.freecam = true; democam.button_a_held = 2; - democam.reset_aiming = true; + camera[0].reset_aiming = true; } else // toggle off { @@ -3093,6 +3093,8 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->radius = 20*FRACUNIT; thiscam->height = 16*FRACUNIT; + thiscam->reset_aiming = true; + while (!P_MoveChaseCamera(player,thiscam,true) && ++tries < 2*TICRATE); }