From 6d743ce92140ce4ea25c7082f81afba0a6b594cb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Apr 2021 00:51:28 +0200 Subject: [PATCH] - most of the summary screen is working --- source/core/gamecontrol.cpp | 1 + source/core/mapinfo.cpp | 22 +++ source/core/mapinfo.h | 10 +- source/core/parsefuncs.h | 4 + source/core/screenjob.cpp | 169 ++++++++++++++++-- source/core/screenjob.h | 8 +- source/games/duke/src/2d_d.cpp | 55 ------ source/games/duke/src/2d_r.cpp | 114 ------------ source/games/duke/src/dispatch.cpp | 4 - source/games/duke/src/duke3d.h | 1 - source/games/duke/src/funct.h | 2 - source/games/duke/src/game_misc.cpp | 34 ++-- source/games/duke/src/gameexec.cpp | 4 +- source/games/duke/src/premap.cpp | 52 ++++-- wadsrc/static/filter/duke/engine/engine.def | 6 + .../static/filter/redneck/engine/engine.def | 3 +- wadsrc/static/zscript/games/duke/dukegame.zs | 1 + .../static/zscript/games/duke/ui/cutscenes.zs | 12 +- .../static/zscript/games/duke/ui/screens.zs | 31 ++-- wadsrc/static/zscript/razebase.zs | 5 +- wadsrc/static/zscript/screenjob.zs | 4 - 21 files changed, 266 insertions(+), 276 deletions(-) diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 95930737e..19c09124d 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -1498,6 +1498,7 @@ DEFINE_FIELD_X(MapRecord, MapRecord, music) DEFINE_FIELD_X(MapRecord, MapRecord, cdSongId) DEFINE_FIELD_X(MapRecord, MapRecord, flags) DEFINE_FIELD_X(MapRecord, MapRecord, levelNumber) +DEFINE_FIELD_X(MapRecord, MapRecord, cluster) DEFINE_FIELD_X(MapRecord, MapRecord, nextLevel) DEFINE_FIELD_X(MapRecord, MapRecord, nextSecret) //native readonly String messages[MAX_MESSAGES]; diff --git a/source/core/mapinfo.cpp b/source/core/mapinfo.cpp index 3f23bca6c..412900dca 100644 --- a/source/core/mapinfo.cpp +++ b/source/core/mapinfo.cpp @@ -93,6 +93,28 @@ MapRecord *FindMapByLevelNum(int num) return nullptr; } +// return a map whose cluster and map number matches. +// if there's only one map with the given level number return that. +MapRecord* FindMapByClusterAndLevelNum(int cluster, int num) +{ + MapRecord* mr = nullptr; + int mapfound = 0; + for (auto& map : mapList) + { + if (map.levelNumber == num) + { + if (map.cluster == cluster) return ↦ + else + { + mr = ↦ + mapfound++; + } + } + } + if (mapfound == 1) return mr; + return nullptr; +} + MapRecord *FindNextMap(MapRecord *thismap) { if (thismap->nextLevel != -1) return FindMapByLevelNum(thismap->nextLevel); diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h index c8b5c0367..951b58a5e 100644 --- a/source/core/mapinfo.h +++ b/source/core/mapinfo.h @@ -44,13 +44,8 @@ enum { MAX_MESSAGES = 32 }; -// Cutscene rules for maps are as follows: -// * when an episode is started, the episode intro will play, if none is defined, the map's intro will play. -// * when an episde is ended, the episode outro will play after the summary screen. -// * when a map ends, its own outro scene will play before the summary screen, if none is defined, use the default map outro handler. -// * when a new map starts after the summary screen, its own intro scene will play, if none is defined, use the default map intro handler. -// * setting any of these fields to 'none' will override any default and play nothing, even if a default is set. class DObject; +struct MapRecord; struct CutsceneDef { @@ -60,6 +55,7 @@ struct CutsceneDef int framespersec = 0; // only relevant for ANM. void Create(DObject* runner); + bool Create(DObject* runner, MapRecord* map); }; struct GlobalCutscenes @@ -67,6 +63,7 @@ struct GlobalCutscenes CutsceneDef Intro; CutsceneDef DefaultMapIntro; CutsceneDef DefaultMapOutro; + CutsceneDef SharewareEnd; FString MPSummaryScreen; FString SummaryScreen; }; @@ -159,6 +156,7 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack = fals MapRecord *FindMapByName(const char *nm); MapRecord *FindMapByLevelNum(int num); +MapRecord* FindMapByClusterAndLevelNum(int clst, int num); MapRecord *FindNextMap(MapRecord *thismap); MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic = nullptr); MapRecord* AllocateMap(); diff --git a/source/core/parsefuncs.h b/source/core/parsefuncs.h index 4e6dbc20c..e5a1031bd 100644 --- a/source/core/parsefuncs.h +++ b/source/core/parsefuncs.h @@ -96,6 +96,10 @@ void parseDefineCutscene(FScanner& sc, FScriptPosition& pos) { parseCutscene(sc, globalCutscenes.DefaultMapOutro); } + else if (sc.Compare("sharewareend")) // sets screens to be shown after the shareware version ends. + { + parseCutscene(sc, globalCutscenes.SharewareEnd); + } else if (sc.Compare({ "episode", "volume", "cluster" })) { FScanner::SavedPos eblockend; diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index ec09ab970..339d945db 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -62,6 +62,7 @@ static PType* maprecordtype; static PType* summaryinfotype; static CompletionFunc completion; static int ticks; +static SummaryInfo summaryinfo; //============================================================================= // @@ -133,6 +134,7 @@ void CallCreateFunction(const char* qname, DObject* runner) void CallCreateMapFunction(const char* qname, DObject* runner, MapRecord* map) { auto func = LookupFunction(qname); + if (func->Proto->ArgumentTypes.Size() == 1) return CallCreateFunction(qname, runner); // accept functions without map parameter as well here. if (func->Proto->ArgumentTypes.Size() != 2) I_Error("Bad map-cutscene function %s. Must receive precisely two arguments.", qname); if (func->Proto->ArgumentTypes[0] != runnerclasstype && func->Proto->ArgumentTypes[1] != maprecordtype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner and MapRecord reference.", qname); @@ -152,7 +154,8 @@ void CallCreateSummaryFunction(const char* qname, DObject* runner, MapRecord* ma if (func->Proto->ArgumentTypes.Size() != 3) I_Error("Bad map-cutscene function %s. Must receive precisely three arguments.", qname); if (func->Proto->ArgumentTypes[0] != runnerclasstype && func->Proto->ArgumentTypes[1] != maprecordtype && func->Proto->ArgumentTypes[2] != summaryinfotype) I_Error("Bad cutscene function %s. Must receive ScreenJobRunner, MapRecord and SummaryInfo reference.", qname); - VMValue val[3] = { runner, map, info }; + summaryinfo = *info; // must be copied to a persistent location. + VMValue val[3] = { runner, map, &summaryinfo }; VMCall(func, val, 3, nullptr, 0); } @@ -209,27 +212,28 @@ void CutsceneDef::Create(DObject* runner) // //============================================================================= -bool StartCutscene(CutsceneDef& cs, int flags, CompletionFunc completion_) +bool CutsceneDef::Create(DObject* runner, MapRecord* map) { - if (cs.function.CompareNoCase("none") != 0) + if (function.CompareNoCase("none") == 0) + return true; // play nothing but return as being validated + if (function.IsNotEmpty()) { - completion = completion_; - runner = CreateRunner(); - GC::WriteBarrier(runner); - cs.Create(runner); - gameaction = (flags & SJ_BLOCKUI) ? ga_intro : ga_intermission; + CallCreateMapFunction(function, runner, map); + return true; + } + else if (video.IsNotEmpty()) + { + AddGenericVideo(runner, video, sound, framespersec); return true; } return false; } -bool StartCutscene(const char* s, int flags, CompletionFunc completion) -{ - CutsceneDef def; - def.function = s; - return StartCutscene(def, 0, completion); -} - +//============================================================================= +// +// +// +//============================================================================= void DeleteScreenJob() { @@ -245,6 +249,12 @@ void EndScreenJob() } +//============================================================================= +// +// +// +//============================================================================= + bool ScreenJobResponder(event_t* ev) { if (ev->type == EV_KeyDown) @@ -272,6 +282,12 @@ bool ScreenJobResponder(event_t* ev) return false; } +//============================================================================= +// +// +// +//============================================================================= + bool ScreenJobTick() { ticks++; @@ -289,12 +305,19 @@ bool ScreenJobTick() return false; } +//============================================================================= +// +// +// +//============================================================================= + void ScreenJobDraw() { double smoothratio = I_GetTimeFrac(); if (runner) { + twod->ClearScreen(); IFVIRTUALPTRNAME(runner, NAME_ScreenJobRunner, RunFrame) { VMValue parm[] = { runner, smoothratio }; @@ -303,6 +326,47 @@ void ScreenJobDraw() } } +//============================================================================= +// +// +// +//============================================================================= + +bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion_) +{ + if (cs.function.CompareNoCase("none") != 0) + { + completion = completion_; + runner = CreateRunner(); + GC::WriteBarrier(runner); + try + { + cs.Create(runner); + } + catch (...) + { + runner->Destroy(); + runner = nullptr; + throw; + } + gameaction = (flags & SJ_BLOCKUI) ? ga_intro : ga_intermission; + return true; + } + return false; +} + +bool StartCutscene(const char* s, int flags, const CompletionFunc& completion) +{ + CutsceneDef def; + def.function = s; + return StartCutscene(def, 0, completion); +} + +//============================================================================= +// +// +// +//============================================================================= void PlayLogos(gameaction_t complete_ga, gameaction_t def_ga, bool stopmusic) { @@ -318,6 +382,74 @@ void PlayLogos(gameaction_t complete_ga, gameaction_t def_ga, bool stopmusic) } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ShowScoreboard(int numplayers, const CompletionFunc& completion_) +{ + completion = completion_; + runner = CreateRunner(); + GC::WriteBarrier(runner); + + const char* qname = globalCutscenes.MPSummaryScreen; + auto func = LookupFunction(qname); + if (func->Proto->ArgumentTypes.Size() != 2) I_Error("Bad map-cutscene function %s. Must receive precisely two arguments.", qname); + if (func->Proto->ArgumentTypes[0] != runnerclasstype && func->Proto->ArgumentTypes[1] != TypeSInt32) + I_Error("Bad cutscene function %s. Must receive ScreenJobRunner reference and integer.", qname); + VMValue val[2] = { runner, numplayers }; + VMCall(func, val, 2, nullptr, 0); + + gameaction = ga_intermission; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, CompletionFunc completion_) +{ + completion = completion_; + runner = CreateRunner(); + GC::WriteBarrier(runner); + + // outro: first check the map's own outro. + // if that is empty, check the cluster's outro + // if that also fails, check the default outro + + try + { + if (!fromMap->outro.Create(runner, fromMap)) + { + auto& cluster = volumeList[fromMap->cluster - 1]; + if ((toMap == nullptr || toMap->cluster != fromMap->cluster) && !cluster.outro.Create(runner, fromMap)) + globalCutscenes.DefaultMapOutro.Create(runner, fromMap); + } + + CallCreateSummaryFunction(globalCutscenes.SummaryScreen, runner, fromMap, info); + + if (toMap) + { + if (!toMap->intro.Create(runner, fromMap)) + globalCutscenes.DefaultMapIntro.Create(runner, fromMap); + } + else if (isShareware()) + { + globalCutscenes.SharewareEnd.Create(runner); + } + gameaction = ga_intermission; + } + catch (...) + { + runner->Destroy(); + runner = nullptr; + throw; + } +} CCMD(testcutscene) { @@ -330,16 +462,19 @@ CCMD(testcutscene) { CutsceneDef def; def.function = argv[1]; - if (StartCutscene(def, 0, [](bool) { })) + if (StartCutscene(def, 0, [](bool) {})) { C_HideConsole(); } } catch (const CRecoverableError& err) { - Printf("Unable to play cutscene\n"); + Printf(TEXTCOLOR_RED "Unable to play cutscene: %s\n", err.what()); } } + + + /* Duke: if (!userConfig.nologo) fi.ShowLogo([](bool) { gameaction = ga_mainmenunostopsound; }); diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 56b26905e..d44669bd1 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -201,6 +201,10 @@ bool ScreenJobTick(); void ScreenJobDraw(); struct CutsceneDef; -bool StartCutscene(CutsceneDef& cs, int flags, CompletionFunc completion); -bool StartCutscene(const char* s, int flags, CompletionFunc completion); +struct MapRecord; +struct SummaryInfo; +bool StartCutscene(CutsceneDef& cs, int flags, const CompletionFunc& completion); +bool StartCutscene(const char* s, int flags, const CompletionFunc& completion); void PlayLogos(gameaction_t complete_ga, gameaction_t def_ga, bool stopmusic); +void ShowScoreboard(int numplayers, const CompletionFunc& completion_); +void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, CompletionFunc completion_); diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 526cc1458..21f97b939 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -131,60 +131,5 @@ void InitFonts_d() } -//========================================================================== -// -// wrappers around DrawText to allow easier reuse of the old code. -// The vertical displacements are to have the same positioning as with the original code. -// -//========================================================================== - -static void BigText(double x, double y, const char* text, int align = -1, double alpha = 1.) -{ - if (align != -1) - x -= BigFont->StringWidth(text) * (align == 0 ? 0.5 : 1); - DrawText(twod, BigFont, CR_UNTRANSLATED, x, y - 12, text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_Alpha, alpha, TAG_DONE); -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -void dobonus_d(int bonusonly, const CompletionFunc& completion) -{ -#if 0 - TArray jobs; - - FX_StopAllSounds(); - - if (bonusonly < 0 && numplayers < 2 && ud.from_bonus == 0) - { - bonussequence_d(volfromlevelnum(currentLevel->levelNumber), jobs); - } - else - Mus_Stop(); - - if (playerswhenstarted > 1 && ud.coop != 1) - { - jobs.Push(Create(playerswhenstarted)); - } - else if (bonusonly <= 0 && ud.multimode <= 1) - { - jobs.Push(Create()); - } - if (jobs.Size()) - { - RunScreenJob(jobs, completion); - } - else if (completion) completion(false); -#endif -} - -void PrintPaused_d() -{ - BigText(160, 100, GStrings("Game Paused")); -} - END_DUKE_NS diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index 7aef5a9a3..f8a530ade 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -123,119 +123,5 @@ void InitFonts_r() } -//========================================================================== -// -// wrappers around DrawText to allow easier reuse of the old code. -// The vertical displacements are to have the same positioning as with the original code. -// -//========================================================================== - -static void BigText(double x, double y, const char* text, int align, double alpha = 1.) -{ - //x *= 2.2; y *= 2.64; - if (align != -1) - x -= BigFont->StringWidth(text) * (align == 0 ? 0.2 : 0.4); - DrawText(twod, BigFont, CR_UNTRANSLATED, x, y - 12, text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, 0.4, DTA_ScaleY, 0.4, DTA_Alpha, alpha, TAG_DONE); -} - - -#if 0 -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -static void bonussequence_r(int num, TArray& jobs) -{ - static const AnimSound turdmov[] = - { - { 1, 82 + 1 }, - { -1, -1 } - }; - - static const AnimSound rr_outro[] = - { - { 1, 35 + 1 }, - { -1, -1 } - }; - - static const int framespeed[] = { 9, 9, 9 }; // same for all 3 anims - - Mus_Stop(); - FX_StopAllSounds(); - - switch (num) - { - case 0: - jobs.Push(PlayVideo("turdmov.anm", turdmov, framespeed)); - jobs.Push(Create(TENSCREEN)); - break; - - case 1: - jobs.Push(PlayVideo("rr_outro.anm", rr_outro, framespeed)); - jobs.Push(Create(TENSCREEN)); - break; - - default: - break; - } -} -#endif - - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -void dobonus_r(int bonusonly, const CompletionFunc& completion) -{ -#if 0 - TArray jobs; - - FX_StopAllSounds(); - Mus_Stop(); - - if (bonusonly < 0 && !isRRRA() && numplayers < 2 && ud.from_bonus == 0) - { - int vol = volfromlevelnum(currentLevel->levelNumber); - bonussequence_r(vol, jobs); - } - - if (playerswhenstarted > 1 && ud.coop != 1) - { - jobs.Push(Create(playerswhenstarted)); - } - 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. - { - jobs.Push(Create(true)); - int levnum = clamp((currentLevel->levelNumber / 100) * 7 + (currentLevel->levelNumber % 100), 0, 13); - char fn[20]; - 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.Push(PlayVideo(fn, nullptr, framespeed)); - if (bonusonly < 0 && currentLevel->levelNumber > 100) - { - jobs.Push(Create()); - } - } - else jobs.Push(Create(false)); - } - if (jobs.Size()) - RunScreenJob(jobs, completion); - else if (completion) completion(false); -#endif -} - - -void PrintPaused_r() -{ - BigText(160, 100, GStrings("Game Paused"), 0); -} - END_DUKE_NS diff --git a/source/games/duke/src/dispatch.cpp b/source/games/duke/src/dispatch.cpp index bf5918bb0..ac110ddcd 100644 --- a/source/games/duke/src/dispatch.cpp +++ b/source/games/duke/src/dispatch.cpp @@ -107,8 +107,6 @@ void animatesprites_r(int x, int y, int a, int smoothratio); void InitFonts_d(); void InitFonts_r(); -void PrintPaused_d(); -void PrintPaused_r(); Dispatcher fi; @@ -119,7 +117,6 @@ void SetDispatcher() { fi = { InitFonts_d, - PrintPaused_d, think_d, initactorflags_d, @@ -165,7 +162,6 @@ void SetDispatcher() { fi = { InitFonts_r, - PrintPaused_r, think_r, initactorflags_r, diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h index 4f31aef02..5b49b4cc6 100644 --- a/source/games/duke/src/duke3d.h +++ b/source/games/duke/src/duke3d.h @@ -72,7 +72,6 @@ struct Dispatcher { // global stuff void (*InitFonts)(); - void (*PrintPaused)(); // sectors_?.cpp void (*think)(); diff --git a/source/games/duke/src/funct.h b/source/games/duke/src/funct.h index 5e0bcc0e1..83d4bbc27 100644 --- a/source/games/duke/src/funct.h +++ b/source/games/duke/src/funct.h @@ -208,8 +208,6 @@ void OffBoat(player_struct *pl); void cameratext(DDukeActor* i); void dobonus(int 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); diff --git a/source/games/duke/src/game_misc.cpp b/source/games/duke/src/game_misc.cpp index cb3f7a1b7..e0efb221a 100644 --- a/source/games/duke/src/game_misc.cpp +++ b/source/games/duke/src/game_misc.cpp @@ -92,13 +92,12 @@ static void endthegame(bool) void GameInterface::ExitFromMenu() { +#if 0 + // do we really need this scoreboard stuff here? auto runbonus = [=](auto completion) { // MP scoreboard - if (playerswhenstarted > 1 && !ud.coop) - { - dobonus(1, completion); - } + if (playerswhenstarted > 1 && !ud.coop) ShowScoreboard(playerswhenstarted); else completion(false); }; @@ -111,6 +110,11 @@ void GameInterface::ExitFromMenu() }; runbonus([=](bool aborted) { runtwoscreens(endthegame); }); +#else + if (isShareware() && !isRR()) + StartCutscene("DukeCutscenes.BuildSharewareExit", 0, endthegame); + else endthegame(false); +#endif } //--------------------------------------------------------------------------- @@ -208,7 +212,7 @@ void V_AddBlend (float r, float g, float b, float a, float v_blend[4]) //--------------------------------------------------------------------------- // -// 'rest' in this case means everything not part of the 3D scene and its weapon sprite. +// // //--------------------------------------------------------------------------- @@ -297,7 +301,13 @@ void drawoverlays(double smoothratio) } if (paused == 2) - fi.PrintPaused(); + { + double x = 160, y = 100; + double scale = isRR() ? 0.4 : 1.; + const char* text = GStrings("Game Paused"); + x -= BigFont->StringWidth(text) * 0.5 * scale; + DrawText(twod, BigFont, CR_UNTRANSLATED, x, y - 12, text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, scale, DTA_ScaleY, scale, TAG_DONE); + } } @@ -342,18 +352,6 @@ void cameratext(DDukeActor *cam) // //--------------------------------------------------------------------------- -void dobonus(int bonusonly, const CompletionFunc& completion) -{ - if (isRR()) dobonus_r(bonusonly, completion); - else dobonus_d(bonusonly, completion); -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - int startrts(int lumpNum, int localPlayer) { if (SoundEnabled() && diff --git a/source/games/duke/src/gameexec.cpp b/source/games/duke/src/gameexec.cpp index 4dd7c7181..f730e6312 100644 --- a/source/games/duke/src/gameexec.cpp +++ b/source/games/duke/src/gameexec.cpp @@ -244,7 +244,7 @@ static void DoUserDef(bool bSet, int lVar1, int lLabelID, int lVar2, DDukeActor* break; case USERDEFS_VOLUME_NUMBER: - if (!bSet) SetGameVarID(lVar2, volfromlevelnum(currentLevel->levelNumber), sActor, sPlayer); + if (!bSet) SetGameVarID(lVar2, currentLevel->cluster-1, sActor, sPlayer); break; case USERDEFS_MARKER: @@ -3572,7 +3572,7 @@ int ParseState::parse(void) { insptr++; int music_select = *insptr++; - auto level = FindMapByLevelNum(levelnum(currentLevel->levelNumber, music_select)); + auto level = FindMapByLevelNum(levelnum(currentLevel->cluster, music_select)); if (level) S_PlayLevelMusic(level); break; } diff --git a/source/games/duke/src/premap.cpp b/source/games/duke/src/premap.cpp index 074020dda..10891de9e 100644 --- a/source/games/duke/src/premap.cpp +++ b/source/games/duke/src/premap.cpp @@ -1040,29 +1040,32 @@ bool setnextmap(bool checksecretexit) // //--------------------------------------------------------------------------- -void exitlevel(MapRecord *nextlevel) +void exitlevel(MapRecord* nextlevel) { bool endofgame = nextlevel == nullptr; STAT_Update(endofgame); StopCommentary(); - dobonus(endofgame? -1 : 0, [=](bool) - { + SummaryInfo info{}; - // Clear potentially loaded per-map ART only after the bonus screens. - artClearMapArt(); - gameaction = ga_level; - ud.eog = false; - if (endofgame) + info.kills = ps[0].actors_killed; + info.maxkills = ps[0].max_actors_killed; + info.secrets = ps[0].secret_rooms; + info.maxsecrets = ps[0].max_secret_rooms; + info.time = ps[0].player_par; + info.endofgame = endofgame; + Mus_Stop(); + + if (playerswhenstarted > 1 && ud.coop != 1) + { + // MP scoreboard + ShowScoreboard(playerswhenstarted, [=](bool) { - if (ud.multimode < 2) - { - if (isShareware()) - StartCutscene("DukeCutscenes.BuildSharewareOrder", 0, [](bool) { gameaction = ga_startup; }); - else gameaction = ga_startup; - return; - } - else + // Clear potentially loaded per-map ART only after the bonus screens. + artClearMapArt(); + gameaction = ga_level; + ud.eog = false; + if (endofgame) { auto nextlevel = FindMapByLevelNum(0); if (!nextlevel) @@ -1072,11 +1075,22 @@ void exitlevel(MapRecord *nextlevel) } else gameaction = ga_nextlevel; } - } - else - gameaction = ga_nextlevel; + else + gameaction = ga_nextlevel; + }); + } + else if (ud.multimode <= 1) + { + // SP cutscene + summary + ShowIntermission(currentLevel, nextlevel, &info, [=](bool) + { + // Clear potentially loaded per-map ART only after the bonus screens. + artClearMapArt(); + ud.eog = false; + gameaction = endofgame? ga_startup : ga_nextlevel; }); + } } diff --git a/wadsrc/static/filter/duke/engine/engine.def b/wadsrc/static/filter/duke/engine/engine.def index 8adfcea29..85a545e49 100644 --- a/wadsrc/static/filter/duke/engine/engine.def +++ b/wadsrc/static/filter/duke/engine/engine.def @@ -49,5 +49,11 @@ definecutscene episode 5 } } +definecutscene sharewareend +{ + function DukeCutscenes.BuildSharewareEnd +} + definecutscene summary DukeCutscenes.BuildSPSummary definecutscene mpsummary DukeCutscenes.BuildMPSummary + diff --git a/wadsrc/static/filter/redneck/engine/engine.def b/wadsrc/static/filter/redneck/engine/engine.def index a569487ad..140e385d6 100644 --- a/wadsrc/static/filter/redneck/engine/engine.def +++ b/wadsrc/static/filter/redneck/engine/engine.def @@ -1,4 +1,4 @@ -// Cutscene definitions for Duke +// Cutscene definitions for RR definecutscene intro { @@ -24,3 +24,4 @@ definecutscene episode 2 definecutscene summary RRCutscenes.BuildSPSummary definecutscene mpsummary DukeCutscenes.BuildMPSummary // identical with Duke's +definecutscene mapintro RRCutscenes.BuildMapIntro // this plays the 'travel' animation. diff --git a/wadsrc/static/zscript/games/duke/dukegame.zs b/wadsrc/static/zscript/games/duke/dukegame.zs index e5632eff1..7b40f78d3 100644 --- a/wadsrc/static/zscript/games/duke/dukegame.zs +++ b/wadsrc/static/zscript/games/duke/dukegame.zs @@ -64,6 +64,7 @@ struct Duke native fsmode = FSMode_Fit640x400; } if (align != -1) x -= SmallFont.StringWidth(t) * (align == 0 ? 0.5 : 1); + if (shade) Console.Printf("%s: shade = %d", t, shade); Screen.DrawText(SmallFont, Font.CR_UNDEFINED, x, y + 2, t, DTA_FullscreenScale, fsmode, DTA_TranslationIndex, Translation.MakeID(Translation_Remap, trans), DTA_Color, Raze.shadeToLight(shade)); } diff --git a/wadsrc/static/zscript/games/duke/ui/cutscenes.zs b/wadsrc/static/zscript/games/duke/ui/cutscenes.zs index 5b0b9cafd..49b5a3020 100644 --- a/wadsrc/static/zscript/games/duke/ui/cutscenes.zs +++ b/wadsrc/static/zscript/games/duke/ui/cutscenes.zs @@ -216,8 +216,7 @@ class DukeCutscenes // Note: must be class, not struct, otherwise we cannot easi static void BuildSPSummary(ScreenJobRunner runner, MapRecord map, SummaryInfo stats) { - let screen = SummaryScreenBase(new("DukeLevelSummaryScreen").Init()); - if (screen) screen.SetParameters(map, stats); + let screen = new("DukeLevelSummaryScreen").Init(map, stats); runner.Append(screen); } @@ -235,11 +234,11 @@ class DukeCutscenes // Note: must be class, not struct, otherwise we cannot easi //--------------------------------------------------------------------------- // - // + // // //--------------------------------------------------------------------------- - static void BuildSharewareOrder(ScreenJobRunner runner) + static void BuildSharewareEnd(ScreenJobRunner runner) { runner.Append(ImageScreen.CreateNamed("ORDERING")); runner.Append(ImageScreen.CreateNamed("ORDERING1")); @@ -339,10 +338,7 @@ class RRCutscenes static void BuildSPSummary(ScreenJobRunner runner, MapRecord map, SummaryInfo stats) { - let sumscreen = new("RRLevelSummaryScreen").Init(!Raze.isRRRA() || stats.endOfGame); - let sumscreens = SummaryScreenBase(sumscreen); - if (sumscreens) sumscreens.SetParameters(map, stats); - runner.Append(sumscreen); + runner.Append(new("RRLevelSummaryScreen").Init(map, stats, !Raze.isRRRA() || stats.endOfGame)); } //--------------------------------------------------------------------------- diff --git a/wadsrc/static/zscript/games/duke/ui/screens.zs b/wadsrc/static/zscript/games/duke/ui/screens.zs index 37dbc63c4..481e9f0f7 100644 --- a/wadsrc/static/zscript/games/duke/ui/screens.zs +++ b/wadsrc/static/zscript/games/duke/ui/screens.zs @@ -57,7 +57,6 @@ class DRealmsScreen : SkippableScreenJob let tex = TexMan.CheckForTexture("DREALMS"); int translation = TexMan.UseGamePalette(tex)? Translation.MakeID(Translation_BasePalette, Duke.DREALMSPAL) : 0; - screen.ClearScreen(); screen.DrawTexture(tex, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal); } } @@ -119,8 +118,6 @@ class DukeTitleScreen : SkippableScreenJob int clock = (ticks + smoothratio) * 120 / GameTicRate; int etrans = Translation.MakeID(Translation_BasePalette, Duke.TITLEPAL); - screen.ClearScreen(); - // Only translate if the image depends on the global palette. let tex = TexMan.CheckForTexture("BETASCREEN"); int trans = TexMan.UseGamePalette(tex)? etrans : 0; @@ -256,7 +253,6 @@ class Episode1End1 : SkippableScreenJob { int etrans = Translation.MakeID(Translation_BasePalette, Duke.ENDINGPAL); - screen.ClearScreen(); let tex = TexMan.CheckForTexture("VICTORY1"); int trans = TexMan.UseGamePalette(tex)? etrans : 0; screen.DrawTexture(tex, false, 0, 50, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TranslationIndex, trans, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TopLeft, true); @@ -411,7 +407,6 @@ class Episode4Text : SkippableScreenJob override void Draw(double sm) { - Screen.ClearScreen(); Duke.BigText(160, 60, "$Thanks to all our", 0); Duke.BigText(160, 60 + 16, "$fans for giving", 0); Duke.BigText(160, 60 + 16 + 16, "$us big heads.", 0); @@ -474,7 +469,6 @@ class DukeMultiplayerBonusScreen : SkippableScreenJob String tempbuf; int currentclock = int((ticks + smoothratio) * 120 / GameTicRate); - Screen.ClearScreen(); Screen.DrawTexture(TexMan.CheckForTexture("MENUSCREEN"), false, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Color, 0xff808080, DTA_LegacyRenderStyle, STYLE_Normal); Screen.DrawTexture(TexMan.CheckForTexture("INGAMEDUKETHREEDEE"), true, 160, 34, DTA_FullscreenScale, FSMode_Fit320x200, DTA_CenterOffsetRel, true, DTA_ScaleX, titlescale, DTA_ScaleY, titlescale); if (Raze.isPlutoPak()) Screen.DrawTexture(TexMan.CheckForTexture("MENUPLUTOPAKSPRITE"), true, 260, 36, DTA_FullscreenScale, FSMode_Fit320x200, DTA_CenterOffsetRel, true); @@ -581,11 +575,12 @@ class DukeLevelSummaryScreen : SummaryScreenBase } - ScreenJob Init() + ScreenJob Init(MapRecord m, SummaryInfo s) { Super.Init(fadein | fadeout); - int vol = level.volumeNum(); - String basetex = vol == 1? "BONUSSCREEN2" : "BONUSSCREEN"; + SetParameters(m, s); + int vol = level.cluster; + String basetex = vol == 2? "BONUSSCREEN2" : "BONUSSCREEN"; texBg = TexMan.CheckForTexture(basetex); for(int i = 0; i < 4; i++) { @@ -737,10 +732,9 @@ class DukeLevelSummaryScreen : SummaryScreenBase override void Draw(double sr) { - Screen.ClearScreen(); Screen.DrawTexture(texBg, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal); - Duke.GameText(160, 190, "$PRESSKEY", 8 - int(sin(ticks * 12 / GameTicRate) * 8), 0); + Duke.GameText(160, 190, "$PRESSKEY", 8 - (sin(ticks * 4) * 8), 0); if (displaystate & printTimeText) { @@ -785,15 +779,15 @@ class DukeLevelSummaryScreen : SummaryScreenBase } } - if (lastmapname) Duke.BigText(160, 20 - 6, lastmapname); - Duke.BigText(160, 36 - 6, "$Completed"); + if (lastmapname) Duke.BigText(160, 20 - 6, lastmapname, 0); + Duke.BigText(160, 36 - 6, "$Completed", 0); } } //--------------------------------------------------------------------------- // -// TBD: fold this into DukeLevelSummaryScreen? +// // //--------------------------------------------------------------------------- @@ -819,9 +813,10 @@ class RRLevelSummaryScreen : SummaryScreenBase } - ScreenJob Init(bool dofadeout = true) + ScreenJob Init(MapRecord m, SummaryInfo s, bool dofadeout = true) { Super.Init(dofadeout? (fadein | fadeout) : fadein); + SetParameters(m, s); String s; if (level.flags & MapRecord.USERMAP) s = "BONUSPIC01"; @@ -968,11 +963,10 @@ class RRLevelSummaryScreen : SummaryScreenBase override void Draw(double sr) { - Screen.ClearScreen(); Screen.DrawTexture(texBg, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal); - if (lastmapname) Duke.BigText(80, 16, lastmapname, -1); - Duke.BigText(15, 192, "$PRESSKEY", -1); + if (lastmapname) Duke.BigText(80, 16, lastmapname, 0, 0); + Duke.BigText(15, 192, "$PRESSKEY", 0, 0); if (displaystate & printTimeText) { @@ -1044,7 +1038,6 @@ class DukeLoadScreen : ScreenJob override void Draw(double sr) { - Screen.ClearScreen(); Screen.DrawTexture(TexMan.CheckForTexture("LOADSCREEN"), false, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal); if (!Raze.IsRR()) diff --git a/wadsrc/static/zscript/razebase.zs b/wadsrc/static/zscript/razebase.zs index c2da19342..12f4e5637 100644 --- a/wadsrc/static/zscript/razebase.zs +++ b/wadsrc/static/zscript/razebase.zs @@ -64,6 +64,7 @@ struct MapRecord native native readonly int cdSongId; native readonly int flags; native readonly int levelNumber; + native readonly int cluster; // The rest is only used by Blood native readonly int nextLevel; @@ -81,10 +82,6 @@ struct MapRecord native if (name == "") return labelName; return name; } - int volumeNum() - { - return levelNumber / 1000; - } } struct SummaryInfo native diff --git a/wadsrc/static/zscript/screenjob.zs b/wadsrc/static/zscript/screenjob.zs index 1285ac3ca..fbfdb98d7 100644 --- a/wadsrc/static/zscript/screenjob.zs +++ b/wadsrc/static/zscript/screenjob.zs @@ -121,7 +121,6 @@ class BlackScreen : ScreenJob override void Draw(double smooth) { cleared = true; - Screen.ClearScreen(); } } @@ -180,7 +179,6 @@ class ImageScreen : SkippableScreenJob override void Draw(double smooth) { - Screen.ClearScreen(); if (texid.IsValid()) Screen.DrawTexture(texid, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TranslationIndex, trans); cleared = true; } @@ -392,7 +390,6 @@ class ScreenJobRunner : Object { if (jobs.Size() == 0) { - screen.ClearScreen(); return 1; } int x = index >= jobs.Size()? jobs.Size()-1 : index; @@ -498,7 +495,6 @@ class ScreenJobRunner : Object if (actionState == State_Clear) { actionState = State_Run; - Screen.ClearScreen(); } else if (actionState == State_Run) {