[Scummvm-git-logs] scummvm branch-3-0 -> 86f01d4cca2fe38becf26aefeade2edcb420129e
neuromancer
noreply at scummvm.org
Thu Nov 20 08:19:05 UTC 2025
This automated email contains information about 14 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
79b87d5bbf FREESCAPE: avoid visual glitches with better offsets and near clip plane values
cb4d1a6a50 FREESCAPE: fix max size of water in eclipse for zx and c64
a883cadeb1 FREESCAPE: avoid visual glitches with better near clip plane values in castle
7278410bd6 FREESCAPE: make sure castle can trigger endgame in the zx release
d3e433e8bc FREESCAPE: improved endgame in the zx release
d5ce90cc0f FREESCAPE: removed undefined behavior in addSkanner (incorrect casting)
0a4bdbf6f9 FREESCAPE: slowed down cutscene in endgame in the zx release
7d86129281 FREESCAPE: allow color remapping to persist
c4bf3283e4 FREESCAPE: avoid freq == 0 for silence pc speaker commmand
d81164749b FREESCAPE: initial implementation for loading Virtual Worlds compressed data for Atari ST (driller)
9b81004df1 FREESCAPE: Fix build, by disabling the non-standard memmem() function
4cae3f0731 FREESCAPE: reimplemented memmem using cross-platform functions
aee6316dfa FREESCAPE: eclipse cpc color fixes
86f01d4cca FREESCAPE: better rendering of score in all the eclipse releases
Commit: 79b87d5bbf16f3c1112f15eb32e3db0db2264e07
https://github.com/scummvm/scummvm/commit/79b87d5bbf16f3c1112f15eb32e3db0db2264e07
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: avoid visual glitches with better offsets and near clip plane values
Changed paths:
engines/freescape/area.cpp
engines/freescape/freescape.cpp
engines/freescape/games/castle/castle.cpp
diff --git a/engines/freescape/area.cpp b/engines/freescape/area.cpp
index d3e675a288f..7dd57ee3efd 100644
--- a/engines/freescape/area.cpp
+++ b/engines/freescape/area.cpp
@@ -242,7 +242,7 @@ void Area::draw(Freescape::Renderer *gfx, uint32 animationTicks, Math::Vector3d
ObjectArray nonPlanarObjects;
Object *floor = nullptr;
Common::HashMap<Object *, float> sizes;
- float offset = 1.0 / _scale;
+ float offset = MAX(0.15, 1.0 / _scale);
for (auto &obj : _drawableObjects) {
if (!obj->isDestroyed() && !obj->isInvisible()) {
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 41db4af5a6e..308edcb0196 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -162,7 +162,9 @@ FreescapeEngine::FreescapeEngine(OSystem *syst, const ADGameDescription *gd)
_extraBuffer = nullptr;
_lastFrame = 0;
- _nearClipPlane = 2;
+ // The near clip plane of 2 is useful for Driller and Dark Side as they have open spaces without too much
+ // close-up detail. Other games need a smaller value to avoid clipping of nearby objects
+ _nearClipPlane = (isDriller() || isDark()) ? 2 : 0.5;
_farClipPlane = 8192 + 1802; // Added some extra distance to avoid flickering
// These depends on the specific game
@@ -821,7 +823,7 @@ Common::Error FreescapeEngine::run() {
if (saveSlot >= 0) { // load the savegame
initGameState();
loadGameState(saveSlot);
- }
+ }
g_system->showMouse(false);
g_system->lockMouse(true);
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 39ef9718d84..c9057345bad 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -339,7 +339,7 @@ void CastleEngine::gotoArea(uint16 areaID, int entranceID) {
assert(_areaMap.contains(areaID));
_currentArea = _areaMap[areaID];
_currentArea->show();
- _maxFallingDistance = MAX(32, _currentArea->getScale() * 16 - 2);
+ _maxFallingDistance = MAX(32, _currentArea->getScale() * 16 - 2);
if (entranceID > 0)
traverseEntrance(entranceID);
@@ -539,7 +539,7 @@ void CastleEngine::pressedKey(const int keycode) {
} else if (keycode == kActionFaceForward) {
_pitch = 0;
updateCamera();
- } else if (keycode == kActionActivate)
+ } else if (keycode == kActionActivate)
activate();
}
Commit: cb4d1a6a5040536969262e90bbce8331c6860a4c
https://github.com/scummvm/scummvm/commit/cb4d1a6a5040536969262e90bbce8331c6860a4c
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: fix max size of water in eclipse for zx and c64
Changed paths:
engines/freescape/games/eclipse/c64.cpp
engines/freescape/games/eclipse/eclipse.cpp
engines/freescape/games/eclipse/zx.cpp
diff --git a/engines/freescape/games/eclipse/c64.cpp b/engines/freescape/games/eclipse/c64.cpp
index 2e37c562f95..0842eca2ac6 100644
--- a/engines/freescape/games/eclipse/c64.cpp
+++ b/engines/freescape/games/eclipse/c64.cpp
@@ -29,6 +29,8 @@ namespace Freescape {
void EclipseEngine::initC64() {
_viewArea = Common::Rect(32, 32, 288, 136);
+
+ _maxEnergy = 35;
}
extern byte kC64Palette[16][3];
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index 9193db013e0..54e71fa788a 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -45,6 +45,12 @@ EclipseEngine::EclipseEngine(OSystem *syst, const ADGameDescription *gd) : Frees
_soundIndexCrushed = -1;
_soundIndexMissionComplete = -1;
+ _maxEnergy = 27;
+ _maxShield = 50;
+
+ _initialEnergy = 16;
+ _initialShield = 50;
+
if (isDOS())
initDOS();
else if (isCPC())
@@ -74,12 +80,6 @@ EclipseEngine::EclipseEngine(OSystem *syst, const ADGameDescription *gd) : Frees
_angleRotations.push_back(10);
_angleRotations.push_back(15);
- _maxEnergy = 27;
- _maxShield = 50;
-
- _initialEnergy = 16;
- _initialShield = 50;
-
_endArea = 1;
_endEntrance = 33;
diff --git a/engines/freescape/games/eclipse/zx.cpp b/engines/freescape/games/eclipse/zx.cpp
index 0747e51ad03..d793c4d0110 100644
--- a/engines/freescape/games/eclipse/zx.cpp
+++ b/engines/freescape/games/eclipse/zx.cpp
@@ -29,11 +29,11 @@ namespace Freescape {
void EclipseEngine::initZX() {
_viewArea = Common::Rect(56, 36, 265, 139);
- _maxEnergy = 63;
- _maxShield = 63;
+ _maxEnergy = 25;
+ _maxShield = 50;
_soundIndexShoot = 5;
- _soundIndexCollide = -1; // Scripted
+ _soundIndexCollide = -1; // Scripted
_soundIndexStepDown = 12;
_soundIndexStepUp = 12;
_soundIndexMenu = -1;
Commit: a883cadeb1040784e09ee87a6f30eba5e548413c
https://github.com/scummvm/scummvm/commit/a883cadeb1040784e09ee87a6f30eba5e548413c
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: avoid visual glitches with better near clip plane values in castle
Changed paths:
engines/freescape/games/castle/castle.cpp
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index c9057345bad..2f10f506552 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -341,6 +341,8 @@ void CastleEngine::gotoArea(uint16 areaID, int entranceID) {
_currentArea->show();
_maxFallingDistance = MAX(32, _currentArea->getScale() * 16 - 2);
+ _nearClipPlane = _currentArea->isOutside() ? 2 : 0.5;
+
if (entranceID > 0)
traverseEntrance(entranceID);
Commit: 7278410bd637e49f3ee5a632f606eb1aad410920
https://github.com/scummvm/scummvm/commit/7278410bd637e49f3ee5a632f606eb1aad410920
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: make sure castle can trigger endgame in the zx release
Changed paths:
engines/freescape/language/instruction.cpp
engines/freescape/movement.cpp
diff --git a/engines/freescape/language/instruction.cpp b/engines/freescape/language/instruction.cpp
index acd779c3a1d..bd25e235c5a 100644
--- a/engines/freescape/language/instruction.cpp
+++ b/engines/freescape/language/instruction.cpp
@@ -108,7 +108,8 @@ bool FreescapeEngine::executeObjectConditions(GeometricObject *obj, bool shot, b
_syncSound = false;
_objExecutingCodeSize = collided ? obj->getSize() : Math::Vector3d();
if (collided) {
- clearGameBit(31); // We collided with something that has code
+ if (!isCastle())
+ clearGameBit(31); // We collided with something that has code
debugC(1, kFreescapeDebugCode, "Executing with collision flag: %s", obj->_conditionSource.c_str());
} else if (shot)
debugC(1, kFreescapeDebugCode, "Executing with shot flag: %s", obj->_conditionSource.c_str());
@@ -368,7 +369,7 @@ void FreescapeEngine::executeExecute(FCLInstruction &instruction) {
if (!obj) {
debugC(1, kFreescapeDebugCode, "WARNING: executing instructions from a non-existent object %d", objId);
return;
- }
+ }
assert(obj);
FCLInstructionVector &condition = ((Entrance *)obj)->_condition;
executeCode(condition, true, true, true, true);
diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp
index d527b33dd60..ed4c5f7a961 100644
--- a/engines/freescape/movement.cpp
+++ b/engines/freescape/movement.cpp
@@ -329,7 +329,8 @@ bool FreescapeEngine::rise() {
if (_currentArea->getAreaID() == previousAreaID) {
_playerHeightNumber--;
changePlayerHeight(_playerHeightNumber);
- setGameBit(31);
+ if (!isCastle())
+ setGameBit(31);
}
} else
result = true;
@@ -438,7 +439,8 @@ void FreescapeEngine::updatePlayerMovementClassic(float deltaTime) {
if (_currentArea->getAreaID() == previousAreaID)
executeMovementConditions();
_gotoExecuted = false;
- clearGameBit(31);
+ if (!isCastle())
+ clearGameBit(31);
}
void FreescapeEngine::updatePlayerMovementSmooth(float deltaTime) {
@@ -486,7 +488,8 @@ void FreescapeEngine::updatePlayerMovementSmooth(float deltaTime) {
executeMovementConditions();
}
_gotoExecuted = false;
- clearGameBit(31);
+ if (!isCastle())
+ clearGameBit(31);
}
void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
@@ -510,7 +513,7 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
if (_flyMode) {
if ((lastPosition - newPosition).length() < 1) { // Something is blocking the player
- if (!executed)
+ if (!executed && !isCastle())
setGameBit(31);
playSound(_soundIndexCollide, false, _movementSoundHandle);
}
@@ -535,7 +538,7 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
if (_lastPosition.y() < newPosition.y())
isSteppingUp = true;
- if (!executed)
+ if (!executed && !isCastle())
setGameBit(31);
isCollidingWithWall = true;
@@ -560,7 +563,7 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
_endGameDelayTicks = 60 * 5;
if (isEclipse()) // No need for an variable index, since these are special types of sound
playSoundFx(0, true);
- else
+ else
playSound(_soundIndexFall, false, _movementSoundHandle);
if (_hasFallen)
@@ -570,7 +573,7 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
if (!_hasFallen && fallen > 0) {
isSteppingDown = true;
// Position in Y was changed, let's re-run effects
- runCollisionConditions(_lastPosition, newPosition);
+ runCollisionConditions(_lastPosition, newPosition);
}
if (isSteppingUp && (newPosition - _lastPosition).length() <= 1) {
Commit: d3e433e8bc7c05ab90482bab1bc23cfe5ed9257d
https://github.com/scummvm/scummvm/commit/d3e433e8bc7c05ab90482bab1bc23cfe5ed9257d
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: improved endgame in the zx release
Changed paths:
engines/freescape/games/castle/castle.cpp
engines/freescape/games/castle/zx.cpp
engines/freescape/ui.cpp
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 2f10f506552..62d90440f5d 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -483,7 +483,8 @@ void CastleEngine::endGame() {
if (isDOS()) {
drawFullscreenEndGameAndWait();
- }
+ } else
+ drawFullscreenGameOverAndWait();
} else {
drawFullscreenGameOverAndWait();
}
@@ -870,11 +871,18 @@ void CastleEngine::drawFullscreenGameOverAndWait() {
playSound(9, false, _soundFxHandle);
}
+ if (isSpectrum() && getGameBit(31)) {
+ insertTemporaryMessage(_messagesList[5], _countdown - 1);
+ }
+
while (!shouldQuit() && cont) {
if (_temporaryMessageDeadlines.empty()) {
insertTemporaryMessage(scoreString, _countdown - 2);
insertTemporaryMessage(spiritsDestroyedString, _countdown - 4);
insertTemporaryMessage(keysCollectedString, _countdown - 6);
+ if (isSpectrum() && getGameBit(31)) {
+ insertTemporaryMessage(_messagesList[5], _countdown - 8);
+ }
}
while (_eventManager->pollEvent(event)) {
@@ -1563,6 +1571,9 @@ void CastleEngine::drawLiftingGate(Graphics::Surface *surface) {
}
void CastleEngine::drawDroppingGate(Graphics::Surface *surface) {
+ if (isSpectrum() && getGameBit(31))
+ return; // No gate dropping when the player escaped
+
if (_droppingGateStartTicks <= 0)
return;
diff --git a/engines/freescape/games/castle/zx.cpp b/engines/freescape/games/castle/zx.cpp
index 2623cf9f901..6eb5354714b 100644
--- a/engines/freescape/games/castle/zx.cpp
+++ b/engines/freescape/games/castle/zx.cpp
@@ -33,7 +33,7 @@ void CastleEngine::initZX() {
_soundIndexCollide = 3;
_soundIndexStartFalling = -1;
_soundIndexFallen = 1;
- _soundIndexFall = 6;
+ _soundIndexFall = 6;
_soundIndexStepUp = 12;
_soundIndexStepDown = 12;
_soundIndexMenu = 3;
@@ -259,7 +259,10 @@ void CastleEngine::drawZXUI(Graphics::Surface *surface) {
_temporaryMessageDeadlines.push_back(deadline);
} else {
if (_gameStateControl != kFreescapeGameStateEnd) {
- drawStringInSurface(_currentArea->_name, 120, 179, front, black, surface);
+ if (getGameBit(31)) { // The final cutscene is playing but it is not ended yet
+ drawStringInSurface(_messagesList[5], 120, 179, front, black, surface); // "You did it!"
+ } else
+ drawStringInSurface(_currentArea->_name, 120, 179, front, black, surface);
}
}
diff --git a/engines/freescape/ui.cpp b/engines/freescape/ui.cpp
index 78621ffc2d2..d4712ff1898 100644
--- a/engines/freescape/ui.cpp
+++ b/engines/freescape/ui.cpp
@@ -41,6 +41,8 @@ void FreescapeEngine::waitInLoop(int maxWait) {
case Common::EVENT_MOUSEMOVE:
if (_hasFallen || _playerWasCrushed || _gameStateControl != kFreescapeGameStatePlaying)
break;
+ if (isCastle() && isSpectrum() && getGameBit(31)) // Game is finished
+ break;
mousePos = event.mouse;
if (_demoMode)
Commit: d5ce90cc0fa93e0a66b06feba867b1208ecb0985
https://github.com/scummvm/scummvm/commit/d5ce90cc0fa93e0a66b06feba867b1208ecb0985
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: removed undefined behavior in addSkanner (incorrect casting)
Changed paths:
engines/freescape/games/dark/dark.cpp
engines/freescape/games/driller/driller.cpp
diff --git a/engines/freescape/games/dark/dark.cpp b/engines/freescape/games/dark/dark.cpp
index caab7991a06..56624a0a7d0 100644
--- a/engines/freescape/games/dark/dark.cpp
+++ b/engines/freescape/games/dark/dark.cpp
@@ -459,32 +459,32 @@ void DarkEngine::addSkanner(Area *area) {
debugC(1, kFreescapeDebugParser, "Adding group %d", id);
area->addGroupFromArea(id, _areaMap[255]);
} else {
- GeometricObject *obj = nullptr;
+ Object *obj = nullptr;
id = 248;
// If first object is already added, do not re-add any
if (area->objectWithID(id) != nullptr)
return;
debugC(1, kFreescapeDebugParser, "Adding object %d to room structure", id);
- obj = (GeometricObject *)_areaMap[255]->objectWithID(id);
+ obj = _areaMap[255]->objectWithID(id);
assert(obj);
- obj = (GeometricObject *)obj->duplicate();
+ obj = obj->duplicate();
obj->makeInvisible();
area->addObject(obj);
id = 249;
debugC(1, kFreescapeDebugParser, "Adding object %d to room structure", id);
- obj = (GeometricObject *)_areaMap[255]->objectWithID(id);
+ obj = _areaMap[255]->objectWithID(id);
assert(obj);
- obj = (GeometricObject *)obj->duplicate();
+ obj = obj->duplicate();
obj->makeInvisible();
area->addObject(obj);
id = 250;
debugC(1, kFreescapeDebugParser, "Adding object %d to room structure", id);
- obj = (GeometricObject *)_areaMap[255]->objectWithID(id);
+ obj = _areaMap[255]->objectWithID(id);
assert(obj);
- obj = (GeometricObject *)obj->duplicate();
+ obj = obj->duplicate();
obj->makeInvisible();
area->addObject(obj);
}
diff --git a/engines/freescape/games/driller/driller.cpp b/engines/freescape/games/driller/driller.cpp
index af291a7ed8d..55083aff94a 100644
--- a/engines/freescape/games/driller/driller.cpp
+++ b/engines/freescape/games/driller/driller.cpp
@@ -727,7 +727,7 @@ bool DrillerEngine::checkDrill(const Math::Vector3d position) {
void DrillerEngine::addSkanner(Area *area) {
debugC(1, kFreescapeDebugParser, "Adding skanner to area: %d", area->getAreaID());
- GeometricObject *obj = nullptr;
+ Object *obj = nullptr;
int16 id;
id = 248;
@@ -736,25 +736,25 @@ void DrillerEngine::addSkanner(Area *area) {
return;
debugC(1, kFreescapeDebugParser, "Adding object %d to room structure", id);
- obj = (GeometricObject *)_areaMap[255]->objectWithID(id);
+ obj = _areaMap[255]->objectWithID(id);
assert(obj);
- obj = (GeometricObject *)obj->duplicate();
+ obj = obj->duplicate();
obj->makeInvisible();
area->addObject(obj);
id = 249;
debugC(1, kFreescapeDebugParser, "Adding object %d to room structure", id);
- obj = (GeometricObject *)_areaMap[255]->objectWithID(id);
+ obj = _areaMap[255]->objectWithID(id);
assert(obj);
- obj = (GeometricObject *)obj->duplicate();
+ obj = obj->duplicate();
obj->makeInvisible();
area->addObject(obj);
id = 250;
debugC(1, kFreescapeDebugParser, "Adding object %d to room structure", id);
- obj = (GeometricObject *)_areaMap[255]->objectWithID(id);
+ obj = _areaMap[255]->objectWithID(id);
assert(obj);
- obj = (GeometricObject *)obj->duplicate();
+ obj = obj->duplicate();
obj->makeInvisible();
area->addObject(obj);
}
Commit: 0a4bdbf6f96e602b12bf8cef92f446a4dce2663b
https://github.com/scummvm/scummvm/commit/0a4bdbf6f96e602b12bf8cef92f446a4dce2663b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: slowed down cutscene in endgame in the zx release
Changed paths:
engines/freescape/language/instruction.cpp
diff --git a/engines/freescape/language/instruction.cpp b/engines/freescape/language/instruction.cpp
index bd25e235c5a..aa646daca7c 100644
--- a/engines/freescape/language/instruction.cpp
+++ b/engines/freescape/language/instruction.cpp
@@ -355,6 +355,8 @@ void FreescapeEngine::executeRedraw(FCLInstruction &instruction) {
if (isEclipse2() && _currentArea->getAreaID() == _startArea && _gameStateControl == kFreescapeGameStateStart)
delay = delay * 10;
+ if (isCastle() && isSpectrum() && getGameBit(31))
+ delay = delay * 15; // Slow down redraws when the final cutscene is playing
waitInLoop(delay);
}
Commit: 7d86129281713ad8c27d1861fb323e1687a6ed48
https://github.com/scummvm/scummvm/commit/7d86129281713ad8c27d1861fb323e1687a6ed48
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: allow color remapping to persist
Changed paths:
engines/freescape/freescape.cpp
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 308edcb0196..6909f2850d5 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -475,6 +475,11 @@ void FreescapeEngine::drawFrame() {
drawSensorShoot(sensor);
}
_underFireFrames--;
+
+ if (_underFireFrames == 0) {
+ _currentArea->unremapColor(_currentArea->_usualBackgroundColor);
+ _currentArea->unremapColor(_currentArea->_skyColor);
+ }
}
if (_shootingFrames > 0) {
@@ -490,11 +495,6 @@ void FreescapeEngine::drawFrame() {
drawBorder();
drawUI();
-
- if (_underFireFrames == 0) {
- _currentArea->unremapColor(_currentArea->_usualBackgroundColor);
- _currentArea->unremapColor(_currentArea->_skyColor);
- }
}
void FreescapeEngine::pressedKey(const int keycode) {}
Commit: c4bf3283e4f812091fd6f22112c4ad7cc8ccd687
https://github.com/scummvm/scummvm/commit/c4bf3283e4f812091fd6f22112c4ad7cc8ccd687
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: avoid freq == 0 for silence pc speaker commmand
Changed paths:
engines/freescape/sound.cpp
diff --git a/engines/freescape/sound.cpp b/engines/freescape/sound.cpp
index f7f9bf24083..e03642c436c 100644
--- a/engines/freescape/sound.cpp
+++ b/engines/freescape/sound.cpp
@@ -508,13 +508,13 @@ void FreescapeEngine::playSoundZX(Common::Array<soundUnitZX> *data, Audio::Sound
if (value.isRaw) {
debugC(1, kFreescapeDebugMedia, "raw hz: %f, duration: %d", value.rawFreq, value.rawLengthus);
if (value.rawFreq == 0) {
- _speaker->playQueue(Audio::PCSpeaker::kWaveFormSilence, 0, 5 * value.rawLengthus);
+ _speaker->playQueue(Audio::PCSpeaker::kWaveFormSilence, 1, 5 * value.rawLengthus);
continue;
}
_speaker->playQueue(Audio::PCSpeaker::kWaveFormSquare, value.rawFreq, 5 * value.rawLengthus);
} else {
if (value.freqTimesSeconds == 0 && value.tStates == 0) {
- _speaker->playQueue(Audio::PCSpeaker::kWaveFormSilence, 0, 1000 * value.multiplier);
+ _speaker->playQueue(Audio::PCSpeaker::kWaveFormSilence, 1, 1000 * value.multiplier);
continue;
}
Commit: d81164749b399a3c35f27574558affa38bddee36
https://github.com/scummvm/scummvm/commit/d81164749b399a3c35f27574558affa38bddee36
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: initial implementation for loading Virtual Worlds compressed data for Atari ST (driller)
Changed paths:
engines/freescape/detection.cpp
engines/freescape/games/driller/atari.cpp
engines/freescape/games/driller/driller.h
diff --git a/engines/freescape/detection.cpp b/engines/freescape/detection.cpp
index df1fb850cb8..0f73184a86b 100644
--- a/engines/freescape/detection.cpp
+++ b/engines/freescape/detection.cpp
@@ -161,7 +161,7 @@ static const ADGameDescription gameDescriptions[] = {
{
// Virtual Worlds release
"driller",
- "This release requires unpacking, check the wiki for instructions: https://wiki.scummvm.org/index.php?title=Driller#AtariST_releases",
+ "",
{
{"d.pak", 0, "607b44b9d31e0da5668b653e03d25efe", 706},
{"dril.all", 0, "65277222effa1eb4d73b234245001d75", 158158},
@@ -169,7 +169,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformAtariST,
- ADGF_UNSUPPORTED,
+ ADGF_UNSTABLE | GF_ATARI_BUDGET,
GUIO3(GUIO_NOMIDI, GUIO_RENDERATARIST, GAMEOPTION_AUTOMATIC_DRILLING)
},
{
diff --git a/engines/freescape/games/driller/atari.cpp b/engines/freescape/games/driller/atari.cpp
index 188898b9c0d..90af8fbeff0 100644
--- a/engines/freescape/games/driller/atari.cpp
+++ b/engines/freescape/games/driller/atari.cpp
@@ -20,6 +20,7 @@
*/
#include "common/file.h"
#include "common/memstream.h"
+#include "common/endian.h"
#include "freescape/freescape.h"
#include "freescape/games/driller/driller.h"
@@ -27,6 +28,149 @@
namespace Freescape {
+Common::SeekableReadStream *DrillerEngine::decryptFileAtariVirtualWorlds(const Common::Path &filename) {
+ Common::File file;
+ if (!file.open(filename)) {
+ error("Failed to open %s", filename.toString().c_str());
+ }
+ const int size = file.size();
+ byte *data = (byte *)malloc(size);
+ file.read(data, size);
+
+ int start = 0;
+ int valid_offset = -1;
+ int chunk_size = 0;
+
+ while (true) {
+ byte *found = (byte *)memmem(data + start, size - start, "CBCP", 4);
+ if (!found) break;
+
+ int idx = found - data;
+ if (idx + 8 <= size) {
+ int sz = READ_BE_UINT32(data + idx + 4);
+ if (sz > 0 && sz < size + 0x20000) {
+ valid_offset = idx;
+ chunk_size = sz;
+ }
+ }
+ start = idx + 1;
+ }
+
+ if (valid_offset == -1) {
+ error("No valid CBCP chunk found in %s", filename.toString().c_str());
+ }
+
+ const byte *payload = data + valid_offset + 8;
+ const int payload_size = chunk_size;
+
+ if (payload_size < 12) {
+ error("Payload too short in %s", filename.toString().c_str());
+ }
+
+ uint32 bit_buf_init = READ_BE_UINT32(payload + payload_size - 12);
+ uint32 checksum_init = READ_BE_UINT32(payload + payload_size - 8);
+ uint32 decoded_size = READ_BE_UINT32(payload + payload_size - 4);
+
+ byte *out_buffer = (byte *)malloc(decoded_size);
+ int dst_idx = decoded_size;
+
+ struct BitStream {
+ const byte *_src_data;
+ int _src_idx;
+ uint32 _bit_buffer;
+ uint32 _checksum;
+ int _refill_carry;
+
+ BitStream(const byte *src_data, int start_idx, uint32 bit_buffer, uint32 checksum) :
+ _src_data(src_data), _src_idx(start_idx), _bit_buffer(bit_buffer), _checksum(checksum), _refill_carry(0) {}
+
+ void refill() {
+ if (_src_idx < 0) {
+ _refill_carry = 0;
+ _bit_buffer = 0x80000000;
+ return;
+ }
+ uint32 val = READ_BE_UINT32(_src_data + _src_idx);
+ _src_idx -= 4;
+ _checksum ^= val;
+ _refill_carry = val & 1;
+ _bit_buffer = (val >> 1) | 0x80000000;
+ }
+
+ int getBits(int count) {
+ uint32 result = 0;
+ for (int i = 0; i < count; ++i) {
+ int carry = _bit_buffer & 1;
+ _bit_buffer >>= 1;
+ if (_bit_buffer == 0) {
+ refill();
+ carry = _refill_carry;
+ }
+ result = (result << 1) | carry;
+ }
+ return result;
+ }
+ };
+
+ int src_idx = payload_size - 16;
+ uint32 checksum = checksum_init ^ bit_buf_init;
+ BitStream bs(payload, src_idx, bit_buf_init, checksum);
+
+ while (dst_idx > 0) {
+ if (bs.getBits(1) == 0) {
+ if (bs.getBits(1) == 1) {
+ int offset = bs.getBits(8);
+ for (int i = 0; i < 2; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = out_buffer[dst_idx + offset];
+ }
+ }
+ } else {
+ int count = bs.getBits(3) + 1;
+ for (int i = 0; i < count; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = bs.getBits(8);
+ }
+ }
+ }
+ } else {
+ int tag = bs.getBits(2);
+ if (tag == 3) {
+ int count = bs.getBits(8) + 9;
+ for (int i = 0; i < count; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = bs.getBits(8);
+ }
+ }
+ } else if (tag == 2) {
+ int length = bs.getBits(8) + 1;
+ int offset = bs.getBits(12);
+ for (int i = 0; i < length; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = out_buffer[dst_idx + offset];
+ }
+ }
+ } else {
+ int bits_offset = 9 + tag;
+ int length = 3 + tag;
+ int offset = bs.getBits(bits_offset);
+ for (int i = 0; i < length; ++i) {
+ dst_idx--;
+ if (dst_idx >= 0) {
+ out_buffer[dst_idx] = out_buffer[dst_idx + offset];
+ }
+ }
+ }
+ }
+ }
+ free(data);
+ return new Common::MemoryReadStream(out_buffer, decoded_size);
+}
+
Common::SeekableReadStream *DrillerEngine::decryptFileAtari(const Common::Path &filename) {
Common::File file;
file.open(filename);
@@ -61,9 +205,9 @@ Common::SeekableReadStream *DrillerEngine::decryptFileAtari(const Common::Path &
}
void DrillerEngine::loadAssetsAtariFullGame() {
-
+ Common::SeekableReadStream *stream = nullptr;
if (_variant & GF_ATARI_RETAIL) {
- Common::SeekableReadStream *stream = decryptFileAtari("x.prg");
+ stream = decryptFileAtari("x.prg");
_border = loadAndConvertNeoImage(stream, 0x14b96);
_borderExtra = loadAndConvertNeoImage(stream, 0x1c916);
@@ -84,8 +228,10 @@ void DrillerEngine::loadAssetsAtariFullGame() {
Common::File file;
file.open("x.prg");
- if (!file.isOpen())
- error("Failed to open 'x.prg' executable for AtariST");
+ if (!file.isOpen()) {
+ stream = decryptFileAtariVirtualWorlds("dril.all");
+ } else
+ stream = &file;
if (isSpaceStationOblivion()) {
_border = loadAndConvertNeoImage(&file, 0x13544);
@@ -104,23 +250,24 @@ void DrillerEngine::loadAssetsAtariFullGame() {
loadPalettes(&file, 0x296fa - 0x1d6);
loadSoundsFx(&file, 0x30da6 - 0x1d6, 25);
} else {
- _border = loadAndConvertNeoImage(&file, 0x1371a);
- _title = loadAndConvertNeoImage(&file, 0x396);
+ _border = loadAndConvertNeoImage(stream, 0x1371a);
+ _title = loadAndConvertNeoImage(stream, 0x396);
- loadFonts(&file, 0x8a32);
+ loadFonts(stream, 0x8a32);
Common::Array<Graphics::ManagedSurface *> chars;
- chars = getCharsAmigaAtariInternal(8, 8, -3, 33, 32, &file, 0x8a32 + 112 * 33 + 1, 100);
+ chars = getCharsAmigaAtariInternal(8, 8, -3, 33, 32, stream, 0x8a32 + 112 * 33 + 1, 100);
_fontSmall = Font(chars);
_fontSmall.setCharWidth(5);
- loadMessagesFixedSize(&file, 0xc5d8, 14, 20);
- loadGlobalObjects(&file, 0xbccc, 8);
- load8bitBinary(&file, 0x29b3c, 16);
- loadPalettes(&file, 0x296fa);
- loadSoundsFx(&file, 0x30da6, 25);
+ loadMessagesFixedSize(stream, 0xc5d8, 14, 20);
+ loadGlobalObjects(stream, 0xbccc, 8);
+ load8bitBinary(stream, 0x29b3c, 16);
+ loadPalettes(stream, 0x296fa);
+ loadSoundsFx(stream, 0x30da6, 25);
}
- }
+ } else
+ error("Unknown Atari ST Driller variant");
for (auto &area : _areaMap) {
// Center and pad each area name so we do not have to do it at each frame
diff --git a/engines/freescape/games/driller/driller.h b/engines/freescape/games/driller/driller.h
index e39c7b53492..5d0ab47deef 100644
--- a/engines/freescape/games/driller/driller.h
+++ b/engines/freescape/games/driller/driller.h
@@ -124,6 +124,7 @@ private:
Texture *_borderExtraTexture;
Common::SeekableReadStream *decryptFileAtari(const Common::Path &filename);
+ Common::SeekableReadStream *decryptFileAtariVirtualWorlds(const Common::Path &filename);
};
enum DrillerReleaseFlags {
Commit: 9b81004df168f49385260a6b139de54a91138e68
https://github.com/scummvm/scummvm/commit/9b81004df168f49385260a6b139de54a91138e68
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: Fix build, by disabling the non-standard memmem() function
memmem() is non-standard and does not exist on Windows, unfortunately.
Comment out its usage, until a viable alternative can be found, to fix
the build.
Reference:
https://codereview.stackexchange.com/questions/182156/memmem-on-windows
Changed paths:
engines/freescape/games/driller/atari.cpp
diff --git a/engines/freescape/games/driller/atari.cpp b/engines/freescape/games/driller/atari.cpp
index 90af8fbeff0..01350807543 100644
--- a/engines/freescape/games/driller/atari.cpp
+++ b/engines/freescape/games/driller/atari.cpp
@@ -42,7 +42,7 @@ Common::SeekableReadStream *DrillerEngine::decryptFileAtariVirtualWorlds(const C
int chunk_size = 0;
while (true) {
- byte *found = (byte *)memmem(data + start, size - start, "CBCP", 4);
+ byte *found = nullptr;//(byte *)memmem(data + start, size - start, "CBCP", 4); // FIXME: memmem() is non-standard
if (!found) break;
int idx = found - data;
Commit: 4cae3f0731ccff62e0c79b1293ab6907ed8366b4
https://github.com/scummvm/scummvm/commit/4cae3f0731ccff62e0c79b1293ab6907ed8366b4
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: reimplemented memmem using cross-platform functions
Changed paths:
engines/freescape/games/driller/atari.cpp
diff --git a/engines/freescape/games/driller/atari.cpp b/engines/freescape/games/driller/atari.cpp
index 01350807543..70628bcc34c 100644
--- a/engines/freescape/games/driller/atari.cpp
+++ b/engines/freescape/games/driller/atari.cpp
@@ -28,6 +28,25 @@
namespace Freescape {
+namespace {
+// A simple implementation of memmem, which is a non-standard GNU extension.
+const void *local_memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) {
+ if (needle_len == 0) {
+ return haystack;
+ }
+ if (haystack_len < needle_len) {
+ return nullptr;
+ }
+ const char *h = (const char *)haystack;
+ for (size_t i = 0; i <= haystack_len - needle_len; ++i) {
+ if (memcmp(h + i, needle, needle_len) == 0) {
+ return h + i;
+ }
+ }
+ return nullptr;
+}
+} // namespace
+
Common::SeekableReadStream *DrillerEngine::decryptFileAtariVirtualWorlds(const Common::Path &filename) {
Common::File file;
if (!file.open(filename)) {
@@ -42,7 +61,7 @@ Common::SeekableReadStream *DrillerEngine::decryptFileAtariVirtualWorlds(const C
int chunk_size = 0;
while (true) {
- byte *found = nullptr;//(byte *)memmem(data + start, size - start, "CBCP", 4); // FIXME: memmem() is non-standard
+ const byte *found = (const byte *)local_memmem(data + start, size - start, "CBCP", 4);
if (!found) break;
int idx = found - data;
Commit: aee6316dfafd7d3c16d3ebd8baf815866d1efb35
https://github.com/scummvm/scummvm/commit/aee6316dfafd7d3c16d3ebd8baf815866d1efb35
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: eclipse cpc color fixes
Changed paths:
engines/freescape/games/eclipse/cpc.cpp
engines/freescape/games/palettes.cpp
diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index d2e41a2581a..b3182388137 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -190,13 +190,11 @@ void EclipseEngine::drawCPCUI(Graphics::Surface *surface) {
drawIndicator(surface, 45, 4, 12);
drawEclipseIndicator(surface, 228, 0, front, other);
- uint32 blue = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0x55, 0x55, 0xFF);
-
Common::Rect jarBackground(124, 165, 148, 192);
surface->fillRect(jarBackground, back);
Common::Rect jarWater(124, 192 - _gameStateVars[k8bitVariableEnergy], 148, 192);
- surface->fillRect(jarWater, blue);
+ surface->fillRect(jarWater, color);
surface->fillRect(Common::Rect(225, 168, 235, 187), front);
drawCompass(surface, 229, 177, _yaw, 10, back);
diff --git a/engines/freescape/games/palettes.cpp b/engines/freescape/games/palettes.cpp
index c666fc09d3a..207fe154153 100644
--- a/engines/freescape/games/palettes.cpp
+++ b/engines/freescape/games/palettes.cpp
@@ -101,14 +101,14 @@ byte kDrillerCPCPalette[32][3] = {
{0xff, 0x00, 0x80}, // 5
{0x00, 0x80, 0x80}, // 6
{0xff, 0x80, 0x80}, // 7
- {0x11, 0x22, 0x33},
+ {0x80, 0x00, 0xff}, // 8
{0x00, 0x80, 0x00}, // 9
{0xff, 0xff, 0x00}, // 10
{0xff, 0xff, 0xff}, // 11
{0xff, 0x00, 0x00}, // 12
{0x11, 0x22, 0x33},
{0xff, 0x80, 0x00}, // 14
- {0x11, 0x22, 0x33},
+ {0xff, 0x80, 0xff}, // 15
{0x11, 0x22, 0x33},
{0x00, 0xff, 0x80}, // 17
{0x00, 0xff, 0x00}, // 18
@@ -122,7 +122,7 @@ byte kDrillerCPCPalette[32][3] = {
{0x80, 0xff, 0x00}, // 26
{0x00, 0xff, 0xff}, // 27
{0x80, 0x00, 0x00}, // 28
- {0x11, 0x22, 0x33},
+ {0x80, 0x00, 0xff}, // 29
{0x80, 0x80, 0x00}, // 30
{0x80, 0x80, 0xff}, // 31
};
Commit: 86f01d4cca2fe38becf26aefeade2edcb420129e
https://github.com/scummvm/scummvm/commit/86f01d4cca2fe38becf26aefeade2edcb420129e
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-11-20T09:14:51+01:00
Commit Message:
FREESCAPE: better rendering of score in all the eclipse releases
Changed paths:
engines/freescape/games/eclipse/c64.cpp
engines/freescape/games/eclipse/cpc.cpp
engines/freescape/games/eclipse/dos.cpp
engines/freescape/games/eclipse/eclipse.cpp
engines/freescape/games/eclipse/eclipse.h
engines/freescape/games/eclipse/zx.cpp
diff --git a/engines/freescape/games/eclipse/c64.cpp b/engines/freescape/games/eclipse/c64.cpp
index 0842eca2ac6..e9e670585f5 100644
--- a/engines/freescape/games/eclipse/c64.cpp
+++ b/engines/freescape/games/eclipse/c64.cpp
@@ -134,8 +134,7 @@ void EclipseEngine::drawC64UI(Graphics::Surface *surface) {
} else if (!_currentAreaMessages.empty())
drawStringInSurface(_currentArea->_name, 104, 138, back, yellow, surface);
- Common::String encodedScoreStr = getScoreString(score);
- drawStringInSurface(encodedScoreStr, 128, 7, black, white, surface);
+ drawScoreString(score, 128, 7, black, white, surface);
Common::String shieldStr = Common::String::format("%d", shield);
diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index b3182388137..0428bdb884c 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -166,8 +166,7 @@ void EclipseEngine::drawCPCUI(Graphics::Surface *surface) {
} else if (!_currentAreaMessages.empty())
drawStringInSurface(_currentArea->_name, 102, 135, back, front, surface);
- Common::String encodedScoreStr = getScoreString(score);
- drawStringInSurface(encodedScoreStr, 136, 6, back, other, surface);
+ drawScoreString(score, 136, 6, back, other, surface);
int x = 171;
if (shield < 10)
diff --git a/engines/freescape/games/eclipse/dos.cpp b/engines/freescape/games/eclipse/dos.cpp
index 91e0c2b3c8f..c77c05a58e9 100644
--- a/engines/freescape/games/eclipse/dos.cpp
+++ b/engines/freescape/games/eclipse/dos.cpp
@@ -117,8 +117,7 @@ void EclipseEngine::drawDOSUI(Graphics::Surface *surface) {
} else if (!_currentAreaMessages.empty())
drawStringInSurface(_currentArea->_name, 102, 135, black, yellow, surface);
- Common::String encodedScoreStr = getScoreString(score);
- drawStringInSurface(encodedScoreStr, 136, 6, black, white, surface);
+ drawScoreString(score, 136, 6, black, white, surface);
int x = 171;
if (shield < 10)
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index 54e71fa788a..c1ce1017846 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -723,24 +723,31 @@ void EclipseEngine::drawSensorShoot(Sensor *sensor) {
}
}
-Common::String EclipseEngine::getScoreString(int score) {
+void EclipseEngine::drawScoreString(int score, int x, int y, uint32 front, uint32 back, Graphics::Surface *surface) {
Common::String scoreStr = Common::String::format("%07d", score);
if (isDOS() || isCPC() || isSpectrum()) {
scoreStr = shiftStr(scoreStr, 'Z' - '0' + 1);
- if (_renderMode == Common::RenderMode::kRenderEGA || isSpectrum())
- return scoreStr;
+ if (_renderMode == Common::RenderMode::kRenderEGA || isSpectrum()) {
+ drawStringInSurface(scoreStr, x, y, front, back, surface);
+ return;
+ }
+
}
- Common::String encodedScoreStr;
+
+ // Start in x,y and draw each digit, from left to right, adding a gap every 3 digits
+ int gapSize = isC64() ? 8 : 4;
for (int i = 0; i < int(scoreStr.size()); i++) {
- encodedScoreStr.insertChar(scoreStr[int(scoreStr.size()) - i - 1], 0);
- if ((i + 1) % 3 == 0 && i > 0)
- encodedScoreStr.insertChar(',', 0);
+ drawStringInSurface(Common::String(scoreStr[i]), x, y, front, back, surface);
+ x += 8;
+ if ((i - scoreStr.size() + 1) % 3 == 1)
+ x += gapSize;
}
- return encodedScoreStr;
+
}
+
void EclipseEngine::updateTimeVariables() {
if (isEclipse2() && _gameStateControl == kFreescapeGameStateStart) {
executeLocalGlobalConditions(false, true, false);
diff --git a/engines/freescape/games/eclipse/eclipse.h b/engines/freescape/games/eclipse/eclipse.h
index 795cb57dd07..0532dea216e 100644
--- a/engines/freescape/games/eclipse/eclipse.h
+++ b/engines/freescape/games/eclipse/eclipse.h
@@ -92,6 +92,7 @@ public:
void drawCompass(Graphics::Surface *surface, int x, int y, double degrees, double magnitude, uint32 color);
void drawEclipseIndicator(Graphics::Surface *surface, int x, int y, uint32 color1, uint32 color2);
Common::String getScoreString(int score);
+ void drawScoreString(int score, int x, int y, uint32 front, uint32 back, Graphics::Surface *surface);
soundFx *load1bPCM(Common::SeekableReadStream *file, int offset);
diff --git a/engines/freescape/games/eclipse/zx.cpp b/engines/freescape/games/eclipse/zx.cpp
index d793c4d0110..ae33ab9dadf 100644
--- a/engines/freescape/games/eclipse/zx.cpp
+++ b/engines/freescape/games/eclipse/zx.cpp
@@ -179,8 +179,7 @@ void EclipseEngine::drawZXUI(Graphics::Surface *surface) {
} else if (!_currentAreaMessages.empty())
drawStringInSurface(_currentArea->_name, 102, 141, back, yellow, surface);
- Common::String encodedScoreStr = getScoreString(score);
- drawStringInSurface(encodedScoreStr, 135, 11, back, gray, surface);
+ drawScoreString(score, 135, 11, back, gray, surface);
Common::String shieldStr = Common::String::format("%d", shield);
More information about the Scummvm-git-logs
mailing list