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.
This commit is contained in:
Sryder 2019-06-16 22:03:26 +01:00
parent 49a8b0ac38
commit 6bcc283d3b
7 changed files with 345 additions and 125 deletions

View file

@ -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);
}
}
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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));
}
}
*/