[Scummvm-git-logs] scummvm master -> 8b4f996cb98fc372deb49de934a3da14ec0d2466
neuromancer
noreply at scummvm.org
Sat Mar 28 08:24:07 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:
8b4f996cb9 FREESCAPE: added win console command and improved some endgame code
Commit: 8b4f996cb98fc372deb49de934a3da14ec0d2466
https://github.com/scummvm/scummvm/commit/8b4f996cb98fc372deb49de934a3da14ec0d2466
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-28T09:23:56+01:00
Commit Message:
FREESCAPE: added win console command and improved some endgame code
Changed paths:
engines/freescape/debugger.cpp
engines/freescape/debugger.h
engines/freescape/freescape.cpp
engines/freescape/freescape.h
engines/freescape/games/castle/castle.cpp
engines/freescape/games/castle/castle.h
engines/freescape/games/dark/dark.cpp
engines/freescape/games/dark/dark.h
engines/freescape/games/driller/amiga.cpp
engines/freescape/games/driller/driller.cpp
engines/freescape/games/driller/driller.h
engines/freescape/games/eclipse/eclipse.cpp
engines/freescape/games/eclipse/eclipse.h
engines/freescape/ui.cpp
diff --git a/engines/freescape/debugger.cpp b/engines/freescape/debugger.cpp
index 15dd7d0bff9..47b58d3199f 100644
--- a/engines/freescape/debugger.cpp
+++ b/engines/freescape/debugger.cpp
@@ -44,6 +44,7 @@ Debugger::Debugger(FreescapeEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("occ", WRAP_METHOD(Debugger, cmdShowOcclusion)); // toggle occlussion boxes
registerCmd("area", WRAP_METHOD(Debugger, cmdArea)); // show current area info
registerCmd("pos", WRAP_METHOD(Debugger, cmdPos)); // show camera position and direction
+ registerCmd("win", WRAP_METHOD(Debugger, cmdWin)); // trigger the current game's win condition
}
Debugger::~Debugger() {}
@@ -287,4 +288,19 @@ bool Debugger::cmdPos(int argc, const char **argv) {
return true;
}
+bool Debugger::cmdWin(int argc, const char **argv) {
+ if (argc > 1) {
+ debugPrintf("Usage: win\n");
+ return true;
+ }
+
+ if (!_vm->triggerWinCondition()) {
+ debugPrintf("No win condition is available for this game or platform.\n");
+ return true;
+ }
+
+ debugPrintf("Triggered the win condition.\n");
+ return true;
+}
+
}
diff --git a/engines/freescape/debugger.h b/engines/freescape/debugger.h
index fd10ae47d33..579a0e57649 100644
--- a/engines/freescape/debugger.h
+++ b/engines/freescape/debugger.h
@@ -48,6 +48,7 @@ private:
bool cmdShowOcclusion(int argc, const char **argv);
bool cmdArea(int argc, const char **argv);
bool cmdPos(int argc, const char **argv);
+ bool cmdWin(int argc, const char **argv);
};
}
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 400b9187568..1788c584ed9 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -940,6 +940,10 @@ void FreescapeEngine::endGame() {
}
}
+bool FreescapeEngine::triggerWinCondition() {
+ return false;
+}
+
void FreescapeEngine::loadBorder() {
if (_border) {
Graphics::Surface *border = _gfx->convertImageFormatIfNecessary(_border);
diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index d3ccc01fae9..22c19b9ccab 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -614,6 +614,7 @@ public:
StateVars _gameStateVars;
uint32 _gameStateBits;
void checkIfPlayerWasCrushed();
+ virtual bool triggerWinCondition();
virtual bool checkIfGameEnded();
virtual void endGame();
int _endGameDelayTicks;
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 4bda08d0893..9e696d4ce2a 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -587,7 +587,7 @@ void CastleEngine::gotoArea(uint16 areaID, int entranceID) {
_pitch = -85;
} else {
// If escaped, play a different sound
- if (getGameBit(31))
+ if (hasEscaped())
playSound(13, true, _soundFxHandle);
else
playSound(_soundIndexAreaChange, true, _soundFxHandle);
@@ -728,7 +728,7 @@ bool CastleEngine::checkIfGameEnded() {
insertTemporaryMessage(_fallenMessage, _countdown - 4);
_gameStateControl = kFreescapeGameStateEnd;
}
- if ((isSpectrum() && getGameBit(31)) || (isDOS() && _currentArea->getAreaID() == 74)) { // Escaped!
+ if (hasEscaped()) {
_gameStateControl = kFreescapeGameStateEnd;
return true;
}
@@ -736,12 +736,28 @@ bool CastleEngine::checkIfGameEnded() {
return FreescapeEngine::checkIfGameEnded();
}
+bool CastleEngine::triggerWinCondition() {
+ if (isDOS()) {
+ if (!_areaMap.contains(74))
+ return false;
+ gotoArea(74, 0);
+ } else {
+ setGameBit(31);
+ }
+
+ _endGameDelayTicks = 0;
+ _endGameKeyPressed = false;
+ _endGamePlayerEndArea = false;
+ _gameStateControl = kFreescapeGameStateEnd;
+ return true;
+}
+
void CastleEngine::endGame() {
_shootingFrames = 0;
_delayedShootObject = nullptr;
_endGamePlayerEndArea = true;
- if ((isSpectrum() && getGameBit(31)) || (isDOS() && _currentArea->getAreaID() == 74)) { // Escaped!
+ if (hasEscaped()) {
insertTemporaryMessage(_messagesList[5], INT_MIN);
if (isDOS()) {
@@ -756,6 +772,13 @@ void CastleEngine::endGame() {
_endGameKeyPressed = false;
}
+bool CastleEngine::hasEscaped() {
+ if (isDOS())
+ return _currentArea && _currentArea->getAreaID() == 74;
+
+ return getGameBit(31);
+}
+
void CastleEngine::pressedKey(const int keycode) {
// This code is duplicated in the DrillerEngine::pressedKey (except for the J case)
if (keycode == Common::KEYCODE_s) {
@@ -1270,7 +1293,7 @@ void CastleEngine::drawFullscreenGameOverAndWait() {
playSound(9, false, _soundFxHandle);
}
- if (isSpectrum() && getGameBit(31)) {
+ if (!isDOS() && hasEscaped()) {
insertTemporaryMessage(_messagesList[5], _countdown - 1);
}
@@ -1279,7 +1302,7 @@ void CastleEngine::drawFullscreenGameOverAndWait() {
insertTemporaryMessage(scoreString, _countdown - 2);
insertTemporaryMessage(spiritsDestroyedString, _countdown - 4);
insertTemporaryMessage(keysCollectedString, _countdown - 6);
- if (isSpectrum() && getGameBit(31)) {
+ if (!isDOS() && hasEscaped()) {
insertTemporaryMessage(_messagesList[5], _countdown - 8);
}
}
@@ -2126,7 +2149,7 @@ void CastleEngine::drawLiftingGate(Graphics::Surface *surface) {
}
void CastleEngine::drawDroppingGate(Graphics::Surface *surface) {
- if (isSpectrum() && getGameBit(31))
+ if (!isDOS() && hasEscaped())
return; // No gate dropping when the player escaped
if (_droppingGateStartTicks <= 0)
diff --git a/engines/freescape/games/castle/castle.h b/engines/freescape/games/castle/castle.h
index dc19aaf8fb4..62e1a08d44c 100644
--- a/engines/freescape/games/castle/castle.h
+++ b/engines/freescape/games/castle/castle.h
@@ -57,6 +57,7 @@ public:
void beforeStarting() override;
void initKeymaps(Common::Keymap *engineKeyMap, Common::Keymap *infoScreenKeyMap, const char *target) override;
void initGameState() override;
+ bool triggerWinCondition() override;
void endGame() override;
void drawInfoMenu() override;
@@ -185,6 +186,7 @@ private:
void drawRiddle(uint16 riddle, uint32 front, uint32 back, Graphics::Surface *surface);
void tryToCollectKey();
void addGhosts();
+ bool hasEscaped();
bool ghostInArea();
void updateThunder();
diff --git a/engines/freescape/games/dark/dark.cpp b/engines/freescape/games/dark/dark.cpp
index d1115ad8045..5360285998d 100644
--- a/engines/freescape/games/dark/dark.cpp
+++ b/engines/freescape/games/dark/dark.cpp
@@ -559,6 +559,18 @@ bool DarkEngine::checkIfGameEnded() {
return false;
}
+bool DarkEngine::triggerWinCondition() {
+ _gameStateVars[kVariableActiveECDs] = 0;
+ _gameStateVars[kVariableDarkECD] = 0;
+ _gameStateVars[kVariableDarkEnding] = kDarkEndingECDsDestroyed;
+ _ticksFromEnd = 0;
+ _endGameDelayTicks = 0;
+ _endGameKeyPressed = false;
+ _endGamePlayerEndArea = false;
+ _gameStateControl = kFreescapeGameStateEnd;
+ return true;
+}
+
void DarkEngine::endGame() {
FreescapeEngine::endGame();
diff --git a/engines/freescape/games/dark/dark.h b/engines/freescape/games/dark/dark.h
index 5a030a6d847..6153cca0326 100644
--- a/engines/freescape/games/dark/dark.h
+++ b/engines/freescape/games/dark/dark.h
@@ -61,6 +61,7 @@ public:
void initKeymaps(Common::Keymap *engineKeyMap, Common::Keymap *infoScreenKeyMap, const char *target) override;
void initGameState() override;
void borderScreen() override;
+ bool triggerWinCondition() override;
bool checkIfGameEnded() override;
void endGame() override;
diff --git a/engines/freescape/games/driller/amiga.cpp b/engines/freescape/games/driller/amiga.cpp
index be955ee1e9c..d942963ea4c 100644
--- a/engines/freescape/games/driller/amiga.cpp
+++ b/engines/freescape/games/driller/amiga.cpp
@@ -438,7 +438,9 @@ void DrillerEngine::drawAmigaAtariSTUI(Graphics::Surface *surface) {
_temporaryMessages.push_back(message);
_temporaryMessageDeadlines.push_back(deadline);
} else {
- if (_currentArea->_gasPocketRadius == 0)
+ if (_gameStateVars[32] == 18)
+ message = _messagesList[19];
+ else if (_currentArea->_gasPocketRadius == 0)
message = _messagesList[2];
else if (_drillStatusByArea[_currentArea->getAreaID()])
message = _messagesList[0];
diff --git a/engines/freescape/games/driller/driller.cpp b/engines/freescape/games/driller/driller.cpp
index e1894280cfa..7298f771d48 100644
--- a/engines/freescape/games/driller/driller.cpp
+++ b/engines/freescape/games/driller/driller.cpp
@@ -93,6 +93,8 @@ DrillerEngine::DrillerEngine(OSystem *syst, const ADGameDescription *gd) : Frees
_endArea = 127;
_endEntrance = 0;
+ _finalAreaWinConditionIndex = -1;
+ _amigaAtariEndGameStep = -1;
_borderExtra = nullptr;
_borderExtraTexture = nullptr;
@@ -305,6 +307,7 @@ void DrillerEngine::gotoArea(uint16 areaID, int entranceID) {
void DrillerEngine::loadAssets() {
FreescapeEngine::loadAssets();
+ _finalAreaWinConditionIndex = -1;
if (_areaMap.contains(18)) {
/*
We are going to inject a small script in the
@@ -328,6 +331,7 @@ void DrillerEngine::loadAssets() {
debugC(1, kFreescapeDebugParser, "%s", conditionSource.c_str());
_areaMap[18]->_conditions.push_back(instructions);
_areaMap[18]->_conditionSources.push_back(conditionSource);
+ _finalAreaWinConditionIndex = _areaMap[18]->_conditions.size() - 1;
}
_timeoutMessage = _messagesList[14];
@@ -876,6 +880,7 @@ void DrillerEngine::initGameState() {
FreescapeEngine::initGameState();
_quitConfirmCounter = 0;
_quitStartTicks = 0;
+ _amigaAtariEndGameStep = -1;
for (auto &it : _areaMap) {
if (_drillStatusByArea[it._key] != kDrillerNoRig)
@@ -910,19 +915,91 @@ bool DrillerEngine::checkIfGameEnded() {
if (_demoData[_demoIndex + 1] == 0x5f)
return true;
+ if ((isAmiga() || isAtariST()) && _gameStateControl == kFreescapeGameStatePlaying &&
+ _currentArea && _currentArea->getAreaID() == _endArea) {
+ stopMovement();
+ _endGameDelayTicks = 0;
+ _endGameKeyPressed = false;
+ _endGamePlayerEndArea = false;
+ _amigaAtariEndGameStep = -1;
+ _gameStateControl = kFreescapeGameStateEnd;
+ return true;
+ }
+
FreescapeEngine::checkIfGameEnded();
return false;
}
+bool DrillerEngine::triggerWinCondition() {
+ _gameStateVars[32] = 18;
+
+ stopMovement();
+ if (!_currentArea || _currentArea->getAreaID() != 18)
+ gotoArea(18, 20);
+
+ if ((isAmiga() || isAtariST()) && _currentArea && _currentArea->getAreaID() == _endArea) {
+ _endGameDelayTicks = 0;
+ _endGameKeyPressed = false;
+ _endGamePlayerEndArea = false;
+ _amigaAtariEndGameStep = -1;
+ _gameStateControl = kFreescapeGameStateEnd;
+ }
+
+ return true;
+}
+
void DrillerEngine::endGame() {
- FreescapeEngine::endGame();
+ if (isAmiga() || isAtariST()) {
+ _shootingFrames = 0;
+ _delayedShootObject = nullptr;
+
+ if (_amigaAtariEndGameStep < 0) {
+ stopMovement();
+ if (!_currentArea || _currentArea->getAreaID() != _endArea)
+ gotoArea(_endArea, _endEntrance);
+
+ // ENDGAME on Amiga/Atari ST switches to set 127 and then runs a 21-step
+ // flythrough. The original Amiga coordinates are stored at twice the engine
+ // position scale, so convert the CMVY/CMVZ deltas before applying them.
+ // The original routine is blocking, so keep the redraw pacing in the
+ // engine's wait loop instead of stretching it across separate frames.
+ const int areaScale = MAX<int>(_currentArea ? _currentArea->getScale() : 1, 1);
+ playSound(11, false, _soundFxHandle);
+ _position.z() -= 8000.0f / areaScale;
+ _position.y() += 3000.0f / areaScale;
+ _lastPosition = _position;
+ _endGamePlayerEndArea = false;
+ _amigaAtariEndGameStep = 0;
+
+ if (_gameStateVars[32] == 18) // All areas are complete
+ insertTemporaryMessage(_messagesList[19], INT_MIN);
+
+ waitInLoop(0); // Initial BT01 after switching to set 127
+ for (int step = 0; step < 21; step++) {
+ _position.z() += 400.0f / areaScale;
+ _position.y() -= 140.0f / areaScale;
+ _lastPosition = _position;
+ waitInLoop(5);
+ }
- if (!_endGamePlayerEndArea)
+ waitInLoop(0); // Final BT01 before LIFTUP
+ waitInLoop(102);
+ _endGamePlayerEndArea = true;
+ waitInLoop(500);
+ _gameStateControl = kFreescapeGameStateRestart;
+ }
+ _endGameKeyPressed = false;
return;
+ } else {
+ FreescapeEngine::endGame();
+
+ if (!_endGamePlayerEndArea)
+ return;
- if (_gameStateVars[32] == 18) { // All areas are complete
- insertTemporaryMessage(_messagesList[19], _countdown - 2);
- _gameStateVars[32] = 0; // Avoid repeating the message
+ if (_gameStateVars[32] == 18) { // All areas are complete
+ insertTemporaryMessage(_messagesList[19], _countdown - 2);
+ _gameStateVars[32] = 0; // Avoid repeating the message
+ }
}
if (_endGameKeyPressed) {
diff --git a/engines/freescape/games/driller/driller.h b/engines/freescape/games/driller/driller.h
index f414ec6990d..059b0bc1ea2 100644
--- a/engines/freescape/games/driller/driller.h
+++ b/engines/freescape/games/driller/driller.h
@@ -62,6 +62,7 @@ public:
void initKeymaps(Common::Keymap *engineKeyMap, Common::Keymap *infoScreenKeyMap, const char *target) override;
void initGameState() override;
+ bool triggerWinCondition() override;
bool checkIfGameEnded() override;
void endGame() override;
@@ -77,6 +78,8 @@ public:
Common::Error loadGameStreamExtended(Common::SeekableReadStream *stream) override;
private:
+ int _finalAreaWinConditionIndex;
+ int _amigaAtariEndGameStep;
bool drillDeployed(Area *area);
GeometricObject *_drillBase;
Math::Vector3d drillPosition();
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index 7ebd1105b91..7a81e20f5dc 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -204,6 +204,15 @@ bool EclipseEngine::checkIfGameEnded() {
return false;
}
+bool EclipseEngine::triggerWinCondition() {
+ setGameBit(16);
+ _endGameDelayTicks = 0;
+ _endGameKeyPressed = false;
+ _endGamePlayerEndArea = false;
+ _gameStateControl = kFreescapeGameStateEnd;
+ return true;
+}
+
void EclipseEngine::endGame() {
FreescapeEngine::endGame();
diff --git a/engines/freescape/games/eclipse/eclipse.h b/engines/freescape/games/eclipse/eclipse.h
index 5b66b8187fa..9d902e65795 100644
--- a/engines/freescape/games/eclipse/eclipse.h
+++ b/engines/freescape/games/eclipse/eclipse.h
@@ -139,6 +139,7 @@ public:
Common::Rect _saveGameArea;
Common::Rect _loadGameArea;
+ bool triggerWinCondition() override;
bool checkIfGameEnded() override;
void endGame() override;
void loadSoundsFx(Common::SeekableReadStream *file, int offset, int number) override;
diff --git a/engines/freescape/ui.cpp b/engines/freescape/ui.cpp
index 421f8bd917a..9f26f70a4de 100644
--- a/engines/freescape/ui.cpp
+++ b/engines/freescape/ui.cpp
@@ -45,6 +45,8 @@ void FreescapeEngine::waitInLoop(int maxWait) {
break;
if (isCastle() && isSpectrum() && getGameBit(31)) // Game is finished
break;
+ if (isDriller() && _gameStateVars[32] == 18) // Game is finished
+ break;
mousePos = event.mouse;
if (_demoMode)
More information about the Scummvm-git-logs
mailing list