diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e5321d225d0e0b1d03a72b0a71061e6b9020ee9b..b03eb478ea16a014fd8c33ec515ece903bdee582 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3599,10 +3599,6 @@ boolean SV_SpawnServer(void) if (netgame && I_NetOpenSocket) { I_NetOpenSocket(); -#ifdef MASTERSERVER - if (cv_advertise.value) - RegisterServer(); -#endif } // non dedicated server just connect to itself diff --git a/src/d_player.h b/src/d_player.h index 81c70c1306ee1dc40455d10f9d6f1f7a67d2acae..4908d849088c2162d49f53d9ca97aacfe22177f9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -328,7 +328,6 @@ typedef struct player_s skybox_t skybox; angle_t viewrollangle; - angle_t old_viewrollangle; // camera tilt // TODO: expose to lua angle_t tilt; diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index 4b264a68ae4293633ba76236ef6fe2949b479366..4994cc206e3e8bad18a11aa1e1c202162fa26315 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -50,6 +50,9 @@ typedef enum // ticcmd turning bits #define TICCMD_REDUCE 16 +// ticcmd latency mask +#define TICCMD_LATENCYMASK 0xFF + // ticcmd flags #define TICCMD_RECEIVED 1 #define TICCMD_TYPING 2/* chat window or console open */ diff --git a/src/g_game.c b/src/g_game.c index 7915c06480fa6e928dd2fd20b16c4a8e50bf961d..21467e592a5f23beb5d706bca87cbfdbab1f7825 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -871,6 +871,78 @@ static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvect INT32 localaiming[MAXSPLITSCREENPLAYERS]; angle_t localangle[MAXSPLITSCREENPLAYERS]; +INT32 localsteering[MAXSPLITSCREENPLAYERS]; +INT32 localdelta[MAXSPLITSCREENPLAYERS]; +INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1]; +UINT8 localtic; + +void G_ResetAnglePrediction(player_t *player) +{ + UINT16 i, j; + + for (i = 0; i <= r_splitscreen; i++) + { + if (&players[displayplayers[i]] == player) + { + localdelta[i] = 0; + for (j = 0; j < TICCMD_LATENCYMASK; j++) + { + localstoredeltas[i][j] = 0; + } + break; + } + } +} + +// Turning was removed from G_BuildTiccmd to prevent easy client hacking. +// This brings back the camera prediction that was lost. +static void G_DoAnglePrediction(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer, player_t *player) +{ + angle_t angleChange = 0; + angle_t destAngle = player->angleturn; + angle_t diff = 0; + + localtic = cmd->latency; + + if (player->pflags & PF_DRIFTEND) + { + // Otherwise, your angle slingshots off to the side violently... + G_ResetAnglePrediction(player); + } + else + { + while (realtics > 0) + { + localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning); + angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE; + + // Store the angle we applied to this tic, so we can revert it later. + // If we trust the camera to do all of the work, then it can get out of sync fast. + localstoredeltas[ssplayer - 1][cmd->latency] += angleChange; + localdelta[ssplayer - 1] += angleChange; + + realtics--; + } + } + + // We COULD set it to destAngle directly... + // but this causes incredible jittering when the prediction turns out to be wrong. So we ease into it. + // Slight increased camera lag in all scenarios > Mostly lagless camera but with jittering + destAngle = player->angleturn + localdelta[ssplayer - 1]; + diff = destAngle - localangle[ssplayer - 1]; + + if (diff > ANGLE_180) + { + diff = InvAngle(InvAngle(diff) / 2); + } + else + { + diff /= 2; + } + + localangle[ssplayer - 1] += diff; +} + void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { const UINT8 forplayer = ssplayer-1; @@ -896,8 +968,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) boolean *rd = &resetdown[forplayer]; const boolean mouseaiming = player->spectator; - (void)realtics; - if (demo.playback) return; // Is there any reason this can't just be I_BaseTiccmd? @@ -1153,7 +1223,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // Send leveltime when this tic was generated to the server for control lag calculations. // Only do this when in a level. Also do this after the hook, so that it can't overwrite this. - cmd->latency = (leveltime & 0xFF); + cmd->latency = (leveltime & TICCMD_LATENCYMASK); } if (cmd->forwardmove > MAXPLMOVE) @@ -1171,6 +1241,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) else if (cmd->throwdir < -KART_FULLTURN) cmd->throwdir = -KART_FULLTURN; + G_DoAnglePrediction(cmd, realtics, ssplayer, player); + // Reset away view if a command is given. if ((cmd->forwardmove || cmd->buttons) && !r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1) @@ -1936,7 +2008,7 @@ void G_Ticker(boolean run) else { //@TODO add a cvar to allow setting this max - cmd->latency = min(((leveltime & 0xFF) - cmd->latency) & 0xFF, MAXPREDICTTICS-1); + cmd->latency = min(((leveltime & TICCMD_LATENCYMASK) - cmd->latency) & TICCMD_LATENCYMASK, MAXPREDICTTICS-1); } } } diff --git a/src/g_game.h b/src/g_game.h index cb0cae127126c88c9bc5b23b0759bc1d55c161ab..52c7c7a0d2ee8c080326a03371996c964f7e4423 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -84,6 +84,7 @@ extern consvar_t cv_resume; // build an internal map name MAPxx from map number const char *G_BuildMapName(INT32 map); +void G_ResetAnglePrediction(player_t *player); void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer); // copy ticcmd_t to and fro the normal way @@ -117,6 +118,10 @@ INT32 PlayerJoyAxis(UINT8 player, axis_input_e axissel); extern angle_t localangle[MAXSPLITSCREENPLAYERS]; extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed +extern INT32 localsteering[MAXSPLITSCREENPLAYERS]; +extern INT32 localdelta[MAXSPLITSCREENPLAYERS]; +extern INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1]; +extern UINT8 localtic; // // GAME diff --git a/src/k_hud.c b/src/k_hud.c index 00537f81b78c6668ecde0af923149bab094aa4ab..3861f2e0876d99f79d52b73997c56634a08677b2 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -825,16 +825,11 @@ void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du } // This version of the function was prototyped in Lua by Nev3r ... a HUGE thank you goes out to them! -// TODO: This should probably support view rolling if we're adding that soon... -void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNum, angle_t angleOffset) +void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean reverse) { #define NEWTAN(x) FINETANGENT(((x + ANGLE_90) >> ANGLETOFINESHIFT) & 4095) // tan function used by Lua #define NEWCOS(x) FINECOSINE((x >> ANGLETOFINESHIFT) & FINEMASK) - camera_t *cam; - player_t *player; - - fixed_t viewpointX, viewpointY, viewpointZ; angle_t viewpointAngle, viewpointAiming, viewpointRoll; INT32 screenWidth, screenHeight; @@ -846,6 +841,8 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu fixed_t h; INT32 da; + UINT8 cameraNum = R_GetViewNumber(); + I_Assert(result != NULL); I_Assert(point != NULL); @@ -854,49 +851,21 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu result->scale = FRACUNIT; result->onScreen = false; - if (cameraNum > r_splitscreen) - { - // Invalid camera ID. - return; - } - - cam = &camera[cameraNum]; - player = &players[displayplayers[cameraNum]]; - - if (cam == NULL || player == NULL || player->mo == NULL || P_MobjWasRemoved(player->mo) == true) - { - // Shouldn't be possible? - return; - } - - // TODO: parts need interp - if (cam->chase == true && !player->spectator) + // Take the view's properties as necessary. + if (reverse) { - // Use the camera's properties. - viewpointX = R_InterpolateFixed(cam->old_x, cam->x); - viewpointY = R_InterpolateFixed(cam->old_y, cam->y); - viewpointZ = R_InterpolateFixed(cam->old_z, cam->z) - point->z; - viewpointAngle = (INT32)R_InterpolateAngle(cam->old_angle, cam->angle); - viewpointAiming = (INT32)R_InterpolateAngle(cam->old_aiming, cam->aiming); - viewpointRoll = (INT32)R_InterpolateAngle(player->old_viewrollangle, player->viewrollangle); + viewpointAngle = (INT32)(viewangle + ANGLE_180); + viewpointAiming = (INT32)InvAngle(aimingangle); + viewpointRoll = (INT32)viewroll; } else { - // Use player properties. - viewpointX = R_InterpolateFixed(player->mo->old_x, player->mo->x); - viewpointY = R_InterpolateFixed(player->mo->old_y, player->mo->y); - viewpointZ = R_InterpolateFixed(player->mo->old_z, player->mo->z) - point->z; //player->old_viewz - viewpointAngle = (INT32)R_InterpolateAngle(player->mo->old_angle, player->mo->angle); - viewpointAiming = (INT32)player->aiming; - viewpointRoll = (INT32)R_InterpolateAngle(player->old_viewrollangle, player->viewrollangle); + viewpointAngle = (INT32)viewangle; + viewpointAiming = (INT32)aimingangle; + viewpointRoll = (INT32)InvAngle(viewroll); } - viewpointAngle += (INT32)angleOffset; - - (void)viewpointRoll; // will be used later... - // Calculate screen size adjustments. - // TODO: Anyone want to make this support non-green resolutions somehow? :V screenWidth = vid.width/vid.dupx; screenHeight = vid.height/vid.dupy; @@ -917,7 +886,7 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu // Calculate FOV adjustments. fovDiff = cv_fov[cameraNum].value - baseFov; - fov = ((baseFov - fovDiff) / 2) - (player->fovadd / 2); + fov = ((baseFov - fovDiff) / 2) - (stplyr->fovadd / 2); fovTangent = NEWTAN(FixedAngle(fov)); if (r_splitscreen == 1) @@ -929,23 +898,36 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNu fg = (screenWidth >> 1) * fovTangent; // Determine viewpoint factors. - h = R_PointToDist2(point->x, point->y, viewpointX, viewpointY); - da = AngleDeltaSigned(viewpointAngle, R_PointToAngle2(point->x, point->y, viewpointX, viewpointY)); - - // Set results! - result->x = screenHalfW + FixedMul(NEWTAN(da), fg); - result->y = screenHalfH + FixedMul((NEWTAN(viewpointAiming) - FixedDiv(viewpointZ, 1 + FixedMul(NEWCOS(da), h))), fg); + h = R_PointToDist2(point->x, point->y, viewx, viewy); + da = AngleDeltaSigned(viewpointAngle, R_PointToAngle2(point->x, point->y, viewx, viewy)); - result->scale = FixedDiv(screenHalfW, h+1); + // Set results relative to top left! + result->x = FixedMul(NEWTAN(da), fg); + result->y = FixedMul((NEWTAN(viewpointAiming) - FixedDiv((viewz - point->z), 1 + FixedMul(NEWCOS(da), h))), fg); - result->onScreen = ((abs(da) > ANG60) || (abs(AngleDeltaSigned(viewpointAiming, R_PointToAngle2(0, 0, h, viewpointZ))) > ANGLE_45)); + // Rotate for screen roll... + if (viewpointRoll) + { + fixed_t tempx = result->x; + viewpointRoll >>= ANGLETOFINESHIFT; + result->x = FixedMul(FINECOSINE(viewpointRoll), tempx) - FixedMul(FINESINE(viewpointRoll), result->y); + result->y = FixedMul(FINESINE(viewpointRoll), tempx) + FixedMul(FINECOSINE(viewpointRoll), result->y); + } + // Flipped screen? if (encoremode) { - // Flipped screen - result->x = (screenWidth << FRACBITS) - result->x; + result->x = -result->x; } + // Center results. + result->x += screenHalfW; + result->y += screenHalfH; + + result->scale = FixedDiv(screenHalfW, h+1); + + result->onScreen = ((abs(da) > ANG60) || (abs(AngleDeltaSigned(viewpointAiming, R_PointToAngle2(0, 0, h, (viewz - point->z)))) > ANGLE_45)); + // Cheap dirty hacks for some split-screen related cases if (result->x < 0 || result->x > (screenWidth << FRACBITS)) { @@ -2841,7 +2823,6 @@ static void K_drawKartWanted(void) static void K_drawKartPlayerCheck(void) { const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - UINT8 cnum = 0; UINT8 i; INT32 splitflags = V_SNAPTOBOTTOM|V_SPLITSCREEN; fixed_t y = CHEK_Y * FRACUNIT; @@ -2861,20 +2842,6 @@ static void K_drawKartPlayerCheck(void) return; } - if (r_splitscreen) - { - y /= 2; - - for (i = 1; i <= r_splitscreen; i++) - { - if (stplyr == &players[displayplayers[i]]) - { - cnum = i; - break; - } - } - } - for (i = 0; i < MAXPLAYERS; i++) { player_t *checkplayer = &players[i]; @@ -2933,7 +2900,7 @@ static void K_drawKartPlayerCheck(void) pnum += 2; } - K_ObjectTracking(&result, &v, cnum, ANGLE_180); + K_ObjectTracking(&result, &v, true); if (result.onScreen == true) { @@ -3008,7 +2975,7 @@ static void K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p) } } -static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT8 cnum) +static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p) { const INT32 clr = skincolors[p->skincolor].chatcolor; const INT32 namelen = V_ThinStringWidth(player_names[p - players], V_6WIDTHSPACE|V_ALLOWLOWERCASE); @@ -3016,6 +2983,8 @@ static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, UINT8 cnum UINT8 *colormap = V_GetStringColormap(clr); INT32 barx = 0, bary = 0, barw = 0; + UINT8 cnum = R_GetViewNumber(); + // Since there's no "V_DrawFixedFill", and I don't feel like making it, // fuck it, we're gonna just V_NOSCALESTART hack it if (cnum & 1) @@ -3100,9 +3069,8 @@ static void K_DrawWeakSpot(weakspotdraw_t *ws) static void K_drawKartNameTags(void) { const fixed_t maxdistance = 8192*mapobjectscale; - camera_t *thiscam; vector3_t c; - UINT8 cnum = 0; + UINT8 cnum = R_GetViewNumber(); UINT8 tobesorted[MAXPLAYERS]; fixed_t sortdist[MAXPLAYERS]; UINT8 sortlen = 0; @@ -3118,32 +3086,9 @@ static void K_drawKartNameTags(void) return; } - if (r_splitscreen) - { - for (i = 1; i <= r_splitscreen; i++) - { - if (stplyr == &players[displayplayers[i]]) - { - cnum = i; - break; - } - } - } - - thiscam = &camera[cnum]; - - if (thiscam->chase == true) - { - c.x = R_InterpolateFixed(thiscam->old_x, thiscam->x); - c.y = R_InterpolateFixed(thiscam->old_y, thiscam->y); - c.z = R_InterpolateFixed(thiscam->old_z, thiscam->z); - } - else - { - c.x = R_InterpolateFixed(stplyr->mo->old_x, stplyr->mo->x); - c.y = R_InterpolateFixed(stplyr->mo->old_y, stplyr->mo->y); - c.z = R_InterpolateFixed(stplyr->mo->old_z, stplyr->mo->z); - } + c.x = viewx; + c.y = viewy; + c.z = viewz; // Maybe shouldn't be handling this here... but the camera info is too good. if (bossinfo.boss) @@ -3175,7 +3120,7 @@ static void K_drawKartNameTags(void) v.z += (bossinfo.weakspots[i].spot->height / 2); - K_ObjectTracking(&result, &v, cnum, 0); + K_ObjectTracking(&result, &v, false); if (result.onScreen == false) { continue; @@ -3328,7 +3273,7 @@ static void K_drawKartNameTags(void) v.z += headOffset; } - K_ObjectTracking(&result, &v, cnum, 0); + K_ObjectTracking(&result, &v, false); if (result.onScreen == true) { @@ -3363,7 +3308,7 @@ static void K_drawKartNameTags(void) { if (K_ShowPlayerNametag(ntplayer) == true) { - K_DrawNameTagForPlayer(result.x, result.y, ntplayer, cnum); + K_DrawNameTagForPlayer(result.x, result.y, ntplayer); K_DrawTypingNotifier(result.x, result.y, ntplayer); } } diff --git a/src/k_hud.h b/src/k_hud.h index fff718ef5bb4fe150c93752a473fee0c2657cdbe..683425e8a7cd6a433c9f70ca722598f4efa49b86 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -28,7 +28,7 @@ typedef struct trackingResult_s boolean onScreen; } trackingResult_t; -void K_ObjectTracking(trackingResult_t *result, vector3_t *point, UINT8 cameraNum, angle_t angleOffset); +void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean reverse); const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_LoadKartHUDGraphics(void); diff --git a/src/k_kart.c b/src/k_kart.c index 74b6f42fde332768825a4387c74147514ba38042..b2fa1b6278a7c273f656710116e4a14d6a33a039 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8236,31 +8236,34 @@ static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer) return basedrift + (FixedMul(driftadjust * FRACUNIT, countersteer) / FRACUNIT); } -void K_UpdateSteeringValue(player_t *player, INT16 destSteering) +INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) { // player->steering is the turning value, but with easing applied. // Keeps micro-turning from old easing, but isn't controller dependent. const INT16 amount = KART_FULLTURN/4; - INT16 diff = destSteering - player->steering; + INT16 diff = destSteering - inputSteering; + INT16 outputSteering = inputSteering; if (abs(diff) <= amount) { // Reached the intended value, set instantly. - player->steering = destSteering; + outputSteering = destSteering; } else { // Go linearly towards the value we wanted. if (diff < 0) { - player->steering -= amount; + outputSteering -= amount; } else { - player->steering += amount; + outputSteering += amount; } } + + return outputSteering; } INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) diff --git a/src/k_kart.h b/src/k_kart.h index c0bd71462e56e9b7f1efd6f268cb15d53fbf13da..20c8cd33f07f838db0830d3ae120f74ccfe4be84 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -98,7 +98,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); INT32 K_GetKartRingPower(player_t *player, boolean boosted); void K_UpdateDistanceFromFinishLine(player_t *const player); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); -void K_UpdateSteeringValue(player_t *player, INT16 destSteering); +INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering); INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); INT32 K_GetUnderwaterTurnAdjust(player_t *player); INT32 K_GetKartDriftSparkValue(player_t *player); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 8245cb1e82ea154678e34a35662296bae79abab7..ad65555413e2d7157d5a9684452589fcae0a455d 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -14,6 +14,7 @@ #include "fastcmp.h" #include "r_defs.h" #include "r_local.h" +#include "r_fps.h" #include "st_stuff.h" #include "g_game.h" #include "i_video.h" // rendermode @@ -1394,26 +1395,9 @@ void LUAh_GameHUD(player_t *stplayr, huddrawlist_h list) lua_remove(gL, -3); // pop HUD LUA_PushUserdata(gL, stplayr, META_PLAYER); - if (r_splitscreen > 2 && stplayr == &players[displayplayers[3]]) - { - LUA_PushUserdata(gL, &camera[3], META_CAMERA); - camnum = 4; - } - else if (r_splitscreen > 1 && stplayr == &players[displayplayers[2]]) - { - LUA_PushUserdata(gL, &camera[2], META_CAMERA); - camnum = 3; - } - else if (r_splitscreen && stplayr == &players[displayplayers[1]]) - { - LUA_PushUserdata(gL, &camera[1], META_CAMERA); - camnum = 2; - } - else - { - LUA_PushUserdata(gL, &camera[0], META_CAMERA); - camnum = 1; - } + camnum = R_GetViewNumber(); + LUA_PushUserdata(gL, &camera[camnum], META_CAMERA); + camnum++; // for compatibility lua_pushnil(gL); while (lua_next(gL, -5) != 0) { diff --git a/src/p_setup.c b/src/p_setup.c index baba85ee87878e451c5256cea8411a5c810f19b1..c1da43eef71ce99b5fd5b0990aac8d20f1f057cb 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4509,6 +4509,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (rendermode == render_none || reloadinggamestate) return true; + R_ResetViewInterpolation(0); + R_ResetViewInterpolation(0); + R_UpdateMobjInterpolators(); + // Title card! G_StartTitleCard(); diff --git a/src/p_user.c b/src/p_user.c index 145835e481c5fe785f6b53d42f05ae0105257e86..dbf7169257b1f12df9ee12ac6602d1f2cacd2638 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2003,13 +2003,46 @@ static void P_3dMovement(player_t *player) static void P_UpdatePlayerAngle(player_t *player) { angle_t angleChange = ANGLE_MAX; + UINT8 p = UINT8_MAX; UINT8 i; - K_UpdateSteeringValue(player, player->cmd.turning); + for (i = 0; i <= splitscreen; i++) + { + if (player == &players[g_localplayers[i]]) + { + p = i; + break; + } + } + + player->steering = K_UpdateSteeringValue(player->steering, player->cmd.turning); angleChange = K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE; - P_SetPlayerAngle(player, player->angleturn + angleChange); - player->mo->angle = player->angleturn; + if (p == UINT8_MAX) + { + // When F12ing players, set local angle directly. + P_SetPlayerAngle(player, player->angleturn + angleChange); + player->mo->angle = player->angleturn; + } + else + { + UINT8 lateTic = ((leveltime - player->cmd.latency) & TICCMD_LATENCYMASK); + UINT8 clearTic = ((localtic + 1) & TICCMD_LATENCYMASK); + + player->angleturn += angleChange; + player->mo->angle = player->angleturn; + + // Undo the ticcmd's old emulated angle, + // now that we added the actual game logic angle. + + while (lateTic != clearTic) + { + localdelta[p] -= localstoredeltas[p][lateTic]; + localstoredeltas[p][lateTic] = 0; + + lateTic = (lateTic - 1) & TICCMD_LATENCYMASK; + } + } if (!cv_allowmlook.value || player->spectator == false) { @@ -2021,13 +2054,9 @@ static void P_UpdatePlayerAngle(player_t *player) player->aiming = G_ClipAimingPitch((INT32 *)&player->aiming); } - for (i = 0; i <= r_splitscreen; i++) + if (p != UINT8_MAX) { - if (player == &players[displayplayers[i]]) - { - localaiming[i] = player->aiming; - break; - } + localaiming[p] = player->aiming; } } @@ -3593,7 +3622,11 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } if (lookbackdown) + { P_MoveChaseCamera(player, thiscam, false); + R_ResetViewInterpolation(num + 1); + R_ResetViewInterpolation(num + 1); + } return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); @@ -4328,7 +4361,6 @@ void P_PlayerThink(player_t *player) } player->old_drawangle = player->drawangle; - player->old_viewrollangle = player->viewrollangle; player->pflags &= ~PF_HITFINISHLINE; @@ -4866,6 +4898,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle) if (player == &players[displayplayers[i]]) { localangle[i] = angle; + G_ResetAnglePrediction(player); break; } } diff --git a/src/r_fps.c b/src/r_fps.c index 6f4281687646ad98de5ba397cd6b75cddf284a89..aff4819105ec34757290d1be181feed02c7bf015 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -163,22 +163,7 @@ void R_InterpolateView(fixed_t frac) if (frac > FRACUNIT) frac = FRACUNIT; - if (viewcontext == VIEWCONTEXT_SKY1 || viewcontext == VIEWCONTEXT_PLAYER1) - { - i = 0; - } - else if (viewcontext == VIEWCONTEXT_SKY2 || viewcontext == VIEWCONTEXT_PLAYER2) - { - i = 1; - } - else if (viewcontext == VIEWCONTEXT_SKY3 || viewcontext == VIEWCONTEXT_PLAYER3) - { - i = 2; - } - else - { - i = 3; - } + i = R_GetViewNumber(); if (oldview_invalid[i] != 0) { diff --git a/src/r_fps.h b/src/r_fps.h index a91f7004eb2e8f6c2356f1ca59a7d5babdf7d0fc..41fc65af05d87bf38a936a3afd5c6e985d2a757e 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -36,6 +36,10 @@ enum viewcontext_e VIEWCONTEXT_SKY4 }; +extern enum viewcontext_e viewcontext; + +#define R_GetViewNumber() ((viewcontext - VIEWCONTEXT_PLAYER1) & 3) + typedef struct { fixed_t x; fixed_t y; diff --git a/src/st_stuff.c b/src/st_stuff.c index 9b98f0b6837262efcc9f55ad98cab2dd1c0066fa..bb1cea9ff601689eb1e81feebef7fa29e5b78fc0 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -33,6 +33,7 @@ #include "p_setup.h" // NiGHTS grading #include "k_grandprix.h" // we need to know grandprix status for titlecards #include "k_boss.h" +#include "r_fps.h" //random index #include "m_random.h" @@ -1002,8 +1003,17 @@ static void ST_overlayDrawer(void) { // hu_showscores = auto hide score/time/rings when tab rankings are shown if (!(hu_showscores && (netgame || multiplayer))) + { K_drawKartHUD(); + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_game); + LUAh_GameHUD(stplyr, luahuddrawlist_game); + } + LUA_HUD_DrawList(luahuddrawlist_game); + } + if (!hu_showscores) // hide the following if TAB is held { if (cv_showviewpointtext.value) @@ -1031,16 +1041,6 @@ static void ST_overlayDrawer(void) } } - if (!(netgame || multiplayer) || !hu_showscores) - { - if (renderisnewtic) - { - LUA_HUD_ClearDrawList(luahuddrawlist_game); - LUAh_GameHUD(stplyr, luahuddrawlist_game); - } - LUA_HUD_DrawList(luahuddrawlist_game); - } - if (!hu_showscores && netgame && !mapreset) { if (stplyr->spectator && LUA_HudEnabled(hud_textspectator)) @@ -1081,32 +1081,6 @@ static void ST_overlayDrawer(void) } } } - - // Replay manual-save stuff - if (demo.recording && multiplayer && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) - { - switch (demo.savemode) - { - case DSM_NOTSAVING: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Look Backward: Save replay"); - break; - - case DSM_WILLAUTOSAVE: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Replay will be saved. (Look Backward: Change title)"); - break; - - case DSM_WILLSAVE: - V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Replay will be saved."); - break; - - case DSM_TITLEENTRY: - ST_DrawDemoTitleEntry(); - break; - - default: // Don't render anything - break; - } - } } void ST_DrawDemoTitleEntry(void) @@ -1217,6 +1191,8 @@ void ST_Drawer(void) for (i = 0; i <= r_splitscreen; i++) { stplyr = &players[displayplayers[i]]; + R_SetViewContext(VIEWCONTEXT_PLAYER1 + i); + R_InterpolateView(rendertimefrac); // to assist with object tracking ST_overlayDrawer(); } @@ -1232,5 +1208,31 @@ void ST_Drawer(void) if (stagetitle) ST_drawTitleCard(); + // Replay manual-save stuff + if (demo.recording && multiplayer && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) + { + switch (demo.savemode) + { + case DSM_NOTSAVING: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Look Backward: Save replay"); + break; + + case DSM_WILLAUTOSAVE: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Replay will be saved. (Look Backward: Change title)"); + break; + + case DSM_WILLSAVE: + V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Replay will be saved."); + break; + + case DSM_TITLEENTRY: + ST_DrawDemoTitleEntry(); + break; + + default: // Don't render anything + break; + } + } + ST_drawDebugInfo(); }