More fun rules for Special Stages

- GTR_ROLLINGSTART
    * Initial instathrust, as before
    * Forced MAXPLMOVE forward
    * Disable finish line beam
    * "Super transformation" sound
        - Reference to the previous entry in the series' Perfect Startboost mechanic
- GTR_SPECIALSTART
    * Instant white fade
    * No titlecard (overridden by Boss intro)
    * Starting warp sound
- Match slidein time with no traditional titlecard to the end of the playsim intro fade
- Remove G_IsSpecialStage
This commit is contained in:
toaster 2022-12-27 17:58:35 +00:00
parent f8999bea36
commit 03c8fd543f
12 changed files with 70 additions and 79 deletions

View file

@ -5813,9 +5813,11 @@ const char *const GAMETYPERULE_LIST[] = {
"CATCHER", "CATCHER",
"BOSS", "BOSS",
"ROLLINGSTART",
"NOCUPSELECT", "NOCUPSELECT",
"CLOSERPLAYERS", "CLOSERPLAYERS",
"ENCORE", "ENCORE",
"SPECIALSTART",
NULL NULL
}; };

View file

@ -513,10 +513,11 @@ enum GameTypeRules
// To be rearranged later // To be rearranged later
GTR_CATCHER = 1<<17, // UFO Catcher (only works with GTR_CIRCUIT) GTR_CATCHER = 1<<17, // UFO Catcher (only works with GTR_CIRCUIT)
GTR_BOSS = 1<<18, // Boss intro and spawning GTR_BOSS = 1<<18, // Boss intro and spawning
GTR_ROLLINGSTART = 1<<19, // Rolling start (only works with GTR_CIRCUIT)
GTR_NOCUPSELECT = 1<<20, // Your maps are not selected via cup. GTR_NOCUPSELECT = 1<<20, // Your maps are not selected via cup.
GTR_CLOSERPLAYERS = 1<<21, // Buffs spindash and draft power to bring everyone together, nerfs invincibility and grow to prevent excessive combos GTR_CLOSERPLAYERS = 1<<21, // Buffs spindash and draft power to bring everyone together, nerfs invincibility and grow to prevent excessive combos
GTR_ENCORE = 1<<22, // Alternate Encore mirroring, scripting, and texture remapping GTR_ENCORE = 1<<22, // Alternate Encore mirroring, scripting, and texture remapping
GTR_SPECIALSTART = 1<<23, // White fade instant start
// free: to and including 1<<31 // free: to and including 1<<31
}; };

View file

@ -1412,7 +1412,7 @@ void G_StartTitleCard(void)
{ {
// The title card has been disabled for this map. // The title card has been disabled for this map.
// Oh well. // Oh well.
if (!G_IsTitleCardAvailable() || demo.rewinding) if (demo.rewinding || !G_IsTitleCardAvailable())
{ {
WipeStageTitle = false; WipeStageTitle = false;
return; return;
@ -1476,11 +1476,17 @@ void G_PreLevelTitleCard(void)
// //
boolean G_IsTitleCardAvailable(void) boolean G_IsTitleCardAvailable(void)
{ {
#if 0 // Overwrites all other title card exceptions.
if (K_CheckBossIntro() == true)
return true;
// The current level has no name. // The current level has no name.
if (!mapheaderinfo[gamemap-1]->lvlttl[0]) if (!mapheaderinfo[gamemap-1]->lvlttl[0])
return false; return false;
#endif
// Instant white fade.
if (gametyperules & GTR_SPECIALSTART)
return false;
// The title card is available. // The title card is available.
return true; return true;
@ -3015,7 +3021,7 @@ static gametype_t defaultgametypes[] =
{ {
"Special", "Special",
"GT_SPECIAL", "GT_SPECIAL",
GTR_CATCHER|GTR_CIRCUIT, GTR_CATCHER|GTR_SPECIALSTART|GTR_ROLLINGSTART|GTR_CIRCUIT,
TOL_SPECIAL, TOL_SPECIAL,
int_time, int_time,
0, 0,
@ -3213,25 +3219,6 @@ void G_AddTOL(UINT32 newtol, const char *tolname)
TYPEOFLEVEL[i].flag = newtol; TYPEOFLEVEL[i].flag = newtol;
} }
//
// G_IsSpecialStage
//
// Returns TRUE if
// the given map is a special stage.
//
boolean G_IsSpecialStage(INT32 mapnum)
{
mapnum--; // gamemap-based to 0 indexed
if (mapnum > nummapheaders || !mapheaderinfo[mapnum])
return false;
if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum)
return false;
return true;
}
// //
// G_GametypeUsesLives // G_GametypeUsesLives
// //
@ -3666,7 +3653,6 @@ static void G_HandleSaveLevel(void)
static void G_GetNextMap(void) static void G_GetNextMap(void)
{ {
boolean spec = G_IsSpecialStage(prevmap+1);
INT32 i; INT32 i;
// go to next level // go to next level
@ -3917,7 +3903,9 @@ static void G_GetNextMap(void)
if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR))) if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)))
I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders);
#if 0 // This is a surprise tool that will help us later.
if (!spec) if (!spec)
#endif //#if 0
lastmap = nextmap; lastmap = nextmap;
} }

