diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index c5e07f025..cfb84c7b8 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -1652,6 +1652,64 @@ bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, return false; } +/*-------------------------------------------------- + bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Immediately warps to another level. +--------------------------------------------------*/ + +bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = NULL; + + ACSVM::String *str = nullptr; + + const char *levelName = NULL; + size_t levelLen = 0; + + UINT16 nextmap = NEXTMAP_INVALID; + + (void)argC; + + if (exitcountdown == 1) + { + // An exit is already in progress. + return false; + } + + map = thread->scopeMap; + + str = map->getString(argV[0]); + + levelName = str->str; + levelLen = str->len; + + if (!levelLen || !levelName) + { + CONS_Alert(CONS_WARNING, "MapWarp level name was not provided.\n"); + } + + nextmap = G_MapNumber(levelName); + + if (nextmap == NEXTMAP_INVALID) + { + CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); + return false; + } + + nextmapoverride = (nextmap + 1); + + if (argV[1] == 0) + skipstats = 1; + + exitcountdown = 1; + + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index e2c43e945..a59b4d916 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -83,6 +83,8 @@ bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index e90c34cb6..a3adaa50f 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -165,6 +165,7 @@ Environment::Environment() addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition)); addFuncDataACS0( 502, addCallFunc(CallFunc_PodiumFinish)); addFuncDataACS0( 503, addCallFunc(CallFunc_SetLineRenderStyle)); + addFuncDataACS0( 504, addCallFunc(CallFunc_MapWarp)); } ACSVM::Thread *Environment::allocThread() diff --git a/src/doomstat.h b/src/doomstat.h index 619f01db3..c5b594e8d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -343,7 +343,7 @@ struct textprompt_t extern textprompt_t *textprompts[MAX_PROMPTS]; // For the Custom Exit linedef. -extern INT16 nextmapoverride; +extern UINT16 nextmapoverride; extern UINT8 skipstats; // Fun extra stuff diff --git a/src/g_game.c b/src/g_game.c index f65f0ba6d..16f999ac9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -183,7 +183,7 @@ boolean exitfadestarted = false; cutscene_t *cutscenes[128]; textprompt_t *textprompts[MAX_PROMPTS]; -INT16 nextmapoverride; +UINT16 nextmapoverride; UINT8 skipstats; // Pointers to each CTF flag @@ -332,7 +332,7 @@ typedef struct joystickvector2_s boolean precache = true; // if true, load all graphics at start -INT16 prevmap, nextmap; +UINT16 prevmap, nextmap; static void weaponPrefChange(void); static void weaponPrefChange2(void); @@ -3303,7 +3303,7 @@ void G_ExitLevel(void) } } - if (!G_GametypeUsesLives()) + if (!G_GametypeUsesLives() || skipstats != 0) ; // never force a retry else if (specialstageinfo.valid == true || (gametyperules & GTR_BOSS)) { @@ -3717,10 +3717,10 @@ UINT32 G_TOLFlag(INT32 pgametype) return 0; } -INT16 G_GetFirstMapOfGametype(UINT8 pgametype) +UINT16 G_GetFirstMapOfGametype(UINT8 pgametype) { UINT8 i = 0; - INT16 mapnum = NEXTMAP_INVALID; + UINT16 mapnum = NEXTMAP_INVALID; levelsearch_t templevelsearch; templevelsearch.cup = NULL; @@ -4181,7 +4181,7 @@ static void G_GetNextMap(void) // nextmap is 0-based, unlike gamemap if (nextmapoverride != 0) { - nextmap = (INT16)(nextmapoverride-1); + nextmap = (nextmapoverride-1); setalready = true; } else if (roundqueue.size > 0) @@ -4520,9 +4520,7 @@ static void G_DoCompleted(void) // If the current gametype has no intermission screen set, then don't start it. Y_DetermineIntermissionType(); - if ((skipstats && !modeattacking) - || (modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST)) - || (intertype == int_none)) + if (intertype == int_none) { G_UpdateVisited(); G_AfterIntermission(); diff --git a/src/g_game.h b/src/g_game.h index 2f498134e..34cfbd514 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -38,7 +38,7 @@ extern boolean playeringame[MAXPLAYERS]; extern tic_t levelstarttic; // for modding? -extern INT16 prevmap, nextmap; +extern UINT16 prevmap, nextmap; // see also G_MapNumber typedef enum @@ -276,7 +276,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); // Don't split up TOL handling UINT32 G_TOLFlag(INT32 pgametype); -INT16 G_GetFirstMapOfGametype(UINT8 pgametype); +UINT16 G_GetFirstMapOfGametype(UINT8 pgametype); UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer); void G_AddMapToBuffer(UINT16 map); diff --git a/src/k_kart.c b/src/k_kart.c index 90a7bd9ba..d47d63390 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -146,6 +146,10 @@ void K_TimerInit(void) P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false)); } } + else if (skipstats != 0) + { + S_StartSound(NULL, sfx_endwrp); + } if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) == (GTR_CATCHER|GTR_CIRCUIT)) { diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 2aeb50f55..68d395abf 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -131,7 +131,7 @@ UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch) UINT16 M_GetFirstLevelInList(UINT8 *i, levelsearch_t *levelsearch) { - INT16 mapnum = NEXTMAP_INVALID; + UINT16 mapnum = NEXTMAP_INVALID; if (!levelsearch) return NEXTMAP_INVALID; diff --git a/src/p_setup.c b/src/p_setup.c index ea1185a67..aa52bc5c5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8095,6 +8095,13 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) levelfadecol = 0; wipetype = wipe_encore_towhite; } + else if (skipstats == 1) + { + if (ranspecialwipe != 2) + S_StartSound(NULL, sfx_s3k73); + levelfadecol = 0; + wipetype = wipe_encore_towhite; + } else if (encoremode) { levelfadecol = 0; @@ -8301,9 +8308,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (precache || dedicated) R_PrecacheLevel(); - nextmapoverride = 0; - skipstats = 0; - if (!demo.playback) { mapheaderinfo[gamemap-1]->records.mapvisited |= MV_VISITED; @@ -8380,6 +8384,9 @@ void P_PostLoadLevel(void) { K_TimerInit(); + nextmapoverride = 0; + skipstats = 0; + P_RunCachedActions(); if (marathonmode & MA_INGAME) diff --git a/src/sounds.c b/src/sounds.c index d8852928b..85b111a50 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1102,6 +1102,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"typri2", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SA2 final boss-type typewriting {"eggspr", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Sonic Unleashed Trap Spring {"achiev", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Achievement"}, + {"endwrp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // End of a "Tutorial Teleport" // SRB2Kart - Drop target sounds {"kdtrg1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Low energy, SF_X8AWAYSOUND diff --git a/src/sounds.h b/src/sounds.h index 422138d65..a2f786030 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1169,6 +1169,7 @@ typedef enum sfx_typri2, sfx_eggspr, sfx_achiev, + sfx_endwrp, // SRB2Kart - Drop target sounds sfx_kdtrg1, diff --git a/src/y_inter.c b/src/y_inter.c index 70ae5e7fb..0d276928f 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1589,7 +1589,11 @@ void Y_Ticker(void) void Y_DetermineIntermissionType(void) { // no intermission for GP events - if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) + if ((grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) + // or for failing in time attack mode + || (modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST)) + // or for explicit requested skip (outside of modeattacking) + || (modeattacking == ATTACKING_NONE && skipstats != 0)) { intertype = int_none; return;