[Scummvm-git-logs] scummvm master -> 50e3033998dbc375ddfab203b29c839a0467837b
bluegr
noreply at scummvm.org
Sun Mar 15 19:21:58 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
50e3033998 TINSEL: New DW1 introduction skip technique
Commit: 50e3033998dbc375ddfab203b29c839a0467837b
https://github.com/scummvm/scummvm/commit/50e3033998dbc375ddfab203b29c839a0467837b
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-03-15T21:21:54+02:00
Commit Message:
TINSEL: New DW1 introduction skip technique
Pressing Escape during the introduction logos and credits
now skips to the title screen in all versions.
Fixes bug #14627
Changed paths:
engines/tinsel/debugger.cpp
engines/tinsel/handle.cpp
engines/tinsel/handle.h
engines/tinsel/pcode.cpp
engines/tinsel/saveload.cpp
engines/tinsel/scene.cpp
engines/tinsel/scene.h
engines/tinsel/tinlib.cpp
engines/tinsel/tinsel.cpp
diff --git a/engines/tinsel/debugger.cpp b/engines/tinsel/debugger.cpp
index 702bee887c9..1357f8b5e94 100644
--- a/engines/tinsel/debugger.cpp
+++ b/engines/tinsel/debugger.cpp
@@ -152,6 +152,7 @@ bool Console::cmd_scene(int argc, const char **argv) {
return true;
}
+ EndDw1Intro();
SetNewScene(sceneNumber << SCNHANDLE_SHIFT, entryNumber, TRANS_CUT);
return false;
}
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 83706c9bd35..a6ae23bbd40 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -67,7 +67,8 @@ enum {
#define MEMFLAGS(x) ((TinselVersion == 3) ? x->flags2 : x->filesize)
#define MEMFLAGSET(x, mask) ((TinselVersion == 3) ? x->flags2 |= mask : x->filesize |= mask)
-Handle::Handle() : _handleTable(0), _numHandles(0), _cdPlayHandle((uint32)-1), _cdBaseHandle(0), _cdTopHandle(0), _cdGraphStream(nullptr) {
+Handle::Handle() : _handleTable(0), _numHandles(0), _cdPlayHandle((uint32)-1), _cdBaseHandle(0), _cdTopHandle(0), _cdGraphStream(nullptr),
+ _dw1TitleSceneHandle(0) {
}
Handle::~Handle() {
@@ -166,6 +167,19 @@ void Handle::SetupHandleTable() {
assert(pH->_node);
}
}
+
+ // Detect DW1 title scene handle for introduction skipping
+ if (TinselVersion == 1) {
+ // PSX versions swapped the title and turtle scene order
+ const char *titleSceneName = TinselV1PSX ? "turtle." : "title.";
+ const int sceneNameLength = strlen(titleSceneName);
+ for (i = 0; i < _numHandles; i++) {
+ if (!scumm_strnicmp(_handleTable[i].szName, titleSceneName, sceneNameLength)) {
+ _dw1TitleSceneHandle = i << SCNHANDLE_SHIFT;
+ break;
+ }
+ }
+ }
}
/**
diff --git a/engines/tinsel/handle.h b/engines/tinsel/handle.h
index 75b57ce0dca..f8c2b5269ea 100644
--- a/engines/tinsel/handle.h
+++ b/engines/tinsel/handle.h
@@ -78,6 +78,9 @@ public:
int CdNumber(SCNHANDLE offset);
+ // Used for skipping DW1 introduction
+ SCNHANDLE GetDw1TitleSceneHandle() { return _dw1TitleSceneHandle; }
+
// Noir
SCNHANDLE FindLanguageSceneHandle(const char *fileName);
@@ -106,6 +109,8 @@ private:
Common::File *_cdGraphStream;
Common::Path _szCdPlayFile;
+
+ SCNHANDLE _dw1TitleSceneHandle;
};
} // End of namespace Tinsel
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index 0011bb07bb9..07dd7cce398 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -41,6 +41,9 @@ namespace Tinsel {
extern int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pic, RESUME_STATE *pResumeState);
+// in SCENE.CPP
+extern bool InDw1Intro();
+
//----------------- LOCAL DEFINES --------------------
#define GLOBALS_FILENAME "gdata" // name of globals file
@@ -957,14 +960,20 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
break;
case OP_ESCON:
- g_bNoPause = true;
- ic->escOn = true;
- ic->myEscape = GetEscEvents();
+ // Ignore EscapeOn during DW1 intro. We implement our own skipping.
+ if (!InDw1Intro()) {
+ g_bNoPause = true;
+ ic->escOn = true;
+ ic->myEscape = GetEscEvents();
+ }
break;
case OP_ESCOFF:
- ic->escOn = false;
- ic->myEscape = 0;
+ // Ignore EscapeOff during DW1 intro. We implement our own skipping.
+ if (!InDw1Intro()) {
+ ic->escOn = false;
+ ic->myEscape = 0;
+ }
break;
case OP_NOOP:
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index 7ed00a73ea3..5c86442f222 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -67,7 +67,8 @@ extern void syncGlobInfo(Common::Serializer &s);
// in POLYGONS.C
extern void syncPolyInfo(Common::Serializer &s);
-extern int g_sceneCtr;
+// in SCENE.CPP
+extern void EndDw1Intro();
extern bool g_ASceneIsSaved;
@@ -685,10 +686,9 @@ static void DoSave() {
void ProcessSRQueue() {
switch (g_SRstate) {
case SR_DORESTORE:
- // If a load has been done directly from title screens, set a larger value for scene ctr so the
- // code used to skip the title screens in Discworld 1 gets properly disabled
- if (g_sceneCtr < 10)
- g_sceneCtr = 10;
+ // Clear the DW1 flag used for implementing introduction skipping.
+ // This restore may have come from the ScummVM GMM or launcher.
+ EndDw1Intro();
if (DoRestore()) {
DoRestoreScene(g_srsd, false);
diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp
index a6f7ef7b390..7a2a1d73bf2 100644
--- a/engines/tinsel/scene.cpp
+++ b/engines/tinsel/scene.cpp
@@ -131,7 +131,7 @@ struct LIGHT_STRUC {
static bool g_ShowPosition = false; // Set when showpos() has been called
#endif
-int g_sceneCtr = 0;
+static bool g_dw1Intro = true;
static int g_initialMyEscape = 0;
static SCNHANDLE g_SceneHandle = 0; // Current scene handle - stored in case of Save_Scene()
@@ -146,8 +146,7 @@ struct TP_INIT {
};
void ResetVarsScene() {
- g_sceneCtr = 0;
- g_initialMyEscape = 0;
+ ResetDw1Intro();
g_SceneHandle = 0;
g_isViewSet = false;
@@ -235,16 +234,30 @@ static void SceneTinselProcess(CORO_PARAM, const void *param) {
CORO_BEGIN_CODE(_ctx);
- // The following myEscape value setting is used for enabling title screen skipping in DW1
- if ((TinselVersion == 1) && (g_sceneCtr == 1)) g_initialMyEscape = GetEscEvents();
- // DW1 PSX, Saturn and Mac has its own scene skipping script code for scenes 2 and 3 (bug #6094).
- _ctx->myEscape = ((TinselVersion == 1) && (g_sceneCtr < ((TinselV1PSX || TinselV1Saturn || TinselV1Mac) ? 2 : 4))) ? g_initialMyEscape : 0;
-
// get the stuff copied to process when it was created
_ctx->pInit = (const TP_INIT *)param;
assert(_ctx->pInit);
assert(_ctx->pInit->hTinselCode); // Must have some code to run
+ // Handle DW1 introduction skipping
+ if (InDw1Intro()) {
+ // Record initial escape events so that Escape can be detected after a scene
+ if (g_initialMyEscape == 0) {
+ g_initialMyEscape = GetEscEvents();
+ }
+ SCNHANDLE sceneHandle = FROM_32(_ctx->pInit->hTinselCode) & HANDLEMASK;
+ if (sceneHandle == _vm->_handle->GetDw1TitleSceneHandle()) {
+ // Title screen reached; introduction has ended
+ EndDw1Intro();
+ _ctx->myEscape = 0;
+ } else {
+ // Enable Escape mode during introduction
+ _ctx->myEscape = GetEscEvents();
+ }
+ } else {
+ _ctx->myEscape = 0;
+ }
+
_ctx->pic = InitInterpretContext(GS_SCENE,
FROM_32(_ctx->pInit->hTinselCode),
(TinselVersion >= 2) ? _ctx->pInit->event : NOEVENT,
@@ -578,4 +591,61 @@ void SetView(int sceneId, int scale) {
// TODO: Update the ground plane
}
+// DW1 Introduction Skipping
+//
+// The DW1 intro has many logos that cannot be skipped with the Escape key.
+// Later versions added limited ability to use Escape on some logos, but only
+// after a long delay. Other versions added even more logos.
+// We allow users to press Escape during any of these logos to skip straight
+// to the title scene. On PSX this is the turtle scene, as they swapped orders.
+//
+// 1. The title scene handle is detected by name in Handle::SetupHandleTable()
+// 2. We assume we are in the DW1 intro until the title scene is reached, or
+// until a game is restored from launcher or the debugger sets a scene.
+// 3. We manually enable Escape mode at the start of intro scenes by initializing
+// ctx->myEscape to GetEscEvents() in SceneTinselProcess().
+// 4. We detect if Escape was pressed during a previous scene by comparing
+// GetEscEvents() with g_initialMyEscape in SetNewScene().
+// If Escape was pressed, we set the next scene to the title scene.
+// 5. We disable the escape opcodes (OP_ESCON, OP_ESCOFF) during the intro,
+// so that the versions that added these calls do not conflict.
+
+/**
+ * Returns true if DW1 is in one of its introduction scenes.
+ * This allows implementing skipping the entire introduction with the Escape key
+ * by initializing ctx->myEscape and ignoring EscapeOn during introduction scenes.
+ */
+bool InDw1Intro() {
+ // Fail-safe: Disable introduction detection if we were
+ // unable to detect the DW1 title scene handle.
+ return (TinselVersion == 1) && g_dw1Intro &&
+ (_vm->_handle->GetDw1TitleSceneHandle() != 0);
+}
+
+/**
+ * Clears the DW1 introduction flag. Called when the title screen is started,
+ * a game is restored, or when loading a scene from the debugger.
+ */
+void EndDw1Intro() {
+ g_dw1Intro = false;
+}
+
+/**
+ * Resets the DW1 introduction state. Called when restarting the game or
+ * destroying the engine.
+ */
+void ResetDw1Intro() {
+ g_dw1Intro = true;
+ g_initialMyEscape = 0;
+}
+
+/**
+ * Returns true if Escape was pressed during the DW1 introduction.
+ * Used to override the scene passed by the script to NewScene()
+ * with the title scene instead.
+ */
+bool WasDw1IntroSkipped() {
+ return InDw1Intro() && g_initialMyEscape != 0 && g_initialMyEscape != GetEscEvents();
+}
+
} // End of namespace Tinsel
diff --git a/engines/tinsel/scene.h b/engines/tinsel/scene.h
index 617dc2f94cc..01a5d5adbc3 100644
--- a/engines/tinsel/scene.h
+++ b/engines/tinsel/scene.h
@@ -90,6 +90,11 @@ void SendSceneTinselProcess(TINSEL_EVENT event);
void SetView(int id, int scale);
+bool InDw1Intro();
+void EndDw1Intro();
+void ResetDw1Intro();
+bool WasDw1IntroSkipped();
+
} // End of namespace Tinsel
#endif // TINSEL_SCENE_H
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index 89ba5322647..62c721fd673 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -99,7 +99,7 @@ extern int NewestSavedGame();
// in SCENE.CPP
extern void setshowpos();
-extern int g_sceneCtr;
+extern void ResetDw1Intro();
// in TINSEL.CPP
extern void SetCdChangeScene(SCNHANDLE hScene);
@@ -1477,9 +1477,6 @@ void NewScene(CORO_PARAM, SCNHANDLE scene, int entrance, int transition) {
else
GetControl(CONTROL_STARTOFF);
- if (TinselVersion == 1)
- ++g_sceneCtr;
-
// Prevent code subsequent to this call running before scene changes
if (CoroScheduler.getCurrentPID() != PID_MASTER_SCR)
CORO_KILL_SELF();
@@ -2505,7 +2502,11 @@ void FnRestartGame() {
StopSample();
g_bRestart = true;
- g_sceneCtr = 0;
+ if (!TinselV1PSX) {
+ // Reset the DW1 intro detection unless PSX.
+ // PSX scripts restart directly to the title screen.
+ ResetDw1Intro();
+ }
}
/**
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 0f757f1a125..1f80f366a6a 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -81,6 +81,7 @@ extern void InventoryProcess(CORO_PARAM, const void *);
// In SCENE.CPP
extern SCNHANDLE GetSceneHandle();
+extern bool WasDw1IntroSkipped();
extern void ResetVarsDrives();
extern void ResetVarsEvents();
@@ -528,6 +529,13 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition) {
g_HookScene.scene = 0;
}
+ // Skip DW1 introduction if Escape was pressed by switching to title screen
+ if (WasDw1IntroSkipped()) {
+ g_NextScene.scene = _vm->_handle->GetDw1TitleSceneHandle();
+ g_NextScene.entry = 1;
+ g_NextScene.trans = TRANS_DEF;
+ }
+
// Workaround for "Missing Red Dragon in square" bug in Discworld 1 PSX, act IV.
// This happens with the original interpreter on PSX too: the red dragon in Act IV
// doesn't show up inside the square at the right time. Original game required the
More information about the Scummvm-git-logs
mailing list