View file

@ -186,7 +186,6 @@ void G_AddTOL(UINT32 newtol, const char *tolname);
INT32 G_GetGametypeByName(const char *gametypestr); INT32 G_GetGametypeByName(const char *gametypestr);
INT32 G_GuessGametypeByTOL(UINT32 tol); INT32 G_GuessGametypeByTOL(UINT32 tol);
boolean G_IsSpecialStage(INT32 mapnum);
boolean G_GametypeUsesLives(void); boolean G_GametypeUsesLives(void);
boolean G_GametypeHasTeams(void); boolean G_GametypeHasTeams(void);
boolean G_GametypeHasSpectators(void); boolean G_GametypeHasSpectators(void);

View file

@ -109,6 +109,36 @@ void K_TimerInit(void)
boolean domodeattack = ((modeattacking != ATTACKING_NONE) boolean domodeattack = ((modeattacking != ATTACKING_NONE)
|| (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)); || (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE));
// Rooooooolllling staaaaaaart
if ((gametyperules & (GTR_ROLLINGSTART|GTR_CIRCUIT)) == (GTR_ROLLINGSTART|GTR_CIRCUIT))
{
S_StartSound(NULL, sfx_s25f);
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *player = NULL;
if (playeringame[i] == false)
{
continue;
}
player = &players[i];
if (player->spectator == true)
{
continue;
}
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
{
continue;
}
// Rolling start? lol
P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false));
}
}
if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) == (GTR_CATCHER|GTR_CIRCUIT)) if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) == (GTR_CATCHER|GTR_CIRCUIT))
{ {
K_InitSpecialStage(); K_InitSpecialStage();
@ -3298,7 +3328,8 @@ SINT8 K_GetForwardMove(player_t *player)
return 0; return 0;
} }
if (player->sneakertimer || player->spindashboost) if (player->sneakertimer || player->spindashboost
|| (((gametyperules & (GTR_ROLLINGSTART|GTR_CIRCUIT)) == (GTR_ROLLINGSTART|GTR_CIRCUIT)) && (leveltime < TICRATE/2)))
{ {
return MAXPLMOVE; return MAXPLMOVE;
} }

View file

