From bda7d26a0fc960895dfad6535f3670224db6ccb4 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Mar 2025 20:03:10 -0400 Subject: [PATCH] Port basic lap anticheat for new waypoints from RR --- src/d_netcmd.c | 1 + src/d_netcmd.h | 2 +- src/d_player.h | 6 +++- src/deh_soc.c | 2 ++ src/deh_tables.c | 2 +- src/doomstat.h | 1 + src/g_game.c | 13 ++++++++ src/k_hud.c | 5 +++ src/k_kart.c | 81 ++++++++++++++++++++++++++++++++++++++++----- src/k_kart.h | 3 ++ src/lua_maplib.c | 2 ++ src/lua_playerlib.c | 12 +++++++ src/p_saveg.c | 9 +++++ src/p_setup.c | 1 + src/p_spec.c | 18 +++++++++- 15 files changed, 145 insertions(+), 13 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4848f2235..0ecb50e84 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -469,6 +469,7 @@ consvar_t cv_kartdebugdistribution = CVAR_INIT ("kartdebugdistribution", "Off", consvar_t cv_kartdebughuddrop = CVAR_INIT ("kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL); static CV_PossibleValue_t kartdebugwaypoint_cons_t[] = {{0, "Off"}, {1, "Forwards"}, {2, "Backwards"}, {0, NULL}}; consvar_t cv_kartdebugwaypoints = CVAR_INIT ("kartdebugwaypoints", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, kartdebugwaypoint_cons_t, NULL); +consvar_t cv_kartdebuglap = CVAR_INIT ("kartdebuglap", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, kartdebugwaypoint_cons_t, NULL); consvar_t cv_kartdebugbotpredict = CVAR_INIT ("kartdebugbotpredict", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL); consvar_t cv_kartdebugcheckpoint = CVAR_INIT ("kartdebugcheckpoint", "Off", CV_NOSHOWHELP, CV_OnOff, NULL); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 1b6ff0d11..285d4b19c 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -106,7 +106,7 @@ extern consvar_t cv_votetime; extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartallowgiveitem, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugcheckpoint, cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector; -extern consvar_t cv_kartdebugwaypoints, cv_kartdebugbotpredict; +extern consvar_t cv_kartdebugwaypoints, cv_kartdebuglap,cv_kartdebugbotpredict; extern consvar_t cv_itemfinder; diff --git a/src/d_player.h b/src/d_player.h index 44899a11f..a081e7476 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -102,7 +102,7 @@ typedef enum PF_UPDATEMYRESPAWN = 1<<19, PF_FLIPCAM = 1<<20, - //free = 1<<21, + PF_TRUSTWAYPOINTS = 1<<21, // Do not activate lap cheat prevention next time finish line distance is updated PF_HITFINISHLINE = 1<<22, // Already hit the finish line this tic PF_WRONGWAY = 1<<23, // Moving the wrong way with respect to waypoints? @@ -548,6 +548,7 @@ struct player_t UINT32 distancetofinishprev; waypoint_t *currentwaypoint; waypoint_t *nextwaypoint; + UINT16 bigwaypointgap; tic_t airtime; // Keep track of how long you've been in the air UINT8 startboost; // (0 to 125) - Boost you get from start of race or respawn drop dash @@ -657,6 +658,9 @@ struct player_t UINT16 breathTimer; // Holding your breath underwater + UINT8 lastsafelap; + UINT8 lastsafestarpost; + // SINT8 lives; diff --git a/src/deh_soc.c b/src/deh_soc.c index d30957647..783cc14e1 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1408,6 +1408,8 @@ void readlevelheader(MYFILE *f, char * name) mapheaderinfo[num]->encorepal = (UINT16)i; else if (fastcmp(word, "NUMLAPS")) mapheaderinfo[num]->numlaps = (UINT8)i; + else if (fastcmp(word, "LAPSPERSECTION")) + mapheaderinfo[num]->lapspersection = max((UINT8)i, 1u); else if (fastcmp(word, "UNLOCKABLE")) { if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something diff --git a/src/deh_tables.c b/src/deh_tables.c index 67c0b6f88..ddaa1fb03 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -267,7 +267,7 @@ const char *const PLAYERFLAG_LIST[] = { "UPDATEMYRESPAWN", "FLIPCAM", - "\x01", + "TRUSTWAYPOINTS", "HITFINISHLINE", // Already hit the finish line this tic "WRONGWAY", // Moving the wrong way with respect to waypoints? diff --git a/src/doomstat.h b/src/doomstat.h index a148e2dd7..2789b6dbd 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -413,6 +413,7 @@ struct mapheader_t UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below UINT32 typeoflevel; ///< Combination of typeoflevel flags. UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. + UINT8 lapspersection; ///< Number of laps per section in hybrid section-circuit maps. fixed_t gravity; ///< Map-wide gravity. // Music information diff --git a/src/g_game.c b/src/g_game.c index 330719adb..9f0c44b5c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2359,6 +2359,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) UINT16 nocontrol; INT32 kickstartaccel; boolean enteredGame; + UINT8 lastsafelap; + UINT8 lastsafestarpost; + UINT16 bigwaypointgap; score = players[player].score; lives = players[player].lives; @@ -2412,6 +2415,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) wanted = 0; rings = 10; kickstartaccel = 0; + lastsafelap = 0; + lastsafestarpost = 0; + bigwaypointgap = 0; nocontrol = 0; laps = 0; latestlap = 0; @@ -2479,6 +2485,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) prevcheck = players[player].nextcheck; pflags |= (players[player].pflags & (PF_STASIS|PF_ELIMINATED|PF_NOCONTEST|PF_LOSTLIFE|PF_FLIPCAM)); + + lastsafelap = players[player].lastsafelap; + lastsafestarpost = players[player].lastsafestarpost; + bigwaypointgap = players[player].bigwaypointgap; } if (!betweenmaps) @@ -2513,6 +2523,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->splitscreenindex = splitscreenindex; p->spectator = spectator; p->angleturn = playerangleturn; + p->lastsafelap = lastsafelap; + p->lastsafestarpost = lastsafestarpost; + p->bigwaypointgap = bigwaypointgap; // save player config truth reborn p->skincolor = skincolor; diff --git a/src/k_hud.c b/src/k_hud.c index 1c98e0204..93d893b2d 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4299,6 +4299,11 @@ static void K_DrawWaypointDebugger(void) if (stplyr != &players[displayplayers[0]]) // only for p1 return; + if (stplyr->bigwaypointgap) + { + V_DrawString(8, 146, 0, va("Auto Respawn Timer: %d", stplyr->bigwaypointgap)); + } + V_DrawString(8, 156, 0, va("Current Waypoint ID: %d", K_GetWaypointID(stplyr->currentwaypoint))); V_DrawString(8, 166, 0, va("Next Waypoint ID: %d", K_GetWaypointID(stplyr->nextwaypoint))); V_DrawString(8, 176, 0, va("Finishline Distance: %d", stplyr->distancetofinish)); diff --git a/src/k_kart.c b/src/k_kart.c index 2047df23f..4ffc56c20 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -238,6 +238,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebugdistribution); CV_RegisterVar(&cv_kartdebughuddrop); CV_RegisterVar(&cv_kartdebugwaypoints); + CV_RegisterVar(&cv_kartdebuglap); CV_RegisterVar(&cv_kartdebugbotpredict); CV_RegisterVar(&cv_kartdebugcheckpoint); @@ -7025,6 +7026,18 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->checkskip) player->checkskip--; + if (player->bigwaypointgap && (player->bigwaypointgap > AUTORESPAWN_THRESHOLD || !P_PlayerInPain(player))) + { + player->bigwaypointgap--; + if (!player->bigwaypointgap) + P_KillMobj(player->mo, NULL, NULL, DMG_INSTAKILL); + else if (player->bigwaypointgap == AUTORESPAWN_THRESHOLD) + { + S_StartSound(player->mo, sfx_s26d); + CONS_Printf("You are going the wrong way! You will automatically respawn in 7 seconds.\n"); + } + } + if (player->growshrinktimer != 0) { if (player->growshrinktimer > 0) @@ -8134,7 +8147,7 @@ static void K_UpdateDistanceFromFinishLine(player_t *player) const mapheader_t *mapheader = mapheaderinfo[gamemap - 1]; if ((mapheader->levelflags & LF_SECTIONRACE) == 0U) { - const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps); + const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps) / mapheader->lapspersection; player->distancetofinish += numfulllapsleft * K_GetCircuitLength(); } } @@ -8183,24 +8196,59 @@ static void K_UpdatePlayerWaypoints(player_t *const player) boolean updaterespawn = K_SetPlayerNextWaypoint(player); // Update prev value (used for grief prevention code) - K_UpdateDistanceFromFinishLine(player); player->distancetofinishprev = player->distancetofinish; + K_UpdateDistanceFromFinishLine(player); // Respawning should be a full reset. UINT32 delta = u32_delta(player->distancetofinish, player->distancetofinishprev); - if (!player->respawn && delta > distance_threshold) + if (delta > distance_threshold && + !player->respawn && // Respawning should be a full reset. + old_currentwaypoint != NULL && // So should touching the first waypoint ever. + player->laps != 0 && // POSITION rooms may have unorthodox waypoints to guide bots. + !(player->pflags & PF_TRUSTWAYPOINTS)) // Special exception. { - CONS_Debug(DBG_GAMELOGIC, "Player %s: waypoint ID %d too far away (%u > %u)\n", - sizeu1(player - players), K_GetWaypointID(player->nextwaypoint), delta, distance_threshold); +#define debug_args "Player %s: waypoint ID %d too far away (%u > %u)\n", \ + sizeu1(player - players), K_GetWaypointID(player->nextwaypoint), delta, distance_threshold + if (cv_kartdebuglap.value) + CONS_Printf(debug_args); + else + CONS_Debug(DBG_GAMELOGIC, debug_args); +#undef debug_args - // Distance jump is too great, keep the old waypoints and recalculate distance. - player->currentwaypoint = old_currentwaypoint; - player->nextwaypoint = old_nextwaypoint; - player->distancetofinish = player->distancetofinishprev; + if (!cv_kartdebuglap.value) + { + // Distance jump is too great, keep the old waypoints and old distance. + player->currentwaypoint = old_currentwaypoint; + player->nextwaypoint = old_nextwaypoint; + player->distancetofinish = player->distancetofinishprev; + + // Start the auto respawn timer when the distance jumps. + if (!player->bigwaypointgap) + { + player->bigwaypointgap = AUTORESPAWN_TIME; + } + } + } + else + { + // Reset the auto respawn timer if distance changes are back to normal. + if (player->bigwaypointgap && player->bigwaypointgap <= AUTORESPAWN_THRESHOLD + 1) + { + player->bigwaypointgap = 0; + + // While the player was in the "bigwaypointgap" state, laps did not change from crossing finish lines. + // So reset the lap back to normal, in case they were able to get behind the line. + player->laps = player->lastsafelap; + if (numbosswaypoints == 0) + { + player->starpostnum = player->lastsafestarpost; + } + } } // Respawn point should only be updated when we're going to a nextwaypoint if ((updaterespawn) && + (player->bigwaypointgap == 0) && (!player->respawn) && (player->nextwaypoint != old_nextwaypoint) && (K_GetWaypointIsSpawnpoint(player->nextwaypoint)) && @@ -8209,6 +8257,9 @@ static void K_UpdatePlayerWaypoints(player_t *const player) if (!(player->pflags & PF_WRONGWAY)) player->grieftime = 0; + player->lastsafelap = player->laps; + player->lastsafestarpost = player->starpostnum; + // Check if respawn is safe. If not then goto next spawnpoint and respawn there. if (K_SafeRespawnPosition(player->mo)) { @@ -8244,6 +8295,8 @@ static void K_UpdatePlayerWaypoints(player_t *const player) K_FudgeRespawn(player, player->nextwaypoint); } } + + player->pflags &= ~PF_TRUSTWAYPOINTS; // clear special exception } INT32 K_GetKartRingPower(player_t *player, boolean boosted) @@ -8819,6 +8872,16 @@ void K_UpdateAllPlayerPositions(void) continue; } + if (player->respawn > 0 && player->lastsafelap != player->laps) + { + player->laps = player->lastsafelap; + + if (numbosswaypoints == 0) + { + player->starpostnum = player->lastsafestarpost; + } + } + K_UpdatePlayerWaypoints(player); } diff --git a/src/k_kart.h b/src/k_kart.h index 93624bc97..539cd5376 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -26,6 +26,9 @@ Make sure this matches the actual number of states #define GROW_SCALE ((3*FRACUNIT)/2) #define SHRINK_SCALE ((6*FRACUNIT)/8) +#define AUTORESPAWN_TIME (10 * TICRATE) +#define AUTORESPAWN_THRESHOLD (7 * TICRATE) + // Used for respawning checks. typedef struct respawnresult_s diff --git a/src/lua_maplib.c b/src/lua_maplib.c index e945c74ab..a3e61f8e6 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2609,6 +2609,8 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->palette); else if (fastcmp(field,"numlaps")) lua_pushinteger(L, header->numlaps); + else if (fastcmp(field,"lapspersection")) + lua_pushinteger(L, header->lapspersection); else if (fastcmp(field,"unlockrequired")) lua_pushinteger(L, header->unlockrequired); else if (fastcmp(field,"levelselect")) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 0664301b9..c4ca9355e 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -388,6 +388,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->confirmVictimDelay); else if (fastcmp(field,"glanceDir")) lua_pushinteger(L, plr->glanceDir); + else if (fastcmp(field,"breathTimer")) + lua_pushinteger(L, plr->breathTimer); + else if (fastcmp(field,"lastsafelap")) + lua_pushinteger(L, plr->lastsafelap); + else if (fastcmp(field,"laststarpost")) + lua_pushinteger(L, plr->lastsafestarpost); else if (fastcmp(field,"roundscore")) plr->roundscore = luaL_checkinteger(L, 3); else if (fastcmp(field,"marescore")) @@ -799,6 +805,12 @@ static int player_set(lua_State *L) plr->confirmVictimDelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"glanceDir")) plr->glanceDir = luaL_checkinteger(L, 3); + else if (fastcmp(field,"breathTimer")) + plr->breathTimer = luaL_checkinteger(L, 3); + else if (fastcmp(field,"lastsafelap")) + plr->lastsafelap = luaL_checkinteger(L, 3); + else if (fastcmp(field,"lastsafestarpost")) + plr->lastsafestarpost = luaL_checkinteger(L, 3); else if (fastcmp(field,"roundscore")) lua_pushinteger(L, plr->roundscore); else if (fastcmp(field,"marescore")) diff --git a/src/p_saveg.c b/src/p_saveg.c index 557b95200..c5b7d7feb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -246,6 +246,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT32(save->p, players[i].distancetofinishprev); WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].currentwaypoint)); WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); + WRITEUINT16(save->p, players[i].bigwaypointgap); WRITEUINT32(save->p, players[i].airtime); WRITEUINT8(save->p, players[i].startboost); @@ -348,6 +349,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT16(save->p, players[i].breathTimer); + WRITEUINT8(save->p, players[i].lastsafelap); + WRITEUINT8(save->p, players[i].lastsafestarpost); + WRITEUINT8(save->p, players[i].typing_timer); WRITEUINT8(save->p, players[i].typing_duration); @@ -552,7 +556,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].distancetofinish = READUINT32(save->p); players[i].distancetofinishprev = READUINT32(save->p); players[i].currentwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); + players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); + players[i].bigwaypointgap = READUINT16(save->p); players[i].airtime = READUINT32(save->p); players[i].startboost = READUINT8(save->p); @@ -655,6 +661,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].breathTimer = READUINT16(save->p); + players[i].lastsafelap = READUINT8(save->p); + players[i].lastsafestarpost = READUINT8(save->p); + players[i].typing_timer = READUINT8(save->p); players[i].typing_duration = READUINT8(save->p); diff --git a/src/p_setup.c b/src/p_setup.c index 96b4228ce..feec6a6d8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -427,6 +427,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->palette = UINT16_MAX; mapheaderinfo[num]->encorepal = UINT16_MAX; mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT; + mapheaderinfo[num]->lapspersection = 1; mapheaderinfo[num]->unlockrequired = -1; mapheaderinfo[num]->levelselect = 0; mapheaderinfo[num]->levelflags = 0; diff --git a/src/p_spec.c b/src/p_spec.c index 224d24516..f45338f8a 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1970,11 +1970,23 @@ void P_SwitchWeather(preciptype_t newWeather) P_SpawnPrecipitation(); } +static boolean K_IgnoreFinishLine(player_t *player) +{ + // If potential lap cheating has been detected, do not + // interact with the finish line at all. + if (player->bigwaypointgap) + return true; + + return false; +} + // Passed over the finish line forwards static void K_HandleLapIncrement(player_t *player) { if (player) { + if (K_IgnoreFinishLine(player)) + return; if (((numbosswaypoints > 0) ? (player->starpostnum >= (numstarposts - (numstarposts/2))) : (player->starpostnum == numstarposts)) || (player->laps == 0)) { size_t i = 0; @@ -1992,6 +2004,9 @@ static void K_HandleLapIncrement(player_t *player) player->starposttime = player->realtime; player->starpostnum = 0; + player->lastsafestarpost = 0; + player->laps++; + if (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) { @@ -2010,7 +2025,8 @@ static void K_HandleLapIncrement(player_t *player) player->starpostangle = player->starpostx = player->starposty = player->starpostz = player->starpostflip = 0; } - player->laps++; + if (!cv_kartdebuglap.value && player->laps == 1) + player->pflags |= PF_TRUSTWAYPOINTS; K_UpdateAllPlayerPositions(); // Set up lap animation vars