From d58aa37228b23b04ae8237b680d946cc40db6c13 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Fri, 2 May 2025 15:44:31 +0200 Subject: [PATCH 01/11] Loading map patches --- src/p_setup.c | 137 +++++++++++++++++++++++++++++++++++++++++++------- src/r_state.h | 3 +- 2 files changed, 122 insertions(+), 18 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 6ed8862d6..3e5292273 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -125,7 +125,7 @@ UINT64 maphash; // boolean udmf; -INT32 udmf_version; +INT32 udmf_version, patch_version; mapnamespace_t mapnamespace = MNS_UNKNOWN; size_t numvertexes, numsegs, numsectors, numsubsectors, numnodes, numlines, numsides, nummapthings; size_t num_orig_vertexes; @@ -1461,30 +1461,82 @@ static void TextmapStorePos(textmap_block_t *blocks, size_t *count) } // Determine total amount of map data in TEXTMAP. -static boolean TextmapCount(size_t size) +static boolean TextmapCount(size_t size, boolean patch) { TracyCZone(__zone, true); const char *tkn = M_TokenizerRead(0); UINT8 brackets = 0; - nummapthings = 0; - numlines = 0; - numsides = 0; - numvertexes = 0; - numsectors = 0; + // check namespace for patches + if (patch) + { + // Look for namespace at the beginning. + if (!fastcmp(tkn, "namespace")) + { + CONS_Alert(CONS_ERROR, "No namespace at beginning of lump!\n"); + return false; + } - // skip namespace, it's checked by P_SetMapNamespace - M_TokenizerRead(0); + // Check if namespace is valid. + tkn = M_TokenizerRead(0); + if (!fastcmp(tkn, "blankart-patch")) + { + CONS_Alert(CONS_ERROR, "Invalid namespace '%s'. Only 'blankart-patch' is supported.\n", tkn); + return false; + } + } + else + M_TokenizerRead(0); // Check for version tkn = M_TokenizerRead(0); if (fastcmp(tkn, "version")) { tkn = M_TokenizerRead(0); - udmf_version = atoi(tkn); - if (udmf_version > UDMF_CURRENT_VERSION) - CONS_Alert(CONS_WARNING, "Map is intended for future UDMF version '%d', current supported version is '%d'. This map may have issues loading.\n", udmf_version, UDMF_CURRENT_VERSION); + if (patch) + { + patch_version = atoi(tkn); + if (patch_version > PATCH_CURRENT_VERSION) + CONS_Alert(CONS_WARNING, "Patch is intended for future patch version '%d', current supported version is '%d'. This patch may have issues loading.\n", patch_version, PATCH_CURRENT_VERSION); + } + else + { + udmf_version = atoi(tkn); + if (udmf_version > UDMF_CURRENT_VERSION) + CONS_Alert(CONS_WARNING, "Map is intended for future UDMF version '%d', current supported version is '%d'. This map may have issues loading.\n", udmf_version, UDMF_CURRENT_VERSION); + } + } + + // check hash for patches + if (patch) + { + tkn = M_TokenizerRead(0); + if (!fastcmp(tkn, "checksum")) + { + CONS_Alert(CONS_ERROR, "No checksum in lump!\n"); + return false; + } + + tkn = M_TokenizerRead(0); + char *end = NULL; + UINT64 hash = strtoull(tkn, &end, 16); + if (!end || *end) + { + CONS_Alert(CONS_ERROR, "Invalid checksum value '%s'\n", tkn); + return false; + } + if (hash != maphash) + CONS_Alert(CONS_WARNING, "Patch checksum " HASHFMT " does not match map checksum " HASHFMT ". This patch may not work.\n", hash, maphash); + } + + nummapthings = 0; + if (!patch) + { + numlines = 0; + numsides = 0; + numvertexes = 0; + numsectors = 0; } while ((tkn = M_TokenizerRead(0)) && M_TokenizerGetEndPos() < size) @@ -1500,6 +1552,8 @@ static boolean TextmapCount(size_t size) // Check for valid fields. else if (fastcmp(tkn, "thing")) TextmapStorePos(&mapthingBlocks, &nummapthings); + else if (patch) + continue; else if (fastcmp(tkn, "linedef")) TextmapStorePos(&linedefBlocks, &numlines); else if (fastcmp(tkn, "sidedef")) @@ -3213,7 +3267,7 @@ static void P_WriteTextmapWaypoints(void) /** Loads the textmap data, after obtaining the elements count and allocating their respective space. */ -static void P_LoadTextmap(void) +static void P_LoadTextmap(boolean patch) { TracyCZone(__zone, true); @@ -3232,6 +3286,7 @@ static void P_LoadTextmap(void) /// from the textmap, and therefore we have to account for it by /// preemptively setting that value beforehand. + if (!patch) for (i = 0, vt = vertexes; i < numvertexes; i++, vt++) { // Defaults. @@ -3247,6 +3302,7 @@ static void P_LoadTextmap(void) I_Error("P_LoadTextmap: vertex %s has no y value set!\n", sizeu1(i)); } + if (!patch) for (i = 0, sc = sectors; i < numsectors; i++, sc++) { // Defaults. @@ -3332,6 +3388,7 @@ static void P_LoadTextmap(void) TextmapFixFlatOffsets(sc); } + if (!patch) for (i = 0, ld = lines; i < numlines; i++, ld++) { // Defaults. @@ -3362,6 +3419,7 @@ static void P_LoadTextmap(void) P_InitializeLinedef(ld); } + if (!patch) for (i = 0, sd = sides; i < numsides; i++, sd++) { // Defaults. @@ -3576,7 +3634,7 @@ static boolean P_LoadMapData(const virtres_t *virt) { virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); M_TokenizerOpen((char *)textmap->data, textmap->size); - if (!TextmapCount(textmap->size)) + if (!TextmapCount(textmap->size, false)) { M_TokenizerClose(); TracyCZoneEnd(__zone); @@ -3640,7 +3698,7 @@ static boolean P_LoadMapData(const virtres_t *virt) // Load map data. if (udmf) { - P_LoadTextmap(); + P_LoadTextmap(false); M_TokenizerClose(); } else @@ -3670,6 +3728,44 @@ static boolean P_LoadMapData(const virtres_t *virt) return true; } +static boolean P_LoadMapPatchData(const lumpnum_t lumpnum) +{ + TracyCZone(__zone, true); + + size_t realnummapthings = nummapthings; + + // Count map data. + size_t patchlen = W_LumpLength(lumpnum); + char *patchdata = malloc(patchlen); + W_ReadLump(lumpnum, patchdata); + M_TokenizerOpen(patchdata, patchlen); + if (!TextmapCount(patchlen, true)) + { + M_TokenizerClose(); + free(patchdata); + TracyCZoneEnd(__zone); + return false; + } + + mapthing_t *realmapthings = mapthings; + mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + + // Load map data. + P_LoadTextmap(true); + M_TokenizerClose(); + free(patchdata); + + // concatenate the two mapthing arrays + realmapthings = Z_Realloc(realmapthings, (nummapthings + realnummapthings) * sizeof (*mapthings), PU_LEVEL, NULL); + memcpy(realmapthings + realnummapthings, mapthings, nummapthings * sizeof (*mapthings)); + Z_Free(mapthings); + mapthings = realmapthings; + nummapthings += realnummapthings; + + TracyCZoneEnd(__zone); + return true; +} + static void P_InitializeSubsector(subsector_t *ss) { ss->sector = NULL; @@ -7728,7 +7824,7 @@ static boolean P_LoadMapFromFile(void) virtlump_t *textmap = vres_Find(curmapvirt, "TEXTMAP"); size_t i; udmf = textmap != NULL; - udmf_version = 0; + udmf_version = patch_version = 0; if (!P_LoadMapData(curmapvirt)) { @@ -7748,6 +7844,14 @@ static boolean P_LoadMapFromFile(void) if (!udmf) P_ConvertBinaryMap(); + P_MakeMapHash(curmapvirt, &maphash); + + // load map patch? + lumpnum_t patchlump = W_CheckNumForNameInFolder(G_BuildMapName(gamemap), "MapPatch/"); + if (patchlump != LUMPERROR) + if (!P_LoadMapPatchData(patchlump)) + CONS_Alert(CONS_ERROR, "Failed to load map patch for %s\n", G_BuildMapName(gamemap)); + // Copy relevant map data for NetArchive purposes. spawnsectors = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL); spawnlines = Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL); @@ -7761,7 +7865,6 @@ static boolean P_LoadMapFromFile(void) if (sectors[i].tags.count) spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); - P_MakeMapHash(curmapvirt, &maphash); TracyCZoneEnd(__zone); return true; } diff --git a/src/r_state.h b/src/r_state.h index bb5aea6b3..2bbcab956 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -64,8 +64,9 @@ extern size_t numspritelumps, max_spritelumps; // Lookup tables for map data. // #define UDMF_CURRENT_VERSION (3) +#define PATCH_CURRENT_VERSION (1) extern boolean udmf; -extern INT32 udmf_version; +extern INT32 udmf_version, patch_version; extern size_t numsprites; extern spritedef_t *sprites; From 54a628bdfdea51a6618e4fca1958d8027cc8fd55 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sat, 3 May 2025 17:30:31 +0200 Subject: [PATCH 02/11] Enable waypoints for patched maps --- src/k_kart.c | 5 +++++ src/p_inter.c | 14 ++------------ src/p_mobj.c | 37 +++++++++++++++++++++++++++++-------- src/p_spec.c | 2 +- src/p_spec.h | 1 + 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 528810383..f1381a410 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -11002,6 +11002,11 @@ boolean K_SlipdashActive(void) boolean K_UsingLegacyCheckpoints(void) { + if (patch_version && waypointcap) + { + // we're presumably adding waypoints to an existing map + return false; + } if (numbosswaypoints > 0) { // We are using Kart V1 waypoints! diff --git a/src/p_inter.c b/src/p_inter.c index 357e4d996..9cee82a17 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -941,8 +941,8 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost) (void)snaptopost; - // Player must have touched all previous starposts - if ((post->health - player->starpostnum > 1) && (!K_UsingLegacyCheckpoints())) + // Going backwards triggers sound + if (post->health >= ((numstarposts/2) + player->starpostnum)) { if (!player->checkskip) { @@ -952,17 +952,7 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost) player->grieftime += TICRATE; } - } - player->checkskip = 3; - return; - } - - // Going backwards triggers sound - if ((post->health >= ((numstarposts/2) + player->starpostnum)) && (K_UsingLegacyCheckpoints())) - { - if (!player->checkskip) - S_StartSound(toucher, sfx_s26d); player->checkskip = 3; return; diff --git a/src/p_mobj.c b/src/p_mobj.c index 9a9f99eca..3ce0d5975 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12860,15 +12860,22 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) return true; } -static void P_SnapToFinishLine(mobj_t *mobj) +static void SpreadFinishLine(line_t *line, line_t *prev, boolean flip) { - line_t *finishline = P_FindNearestLine(mobj->x, mobj->y, - mobj->subsector->sector, 2001); // case 2001: Finish Line - if (finishline != NULL) + size_t i; + for (i = 0; i < numlines; i++) { - P_UnsetThingPosition(mobj); - P_ClosestPointOnLine(mobj->x, mobj->y, finishline, (vertex_t *)&mobj->x); - P_SetThingPosition(mobj); + line_t *line2 = &lines[i]; + if (line2 != line && line2 != prev && (line2->slopetype == ST_HORIZONTAL || line2->slopetype == ST_VERTICAL) && line2->slopetype == line->slopetype && + (line->v1 == line2->v1 || line->v2 == line2->v2 || line->v1 == line2->v2 || line->v2 == line2->v1)) + { + boolean flipped = line->v1 == line2->v1 || line->v2 == line2->v2; + line2->special = 2001; // Finish Line + line2->activation = SPAC_CROSS|SPAC_REPEATSPECIAL; + if (flipped != flip) + line2->args[0] |= TMCFF_FLIP; + SpreadFinishLine(line2, line, flipped != flip); + } } } @@ -13161,7 +13168,21 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->extravalue2 = 1; // args[2] of 1 means the waypoint is at the finish line mobj->reactiontime = 0; // Also don't respawn at finish lines - P_SnapToFinishLine(mobj); + line_t *finishline = P_FindNearestLine(mobj->x, mobj->y, + mobj->subsector->sector, -1); + if (finishline != NULL) + { + P_UnsetThingPosition(mobj); + P_ClosestPointOnLine(mobj->x, mobj->y, finishline, (vertex_t *)&mobj->x); + P_SetThingPosition(mobj); + + boolean flip = mthing->args[2] & TMWPF_FLIPFINISH; + finishline->special = 2001; // Finish Line + finishline->activation = SPAC_CROSS|SPAC_REPEATSPECIAL; + if (flip) + finishline->args[0] |= TMCFF_FLIP; + SpreadFinishLine(finishline, NULL, flip); + } } else { diff --git a/src/p_spec.c b/src/p_spec.c index a5a068028..8616dc5f2 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5356,7 +5356,7 @@ static void P_EvaluateSpecialFlags(player_t *player, sector_t *sector, sector_t P_ProcessZoomTube(player, sectag, true); if (sector->specialflags & SSF_FINISHLINE) { - if ((gametyperules & GTR_CIRCUIT) && (player->exiting == 0) && !(player->pflags & PF_HITFINISHLINE)) + if (K_UsingLegacyCheckpoints() && (gametyperules & GTR_CIRCUIT) && (player->exiting == 0) && !(player->pflags & PF_HITFINISHLINE)) { K_HandleLapIncrement(player); player->pflags |= PF_HITFINISHLINE; diff --git a/src/p_spec.h b/src/p_spec.h index 7bfab7f13..9983829f6 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -63,6 +63,7 @@ typedef enum TMWPF_SHORTCUT = 1<<1, TMWPF_NORESPAWN = 1<<2, TMWPF_FINISHLINE = 1<<3, + TMWPF_FLIPFINISH = 1<<4, } textmapwaypointflags_t; typedef enum From 144b93f262a13cad0e60d259bcd9f04f0fa7cfa0 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sat, 3 May 2025 22:41:09 +0200 Subject: [PATCH 03/11] Misc waypoint fixes, make bogus finish line waypoints work --- src/k_kart.c | 8 +++++++- src/k_waypoint.cpp | 4 ++-- src/p_spec.c | 6 ++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index f1381a410..2e92d3741 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8382,6 +8382,11 @@ static boolean K_SetPlayerNextWaypoint(player_t *player) if (bestwaypoint != NULL) { player->currentwaypoint = bestwaypoint; + + // if currentwaypoint is the finish line, don't set nextwaypoint to it! + // fixes bigwaypointgap triggering if we're facing the back of the finish line + if (bestwaypoint == finishline) + bestwaypoint = NULL; } // check the waypoint's location in relation to the player @@ -8499,7 +8504,8 @@ static boolean K_SetPlayerNextWaypoint(player_t *player) } if ((waypoint->prevwaypoints != NULL) && (waypoint->numprevwaypoints > 0U) - && !(K_PlayerUsesBotMovement(player))) // Bots do not need prev waypoints + && !(K_PlayerUsesBotMovement(player)) // Bots do not need prev waypoints + && waypoint != finishline) // do not check finish line's prevwaypoints { for (i = 0U; i < waypoint->numprevwaypoints; i++) { diff --git a/src/k_waypoint.cpp b/src/k_waypoint.cpp index b30b913e7..cefdb0b4b 100644 --- a/src/k_waypoint.cpp +++ b/src/k_waypoint.cpp @@ -2179,14 +2179,14 @@ static waypoint_t *K_SetupWaypoint(mobj_t *const mobj) firstwaypoint = thiswaypoint; } - if (K_GetWaypointIsFinishline(thiswaypoint)) + if (K_GetWaypointIsFinishline(thiswaypoint) && K_GetWaypointIsEnabled(thiswaypoint)) { if (finishline != NULL) { const INT32 oldfinishlineid = K_GetWaypointID(finishline); const INT32 thiswaypointid = K_GetWaypointID(thiswaypoint); CONS_Alert( - CONS_WARNING, "Multiple finish line waypoints with IDs %d and %d! Using %d.", + CONS_WARNING, "Multiple finish line waypoints with IDs %d and %d! Using %d.\n", oldfinishlineid, thiswaypointid, thiswaypointid); } finishline = thiswaypoint; diff --git a/src/p_spec.c b/src/p_spec.c index 8616dc5f2..6063a5969 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2051,7 +2051,7 @@ static void K_HandleLapIncrement(player_t *player) player->karthud[khud_lapanimation] = 80; } - if (netgame && player->laps >= numlaps) + if (netgame && player->laps > numlaps) CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players])); if (P_IsDisplayPlayer(player)) @@ -2135,7 +2135,9 @@ static void K_HandleLapDecrement(player_t *player) { if (player) { - if ((player->starpostnum == 0) && (player->laps > 0)) + if (K_IgnoreFinishLine(player)) + return; + if (player->laps > 0) { player->starpostnum = numstarposts; player->laps--; From 0a02cc84dd9ca184230765924d99b07b7de18f7d Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sat, 3 May 2025 23:45:22 +0200 Subject: [PATCH 04/11] Add finish line flip to config --- extras/blanudmf/Includes/BlanKart_things.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index 2b0662aa8..f72c66c88 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -5372,6 +5372,7 @@ udmf 2 = "Shortcut"; 4 = "No respawn"; 8 = "Finish line"; + 16 = "Flip special (patch)"; } } arg3 From 0239543d3f464776d45d1db1cc9d5188ffd10125 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sun, 4 May 2025 00:24:06 +0200 Subject: [PATCH 05/11] Fix the binary config interface --- extras/blanbinary/BlanKartBinary-Config.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/blanbinary/BlanKartBinary-Config.cfg b/extras/blanbinary/BlanKartBinary-Config.cfg index e23530ffd..4f02d8429 100644 --- a/extras/blanbinary/BlanKartBinary-Config.cfg +++ b/extras/blanbinary/BlanKartBinary-Config.cfg @@ -43,7 +43,7 @@ engine = "zdoom"; linetagindicatesectors = true; // The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder -formatinterface = "SRB2MapSetIO"; +formatinterface = "DoomMapSetIO"; //Sky textures for vanilla maps defaultskytextures From 4beb4e6f0207aee8987a5dc0135a7fc76ae9eb90 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 5 May 2025 09:06:06 -0400 Subject: [PATCH 06/11] Only Run patch waypoint functionality on patched maps The Wiki says its only active on patched maps, so I'm acutally making that true. --- src/k_kart.c | 11 +++++++++++ src/k_kart.h | 1 + src/p_mobj.c | 4 +++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index d81e5dbce..7ead79de4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -11018,6 +11018,17 @@ boolean K_UsingLegacyCheckpoints(void) return false; } +boolean K_UsingPatchedMap(void) +{ + if (patch_version) + { + // This map has been patched! + return true; + } + + return false; +} + void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount) { switch (itemType) diff --git a/src/k_kart.h b/src/k_kart.h index 4890f92bc..5775666ed 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -246,6 +246,7 @@ boolean K_SlipdashActive(void); boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound); INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound); boolean K_UsingLegacyCheckpoints(void); +boolean K_UsingPatchedMap(void); void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount); diff --git a/src/p_mobj.c b/src/p_mobj.c index 3ce0d5975..0d1bab4a5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13139,6 +13139,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->threshold = mthing->args[0]; mobj->movecount = tag; + if (mthing->args[2] & TMWPF_DISABLED) { mobj->extravalue1 = 0; // The waypoint is disabled if extra is on @@ -13163,6 +13164,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean { mobj->reactiontime = 1; } + if (mthing->args[2] & TMWPF_FINISHLINE) { mobj->extravalue2 = 1; // args[2] of 1 means the waypoint is at the finish line @@ -13170,7 +13172,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean line_t *finishline = P_FindNearestLine(mobj->x, mobj->y, mobj->subsector->sector, -1); - if (finishline != NULL) + if (K_UsingPatchedMap() && finishline != NULL) { P_UnsetThingPosition(mobj); P_ClosestPointOnLine(mobj->x, mobj->y, finishline, (vertex_t *)&mobj->x); From 67888c237d49a4f91ae252ffbb9a1df0ee09e025 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 1 Feb 2024 18:51:07 -0800 Subject: [PATCH 07/11] Activate sector each time / once actions when mobj touches the ground Before - Each time / once only activates when the mobj's sector changes - The activation may depend on the mobj touching the floor - If the mobj is in the air when the sector changes, the action will never be activated After - Each time / once actions that require floor touching also activate every time the mobj lands on the ground from the air (regardless of whether the sector changed) --- src/p_map.c | 8 ++++++++ src/p_maputl.c | 12 ------------ src/p_mobj.c | 12 +++++++++++- src/p_spec.c | 44 +++++++++++++++++++++++++++++++++++++------- src/p_spec.h | 3 ++- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index e629db522..b5de9cb23 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -100,6 +100,9 @@ camera_t *mapcampointer; // static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) { + boolean startingonground = P_IsObjectOnGround(thing); + sector_t *oldsector = thing->subsector->sector; + numspechit = 0U; // the move is ok, @@ -129,6 +132,8 @@ static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorrover = g_tm.floorrover; thing->ceilingrover = g_tm.ceilingrover; + P_CheckSectorTransitionalEffects(thing, oldsector, startingonground); + return true; } @@ -2745,6 +2750,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try fixed_t oldx = thing->x; fixed_t oldy = thing->y; fixed_t startingonground = P_IsObjectOnGround(thing); + sector_t *oldsector = thing->subsector->sector; // Is the move OK? if (increment_move(thing, x, y, allowdropoff, result) == false) @@ -2847,6 +2853,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try P_SetThingPosition(thing); + P_CheckSectorTransitionalEffects(thing, oldsector, startingonground); + // remove any duplicates that may be in spechitint spechitint_removedups(); diff --git a/src/p_maputl.c b/src/p_maputl.c index 9069026dd..95fc912f8 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -1236,7 +1236,6 @@ static void P_LinkToBlockMap(mobj_t *thing, mobj_t **bmap) void P_SetThingPosition(mobj_t *thing) { // link into subsector subsector_t *ss; - sector_t *prevsec = NULL; sector_t *oldsec = NULL; fixed_t tfloorz, tceilz; @@ -1249,11 +1248,6 @@ void P_SetThingPosition(mobj_t *thing) oldsec = thing->subsector->sector; } - if (thing->subsector) - { - prevsec = thing->subsector->sector; - } - ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); if (!(thing->flags & MF_NOSECTOR)) @@ -1310,12 +1304,6 @@ void P_SetThingPosition(mobj_t *thing) else if (thing->z <= tfloorz) thing->eflags |= MFE_JUSTSTEPPEDDOWN; } - - if (udmf && prevsec != thing->subsector->sector) - { - // Check for each time / once sector special actions - P_CheckMobjTouchingSectorActions(thing, false); - } } // diff --git a/src/p_mobj.c b/src/p_mobj.c index 0d1bab4a5..67df9b58b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2175,10 +2175,13 @@ boolean P_ZMovement(mobj_t *mo) { fixed_t dist, delta; boolean onground; + boolean wasonground; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); + wasonground = P_IsObjectOnGround(mo); + // Intercept the stupid 'fall through 3dfloors' bug if (mo->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0); @@ -2604,6 +2607,8 @@ boolean P_ZMovement(mobj_t *mo) } } + P_CheckSectorTransitionalEffects(mo, mo->subsector->sector, wasonground); + return true; } @@ -2697,6 +2702,7 @@ static boolean P_PlayerPolyObjectZMovement(mobj_t *mo) void P_PlayerZMovement(mobj_t *mo) { boolean onground; + boolean wasonground; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -2704,6 +2710,8 @@ void P_PlayerZMovement(mobj_t *mo) if (!mo->player) return; + wasonground = P_IsObjectOnGround(mo); + // Intercept the stupid 'fall through 3dfloors' bug if (mo->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0); @@ -2834,6 +2842,8 @@ void P_PlayerZMovement(mobj_t *mo) P_CheckGravity(mo, true); } } + + P_CheckSectorTransitionalEffects(mo, mo->subsector->sector, wasonground); } boolean P_SceneryZMovement(mobj_t *mo) @@ -10216,7 +10226,7 @@ void P_MobjThinker(mobj_t *mobj) if (udmf) { // Check for continuous sector special actions - P_CheckMobjTouchingSectorActions(mobj, true); + P_CheckMobjTouchingSectorActions(mobj, true, true); } else { diff --git a/src/p_spec.c b/src/p_spec.c index 6063a5969..1f73a6f74 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5763,7 +5763,7 @@ static boolean P_AllowSpecialCeiling(sector_t *sec, mobj_t *thing) return false; } -static void P_CheckMobj3DFloorAction(mobj_t *mo, sector_t *sec, boolean continuous) +static void P_CheckMobj3DFloorAction(mobj_t *mo, sector_t *sec, boolean continuous, boolean sectorchanged) { sector_t *originalsector = mo->subsector->sector; ffloor_t *rover; @@ -5822,6 +5822,10 @@ static void P_CheckMobj3DFloorAction(mobj_t *mo, sector_t *sec, boolean continuo continue; } } + else if (sectorchanged == false) + { + continue; + } activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); I_Assert(activator != NULL); @@ -5841,7 +5845,7 @@ static void P_CheckMobj3DFloorAction(mobj_t *mo, sector_t *sec, boolean continuo } } -static void P_CheckMobjPolyobjAction(mobj_t *mo, boolean continuous) +static void P_CheckMobjPolyobjAction(mobj_t *mo, boolean continuous, boolean sectorchanged) { sector_t *originalsector = mo->subsector->sector; polyobj_t *po; @@ -5896,6 +5900,10 @@ static void P_CheckMobjPolyobjAction(mobj_t *mo, boolean continuous) continue; } } + else if (sectorchanged == false) + { + continue; + } activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); I_Assert(activator != NULL); @@ -5915,7 +5923,7 @@ static void P_CheckMobjPolyobjAction(mobj_t *mo, boolean continuous) } } -static void P_CheckMobjSectorAction(mobj_t *mo, sector_t *sec, boolean continuous) +static void P_CheckMobjSectorAction(mobj_t *mo, sector_t *sec, boolean continuous, boolean sectorchanged) { activator_t *activator = NULL; boolean result = false; @@ -5952,6 +5960,10 @@ static void P_CheckMobjSectorAction(mobj_t *mo, sector_t *sec, boolean continuou return; } } + else if (sectorchanged == false) + { + return; + } activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); I_Assert(activator != NULL); @@ -5968,7 +5980,7 @@ static void P_CheckMobjSectorAction(mobj_t *mo, sector_t *sec, boolean continuou } } -void P_CheckMobjTouchingSectorActions(mobj_t *mobj, boolean continuous) +void P_CheckMobjTouchingSectorActions(mobj_t *mobj, boolean continuous, boolean sectorchanged) { sector_t *originalsector; @@ -5994,13 +6006,13 @@ void P_CheckMobjTouchingSectorActions(mobj_t *mobj, boolean continuous) } } - P_CheckMobj3DFloorAction(mobj, originalsector, continuous); + P_CheckMobj3DFloorAction(mobj, originalsector, continuous, sectorchanged); if TELEPORTED(mobj) return; - P_CheckMobjPolyobjAction(mobj, continuous); + P_CheckMobjPolyobjAction(mobj, continuous, sectorchanged); if TELEPORTED(mobj) return; - P_CheckMobjSectorAction(mobj, originalsector, continuous); + P_CheckMobjSectorAction(mobj, originalsector, continuous, sectorchanged); } #undef TELEPORTED @@ -9493,3 +9505,21 @@ void P_StartQuake(fixed_t intensity, tic_t time) quake.intensity = FixedMul(intensity, mapobjectscale); quake.time = time; } + +void P_CheckSectorTransitionalEffects(mobj_t *thing, sector_t *prevsec, boolean wasgrounded) +{ + if (!udmf) + { + return; + } + + boolean sectorchanged = (prevsec != thing->subsector->sector); + + if (!sectorchanged && wasgrounded == P_IsObjectOnGround(thing)) + { + return; + } + + // Check for each time / once sector special actions + P_CheckMobjTouchingSectorActions(thing, false, sectorchanged); +} diff --git a/src/p_spec.h b/src/p_spec.h index 9983829f6..a4ed56192 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -543,12 +543,13 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n sector_t *P_PlayerTouchingSectorSpecialFlag(player_t *player, sectorspecialflags_t flag); void P_PlayerInSpecialSector(player_t *player); void P_CheckMobjTrigger(mobj_t *mobj, boolean pushable); -void P_CheckMobjTouchingSectorActions(mobj_t *mobj, boolean continuous); +void P_CheckMobjTouchingSectorActions(mobj_t *mobj, boolean continuous, boolean sectorchanged); sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline); boolean P_IsPlayerValid(size_t playernum); boolean P_CanPlayerTrigger(size_t playernum); void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *roversector); sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo); +void P_CheckSectorTransitionalEffects(mobj_t *thing, sector_t *prevsec, boolean wasgrounded); fixed_t P_FindLowestFloorSurrounding(sector_t *sec); fixed_t P_FindHighestFloorSurrounding(sector_t *sec); From 20396e14cb5e956c7c4bd085b81b538c5b2dc9fe Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 6 May 2025 20:43:31 +0200 Subject: [PATCH 08/11] Operation: Save Megablock Castle Two new finish line flags: Single-Use, to make a finish line that only works on lap 0 and nowhere else Require Sector Special, for the maps with FOF finish lines For waypoints, the "flip finish line" flag on arg0 has been removed. Instead, arg4 is now dedicated to holding flags applied to the finish line. --- .../blanudmf/Includes/BlanKart_linedefs.cfg | 10 +++++-- extras/blanudmf/Includes/BlanKart_things.cfg | 12 +++++++- src/k_kart.c | 2 +- src/p_mobj.c | 26 ++++++++-------- src/p_spec.c | 30 +++++++++++++++++++ src/p_spec.h | 5 ++-- 6 files changed, 66 insertions(+), 19 deletions(-) diff --git a/extras/blanudmf/Includes/BlanKart_linedefs.cfg b/extras/blanudmf/Includes/BlanKart_linedefs.cfg index c32780194..a9734db93 100644 --- a/extras/blanudmf/Includes/BlanKart_linedefs.cfg +++ b/extras/blanudmf/Includes/BlanKart_linedefs.cfg @@ -82,8 +82,14 @@ udmf prefix = "(2001)"; arg0 { - title = "Flip?"; - type = 3; + title = "Flags"; + type = 12; + enum + { + 1 = "Flip"; + 2 = "Single-use"; + 4 = "Require sector special"; + } } } diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index f72c66c88..876cf637e 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -5372,7 +5372,6 @@ udmf 2 = "Shortcut"; 4 = "No respawn"; 8 = "Finish line"; - 16 = "Flip special (patch)"; } } arg3 @@ -5389,6 +5388,17 @@ udmf 5 = "End drift"; } } + arg4 + { + title = "Patch finish flags"; + type = 12; + enum + { + 1 = "Flip"; + 2 = "Single-use"; + 4 = "Require sector special"; + } + } } 2004 diff --git a/src/k_kart.c b/src/k_kart.c index 7ead79de4..d962b75c1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -11004,7 +11004,7 @@ boolean K_SlipdashActive(void) boolean K_UsingLegacyCheckpoints(void) { - if (patch_version && waypointcap) + if (K_UsingPatchedMap() && waypointcap) { // we're presumably adding waypoints to an existing map return false; diff --git a/src/p_mobj.c b/src/p_mobj.c index 67df9b58b..852d81357 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12870,7 +12870,7 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) return true; } -static void SpreadFinishLine(line_t *line, line_t *prev, boolean flip) +static void SpreadFinishLine(line_t *line, line_t *prev, INT32 args) { size_t i; for (i = 0; i < numlines; i++) @@ -12879,12 +12879,11 @@ static void SpreadFinishLine(line_t *line, line_t *prev, boolean flip) if (line2 != line && line2 != prev && (line2->slopetype == ST_HORIZONTAL || line2->slopetype == ST_VERTICAL) && line2->slopetype == line->slopetype && (line->v1 == line2->v1 || line->v2 == line2->v2 || line->v1 == line2->v2 || line->v2 == line2->v1)) { - boolean flipped = line->v1 == line2->v1 || line->v2 == line2->v2; + boolean flipped = line->v1 == line2->v1 || line->v2 == line2->v2 ? TMCFF_FLIP : 0; line2->special = 2001; // Finish Line line2->activation = SPAC_CROSS|SPAC_REPEATSPECIAL; - if (flipped != flip) - line2->args[0] |= TMCFF_FLIP; - SpreadFinishLine(line2, line, flipped != flip); + line2->args[0] = args ^ flipped; + SpreadFinishLine(line2, line, args ^ flipped); } } } @@ -13181,19 +13180,20 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->reactiontime = 0; // Also don't respawn at finish lines line_t *finishline = P_FindNearestLine(mobj->x, mobj->y, - mobj->subsector->sector, -1); - if (K_UsingPatchedMap() && finishline != NULL) + mobj->subsector->sector, K_UsingPatchedMap() ? -1 : 2001); // case 2001: Finish Line + if (finishline != NULL) { P_UnsetThingPosition(mobj); P_ClosestPointOnLine(mobj->x, mobj->y, finishline, (vertex_t *)&mobj->x); P_SetThingPosition(mobj); - boolean flip = mthing->args[2] & TMWPF_FLIPFINISH; - finishline->special = 2001; // Finish Line - finishline->activation = SPAC_CROSS|SPAC_REPEATSPECIAL; - if (flip) - finishline->args[0] |= TMCFF_FLIP; - SpreadFinishLine(finishline, NULL, flip); + if (K_UsingPatchedMap()) + { + finishline->special = 2001; // Finish Line + finishline->activation = SPAC_CROSS|SPAC_REPEATSPECIAL; + finishline->args[0] = mthing->args[4]; + SpreadFinishLine(finishline, NULL, mthing->args[4]); + } } } else diff --git a/src/p_spec.c b/src/p_spec.c index 1f73a6f74..ebe8584e3 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4451,6 +4451,36 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha if ((gametyperules & GTR_CIRCUIT) && (mo->player->exiting == 0) && !(mo->player->pflags & PF_HITFINISHLINE)) { + // megablock cope 1: single-use finish lines + if (args[0] & TMCFF_SINGLEUSE && mo->player->laps > 0) + return false; + + // megablock cope 2: require a circuit finish line special to be hit at the same time + if (args[0] & TMCFF_NEEDSECTOR) + { + boolean touching = false; + if (P_MobjTouchingSectorSpecialFlag(mo, SSF_FINISHLINE)) + touching = true; + + // we have to check if we WERE touching a finish line sector last tic too! + // otherwise lap decrementing wouldn't work! + // YAAAAAAAAAAAAAAY + fixed_t realx = mo->x, realy = mo->y; + P_UnsetThingPosition(mo); + mo->x = mo->old_x, mo->y = mo->old_y; + P_SetThingPosition(mo); + + if (P_MobjTouchingSectorSpecialFlag(mo, SSF_FINISHLINE)) + touching = true; + + P_UnsetThingPosition(mo); + mo->x = realx, mo->y = realy; + P_SetThingPosition(mo); + + if (!touching) + return false; + } + if (((args[0] & TMCFF_FLIP) && (side == 0)) || (!(args[0] & TMCFF_FLIP) && (side == 1))) // crossed from behind to infront { diff --git a/src/p_spec.h b/src/p_spec.h index a4ed56192..9b247ab7f 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -63,7 +63,6 @@ typedef enum TMWPF_SHORTCUT = 1<<1, TMWPF_NORESPAWN = 1<<2, TMWPF_FINISHLINE = 1<<3, - TMWPF_FLIPFINISH = 1<<4, } textmapwaypointflags_t; typedef enum @@ -488,7 +487,9 @@ typedef enum typedef enum { - TMCFF_FLIP = 1, + TMCFF_FLIP = 1, + TMCFF_SINGLEUSE = 1<<1, + TMCFF_NEEDSECTOR = 1<<2, } textmapcrossfinishflags_t; typedef enum From d0ed82a5407775ff0e370a6ab5bfebedd1738a9a Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 8 May 2025 22:00:46 +0200 Subject: [PATCH 09/11] Allow multiple checksums to be specified in a patch ...and while I'm at it, actually pad the printed hash --- src/doomdef.h | 2 +- src/p_setup.c | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 0e596946b..4a5f83f0b 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -441,7 +441,7 @@ UINT32 quickncasehash (const char *p, size_t n) #include "xxhash.h" #define HASH64(p, n) ((UINT64)XXH3_64bits(p, n)) #define HASH32(p, n) ((UINT32)(XXH3_64bits(p, n) & UINT32_MAX)) -#define HASHFMT "%jx" +#define HASHFMT "%016jx" #ifndef __cplusplus #ifndef min // Double-Check with WATTCP-32's cdefs.h diff --git a/src/p_setup.c b/src/p_setup.c index 3e5292273..7c9532122 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1519,15 +1519,28 @@ static boolean TextmapCount(size_t size, boolean patch) } tkn = M_TokenizerRead(0); - char *end = NULL; - UINT64 hash = strtoull(tkn, &end, 16); - if (!end || *end) + boolean foundhash = false; + const char *hashstr = tkn; + char *end; + + // check for hashes separated by pipes + // e.g. "abc123|def456|ghi789" + do { - CONS_Alert(CONS_ERROR, "Invalid checksum value '%s'\n", tkn); - return false; + UINT64 hash = strtoull(hashstr, &end, 16); + if (hash == maphash) + foundhash = true; + if (end == hashstr || (*end && *end != '|')) + { + CONS_Alert(CONS_ERROR, "Invalid checksum string '%s'\n", tkn); + return false; + } + hashstr = end + 1; } - if (hash != maphash) - CONS_Alert(CONS_WARNING, "Patch checksum " HASHFMT " does not match map checksum " HASHFMT ". This patch may not work.\n", hash, maphash); + while (*end); + + if (!foundhash) + CONS_Alert(CONS_WARNING, "This map patch is not compatible with the current map (checksum: " HASHFMT "). The patch may not work.\n", maphash); } nummapthings = 0; From b7afe4f3470d9eb5286857d15b3066b012c42557 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 8 May 2025 22:23:03 +0200 Subject: [PATCH 10/11] Use legacy checkpoint threshold for patched maps --- src/k_hud.c | 22 ++++++++-------------- src/k_kart.c | 5 +++++ src/k_kart.h | 1 + src/p_spec.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 3f179e861..4578e9b76 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4790,21 +4790,15 @@ static void K_drawCheckpointDebugger(void) if (stplyr != &players[displayplayers[0]]) // only for p1 return; - if (K_UsingLegacyCheckpoints()) - { - if (stplyr->starpostnum >= (numstarposts - (numstarposts/2))) - V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Can finish)", stplyr->starpostnum, numstarposts)); - else - V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Skip: %d)", stplyr->starpostnum, numstarposts, ((numstarposts/2) + stplyr->starpostnum))); - V_DrawString(8, 192, 0, va("Waypoint dist: Prev %d, Next %d", stplyr->prevcheck, stplyr->nextcheck)); - } + if (stplyr->starpostnum >= K_CheckpointThreshold()) + V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Can finish)", stplyr->starpostnum, numstarposts)); + else if (K_CheckpointThreshold() != numstarposts) + V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Skip: %d)", stplyr->starpostnum, numstarposts, ((numstarposts/2) + stplyr->starpostnum))); else - { - if (stplyr->starpostnum == numstarposts) - V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Can finish)", stplyr->starpostnum, numstarposts)); - else - V_DrawString(8, 184, 0, va("Checkpoint: %d / %d", stplyr->starpostnum, numstarposts)); - } + V_DrawString(8, 184, 0, va("Checkpoint: %d / %d", stplyr->starpostnum, numstarposts)); + + if (K_UsingLegacyCheckpoints()) + V_DrawString(8, 192, 0, va("Waypoint dist: Prev %d, Next %d", stplyr->prevcheck, stplyr->nextcheck)); } static void K_DrawWaypointDebugger(void) diff --git a/src/k_kart.c b/src/k_kart.c index 223ef391f..3d1805b2e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -11009,6 +11009,11 @@ boolean K_UsingPatchedMap(void) return false; } +INT32 K_CheckpointThreshold(void) +{ + return K_UsingLegacyCheckpoints() || K_UsingPatchedMap() ? numstarposts - numstarposts/2 : numstarposts; +} + void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount) { switch (itemType) diff --git a/src/k_kart.h b/src/k_kart.h index b2a21dfcd..fdcdafbc7 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -256,6 +256,7 @@ boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound); INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound); boolean K_UsingLegacyCheckpoints(void); boolean K_UsingPatchedMap(void); +INT32 K_CheckpointThreshold(void); void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount); diff --git a/src/p_spec.c b/src/p_spec.c index 17c013c11..f44c9990d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1988,7 +1988,7 @@ static void K_HandleLapIncrement(player_t *player) { if (K_IgnoreFinishLine(player)) return; - if (((K_UsingLegacyCheckpoints()) ? (player->starpostnum >= (numstarposts - (numstarposts/2))) : (player->starpostnum == numstarposts)) || (player->laps == 0)) + if ((player->starpostnum >= K_CheckpointThreshold()) || (player->laps == 0)) { size_t i = 0; UINT8 nump = 0; From a5ec18ead7121c4728b9111ff7d17a481344a768 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 8 May 2025 23:20:52 +0200 Subject: [PATCH 11/11] Fix regression in checkpoint handling for unpatched waypoint maps --- src/k_hud.c | 6 +++--- src/k_kart.c | 7 +++++-- src/k_kart.h | 2 +- src/p_inter.c | 4 +++- src/p_spec.c | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 4578e9b76..c34bd2a67 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4790,10 +4790,10 @@ static void K_drawCheckpointDebugger(void) if (stplyr != &players[displayplayers[0]]) // only for p1 return; - if (stplyr->starpostnum >= K_CheckpointThreshold()) + if (stplyr->starpostnum >= K_CheckpointThreshold(true)) V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Can finish)", stplyr->starpostnum, numstarposts)); - else if (K_CheckpointThreshold() != numstarposts) - V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Skip: %d)", stplyr->starpostnum, numstarposts, ((numstarposts/2) + stplyr->starpostnum))); + else if (K_CheckpointThreshold(false) != numstarposts) + V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Skip: %d)", stplyr->starpostnum, numstarposts, K_CheckpointThreshold(false) + stplyr->starpostnum)); else V_DrawString(8, 184, 0, va("Checkpoint: %d / %d", stplyr->starpostnum, numstarposts)); diff --git a/src/k_kart.c b/src/k_kart.c index 3d1805b2e..54d0fb492 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -11009,9 +11009,12 @@ boolean K_UsingPatchedMap(void) return false; } -INT32 K_CheckpointThreshold(void) +INT32 K_CheckpointThreshold(boolean roundup) { - return K_UsingLegacyCheckpoints() || K_UsingPatchedMap() ? numstarposts - numstarposts/2 : numstarposts; + if (K_UsingLegacyCheckpoints() || K_UsingPatchedMap()) + return roundup ? numstarposts - numstarposts/2 : numstarposts/2; + else + return numstarposts; } void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount) diff --git a/src/k_kart.h b/src/k_kart.h index fdcdafbc7..13f50aaca 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -256,7 +256,7 @@ boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound); INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound); boolean K_UsingLegacyCheckpoints(void); boolean K_UsingPatchedMap(void); -INT32 K_CheckpointThreshold(void); +INT32 K_CheckpointThreshold(boolean roundup); void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount); diff --git a/src/p_inter.c b/src/p_inter.c index e1d4d5674..ad37fa90a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -942,7 +942,9 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost) (void)snaptopost; // Going backwards triggers sound - if (post->health >= ((numstarposts/2) + player->starpostnum)) + if (K_CheckpointThreshold(false) == numstarposts + ? post->health - player->starpostnum > 1 + : post->health >= player->starpostnum + K_CheckpointThreshold(false)) { if (!player->checkskip) { diff --git a/src/p_spec.c b/src/p_spec.c index f44c9990d..5cc241847 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1988,7 +1988,7 @@ static void K_HandleLapIncrement(player_t *player) { if (K_IgnoreFinishLine(player)) return; - if ((player->starpostnum >= K_CheckpointThreshold()) || (player->laps == 0)) + if ((player->starpostnum >= K_CheckpointThreshold(true)) || (player->laps == 0)) { size_t i = 0; UINT8 nump = 0;