@ -400,7 +400,7 @@ static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *
void K_RunFinishLineBeam(void) void K_RunFinishLineBeam(void)
{ {
if (!(leveltime < starttime || rainbowstartavailable == true)) if ((gametyperules & GTR_ROLLINGSTART) || !(leveltime < starttime || rainbowstartavailable == true))
{ {
return; return;
} }

View file

@ -42,8 +42,6 @@ void K_ResetSpecialStage(void)
--------------------------------------------------*/ --------------------------------------------------*/
void K_InitSpecialStage(void) void K_InitSpecialStage(void)
{ {
INT32 i;
if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) != (GTR_CATCHER|GTR_CIRCUIT)) if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) != (GTR_CATCHER|GTR_CIRCUIT))
{ {
return; return;
@ -53,30 +51,6 @@ void K_InitSpecialStage(void)
specialstageinfo.beamDist = UINT32_MAX; // TODO: make proper value specialstageinfo.beamDist = UINT32_MAX; // TODO: make proper value
P_SetTarget(&specialstageinfo.ufo, Obj_CreateSpecialUFO()); P_SetTarget(&specialstageinfo.ufo, Obj_CreateSpecialUFO());
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *player = NULL;
if (playeringame[i] == false)
{
continue;
}
player = &players[i];
if (player->spectator == true)
{
continue;
}
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
{
continue;
}
// Rolling start? lol
P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false));
}
} }
/*-------------------------------------------------- /*--------------------------------------------------

View file

@ -3282,15 +3282,6 @@ static int lib_gExitLevel(lua_State *L)
return 0; return 0;
} }
static int lib_gIsSpecialStage(lua_State *L)
{
INT32 mapnum = luaL_optinteger(L, 1, gamemap);
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_IsSpecialStage(mapnum));
return 1;
}
static int lib_gGametypeUsesLives(lua_State *L) static int lib_gGametypeUsesLives(lua_State *L)
{ {
//HUDSAFE //HUDSAFE
@ -4099,7 +4090,6 @@ static luaL_Reg lib[] = {
{"G_DoReborn",lib_gDoReborn}, {"G_DoReborn",lib_gDoReborn},
{"G_SetCustomExitVars",lib_gSetCustomExitVars}, {"G_SetCustomExitVars",lib_gSetCustomExitVars},
{"G_ExitLevel",lib_gExitLevel}, {"G_ExitLevel",lib_gExitLevel},
{"G_IsSpecialStage",lib_gIsSpecialStage},
{"G_GametypeUsesLives",lib_gGametypeUsesLives}, {"G_GametypeUsesLives",lib_gGametypeUsesLives},
{"G_GametypeHasTeams",lib_gGametypeHasTeams}, {"G_GametypeHasTeams",lib_gGametypeHasTeams},
{"G_GametypeHasSpectators",lib_gGametypeHasSpectators}, {"G_GametypeHasSpectators",lib_gGametypeHasSpectators},

View file

@ -7326,13 +7326,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
} }
G_ClearModeAttackRetryFlag(); G_ClearModeAttackRetryFlag();
} }
/*
else if (rendermode != render_none && G_IsSpecialStage(gamemap))
{
P_RunSpecialStageWipe();
ranspecialwipe = 1;
}
*/
// Make sure all sounds are stopped before Z_FreeTags. // Make sure all sounds are stopped before Z_FreeTags.
S_StopSounds(); S_StopSounds();
@ -7367,7 +7360,20 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
S_Start(); S_Start();
} }
levelfadecol = (encoremode ? 0 : 31); if (gametyperules & GTR_SPECIALSTART)
{
if (ranspecialwipe != 2)
S_StartSound(NULL, sfx_s3kaf);
levelfadecol = 0;
}
else if (encoremode)
{
levelfadecol = 0;
}
else
{
levelfadecol = 31;
}
if (rendermode != render_none) if (rendermode != render_none)
{ {

View file

@ -1843,7 +1843,7 @@ static void K_HandleLapIncrement(player_t *player)
{ {
if (player) if (player)
{ {
if (leveltime < starttime) if (leveltime < starttime && !(gametyperules & GTR_ROLLINGSTART))
{ {
// Will fault the player // Will fault the player
K_DoIngameRespawn(player); K_DoIngameRespawn(player);
@ -1902,7 +1902,7 @@ static void K_HandleLapIncrement(player_t *player)
if (P_IsDisplayPlayer(player)) if (P_IsDisplayPlayer(player))
{ {
if (player->laps == numlaps) // final lap if (numlaps > 1 && player->laps == numlaps) // final lap
S_StartSound(NULL, sfx_s3k68); S_StartSound(NULL, sfx_s3k68);
else if ((player->laps > 1) && (player->laps < numlaps)) // non-final lap else if ((player->laps > 1) && (player->laps < numlaps)) // non-final lap
S_StartSound(NULL, sfx_s221); S_StartSound(NULL, sfx_s221);

View file

@ -802,7 +802,7 @@ void ST_drawTitleCard(void)
#define HITIME 15 #define HITIME 15
patch_t *localwarn = (encoremode ? twarn2 : twarn); patch_t *localwarn = (encoremode ? twarn2 : twarn);
INT32 transp = (lt_ticker+HITIME) % (LOTIME+HITIME); INT32 transp = (lt_ticker+HITIME) % (LOTIME+HITIME);
boolean encorehack = (encoremode && lt_ticker <= PRELEVELTIME+4); boolean encorehack = ((levelfadecol == 0) && lt_ticker <= PRELEVELTIME+4);
if ((localwarn->width > 0) && (lt_ticker + (HITIME-transp) <= lt_endtime)) if ((localwarn->width > 0) && (lt_ticker + (HITIME-transp) <= lt_endtime))
{ {

View file

@ -585,16 +585,16 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
} }
} }
if (options & V_SLIDEIN) if ((options & V_SLIDEIN))
{ {
const tic_t length = TICRATE/4; const tic_t length = TICRATE/4;
tic_t timer = lt_exitticker; tic_t timer = lt_exitticker;
if (K_CheckBossIntro() == true) if (K_CheckBossIntro() == true || G_IsTitleCardAvailable() == false)
{ {
if (leveltime <= 3) if (leveltime <= 16)
timer = 0; timer = 0;
else else
timer = leveltime-3; timer = leveltime-16;
} }
if (timer < length) if (timer < length)