diff --git a/src/g_game.c b/src/g_game.c index 4051ef571..52d325263 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4951,6 +4951,14 @@ mapnum_t G_CheckNextMap(boolean noadvancemap) //boolean spec = G_IsSpecialStage(currentmap); INT32 i; + // Kill nextmapoverride if it's not a safe move + if (!G_MapIsSafe(nextmapoverride)) + { + // At least beat the programmer/host over the head for it + CONS_Alert(CONS_WARNING, "Overriding map ID %d is unsafe!", nextmapoverride); + nextmapoverride = 0; + } + if (nextmapoverride != 0) { return nextmapoverride-1; @@ -5104,6 +5112,14 @@ mapnum_t G_CheckNextMap(boolean noadvancemap) } } +// Tests if a given map number is safe to go to. If not, this returns false. +boolean G_MapIsSafe(mapnum_t map) +{ + return (map != NEXTMAP_INVALID && + (map >= NEXTMAP_SPECIAL || (map < nummapheaders && mapheaderinfo[map] && + mapheaderinfo[map]->lumpnum != LUMPERROR))); +} + void G_GetNextMap(void) { if (!server) @@ -5222,7 +5238,7 @@ void G_GetNextMap(void) } // We are committed to this map now. - if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR))) + if (!G_MapIsSafe(nextmap)) 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. diff --git a/src/g_game.h b/src/g_game.h index c33b7cde2..f93bf9be1 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -223,6 +223,7 @@ UINT8 G_GetGametypeColor(INT16 gt); void G_BeginLevelExit(void); void G_FinishExitLevel(void); void G_NextLevel(void); +boolean G_MapIsSafe(mapnum_t map); mapnum_t G_CheckNextMap(boolean noadvancemap); void G_GetNextMap(void); void G_Continue(void); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 52cbf9098..36ae24785 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3502,10 +3502,11 @@ static int lib_gDoReborn(lua_State *L) } // Another Lua function that doesn't actually exist! -// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts. -static int lib_gSetCustomExitVars(lua_State *L) +// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other +// sources should be exiting the level, like normal signposts. +static int lib_gSetCustomExitVars(lua_State* L) { - int n = lua_gettop(L); // Num arguments + int n = lua_gettop(L); // Num arguments NOHUD INLEVEL @@ -3516,15 +3517,36 @@ static int lib_gSetCustomExitVars(lua_State *L) // G_SetCustomExitVars(nil, int) [skipstats only] // G_SetCustomExitVars(int, int) [both of the above] + mapnum_t potential_override = 0; + nextmapoverride = 0; skipstats = 0; if (n >= 1) { - nextmapoverride = luaL_optinteger(L, 1, 0); + potential_override = luaL_optinteger(L, 1, 0); skipstats = (INT16)luaL_optinteger(L, 2, 0); - if (lua_compatmode && nextmapoverride) - nextmapoverride = G_KartMapToNative(nextmapoverride); + if (lua_compatmode && potential_override) + potential_override = G_KartMapToNative(potential_override); + + if (potential_override != 0) + { + // Prevent crashes by making sure the override is safe + if (!G_MapIsSafe(potential_override)) + { + // Override is very definitively NOT safe; error out + return luaL_error( + L, + "provided map override %d is invalid (nummapheaders = %d)", + potential_override, + nummapheaders); + } + else + { + // Allow the override + nextmapoverride = potential_override; + } + } } return 0; @@ -3630,6 +3652,18 @@ static int lib_gTicsToMilliseconds(lua_State *L) return 1; } +static int lib_gMapIsSafe(lua_State *L) +{ + mapnum_t map = (mapnum_t)luaL_checkinteger(L, 1); + + if (lua_compatmode && map) + map = G_KartMapToNative(map); + + //HUDSAFE + lua_pushboolean(L, G_MapIsSafe(map)); + return 1; +} + // K_KART //////////// @@ -5781,6 +5815,7 @@ static luaL_Reg lib[] = { {"G_AddGametype", lib_gAddGametype}, {"G_BuildMapName",lib_gBuildMapName}, {"G_MapNumber",lib_gMapNumber}, + {"G_MapIsSafe",lib_gMapIsSafe}, {"G_BuildMapTitle",lib_gBuildMapTitle}, {"G_FindMap",lib_gFindMap}, {"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode},