From e5e8c02f1d21cd66efc18548e649884c06c61f1b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Sep 2020 23:10:28 +0200 Subject: [PATCH] - WIP level transition refactored to a game independent event system. --- source/blood/src/blood.cpp | 11 +- source/blood/src/blood.h | 1 + source/build/include/build.h | 12 -- source/core/cheats.cpp | 274 ++++++++++++++++++++++++++- source/core/cheats.h | 1 + source/core/d_net.cpp | 1 + source/core/gamecontrol.cpp | 13 ++ source/core/gamecontrol.h | 9 + source/core/gamestate.h | 16 ++ source/core/gamestruct.h | 8 +- source/core/mainloop.cpp | 66 ++++++- source/core/mapinfo.cpp | 9 + source/core/mapinfo.h | 1 + source/core/menu/menu.cpp | 22 --- source/core/menu/savegamemanager.cpp | 15 +- source/exhumed/src/gameloop.cpp | 3 +- source/games/duke/src/2d_d.cpp | 70 +------ source/games/duke/src/2d_r.cpp | 8 +- source/games/duke/src/actors_r.cpp | 4 +- source/games/duke/src/ccmds.cpp | 91 +-------- source/games/duke/src/cheats.cpp | 13 +- source/games/duke/src/constants.h | 2 - source/games/duke/src/d_menu.cpp | 9 +- source/games/duke/src/duke3d.h | 5 +- source/games/duke/src/funct.h | 6 +- source/games/duke/src/game_misc.cpp | 5 +- source/games/duke/src/gameexec.cpp | 17 +- source/games/duke/src/gameloop.cpp | 46 ++++- source/games/duke/src/premap.cpp | 115 ++++------- source/games/duke/src/savegame.cpp | 3 - source/games/duke/src/sounds.cpp | 4 +- source/games/duke/src/types.h | 5 +- source/sw/src/d_menu.cpp | 11 +- source/sw/src/game.cpp | 17 +- source/sw/src/game.h | 2 +- source/sw/src/save.cpp | 9 +- 36 files changed, 536 insertions(+), 368 deletions(-) diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index 7a5205824..caa1de1f0 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -509,9 +509,7 @@ void GameInterface::Startup() if (!userConfig.nologo && gGameOptions.nGameType == 0) playlogos(); else { - gamestate = GS_MENUSCREEN; - M_StartControlPanel(false); - M_SetMenu(NAME_Mainmenu); + startmainmenu(); } } } @@ -573,6 +571,13 @@ void GameInterface::FreeGameData() if (BloodINI) delete BloodINI; } +void GameInterface::FreeLevelData() +{ + EndLevel(); + ::GameInterface::FreeLevelData(); +} + + ReservedSpace GameInterface::GetReservedScreenSpace(int viewsize) { int top = 0; diff --git a/source/blood/src/blood.h b/source/blood/src/blood.h index 98f5152c0..06bcc7649 100644 --- a/source/blood/src/blood.h +++ b/source/blood/src/blood.h @@ -79,6 +79,7 @@ struct GameInterface : ::GameInterface const char* Name() override { return "Blood"; } void app_init() override; bool GenerateSavePic() override; + void FreeLevelData() override; void FreeGameData() override; FSavegameInfo GetSaveSig() override; void MenuOpened() override; diff --git a/source/build/include/build.h b/source/build/include/build.h index 7f0a9553c..bc3484fcc 100644 --- a/source/build/include/build.h +++ b/source/build/include/build.h @@ -99,17 +99,6 @@ enum rendmode_t { Iter>=0 && (Next=nextspritestat[Iter], 1); Iter=Next -////////// True Room over Room (YAX == rot -17 of "PRO") ////////// -#define YAX_ENABLE -//#define YAX_DEBUG -//#define ENGINE_SCREENSHOT_DEBUG - -#ifdef YAX_ENABLE -# if !defined NEW_MAP_FORMAT -# define YAX_ENABLE__COMPAT -# endif -#endif - ////////// yax defs ////////// #define SECTORFLD(Sect,Fld, Cf) (*((Cf) ? (§or[Sect].floor##Fld) : (§or[Sect].ceiling##Fld))) @@ -648,7 +637,6 @@ int32_t videoSetGameMode(char davidoption, int32_t daupscaledxdim, int32_t dau void videoSetCorrectedAspect(); void videoSetViewableArea(int32_t x1, int32_t y1, int32_t x2, int32_t y2); void renderSetAspect(int32_t daxrange, int32_t daaspect); -inline void renderFlushPerms(void) {} void plotpixel(int32_t x, int32_t y, char col); FCanvasTexture *renderSetTarget(int16_t tilenume); diff --git a/source/core/cheats.cpp b/source/core/cheats.cpp index b1dcd1ef9..62c21cb0f 100644 --- a/source/core/cheats.cpp +++ b/source/core/cheats.cpp @@ -43,10 +43,18 @@ #include "gamestate.h" #include "mmulti.h" #include "gstrings.h" +#include "gamecontrol.h" +#include "mapinfo.h" CVAR(Bool, sv_cheats, true, CVAR_ARCHIVE|CVAR_SERVERINFO) CVAR(Bool, cl_blockcheats, false, 0) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool CheckCheatmode (bool printmsg, bool sponly) { if ((sponly && netgame) || gamestate != GS_LEVEL) @@ -76,6 +84,12 @@ bool CheckCheatmode (bool printmsg, bool sponly) } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void genericCheat(int player, uint8_t** stream, bool skip) { int cheat = ReadByte(stream); @@ -94,6 +108,11 @@ void genericCheat(int player, uint8_t** stream, bool skip) } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- CCMD(god) { @@ -140,6 +159,12 @@ CCMD(allmap) } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + CCMD(give) { static const char* type[] = { "ALL","AMMO","ARMOR","HEALTH","INVENTORY","ITEMS","KEYS","WEAPONS",nullptr }; @@ -166,4 +191,251 @@ CCMD(give) Net_WriteByte(DEM_GIVE); Net_WriteByte(found); } -} \ No newline at end of file +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void CompleteLevel(MapRecord* map) +{ + gameaction = ga_completed; + g_nextmap = !currentLevel || !(currentLevel->flags & MI_FORCEEOG)? map : nullptr; + g_nextskill = -1; // This does not change the skill +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void changeMap(int player, uint8_t** stream, bool skip) +{ + int skill = (int8_t)ReadByte(stream); + auto mapname = ReadStringConst(stream); + if (skip) return; + auto map = FindMapByName(mapname); + if (map || *mapname == 0) // mapname = "" signals end of episode + { + gameaction = ga_completed; + g_nextmap = map; + g_nextskill = skill; + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ChangeLevel(MapRecord* map, int skill) +{ + Net_WriteByte(DEM_CHANGEMAP); + Net_WriteByte(skill); + Net_WriteString(map->labelName); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DeferedStartGame(MapRecord* map, int skill) +{ + g_nextmap = map; + g_nextskill = skill; + gameaction = ga_newgame; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static MapRecord* levelwarp_common(FCommandLine& argv, const char *cmdname, const char *t2) +{ + int numparm = g_gameType & (GAMEFLAG_SW | GAMEFLAG_PSEXHUMED) ? 1 : 2; // Handle games with episodic and non-episodic level order. + if (argv.argc() <= numparm) + { + if (numparm == 2) Printf(PRINT_BOLD, "%s : %s episode 'e' and map 'm'\n", cmdname, t2); + else Printf(PRINT_BOLD, "%s : %s map 'm'\n", cmdname, t2); + return nullptr; + } + // Values are one-based. + int e = numparm == 2 ? atoi(argv[1]) : 0; + int m = atoi(numparm == 2 ? argv[2] : argv[1]); + if (e <= 0 || m <= 0) + { + Printf(PRINT_BOLD, "Invalid level! Numbers must be > 0\n"); + return nullptr; + } + auto map = FindMapByLevelNum(levelnum(e - 1, m - 1)); + if (!map) + { + if (numparm == 2) Printf(PRINT_BOLD, "Level E%s L%s not found!\n", argv[1], argv[2]); + else Printf(PRINT_BOLD, "Level %s not found!\n", argv[1]); + return nullptr; + } + return map; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +CCMD(levelwarp) +{ + if (gamestate != GS_LEVEL) + { + Printf("Use the startgame command when not in a game.\n"); + return; + } + +#if 0 + if (/*!players[consoleplayer].settings_controller &&*/ netgame) + { + Printf("Only setting controllers can change the map.\n"); + return; + } +#endif + + auto map = levelwarp_common(argv, "levelwarp", "warp to"); + if (map) + { + ChangeLevel(map, -1); + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +CCMD(startgame) +{ + if (netgame) + { + Printf("Use " TEXTCOLOR_BOLD "levelwarp" TEXTCOLOR_NORMAL " instead. " TEXTCOLOR_BOLD "startgame" + TEXTCOLOR_NORMAL " is for single-player only.\n"); + return; + } + auto map = levelwarp_common(argv, "start game", "start new game at"); + if (map) + { + DeferedStartGame(map, -1); + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +CCMD(changemap) +{ + if (argv.argc() < 2) + { + Printf(PRINT_BOLD, "changemap : warp to the given map, identified by its name.\n"); + return; + } + if (gamestate != GS_LEVEL) + { + Printf("Use the map command when not in a game.\n"); + return; + } + +#if 0 + if (/*!players[consoleplayer].settings_controller &&*/ netgame) + { + Printf("Only setting controllers can change the map.\n"); + return; + } +#endif + + FString mapname = argv[1]; + FString mapfilename = mapname; + DefaultExtension(mapfilename, ".map"); + + auto map = FindMapByName(mapname); + if (map == nullptr) + { + // got a user map + Printf(PRINT_BOLD, "%s: Map not defined.\n", mapname.GetChars()); + return; + } + if (map->flags & MI_USERMAP) + { + // got a user map + Printf(PRINT_BOLD, "%s: Cannot warp to user maps.\n", mapname.GetChars()); + return; + } + ChangeLevel(map, -1); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +CCMD(map) +{ + if (argv.argc() < 2) + { + Printf(PRINT_BOLD, "map : start new game at the given map, identified by its name.\n"); + return; + } + if (netgame) + { + Printf("Use " TEXTCOLOR_BOLD "changemap" TEXTCOLOR_NORMAL " instead. " TEXTCOLOR_BOLD "map" + TEXTCOLOR_NORMAL " is for single-player only.\n"); + return; + } + + FString mapname = argv[1]; + FString mapfilename = mapname; + DefaultExtension(mapfilename, ".map"); + + // Check if the map is already defined. + auto map = FindMapByName(mapname); + if (map == nullptr) + { + // got a user map + if (g_gameType & GAMEFLAG_SHAREWARE) + { + Printf(PRINT_BOLD, "Cannot use user maps in shareware.\n"); + return; + } + map = SetupUserMap(mapfilename, g_gameType & GAMEFLAG_DUKE? "dethtoll.mid" : nullptr); + } + if (map) + { + DeferedStartGame(map, -1); + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +CCMD(restartmap) +{ + if (gamestate != GS_LEVEL || currentLevel == nullptr) + { + Printf("Must be in a game to restart a level.\n"); + return; + } + ChangeLevel(currentLevel, -1); +} diff --git a/source/core/cheats.h b/source/core/cheats.h index 85942b912..bc4245ede 100644 --- a/source/core/cheats.h +++ b/source/core/cheats.h @@ -7,3 +7,4 @@ EXTERN_CVAR(Bool, sv_cheats) void genericCheat(int player, uint8_t** stream, bool skip); +void changeMap(int player, uint8_t** stream, bool skip); diff --git a/source/core/d_net.cpp b/source/core/d_net.cpp index 44b47900b..8c1edbbb5 100644 --- a/source/core/d_net.cpp +++ b/source/core/d_net.cpp @@ -1664,6 +1664,7 @@ bool D_CheckNetGame (void) // First install the global net command handlers Net_SetCommandHandler(DEM_GENERICCHEAT, genericCheat); + Net_SetCommandHandler(DEM_CHANGEMAP, changeMap); for (i = 0; i < MAXNETNODES; i++) { diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index bd648a470..892c95ebd 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -122,6 +122,11 @@ CCMD(togglefollow) cycle_t thinktime, actortime, gameupdatetime, drawtime; gamestate_t gamestate = GS_STARTUP; +gameaction_t gameaction = ga_nothing; +// gameaction state +MapRecord* g_nextmap; +int g_nextskill; + FILE* hashfile; @@ -1182,3 +1187,11 @@ void startmainmenu() FX_StopAllSounds(); } + +void GameInterface::FreeLevelData() +{ + // Make sure that there is no more level to toy around with. + initspritelists(); + numsectors = numwalls = 0; + currentLevel = nullptr; +} diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h index bae8b8f18..1472be452 100644 --- a/source/core/gamecontrol.h +++ b/source/core/gamecontrol.h @@ -19,6 +19,12 @@ extern bool AppActive; extern cycle_t drawtime, actortime, thinktime, gameupdatetime; extern bool r_NoInterpolate; +struct MapRecord; +struct FSaveGameNode; +extern MapRecord* g_nextmap; +extern int g_nextskill; +extern FSaveGameNode* g_savenode; + extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown. extern TMap NameToTileIndex; @@ -50,6 +56,9 @@ void CONFIG_ReadCombatMacros(); int GameMain(); void startmainmenu(); void updatePauseStatus(); +void DeferedStartGame(MapRecord* map, int skill); +void ChangeLevel(MapRecord* map, int skill); +void CompleteLevel(MapRecord* map); struct UserConfig { diff --git a/source/core/gamestate.h b/source/core/gamestate.h index 1911e860e..ad6d742e0 100644 --- a/source/core/gamestate.h +++ b/source/core/gamestate.h @@ -21,4 +21,20 @@ enum gamestate_t : int GS_FORCEWIPEMELT = -4 }; +enum gameaction_t : int +{ + ga_nothing, + ga_startup, // go back to intro after uninitializing the game state + ga_mainmenu, // go back to main menu after uninitializing the game state + ga_newgame, // start a new game + ga_recordgame, // start a new demo recording (later) + ga_loadgame, // load a savegame and resume play. + ga_loadgameplaydemo, // load a savegame and play a demo. + ga_autoloadgame, // load last autosave and resume play. + ga_savegame, // save the game + ga_autosave, // autosave the game (for triggering a save from within the game.) + ga_completed, // Level was exited. + ga_nextlevel // Actually start the next level. +}; extern gamestate_t gamestate; +extern gameaction_t gameaction; diff --git a/source/core/gamestruct.h b/source/core/gamestruct.h index 6c01d2cfd..49fdb5d49 100644 --- a/source/core/gamestruct.h +++ b/source/core/gamestruct.h @@ -23,8 +23,6 @@ struct FNewGameStartup int Episode; int Level; int Skill; - int CustomLevel1; - int CustomLevel2; }; struct FSavegameInfo @@ -56,6 +54,7 @@ struct ReservedSpace }; enum EMenuSounds : int; +struct MapRecord; extern cycle_t drawtime, actortime, thinktime, gameupdatetime; @@ -67,6 +66,7 @@ struct GameInterface virtual void app_init() = 0; virtual void clearlocalinputstate() {} virtual void UpdateScreenSize() {} + virtual void FreeLevelData(); virtual void FreeGameData() {} virtual void PlayHudSound() {} virtual GameStats getStats() { return {}; } @@ -86,7 +86,6 @@ struct GameInterface virtual bool SaveGame(FSaveGameNode*) { return true; } virtual bool LoadGame(FSaveGameNode*) { return true; } virtual void SerializeGameState(FSerializer& arc) {} - virtual bool CleanupForLoad() { return true; } virtual void DrawPlayerSprite(const DVector2& origin, bool onteam) {} virtual void QuitToTitle() {} virtual void SetAmbience(bool on) {} @@ -104,6 +103,9 @@ struct GameInterface virtual int GetPlayerChecksum(int pnum) { return 0x12345678 + pnum; } virtual const char *CheckCheatMode() { return nullptr; } virtual const char* GenericCheat(int player, int cheat) = 0; + virtual void NextLevel(MapRecord* map, int skill) {} + virtual void NewGame(MapRecord* map, int skill) {} + virtual void LevelCompleted(MapRecord* map, int skill) {} virtual FString statFPS() { diff --git a/source/core/mainloop.cpp b/source/core/mainloop.cpp index 19ae1d70f..82a1ad3bd 100644 --- a/source/core/mainloop.cpp +++ b/source/core/mainloop.cpp @@ -83,6 +83,7 @@ #include "palette.h" #include "build.h" #include "g_input.h" +#include "mapinfo.h" CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, r_ticstability, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -125,16 +126,75 @@ static void GameTicker() handleevents(); -#if 0 // Todo: Migrate state changes to here instead of doing them ad-hoc while (gameaction != ga_nothing) { - switch (gameaction) + auto ga = gameaction; + gameaction = ga_nothing; + switch (ga) { + case ga_autoloadgame: + // todo: for now just handle the restart case + g_nextmap = currentLevel; + g_nextskill = -1; + FX_StopAllSounds(); + FX_SetReverb(0); + gi->NextLevel(currentLevel, -1); + break; + + case ga_completed: + FX_StopAllSounds(); + FX_SetReverb(0); + if (g_nextmap == currentLevel) + { + // if the same level is restarted, skip any progression stuff like summary screens or cutscenes. + gi->FreeLevelData(); + gi->NextLevel(currentLevel, g_nextskill); + } + else + gi->LevelCompleted(g_nextmap, g_nextskill); + break; + + case ga_nextlevel: + gi->FreeLevelData(); + gi->NextLevel(currentLevel, g_nextskill); + break; + + case ga_newgame: + FX_StopAllSounds(); + FX_SetReverb(0); + gi->FreeLevelData(); + gi->NewGame(g_nextmap, g_nextskill); + break; + + case ga_startup: + gi->FreeLevelData(); + gamestate = GS_STARTUP; + break; + + case ga_mainmenu: + gi->FreeLevelData(); + startmainmenu(); + break; + + case ga_savegame: + // We only need this for multiplayer saves that need to go through the network. + // gi->SaveGame(); + break; + + case ga_autosave: + M_Autosave(); + break; + + // for later + // case ga_recordgame, // start a new demo recording (later) + // case ga_loadgameplaydemo, // load a savegame and play a demo. + + default: + break; } C_AdjustBottom(); } -#endif // get commands, check consistancy, and build new consistancy check int buf = (gametic / ticdup) % BACKUPTICS; diff --git a/source/core/mapinfo.cpp b/source/core/mapinfo.cpp index 611a2c9d2..eaea5cf0f 100644 --- a/source/core/mapinfo.cpp +++ b/source/core/mapinfo.cpp @@ -35,6 +35,8 @@ #include "mapinfo.h" #include "raze_music.h" +#include "filesystem.h" +#include "printf.h" MapRecord mapList[512]; // Due to how this gets used it needs to be static. EDuke defines 7 episode plus one spare episode with 64 potential levels each and relies on the static array which is freely accessible by scripts. MapRecord *currentLevel; // level that is currently played. (The real level, not what script hacks modfifying the current level index can pretend.) @@ -127,6 +129,13 @@ MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic) return ↦ } } + + if (!fileSystem.FileExists(boardfilename)) + { + Printf(TEXTCOLOR_RED "map: file \"%s\" not found.\n", boardfilename); + return nullptr; + } + auto map = AllocateMap(); map->name = ""; map->SetFileName(boardfilename); diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h index 81a72c40c..f9f1d1b70 100644 --- a/source/core/mapinfo.h +++ b/source/core/mapinfo.h @@ -61,6 +61,7 @@ struct MapRecord } void SetFileName(const char* n) { + if (*n == '/' || *n == '\\') n++; fileName = n; FixPathSeperator(fileName); labelName = ExtractFileBase(n); diff --git a/source/core/menu/menu.cpp b/source/core/menu/menu.cpp index 623775e0c..0e971049f 100644 --- a/source/core/menu/menu.cpp +++ b/source/core/menu/menu.cpp @@ -434,12 +434,10 @@ bool M_SetMenu(FName menu, int param, FName caller) switch (caller.GetIndex()) { case NAME_Episodemenu: - case NAME_HuntMenu: case NAME_TargetMenu: // sent from the episode menu NewGameStartupInfo.Episode = param; NewGameStartupInfo.Level = 0; - NewGameStartupInfo.CustomLevel1 = NewGameStartupInfo.CustomLevel2 = -1; NewGameStartupInfo.Skill = gDefaultSkill; break; @@ -447,26 +445,6 @@ bool M_SetMenu(FName menu, int param, FName caller) NewGameStartupInfo.Skill = param; break; - case NAME_CustomGameMenu: - NewGameStartupInfo.CustomLevel1 = param; - NewGameStartupInfo.CustomLevel2 = -1; - NewGameStartupInfo.Episode = 0; // Set start to E1L1 so that even if the script fails to set the starting level it is set to something valid. - NewGameStartupInfo.Level = 0; - NewGameStartupInfo.Skill = gDefaultSkill; - gi->CustomMenuSelection(param, -1); - break; - - case NAME_CustomSubMenu1: - case NAME_CustomSubMenu2: - case NAME_CustomSubMenu3: - case NAME_CustomSubMenu4: - case NAME_CustomSubMenu5: - case NAME_CustomSubMenu6: - case NAME_CustomSubMenu7: - NewGameStartupInfo.CustomLevel2 = param; - gi->CustomMenuSelection(NewGameStartupInfo.CustomLevel1, param); - break; - case NAME_Skillmenu: NewGameStartupInfo.Skill = param; break; diff --git a/source/core/menu/savegamemanager.cpp b/source/core/menu/savegamemanager.cpp index c554b59db..393794f19 100644 --- a/source/core/menu/savegamemanager.cpp +++ b/source/core/menu/savegamemanager.cpp @@ -53,6 +53,7 @@ #include "serializer.h" #include "findfile.h" #include "inputstate.h" +#include "gamestate.h" FSavegameManager savegameManager; @@ -60,14 +61,12 @@ FSavegameManager savegameManager; void FSavegameManager::LoadGame(FSaveGameNode* node) { inputState.ClearAllInput(); - if (gi->CleanupForLoad()) + gi->FreeLevelData(); + if (OpenSaveGameForRead(node->Filename)) { - if (OpenSaveGameForRead(node->Filename)) + if (gi->LoadGame(node)) { - if (gi->LoadGame(node)) - { - // do something here? - } + // do something here? } } } @@ -576,6 +575,7 @@ static int nextquicksave = -1; void M_Autosave() { + if (disableautosave) return; if (!gi->CanSave()) return; FString description; FString file; @@ -602,8 +602,7 @@ void M_Autosave() CCMD(autosave) { - if (disableautosave) return; - M_Autosave(); + gameaction = ga_autosave; } CCMD(rotatingquicksave) diff --git a/source/exhumed/src/gameloop.cpp b/source/exhumed/src/gameloop.cpp index 16f8a6ea6..2339f833a 100644 --- a/source/exhumed/src/gameloop.cpp +++ b/source/exhumed/src/gameloop.cpp @@ -267,7 +267,8 @@ void GameInterface::Startup() } else { - DoTitle([](bool) { startmainmenu(); }); + if (!userConfig.nologo) DoTitle([](bool) { startmainmenu(); }); + else startmainmenu(); } } diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 469a2d1a2..3f2d38697 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -968,7 +968,7 @@ public: // //--------------------------------------------------------------------------- -void dobonus_d(bool bonusonly, const CompletionFunc& completion) +void dobonus_d(int bonusonly, const CompletionFunc& completion) { JobDesc jobs[20]; int job = 0; @@ -976,7 +976,7 @@ void dobonus_d(bool bonusonly, const CompletionFunc& completion) FX_StopAllSounds(); Mus_Stop(); - if (!bonusonly && numplayers < 2 && ud.eog && ud.from_bonus == 0) + if (bonusonly < 0 && numplayers < 2 && ud.from_bonus == 0) { bonussequence_d(volfromlevelnum(currentLevel->levelNumber), jobs, job); } @@ -985,7 +985,7 @@ void dobonus_d(bool bonusonly, const CompletionFunc& completion) { jobs[job++] = { Create(playerswhenstarted) }; } - else if (!bonusonly && ud.multimode <= 1) + else if (bonusonly <= 0 && ud.multimode <= 1) { jobs[job++] = { Create() }; } @@ -1081,68 +1081,4 @@ void PrintLevelName_d(double alpha) BigText(160, 114, currentLevel->DisplayName(), alpha); } -// Utility for testing the above screens -CCMD(testscreen) -{ - JobDesc jobs[10]; - int job = 0; - C_HideConsole(); - FX_StopAllSounds(); - Mus_Stop(); - - auto gs = gamestate; - auto completion = [=](bool) - { - if (gs == GS_LEVEL || gs == GS_MENUSCREEN) gamestate = gs; - else gamestate = GS_STARTUP; - }; - - - if (argv.argc() > 1) - { - int screen = strtol(argv[1], nullptr, 0); - switch (screen) - { - case 0: - case 1: - case 2: - case 3: - case 4: - bonussequence_d(screen, jobs, job); - RunScreenJob(jobs, job, completion); - break; - - case 5: - e4intro(nullptr); - break; - - case 6: - jobs[job++] = { Create(6) }; - RunScreenJob(jobs, job, completion); - break; - - case 7: - showtwoscreens(nullptr); - break; - - case 8: - doorders(nullptr); - break; - - case 9: - jobs[job++] = { Create() }; - RunScreenJob(jobs, job, completion); - break; - - case 10: - ud.eog = true; - jobs[job++] = { Create() }; - RunScreenJob(jobs, job, completion); - ud.eog = false; - break; - - } - } -} - END_DUKE_NS diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index 9197cae7e..95f546746 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -556,7 +556,7 @@ public: // //--------------------------------------------------------------------------- -void dobonus_r(bool bonusonly, const CompletionFunc& completion) +void dobonus_r(int bonusonly, const CompletionFunc& completion) { JobDesc jobs[20]; int job = 0; @@ -564,7 +564,7 @@ void dobonus_r(bool bonusonly, const CompletionFunc& completion) FX_StopAllSounds(); Mus_Stop(); - if (!bonusonly && !isRRRA() && numplayers < 2 && ud.eog && ud.from_bonus == 0) + if (bonusonly < 0 && !isRRRA() && numplayers < 2 && ud.from_bonus == 0) { int vol = volfromlevelnum(currentLevel->levelNumber); bonussequence_r(vol, jobs, job); @@ -574,7 +574,7 @@ void dobonus_r(bool bonusonly, const CompletionFunc& completion) { jobs[job++] = { Create(playerswhenstarted) }; } - else if (!bonusonly && ud.multimode <= 1) + else if (bonusonly <= 0 && ud.multimode <= 1) { if (isRRRA() && !(currentLevel->flags & MI_USERMAP) && currentLevel->levelNumber < 106) // fixme: The logic here is awful. Shift more control to the map records. { @@ -584,7 +584,7 @@ void dobonus_r(bool bonusonly, const CompletionFunc& completion) mysnprintf(fn, 20, "lvl%d.anm", levnum + 1); static const int framespeed[] = { 20, 20, 7200 }; // wait for one minute on the final frame so that the video doesn't stop before the user notices. jobs[job++] = { PlayVideo(fn, nullptr, framespeed) }; - if (ud.eog && currentLevel->levelNumber > 100) + if (bonusonly < 0 && currentLevel->levelNumber > 100) { jobs[job++] = { Create() }; } diff --git a/source/games/duke/src/actors_r.cpp b/source/games/duke/src/actors_r.cpp index e0d416a66..c13cef900 100644 --- a/source/games/duke/src/actors_r.cpp +++ b/source/games/duke/src/actors_r.cpp @@ -2133,9 +2133,7 @@ static void rrra_specialstats() ps[screenpeek].MamaEnd--; if (ps[screenpeek].MamaEnd == 0) { - ps[screenpeek].gm = MODE_EOL; - ud.eog = 1; - ud.nextLevel = nullptr; + CompleteLevel(nullptr); } } diff --git a/source/games/duke/src/ccmds.cpp b/source/games/duke/src/ccmds.cpp index aee73a047..50640206e 100644 --- a/source/games/duke/src/ccmds.cpp +++ b/source/games/duke/src/ccmds.cpp @@ -37,90 +37,6 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) BEGIN_DUKE_NS -static void dowarp(MapRecord *map) -{ - ud.m_monsters_off = ud.monsters_off = 0; - - ud.m_respawn_items = 0; - ud.m_respawn_inventory = 0; - - ud.multimode = 1; - - if (ps[myconnectindex].gm & MODE_GAME) - { - donewgame(map, ud.m_player_skill); - ps[myconnectindex].gm = MODE_RESTART; - } - else startnewgame(map, ud.m_player_skill); -} - -static int ccmd_levelwarp(CCmdFuncPtr parm) -{ - if (parm->numparms != 2) - return CCMD_SHOWHELP; - int e = atoi(parm->parms[0]); - int m = atoi(parm->parms[1]); - if (e == 0 || m == 0) - { - Printf(TEXTCOLOR_RED "Invalid level!: E%sL%s\n", parm->parms[0], parm->parms[1]); - return CCMD_OK; - } - auto map = FindMapByLevelNum(levelnum(e - 1, m - 1)); - if (!map) - { - Printf(TEXTCOLOR_RED "Level not found!: E%sL%s\n", parm->parms[0], parm->parms[1]); - return CCMD_OK; - } - dowarp(map); - - return CCMD_OK; -} - -static int ccmd_map(CCmdFuncPtr parm) -{ - if (parm->numparms != 1) - { - return CCMD_SHOWHELP; - } - FString mapname = parm->parms[0]; - FString mapfilename = mapname; - DefaultExtension(mapfilename, ".map"); - - if (!fileSystem.FileExists(mapfilename)) - { - Printf(TEXTCOLOR_RED "map: file \"%s\" not found.\n", mapname.GetChars()); - return CCMD_OK; - } - // Check if the map is already defined. - auto map = FindMapByName(mapname); - if (map == nullptr) - { - // got a user map - if (VOLUMEONE) - { - Printf(TEXTCOLOR_RED "Cannot use user maps in shareware.\n"); - return CCMD_OK; - } - if (mapfilename[0] != '/') mapfilename.Insert(0, "/"); - map = SetupUserMap(mapfilename, !isRR() ? "dethtoll.mid" : nullptr); - } - if (numplayers > 1) - { - return CCMD_OK; - } - - dowarp(map); - return CCMD_OK; -} - -static int ccmd_restartmap(CCmdFuncPtr) -{ - if (ps[myconnectindex].gm & MODE_GAME && ud.multimode == 1) - ps[myconnectindex].gm = MODE_RESTART; - - return CCMD_OK; -} - int getlabelvalue(const char* text); static int ccmd_spawn(CCmdFuncPtr parm) @@ -131,10 +47,12 @@ static int ccmd_spawn(CCmdFuncPtr parm) int ang = 0; int set = 0, idx; - if (numplayers > 1 || !(ps[myconnectindex].gm & MODE_GAME)) { +#if 0 // fixme - route through the network and this limitation becomes irrelevant + if (netgame || numplayers > 1 || !(ps[myconnectindex].gm & MODE_GAME)) { Printf("spawn: Can't spawn sprites in multiplayer games or demos\n"); return CCMD_OK; } +#endif switch (parm->numparms) { case 7: // x,y,z @@ -252,9 +170,6 @@ static int osdcmd_show_weapon(CCmdFuncPtr parm) int registerosdcommands(void) { - C_RegisterFunction("map","map : warp to the given map, identified by its name", ccmd_map); - C_RegisterFunction("levelwarp","levelwarp : warp to episode 'e' and map 'm'", ccmd_levelwarp); - C_RegisterFunction("restartmap", "restartmap: restarts the current map", ccmd_restartmap); C_RegisterFunction("spawn","spawn [palnum] [cstat] [ang] [x y z]: spawns a sprite with the given properties",ccmd_spawn); C_RegisterFunction("warptocoords","warptocoords [x] [y] [z] [ang] (optional) [horiz] (optional): warps the player to the specified coordinates",osdcmd_warptocoords); C_RegisterFunction("third_person_view", "Switch to third person view", osdcmd_third_person_view); diff --git a/source/games/duke/src/cheats.cpp b/source/games/duke/src/cheats.cpp index 12dfd0bbd..7c31f80e1 100644 --- a/source/games/duke/src/cheats.cpp +++ b/source/games/duke/src/cheats.cpp @@ -295,21 +295,16 @@ static bool cheatLevel(cheatseq_t *s) auto map = FindMapByLevelNum(levelnum(volnume, levnume)); if (map) { - ud.nextLevel = map; - FX_StopAllSounds(); - FX_SetReverb(0); - ps[myconnectindex].gm |= MODE_RESTART; + ChangeLevel(map, -1); } return true; } static bool cheatSkill(cheatseq_t *s) { - lastlevel = 0; - ud.m_player_skill = ud.player_skill = s->Args[0] - '1'; - ps[myconnectindex].gm |= MODE_RESTART; - FX_StopAllSounds(); - FX_SetReverb(0); + ChangeLevel(currentLevel, s->Args[0] - '1'); + //FX_StopAllSounds(); + //FX_SetReverb(0); return true; } diff --git a/source/games/duke/src/constants.h b/source/games/duke/src/constants.h index 7315a21f4..b0c8bc45e 100644 --- a/source/games/duke/src/constants.h +++ b/source/games/duke/src/constants.h @@ -416,10 +416,8 @@ enum EFlamethrowerState }; enum gamemode_t { - MODE_DEMO = 0x00000002, MODE_GAME = 0x00000004, MODE_EOL = 0x00000008, - MODE_RESTART = 0x00000020, }; diff --git a/source/games/duke/src/d_menu.cpp b/source/games/duke/src/d_menu.cpp index 535d82eed..870c37a55 100644 --- a/source/games/duke/src/d_menu.cpp +++ b/source/games/duke/src/d_menu.cpp @@ -273,7 +273,6 @@ void GameInterface::StartGame(FNewGameStartup& gs) static const short sounds_r[] = { 427, 428, 196, 195, 197 }; if (gs.Skill >=0 && gs.Skill <= 5) skillsound = isRR()? sounds_r[gs.Skill] : sounds_d[gs.Skill]; - ud.m_player_skill = gs.Skill + 1; if (menu_sounds && skillsound >= 0 && SoundEnabled() && !netgame) { S_PlaySound(skillsound, CHAN_AUTO, CHANF_UI); @@ -286,16 +285,10 @@ void GameInterface::StartGame(FNewGameStartup& gs) } Net_ClearFifo(); } - ud.m_respawn_monsters = (gs.Skill == 3); - - ud.m_monsters_off = ud.monsters_off = 0; - ud.m_respawn_items = 0; - ud.m_respawn_inventory = 0; - ud.multimode = 1; auto map = FindMapByLevelNum(levelnum(gs.Episode, gs.Level)); if (map) { - startnewgame(map, ud.m_player_skill); + DeferedStartGame(map, gs.Skill); } } diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h index 87061c2ba..de249f658 100644 --- a/source/games/duke/src/duke3d.h +++ b/source/games/duke/src/duke3d.h @@ -58,7 +58,10 @@ struct GameInterface : public ::GameInterface void Render() override; void Ticker() override; const char* GenericCheat(int player, int cheat) override; - const char* CheckCheatMode(); + const char* CheckCheatMode() override; + void NextLevel(MapRecord* map, int skill) override; + void NewGame(MapRecord* map, int skill) override; + void LevelCompleted(MapRecord* map, int skill) override; }; diff --git a/source/games/duke/src/funct.h b/source/games/duke/src/funct.h index 2d78459dc..da7691791 100644 --- a/source/games/duke/src/funct.h +++ b/source/games/duke/src/funct.h @@ -208,8 +208,8 @@ void drawstatusbar_r(int snum); void drawoverheadmap(int cposx, int cposy, int czoom, int cang); void cameratext(int i); void dobonus(int bonusonly, const CompletionFunc& completion); -void dobonus_d(bool bonusonly, const CompletionFunc& completion); -void dobonus_r(bool bonusonly, const CompletionFunc& completion); +void dobonus_d(int bonusonly, const CompletionFunc& completion); +void dobonus_r(int bonusonly, const CompletionFunc& completion); void drawoverlays(double smoothratio); void drawbackground(void); @@ -221,7 +221,7 @@ bool setnextmap(bool checksecretexit); void prelevel_d(int g); void prelevel_r(int g); void e4intro(const CompletionFunc& completion); -void exitlevel(); +void exitlevel(MapRecord *next); int enterlevel(MapRecord* mi, int gm); void donewgame(MapRecord* map, int sk); void startnewgame(MapRecord* map, int skill); diff --git a/source/games/duke/src/game_misc.cpp b/source/games/duke/src/game_misc.cpp index 600d89289..f9102a946 100644 --- a/source/games/duke/src/game_misc.cpp +++ b/source/games/duke/src/game_misc.cpp @@ -41,6 +41,7 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) #include "prediction.h" #include "sbar.h" #include "glbackend/glbackend.h" +#include "gamestate.h" BEGIN_DUKE_NS @@ -84,7 +85,7 @@ template void runbonus(func completion) { // MP scoreboard - if (playerswhenstarted > 1 && ps[myconnectindex].gm & MODE_GAME && !ud.coop) + if (playerswhenstarted > 1 && !ud.coop) { dobonus(1, completion); } @@ -127,7 +128,7 @@ void GameInterface::ExitFromMenu() void FTA(int q, struct player_struct* p) { - if (q < 0 || !(p->gm & MODE_GAME)) + if (q < 0 || gamestate != GS_LEVEL) return; if (p->ftq != q || (ud.levelclock - p->ftt > TICRATE && q != QUOTE_DEAD)) diff --git a/source/games/duke/src/gameexec.cpp b/source/games/duke/src/gameexec.cpp index 8ec612cfa..048a87efc 100644 --- a/source/games/duke/src/gameexec.cpp +++ b/source/games/duke/src/gameexec.cpp @@ -36,6 +36,7 @@ source as it is released. #include "duke3d.h" #include "gamevar.h" #include "mapinfo.h" +#include "gamestate.h" BEGIN_DUKE_NS @@ -692,7 +693,7 @@ int ParseState::parse(void) insptr++; ps[g_p].timebeforeexit = *insptr; ps[g_p].customexitsound = -1; - ud.eog = 1; + ChangeLevel(nullptr, -1); insptr++; break; @@ -975,18 +976,9 @@ int ParseState::parse(void) case concmd_resetplayer: insptr++; -//AddLog("resetplayer"); if(ud.multimode < 2) { -#if 0 - if( lastsavedpos >= 0 && ud.recstat != 2 ) - { - KB_ClearKeyDown(sc_Space); - cmenu(15000); - } - else -#endif - ps[g_p].gm = MODE_RESTART; + gameaction = ga_autoloadgame; killit_flag = 2; } else @@ -1737,8 +1729,7 @@ CCMD(endofgame) { ps[0].timebeforeexit = 120; ps[0].customexitsound = -1; - ud.eog = 1; - + ChangeLevel(nullptr, -1); } END_DUKE_NS diff --git a/source/games/duke/src/gameloop.cpp b/source/games/duke/src/gameloop.cpp index 7eefb0360..808259c13 100644 --- a/source/games/duke/src/gameloop.cpp +++ b/source/games/duke/src/gameloop.cpp @@ -103,11 +103,6 @@ void GameInterface::Ticker() } else r_NoInterpolate = true; - - if (ps[myconnectindex].gm & (MODE_EOL | MODE_RESTART)) - { - exitlevel(); - } } //--------------------------------------------------------------------------- @@ -138,7 +133,8 @@ void GameInterface::Startup() } else { - fi.ShowLogo([](bool) { startmainmenu(); }); + if (!userConfig.nologo) fi.ShowLogo([](bool) { startmainmenu(); }); + else startmainmenu(); } } @@ -160,6 +156,44 @@ void GameInterface::Render() drawtime.Unclock(); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void GameInterface::NextLevel(MapRecord* map, int skill) +{ + ud.m_player_skill = skill + 1; + int res = enterlevel(map, 0); + if (!res) gameaction = ga_startup; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void GameInterface::NewGame(MapRecord* map, int skill) +{ + // Hmm... What about the other players? + ps[0].last_extra = max_player_health; + resetweapons(0); + resetinventory(0); + NextLevel(map, skill); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void GameInterface::LevelCompleted(MapRecord* map, int skill) +{ + exitlevel(map); +} END_DUKE_NS diff --git a/source/games/duke/src/premap.cpp b/source/games/duke/src/premap.cpp index 3000d1868..bde70e2d7 100644 --- a/source/games/duke/src/premap.cpp +++ b/source/games/duke/src/premap.cpp @@ -420,7 +420,6 @@ void resetprestat(int snum,int g) randomseed = 17L; paused = 0; ud.camerasprite =-1; - ud.eog = 0; tempwallptr = 0; camsprite =-1; earthquaketime = 0; @@ -435,12 +434,7 @@ void resetprestat(int snum,int g) numinterpolations = 0; //startofdynamicinterpolations = 0; - if( ( (g&MODE_EOL) != MODE_EOL && numplayers < 2) || (ud.coop != 1 && numplayers > 1) ) - { - resetweapons(snum); - resetinventory(snum); - } - else if(p->curr_weapon == HANDREMOTE_WEAPON) + if(p->curr_weapon == HANDREMOTE_WEAPON) { p->ammo_amount[HANDBOMB_WEAPON]++; p->curr_weapon = HANDBOMB_WEAPON; @@ -581,7 +575,7 @@ void resetpspritevars(int g) which_palookup = 9; j = connecthead; - i = headspritestat[10]; // 10 == players... + i = headspritestat[STAT_PLAYER]; while (i >= 0) { nexti = nextspritestat[i]; @@ -613,7 +607,7 @@ void resetpspritevars(int g) s->xoffset = 0; s->clipdist = 64; - if ((g & MODE_EOL) != MODE_EOL || ps[j].last_extra == 0) + if (ps[j].last_extra == 0) { ps[j].last_extra = max_player_health; s->extra = max_player_health; @@ -774,7 +768,7 @@ void donewgame(MapRecord* map, int sk) auto p = &ps[0]; show_shareware = 26 * 34; - ud.nextLevel = map; + //ud.nextLevel = map; ud.player_skill = sk; ud.secretlevel = 0; ud.from_bonus = 0; @@ -782,7 +776,6 @@ void donewgame(MapRecord* map, int sk) ud.last_level = -1; p->zoom = 768; - p->gm = 0; M_ClearMenus(); ResetGameVars(); @@ -950,9 +943,6 @@ int enterlevel(MapRecord *mi, int gamemode) ud.coop = ud.m_coop; ud.ffire = ud.m_ffire; - if ((gamemode & MODE_DEMO) == 0 && ud.recstat == 2) - ud.recstat = 0; - OnEvent(EVENT_ENTERLEVEL); // Stop all sounds @@ -970,7 +960,7 @@ int enterlevel(MapRecord *mi, int gamemode) if (res != 0) return res; // Try this first so that it can disable the CD player if no tracks are found. - if (isRR() && !(gamemode & MODE_DEMO)) + if (isRR()) S_PlayRRMusic(); if (ud.recstat != 2) @@ -978,17 +968,6 @@ int enterlevel(MapRecord *mi, int gamemode) S_PlayLevelMusic(mi); } - if (gamemode & (MODE_GAME|MODE_EOL)) - { - ps[myconnectindex].gm = MODE_GAME; - } - else if (gamemode & MODE_RESTART) - { - if (ud.recstat == 2) - ps[myconnectindex].gm = MODE_DEMO; - else ps[myconnectindex].gm = MODE_GAME; - } - if (VOLUMEONE && mi->levelNumber == 0 && ud.recstat != 2) FTA(QUOTE_F1HELP, &ps[myconnectindex]); for (int i = connecthead; i >= 0; i = connectpoint2[i]) @@ -1027,11 +1006,17 @@ int enterlevel(MapRecord *mi, int gamemode) void startnewgame(MapRecord* map, int skill) { + ud.m_player_skill = skill; + ud.m_respawn_monsters = (skill == 4); + ud.m_monsters_off = ud.monsters_off = 0; + ud.m_respawn_items = 0; + ud.m_respawn_inventory = 0; + ud.multimode = 1; + newgame(map, skill, [=](bool) { - if (enterlevel(map, MODE_GAME)) + if (enterlevel(map, 0)) { - ps[myconnectindex].gm = 0; startmainmenu(); } else @@ -1077,16 +1062,11 @@ bool setnextmap(bool checksecretexit) map = FindNextMap(currentLevel); } - for (int i = connecthead; i >= 0; i = connectpoint2[i]) - ps[i].gm = MODE_EOL; - if (map) { ud.from_bonus = from_bonus; - ud.nextLevel = map; - return true; } - ud.eog = true; + CompleteLevel(map); return false; } @@ -1096,61 +1076,42 @@ bool setnextmap(bool checksecretexit) // //--------------------------------------------------------------------------- -int exitlevelend() +void exitlevel(MapRecord *nextlevel) { - if (numplayers > 1) - ps[myconnectindex].gm = MODE_GAME; - - int res = enterlevel(ud.nextLevel, ps[myconnectindex].gm); - ud.nextLevel = nullptr; - return res; -} - -void exitlevel(void) -{ - bool endofgame = ud.eog || (currentLevel->flags & MI_FORCEEOG) || ud.nextLevel == nullptr; + bool endofgame = nextlevel == nullptr; STAT_Update(endofgame); setpal(&ps[myconnectindex]); - if (ps[myconnectindex].gm & MODE_RESTART) - { - // If no level was set, restart the current one. - if (!ud.nextLevel) ud.nextLevel = currentLevel; - } + dobonus(endofgame? -1 : 0, [=](bool) + { - if (ps[myconnectindex].gm & MODE_EOL) - { - dobonus(0, [=](bool) + // Clear potentially loaded per-map ART only after the bonus screens. + artClearMapArt(); + gamestate = GS_LEVEL; + if (endofgame) { - - // Clear potentially loaded per-map ART only after the bonus screens. - artClearMapArt(); - gamestate = GS_LEVEL; - if (endofgame) + if (ud.multimode < 2) { - ud.eog = 0; - if (ud.multimode < 2) + if (!VOLUMEALL) + doorders([](bool) { gameaction = ga_startup; }); + else gameaction = ga_startup; + return; + } + else + { + auto nextlevel = FindMapByLevelNum(0); + if (!nextlevel) { - ps[myconnectindex].gm = 0; - if (!VOLUMEALL) - doorders([](bool) { gamestate = GS_STARTUP; }); - else gamestate = GS_STARTUP; + gameaction = ga_startup; return; } - else - { - ud.nextLevel = FindMapByLevelNum(0); - if (!ud.nextLevel || exitlevelend()) - gamestate = GS_STARTUP; - } + else gameaction = ga_nextlevel; } - else if (exitlevelend()) - gamestate = GS_STARTUP; + } + else + gameaction = ga_nextlevel; - }); - } - else if (exitlevelend()) - gamestate = GS_STARTUP; + }); } diff --git a/source/games/duke/src/savegame.cpp b/source/games/duke/src/savegame.cpp index f55dc8f95..990fa4c45 100644 --- a/source/games/duke/src/savegame.cpp +++ b/source/games/duke/src/savegame.cpp @@ -207,7 +207,6 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, player_struct& w, ("last_full_weapon", w.last_full_weapon) ("footprintshade", w.footprintshade) ("boot_amount", w.boot_amount) - ("gm", w.gm) ("on_warping_sector", w.on_warping_sector) ("footprintcount", w.footprintcount) ("hbomb_on", w.hbomb_on) @@ -400,7 +399,6 @@ void GameInterface::SerializeGameState(FSerializer& arc) //("auto_run", ud.auto_run) ("monsters_off", ud.monsters_off) ("last_level", ud.last_level) - ("eog", ud.eog) ("coop", ud.coop) ("marker", ud.marker) ("ffire", ud.ffire) @@ -488,7 +486,6 @@ void GameInterface::SerializeGameState(FSerializer& arc) if (arc.isReading()) { screenpeek = myconnectindex; - ps[myconnectindex].gm = MODE_GAME; gamestate = GS_LEVEL; ud.recstat = 0; diff --git a/source/games/duke/src/sounds.cpp b/source/games/duke/src/sounds.cpp index 444ebb8ac..405678800 100644 --- a/source/games/duke/src/sounds.cpp +++ b/source/games/duke/src/sounds.cpp @@ -42,6 +42,7 @@ source as it is released. #include "raze_music.h" #include "mapinfo.h" #include "raze_sound.h" +#include "gamestate.h" BEGIN_DUKE_NS @@ -324,8 +325,7 @@ void GameInterface::UpdateSounds(void) vec3_t* c; int32_t ca, cs; - auto& gm = ps[myconnectindex].gm; - if (isRR() && !Mus_IsPlaying() && (gm && gm & MODE_GAME)) + if (isRR() && !Mus_IsPlaying() && !paused && gamestate == GS_LEVEL) S_PlayRRMusic(); S_GetCamera(&c, &ca, &cs); diff --git a/source/games/duke/src/types.h b/source/games/duke/src/types.h index 0e03228b3..d415cfd3f 100644 --- a/source/games/duke/src/types.h +++ b/source/games/duke/src/types.h @@ -52,7 +52,7 @@ struct TileInfo struct user_defs { int levelclock; - unsigned char god, cashman, eog; + unsigned char god, cashman; unsigned char show_help, scrollmode, clipping; char user_name[MAXPLAYERS][32]; unsigned char showweapons; @@ -76,7 +76,7 @@ struct user_defs int m_respawn_items, m_respawn_monsters, m_respawn_inventory, m_recstat, m_monsters_off, detail; int m_ffire, ffire, m_player_skill, multimode; int player_skill, marker; - MapRecord* nextLevel; + //MapRecord* nextLevel; }; @@ -156,7 +156,6 @@ struct player_struct short holoduke_on, pycount, frag_ps; short transporter_hold, last_full_weapon, footprintshade, boot_amount; - unsigned char gm; unsigned char on_warping_sector, footprintcount; unsigned char hbomb_on, jumping_toggle, rapid_fire_hold, on_ground; char name[32]; diff --git a/source/sw/src/d_menu.cpp b/source/sw/src/d_menu.cpp index 20d3df284..c626821d8 100644 --- a/source/sw/src/d_menu.cpp +++ b/source/sw/src/d_menu.cpp @@ -205,16 +205,14 @@ void GameInterface::StartGame(FNewGameStartup& gs) ready2send = 0; + MapRecord* map; if (gs.Episode >= 1) - NextLevel = FindMapByLevelNum(5); + map = FindMapByLevelNum(5); else - NextLevel = FindMapByLevelNum(1); + map = FindMapByLevelNum(1); - if (!NextLevel) return; - ExitLevel = TRUE; - NewGame = TRUE; + if (!map) return; CameraTestMode = FALSE; - Skill = gs.Skill; StopFX(); //InitNewGame(); @@ -238,6 +236,7 @@ void GameInterface::StartGame(FNewGameStartup& gs) } Net_ClearFifo(); } + DeferedStartGame(map, gs.Skill); } FSavegameInfo GameInterface::GetSaveSig() diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index c8c40ea79..5441c4163 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -280,13 +280,6 @@ void GameInterface::DrawBackground(void) MNU_DrawString(160, 170, "Lo Wang is waiting for other players...", 1, 16, 0); MNU_DrawString(160, 180, "They are afraid!", 1, 16, 0); } - // hack alert. This needs to go away. - if (SavegameLoaded || NextLevel) - { - TerminateLevel(); - ExitLevel = false; - gamestate = GS_LEVEL; - } } //--------------------------------------------------------------------------- @@ -663,7 +656,7 @@ void GameInterface::Ticker(void) StartAmbientSound(); ExitLevel = false; } - else if (NextLevel) + else if (ShadowWarrior::NextLevel) { InitLevel(); InitRunLevel(); @@ -731,7 +724,7 @@ void GameInterface::ErrorCleanup() { // Make sure we do not leave the game in an unstable state TerminateLevel(); - NextLevel = nullptr; + ShadowWarrior::NextLevel = nullptr; SavegameLoaded = false; ExitLevel = false; FinishAnim = 0; @@ -847,4 +840,10 @@ void GameInterface::FreeGameData() TerminateLevel(); } +void GameInterface::FreeLevelData() +{ + TerminateLevel(); + ::GameInterface::FreeLevelData(); +} + END_SW_NS diff --git a/source/sw/src/game.h b/source/sw/src/game.h index 0f9d99f90..8e9f4763f 100644 --- a/source/sw/src/game.h +++ b/source/sw/src/game.h @@ -2203,6 +2203,7 @@ struct GameInterface : ::GameInterface const char* Name() override { return "ShadowWarrior"; } void app_init() override; void FreeGameData() override; + void FreeLevelData() override; bool GenerateSavePic() override; void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) override; void MenuOpened() override; @@ -2212,7 +2213,6 @@ struct GameInterface : ::GameInterface void StartGame(FNewGameStartup& gs) override; FSavegameInfo GetSaveSig() override; void DrawMenuCaption(const DVector2& origin, const char* text) override; - bool CleanupForLoad() override; bool LoadGame(FSaveGameNode* sv) override; bool SaveGame(FSaveGameNode* sv) override; void SetAmbience(bool on) override { if (on) StartAmbientSound(); else StopAmbientSound(); } diff --git a/source/sw/src/save.cpp b/source/sw/src/save.cpp index 45929667f..4b903ef79 100644 --- a/source/sw/src/save.cpp +++ b/source/sw/src/save.cpp @@ -650,13 +650,6 @@ bool GameInterface::SaveGame(FSaveGameNode *sv) extern SWBOOL SavegameLoaded; - bool GameInterface::CleanupForLoad() - { - TerminateLevel(); - StopFX(); - return true; - } - bool GameInterface::LoadGame(FSaveGameNode* sv) { MFILE_READ fil; @@ -1089,7 +1082,7 @@ bool GameInterface::LoadGame(FSaveGameNode* sv) } // this is not a new game - NewGame = FALSE; + ShadowWarrior::NewGame = FALSE; DoPlayerDivePalette(Player+myconnectindex);