From 6bcc283d3b47a93b7165dcbba78d1870d47fcfba Mon Sep 17 00:00:00 2001 From: Sryder Date: Sun, 16 Jun 2019 22:03:26 +0100 Subject: [PATCH] Reimplement system for specials that activate when crossing a linedef from DOOM Used for the finish line, crossing it the correct way increments the lap count, the wrong way decrements it Remove usability of the sector special for the finish line Undo another check of numstarposts to force all of them to need passing to complete the stage player laps start from 0 now, it goes to lap 1 when you initially cross the start line. --- src/k_kart.c | 18 +-- src/p_inter.c | 2 +- src/p_map.c | 151 +++++++++++++++++++++++++ src/p_spec.c | 293 ++++++++++++++++++++++++++++++------------------- src/p_spec.h | 2 + src/p_user.c | 2 +- src/st_stuff.c | 2 +- 7 files changed, 345 insertions(+), 125 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 07d44909b..33f985746 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6959,7 +6959,7 @@ void K_CheckSpectateStatus(void) continue; if (leveltime > (starttime + 20*TICRATE)) // DON'T allow if the match is 20 seconds in return; - if (G_RaceGametype() && players[i].laps) // DON'T allow if the race is at 2 laps + if (G_RaceGametype() && players[i].laps >= 2) // DON'T allow if the race is at 2 laps return; continue; } @@ -8197,7 +8197,7 @@ static void K_DrawKartPositionNum(INT32 num) { if (win) // 1st place winner? You get rainbows!! localpatch = kp_winnernum[(leveltime % (NUMWINFRAMES*3)) / 3]; - else if (stplyr->laps+1 >= cv_numlaps.value || stplyr->exiting) // Check for the final lap, or won + else if (stplyr->laps >= cv_numlaps.value || stplyr->exiting) // Check for the final lap, or won { // Alternate frame every three frames switch (leveltime % 9) @@ -8555,8 +8555,8 @@ static void K_drawKartLapsAndRings(void) if (cv_numlaps.value >= 10) { UINT8 ln[2]; - ln[0] = ((abs(stplyr->laps+1) / 10) % 10); - ln[1] = (abs(stplyr->laps+1) % 10); + ln[0] = ((abs(stplyr->laps) / 10) % 10); + ln[1] = (abs(stplyr->laps) % 10); V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); @@ -8569,7 +8569,7 @@ static void K_drawKartLapsAndRings(void) } else { - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->laps+1) % 10]); + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->laps) % 10]); V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(cv_numlaps.value) % 10]); } @@ -8611,7 +8611,7 @@ static void K_drawKartLapsAndRings(void) if (stplyr->exiting) V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, "FIN"); else - V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->laps+1, cv_numlaps.value)); + V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->laps, cv_numlaps.value)); // Rings if (netgame) @@ -9617,7 +9617,7 @@ static void K_drawLapStartAnim(void) kp_lapanim_hand[stplyr->karthud[khud_laphand]-1], NULL); } - if (stplyr->laps == (UINT8)(cv_numlaps.value - 1)) + if (stplyr->laps == (UINT8)(cv_numlaps.value)) { V_DrawFixedPatch((62 - (32*max(0, progress-76)))*FRACUNIT, // 27 30*FRACUNIT, // 24 @@ -9644,14 +9644,14 @@ static void K_drawLapStartAnim(void) V_DrawFixedPatch((188 + (32*max(0, progress-76)))*FRACUNIT, // 194 30*FRACUNIT, // 24 FRACUNIT, V_SNAPTOTOP|V_HUDTRANS, - kp_lapanim_number[(((UINT32)stplyr->laps+1) / 10)][min(progress/2-8, 2)], NULL); + kp_lapanim_number[(((UINT32)stplyr->laps) / 10)][min(progress/2-8, 2)], NULL); if (progress/2-10 >= 0) { V_DrawFixedPatch((208 + (32*max(0, progress-76)))*FRACUNIT, // 221 30*FRACUNIT, // 24 FRACUNIT, V_SNAPTOTOP|V_HUDTRANS, - kp_lapanim_number[(((UINT32)stplyr->laps+1) % 10)][min(progress/2-10, 2)], NULL); + kp_lapanim_number[(((UINT32)stplyr->laps) % 10)][min(progress/2-10, 2)], NULL); } } } diff --git a/src/p_inter.c b/src/p_inter.c index 4ea169a83..2d4571e11 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1463,7 +1463,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // // SRB2kart: make sure the player will have enough checkpoints to touch - if (circuitmap && special->health >= ((numstarposts/2) + player->starpostnum)) + if (circuitmap && special->health >= player->starpostnum) { // blatant reuse of a variable that's normally unused in circuit if (!player->tossdelay) diff --git a/src/p_map.c b/src/p_map.c index d99105005..1d1b03e57 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -68,6 +68,20 @@ line_t *ceilingline; // that is, for any line which is 'solid' line_t *blockingline; +// Mostly re-ported from DOOM Legacy +// Keep track of special lines as they are hit, process them when the move is valid +static size_t *spechit = NULL; +static size_t spechit_max = 0U; +static size_t numspechit = 0U; + +// Need a intermediate buffer for P_TryMove because it performs multiple moves +// the lines put into spechit will be moved into here after each checkposition, +// then and duplicates will be removed before processing +static size_t *spechitint = NULL; +static size_t spechitint_max = 0U; +static size_t numspechitint = 0U; + + msecnode_t *sector_list = NULL; mprecipsecnode_t *precipsector_list = NULL; camera_t *mapcampointer; @@ -81,6 +95,8 @@ camera_t *mapcampointer; // boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) { + numspechit = 0U; + // the move is ok, // so link the thing into its new position P_UnsetThingPosition(thing); @@ -113,6 +129,100 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) // MOVEMENT ITERATOR FUNCTIONS // ========================================================================= +// For our intermediate buffer, remove any duplicate entries by adding each one to +// a temprary buffer if it's not already in there, copy the temporary buffer back over the intermediate afterwards +static void spechitint_removedups(void) +{ + // Only needs to be run if there's more than 1 line crossed + if (numspechitint > 1U) + { + boolean valueintemp = false; + size_t i = 0U, j = 0U; + size_t numspechittemp = 0U; + size_t *spechittemp = Z_Calloc(numspechitint * sizeof(size_t), PU_STATIC, NULL); + + // Fill the hashtable + for (i = 0U; i < numspechitint; i++) + { + valueintemp = false; + for (j = 0; j < numspechittemp; j++) + { + if (spechitint[i] == spechittemp[j]) + { + valueintemp = true; + break; + } + } + + if (!valueintemp) + { + spechittemp[numspechittemp] = spechitint[i]; + numspechittemp++; + } + } + + // The hash table now IS the result we want to send back + // easiest way to handle this is a memcpy + if (numspechittemp != numspechitint) + { + memcpy(spechitint, spechittemp, numspechittemp * sizeof(size_t)); + numspechitint = numspechittemp; + } + + Z_Free(spechittemp); + } +} + +// copy the contents of spechit into the end of spechitint +static void spechitint_copyinto(void) +{ + if (numspechit > 0U) + { + if (numspechitint + numspechit >= spechitint_max) + { + spechitint_max = spechitint_max + numspechit; + spechitint = Z_Realloc(spechitint, spechitint_max * sizeof(size_t), PU_STATIC, NULL); + } + + memcpy(&spechitint[numspechitint], spechit, numspechit * sizeof(size_t)); + numspechitint += numspechit; + } +} + +static void add_spechit(line_t *ld) +{ + if (numspechit >= spechit_max) + { + spechit_max = spechit_max ? spechit_max * 2U : 16U; + spechit = Z_Realloc(spechit, spechit_max * sizeof(size_t), PU_STATIC, NULL); + } + + spechit[numspechit] = ld - lines; + numspechit++; +} + +static boolean P_SpecialIsLinedefCrossType(UINT16 ldspecial) +{ + boolean linedefcrossspecial = false; + + switch (ldspecial) + { + case 2001: // Finish line + { + linedefcrossspecial = true; + } + break; + + default: + { + linedefcrossspecial = false; + } + break; + } + + return linedefcrossspecial; +} + boolean P_DoSpring(mobj_t *spring, mobj_t *object) { //INT32 pflags; @@ -1994,6 +2104,12 @@ if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; + // we've crossed the line + if (P_SpecialIsLinedefCrossType(ld->special)) + { + add_spechit(ld); + } + return true; } @@ -2268,6 +2384,9 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) validcount++; + // reset special lines + numspechit = 0U; + if (tmflags & MF_NOCLIP) return true; @@ -2707,6 +2826,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) { fixed_t tryx = thing->x; fixed_t tryy = thing->y; + fixed_t oldx = tryx; + fixed_t oldy = tryy; fixed_t radius = thing->radius; fixed_t thingtop = thing->z + thing->height; #ifdef ESLOPE @@ -2714,6 +2835,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) #endif floatok = false; + // reset this to 0 at the start of each trymove call as it's only used here + numspechitint = 0U; + if (radius < MAXRADIUS/2) radius = MAXRADIUS/2; @@ -2739,6 +2863,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (!P_CheckPosition(thing, tryx, tryy)) return false; // solid wall or thing + // copy into the spechitint buffer from spechit + spechitint_copyinto(); + if (!(thing->flags & MF_NOCLIP)) { //All things are affected by their scale. @@ -2915,6 +3042,30 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->eflags |= MFE_ONGROUND; P_SetThingPosition(thing); + + // remove any duplicates that may be in spechitint + spechitint_removedups(); + + // handle any of the special lines that were crossed + if (!(thing->flags & (MF_NOCLIP))) + { + line_t *ld = NULL; + INT32 side = 0, oldside = 0; + while (numspechitint--) + { + ld = &lines[spechitint[numspechitint]]; + side = P_PointOnLineSide(thing->x, thing->y, ld); + oldside = P_PointOnLineSide(oldx, oldy, ld); + if (side != oldside) + { + if (ld->special) + { + P_CrossSpecialLine(ld, oldside, thing); + } + } + } + } + return true; } diff --git a/src/p_spec.c b/src/p_spec.c index 209aa1a18..eb1190007 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2200,6 +2200,178 @@ void P_SwitchWeather(INT32 weathernum) } } +// Passed over the finish line forwards +static void K_HandleLapIncrement(player_t *player) +{ + if (player) + { + if ((player->starpostnum == numstarposts) || (player->laps == 0)) + { + UINT8 i = 0; + UINT8 nump = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + nump++; + } + + player->laps++; + + // Set up lap animation vars + if (player->laps > 1) + { + if (nump > 1) + { + if (K_IsPlayerLosing(player)) + player->karthud[khud_laphand] = 3; + else + { + if (nump > 2 && player->kartstuff[k_position] == 1) // 1st place in 1v1 uses thumbs up + player->karthud[khud_laphand] = 1; + else + player->karthud[khud_laphand] = 2; + } + } + else + player->karthud[khud_laphand] = 0; // No hands in FREE PLAY + + player->karthud[khud_lapanimation] = 80; + } + + if (netgame && player->laps >= (UINT8)cv_numlaps.value) + CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players])); + + // SRB2Kart: save best lap for record attack + if (player == &players[consoleplayer]) + { + if (curlap < bestlap || bestlap == 0) + bestlap = curlap; + curlap = 0; + } + + player->starposttime = player->realtime; + player->starpostnum = 0; + + if (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) + { + // SRB2Kart 281118 + // Save the player's time and position. + player->starpostx = player->mo->x>>FRACBITS; + player->starposty = player->mo->y>>FRACBITS; + player->starpostz = player->mo->floorz>>FRACBITS; + player->kartstuff[k_starpostflip] = player->mo->flags2 & MF2_OBJECTFLIP; // store flipping + player->starpostangle = player->mo->angle; //R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); torn; a momentum-based guess is less likely to be wrong in general, but when it IS wrong, it fucks you over entirely... + } + else + { + // SRB2kart 200117 + // Reset starposts (checkpoints) info + player->starpostangle = player->starpostx = player->starposty = player->starpostz = player->kartstuff[k_starpostflip] = 0; + } + + if (P_IsDisplayPlayer(player)) + { + if (player->laps == (UINT8)(cv_numlaps.value)) // final lap + S_StartSound(NULL, sfx_s3k68); + else if ((player->laps > 1) && (player->laps < (UINT8)(cv_numlaps.value))) // non-final lap + S_StartSound(NULL, sfx_s221); + else if (player->laps > (UINT8)(cv_numlaps.value)) + { + // finished + S_StartSound(NULL, sfx_s3k6a); + } + + } + else + { + if ((player->laps > (UINT8)(cv_numlaps.value)) && (player->kartstuff[k_position] == 1)) + { + // opponent finished + S_StartSound(NULL, sfx_s253); + } + } + + // finished race exit setup + if (player->laps > (unsigned)cv_numlaps.value) + { + P_DoPlayerExit(player); + P_SetupSignExit(player); + } + + //player->starpostangle = player->starposttime = player->starpostnum = 0; + //player->starpostx = player->starposty = player->starpostz = 0; + + // Play the starpost sound for 'consistency' + // S_StartSound(player->mo, sfx_strpst); + + // Figure out how many are playing on the last lap, to prevent spectate griefing + if (!nospectategrief && player->laps > (UINT8)(cv_numlaps.value)) + nospectategrief = nump; + + thwompsactive = true; // Lap 2 effects + } + else if (player->starpostnum) + { + S_StartSound(player->mo, sfx_s26d); + } + } +} + +// player went backwards over the line +static void K_HandleLapDecrement(player_t *player) +{ + if (player) + { + if (player->laps > 0) + { + player->starpostnum = numstarposts; + player->laps--; + } + } +} + +// +// P_CrossSpecialLine - TRIGGER +// Called every time a thing origin is about +// to cross a line with specific specials +// Kart - Only used for the finish line currently +// +void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing) +{ + // only used for the players currently + if (thing && thing->player) + { + player_t *player = thing->player; + switch (line->special) + { + case 2001: // Finish Line + { + if (G_RaceGametype() && !(player->exiting)) + { + if (((line->flags & (ML_NOCLIMB)) && (side == 1)) + || (!(line->flags & (ML_NOCLIMB)) && (side == 0))) // crossed from behind to infront + { + K_HandleLapIncrement(player); + } + else + { + K_HandleLapDecrement(player); + } + } + } + break; + + default: + { + // Do nothing + } + break; + } + } +} + /** Gets an object. * * \param type Object type to look for. @@ -4223,115 +4395,8 @@ DoneSection2: } break; - case 10: // Finish Line - // SRB2kart - 150117 - // - if (G_RaceGametype() && !player->exiting) - { - if (player->starpostnum == numstarposts) - { - UINT8 nump = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - nump++; - } - - player->laps++; - - // Set up lap animation vars - if (nump > 1) - { - if (K_IsPlayerLosing(player)) - player->karthud[khud_laphand] = 3; - else - { - if (nump > 2 && player->kartstuff[k_position] == 1) // 1st place in 1v1 uses thumbs up - player->karthud[khud_laphand] = 1; - else - player->karthud[khud_laphand] = 2; - } - } - else - player->karthud[khud_laphand] = 0; // No hands in FREE PLAY - - player->karthud[khud_lapanimation] = 80; - - if (player->pflags & PF_NIGHTSMODE) - player->drillmeter += 48*20; - - if (netgame && player->laps >= (UINT8)cv_numlaps.value) - CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players])); - - // SRB2Kart: save best lap for record attack - if (player == &players[consoleplayer]) - { - if (curlap < bestlap || bestlap == 0) - bestlap = curlap; - curlap = 0; - } - - player->starposttime = player->realtime; - player->starpostnum = 0; - - if (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) - { - // SRB2Kart 281118 - // Save the player's time and position. - player->starpostx = player->mo->x>>FRACBITS; - player->starposty = player->mo->y>>FRACBITS; - player->starpostz = player->mo->floorz>>FRACBITS; - player->kartstuff[k_starpostflip] = player->mo->flags2 & MF2_OBJECTFLIP; // store flipping - player->starpostangle = player->mo->angle; //R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); torn; a momentum-based guess is less likely to be wrong in general, but when it IS wrong, it fucks you over entirely... - } - else - { - // SRB2kart 200117 - // Reset starposts (checkpoints) info - player->starpostangle = player->starpostx = player->starposty = player->starpostz = player->kartstuff[k_starpostflip] = 0; - } - - if (P_IsDisplayPlayer(player)) - { - if (player->laps == (UINT8)(cv_numlaps.value - 1)) - S_StartSound(NULL, sfx_s3k68); - else if (player->laps < (UINT8)(cv_numlaps.value - 1)) - S_StartSound(NULL, sfx_s221); - } - - //player->starpostangle = player->starposttime = player->starpostnum = 0; - //player->starpostx = player->starposty = player->starpostz = 0; - - // Play the starpost sound for 'consistency' - // S_StartSound(player->mo, sfx_strpst); - - // Figure out how many are playing on the last lap, to prevent spectate griefing - if (!nospectategrief && player->laps >= (UINT8)(cv_numlaps.value - 1)) - nospectategrief = nump; - - thwompsactive = true; // Lap 2 effects - } - else if (player->starpostnum) - { - // blatant reuse of a variable that's normally unused in circuit - if (!player->tossdelay) - S_StartSound(player->mo, sfx_s26d); - player->tossdelay = 3; - } - - if (player->laps >= (unsigned)cv_numlaps.value) - { - if (P_IsDisplayPlayer(player)) - S_StartSound(NULL, sfx_s3k6a); - else if (player->kartstuff[k_position] == 1) - S_StartSound(NULL, sfx_s253); - - P_DoPlayerExit(player); - P_SetupSignExit(player); - } - } + case 10: // Finish Line (Unused) + // SRB2Kart 20190616 - Is now a linedef type that activates by crossing over it break; case 11: // Rope hang @@ -4884,7 +4949,7 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) case 6: // Super Sonic Transform case 8: // Zoom Tube Start case 9: // Zoom Tube End - case 10: // Finish line + case 10: // Finish line (Unused) nofloorneeded = true; break; } @@ -5758,9 +5823,7 @@ void P_SpawnSpecials(INT32 fromnetsave) // Process Section 4 switch(GETSECSPECIAL(sector->special, 4)) { - case 10: // Circuit finish line - if (G_RaceGametype()) - circuitmap = true; + case 10: // Circuit finish line (Unused) break; } } @@ -6701,6 +6764,10 @@ void P_SpawnSpecials(INT32 fromnetsave) case 2000: // Waypoint Parameters break; + case 2001: // Finish Line + if (G_RaceGametype()) + circuitmap = true; + break; default: break; } diff --git a/src/p_spec.h b/src/p_spec.h index b604ac951..2763a34ad 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -56,6 +56,8 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max); +void P_CrossSpecialLine(line_t *ld, INT32 side, mobj_t *thing); + void P_SetupSignExit(player_t *player); boolean P_IsFlagAtBase(mobjtype_t flag); diff --git a/src/p_user.c b/src/p_user.c index 46478d7d9..275ad1b69 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1253,7 +1253,7 @@ void P_RestoreMusic(player_t *player) #if 0 // Event - Final Lap // Still works for GME, but disabled for consistency - if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value - 1)) + if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value)) S_SpeedMusic(1.2f); #endif S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); diff --git a/src/st_stuff.c b/src/st_stuff.c index e59846aed..c55724359 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1514,7 +1514,7 @@ static inline void ST_drawRaceHUD(void) // SRB2kart - unused. if (stplyr->exiting) V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), V_YELLOWMAP, "FINISHED!"); else - V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), 0, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); + V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), 0, va("Lap: %u/%d", stplyr->laps, cv_numlaps.value)); } } */