[Scummvm-git-logs] scummvm master -> c489c0f061b0a82c45b7a965266a5326949f2321
Helco
noreply at scummvm.org
Sun Oct 19 14:49:08 UTC 2025
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
baf314f907 ALCACHOFA: Add engine version to detection entries
e99af42413 ALCACHOFA: Add script translation tables for V3.0
a94fdf73bf ALCACHOFA: Reencode animation paths to UTF8
c489c0f061 ALCACHOFA: Replace dependencies on version-dependent script variables
Commit: baf314f90777e2787d908baa418df2f86a918c5c
https://github.com/scummvm/scummvm/commit/baf314f90777e2787d908baa418df2f86a918c5c
Author: Helco (hermann.noll at hotmail.com)
Date: 2025-10-19T16:47:21+02:00
Commit Message:
ALCACHOFA: Add engine version to detection entries
Changed paths:
engines/alcachofa/alcachofa.cpp
engines/alcachofa/alcachofa.h
engines/alcachofa/detection.cpp
engines/alcachofa/detection.h
engines/alcachofa/detection_tables.h
engines/alcachofa/game-movie-adventure.cpp
engines/alcachofa/metaengine.cpp
engines/alcachofa/metaengine.h
diff --git a/engines/alcachofa/alcachofa.cpp b/engines/alcachofa/alcachofa.cpp
index 1e5d6b664f6..a7f387871c6 100644
--- a/engines/alcachofa/alcachofa.cpp
+++ b/engines/alcachofa/alcachofa.cpp
@@ -54,7 +54,7 @@ constexpr uint kDefaultFramerate = 100; // the original target framerate, not cr
AlcachofaEngine *g_engine;
-AlcachofaEngine::AlcachofaEngine(OSystem *syst, const ADGameDescription *gameDesc)
+AlcachofaEngine::AlcachofaEngine(OSystem *syst, const AlcachofaGameDescription *gameDesc)
: Engine(syst)
, _gameDescription(gameDesc)
, _eventLoopSemaphore("engine") {
@@ -68,11 +68,11 @@ AlcachofaEngine::~AlcachofaEngine() {
}
uint32 AlcachofaEngine::getFeatures() const {
- return _gameDescription->flags;
+ return _gameDescription->desc.flags;
}
Common::String AlcachofaEngine::getGameId() const {
- return _gameDescription->gameId;
+ return _gameDescription->desc.gameId;
}
Common::Error AlcachofaEngine::run() {
diff --git a/engines/alcachofa/alcachofa.h b/engines/alcachofa/alcachofa.h
index 4d089d8dc4e..06de0f30ab4 100644
--- a/engines/alcachofa/alcachofa.h
+++ b/engines/alcachofa/alcachofa.h
@@ -108,10 +108,14 @@ protected:
// Engine APIs
Common::Error run() override;
public:
- AlcachofaEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ AlcachofaEngine(OSystem *syst, const AlcachofaGameDescription *gameDesc);
~AlcachofaEngine() override;
- inline const ADGameDescription &gameDescription() const { return *_gameDescription; }
+ inline bool isV1() const { return gameDescription().isVersionBetween(10, 19); }
+ inline bool isV2() const { return gameDescription().isVersionBetween(20, 29); }
+ inline bool isV3() const { return gameDescription().isVersionBetween(30, 39); }
+
+ inline const AlcachofaGameDescription &gameDescription() const { return *_gameDescription; }
inline IRenderer &renderer() { return *_renderer; }
inline DrawQueue &drawQueue() { return *_drawQueue; }
inline Camera &camera() { return _camera; }
@@ -168,7 +172,7 @@ public:
private:
bool tryLoadFromLauncher();
- const ADGameDescription *_gameDescription;
+ const AlcachofaGameDescription *_gameDescription;
Console *_console = new Console();
Common::ScopedPtr<IDebugHandler> _debugHandler;
Common::ScopedPtr<IRenderer> _renderer;
diff --git a/engines/alcachofa/detection.cpp b/engines/alcachofa/detection.cpp
index f8e59c3ddf8..1a000192ffc 100644
--- a/engines/alcachofa/detection.cpp
+++ b/engines/alcachofa/detection.cpp
@@ -38,7 +38,7 @@ const DebugChannelDef AlcachofaMetaEngineDetection::debugFlagList[] = {
DEBUG_CHANNEL_END
};
-AlcachofaMetaEngineDetection::AlcachofaMetaEngineDetection() : AdvancedMetaEngineDetection<ADGameDescription>(
+AlcachofaMetaEngineDetection::AlcachofaMetaEngineDetection() : AdvancedMetaEngineDetection<Alcachofa::AlcachofaGameDescription>(
Alcachofa::gameDescriptions, Alcachofa::alcachofaGames) {
_flags |= kADFlagMatchFullPaths;
}
diff --git a/engines/alcachofa/detection.h b/engines/alcachofa/detection.h
index 982cc618159..0c8ce953738 100644
--- a/engines/alcachofa/detection.h
+++ b/engines/alcachofa/detection.h
@@ -34,16 +34,36 @@ enum AlcachofaDebugChannels {
kDebugSemaphores
};
+enum class EngineVersion {
+ V1_0 = 10, // edicion orginal, vaqueros and terror
+ V2_0 = 20, // the rest
+ V3_0 = 30, // Remastered movie adventure (used for original spanish release)
+ V3_1 = 31, // Remastered movie adventure (for german release and english/spanish steam release)
+};
+
+struct AlcachofaGameDescription {
+ AD_GAME_DESCRIPTION_HELPERS(desc);
+
+ ADGameDescription desc;
+
+ EngineVersion engineVersion;
+
+ inline bool isVersionBetween(int min, int max) const {
+ int intVersion = (int)engineVersion;
+ return intVersion >= min && intVersion <= max;
+ }
+};
+
extern const PlainGameDescriptor alcachofaGames[];
-extern const ADGameDescription gameDescriptions[];
+extern const AlcachofaGameDescription gameDescriptions[];
#define GAMEOPTION_HIGH_QUALITY GUIO_GAMEOPTIONS1 // I should comment what this does, but I don't know
#define GAMEOPTION_32BITS GUIO_GAMEOPTIONS2
} // End of namespace Alcachofa
-class AlcachofaMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
+class AlcachofaMetaEngineDetection : public AdvancedMetaEngineDetection<Alcachofa::AlcachofaGameDescription> {
static const DebugChannelDef debugFlagList[];
public:
diff --git a/engines/alcachofa/detection_tables.h b/engines/alcachofa/detection_tables.h
index 6f52319c4ba..2869f4b0f93 100644
--- a/engines/alcachofa/detection_tables.h
+++ b/engines/alcachofa/detection_tables.h
@@ -26,74 +26,92 @@ const PlainGameDescriptor alcachofaGames[] = {
{ 0, 0 }
};
-const ADGameDescription gameDescriptions[] = {
+const AlcachofaGameDescription gameDescriptions[] = {
//
// A Movie Adventure
//
{
- "aventuradecine",
- "Clever & Smart - A Movie Adventure",
- AD_ENTRY2s(
- "Textos/Objetos.nkr", "a2b1deff5ca7187f2ebf7f2ab20747e9", 17606,
- "Data/DATA02.BIN", "ab6d8867585fbc0f555f5b13d8d1bdf3", 55906308
- ),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED,
- GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ {
+ "aventuradecine",
+ "Clever & Smart - A Movie Adventure",
+ AD_ENTRY2s(
+ "Textos/Objetos.nkr", "a2b1deff5ca7187f2ebf7f2ab20747e9", 17606,
+ "Data/DATA02.BIN", "ab6d8867585fbc0f555f5b13d8d1bdf3", 55906308
+ ),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED,
+ GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ },
+ EngineVersion::V3_1
},
{
- "aventuradecine",
- "Clever & Smart - A Movie Adventure",
- AD_ENTRY2s(
- "Textos/Objetos.nkr", "a2b1deff5ca7187f2ebf7f2ab20747e9", 17606,
- "Data/DATA02.BIN", "4693e52835bad0c6deab63b60ead81fb", 38273192
- ),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED | ADGF_PIRATED,
- GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ {
+ "aventuradecine",
+ "Clever & Smart - A Movie Adventure",
+ AD_ENTRY2s(
+ "Textos/Objetos.nkr", "a2b1deff5ca7187f2ebf7f2ab20747e9", 17606,
+ "Data/DATA02.BIN", "4693e52835bad0c6deab63b60ead81fb", 38273192
+ ),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED | ADGF_PIRATED,
+ GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ },
+ EngineVersion::V3_1
},
{
- "aventuradecine",
- "Clever & Smart - A Movie Adventure",
- AD_ENTRY1s("Textos/Objetos.nkr", "8dce25494470209d4882bf12f1a5ea42", 19208),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED | ADGF_DEMO,
- GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ {
+ "aventuradecine",
+ "Clever & Smart - A Movie Adventure",
+ AD_ENTRY1s("Textos/Objetos.nkr", "8dce25494470209d4882bf12f1a5ea42", 19208),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED | ADGF_DEMO,
+ GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ },
+ EngineVersion::V3_1
},
// The "english" version is just the spanish version with english subtitles...
{
- "aventuradecine",
- "Mortadelo y Filemón: Una Aventura de Cine - Edición Especial",
- AD_ENTRY1s("Textos/Objetos.nkr", "ad3cb78ad7a51cfe63ee6f84768c7e66", 15895),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED,
- GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ {
+ "aventuradecine",
+ "Mortadelo y Filemón: Una Aventura de Cine - Edición Especial",
+ AD_ENTRY1s("Textos/Objetos.nkr", "ad3cb78ad7a51cfe63ee6f84768c7e66", 15895),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED,
+ GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ },
+ EngineVersion::V3_1
},
// the spanish Steam variant
{
- "aventuradecine",
- "Mortadelo y Filemón: Una Aventura de Cine - Edición Especial",
- AD_ENTRY1s("Textos/Objetos.nkr", "93331e4cc8d2f8f8a0007bfb5140dff5", 16403),
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED,
- GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ {
+ "aventuradecine",
+ "Mortadelo y Filemón: Una Aventura de Cine - Edición Especial",
+ AD_ENTRY1s("Textos/Objetos.nkr", "93331e4cc8d2f8f8a0007bfb5140dff5", 16403),
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ ADGF_TESTING | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED,
+ GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ },
+ EngineVersion::V3_1
},
// the spanish CD variant
{
- "aventuradecine",
- "Mortadelo y Filemón: Una Aventura de Cine - Edición Especial",
- AD_ENTRY1s("Textos/Objetos.nkr", "8a8b23c04fdc4ced8070a7bccd0177bb", 24467),
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_UNSTABLE | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED | ADGF_CD,
- GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ {
+ "aventuradecine",
+ "Mortadelo y Filemón: Una Aventura de Cine - Edición Especial",
+ AD_ENTRY1s("Textos/Objetos.nkr", "8a8b23c04fdc4ced8070a7bccd0177bb", 24467),
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE | ADGF_USEEXTRAASTITLE | ADGF_REMASTERED | ADGF_CD,
+ GUIO2(GAMEOPTION_32BITS, GAMEOPTION_HIGH_QUALITY)
+ },
+ EngineVersion::V3_0
},
AD_TABLE_END_MARKER
diff --git a/engines/alcachofa/game-movie-adventure.cpp b/engines/alcachofa/game-movie-adventure.cpp
index 66073d08bb8..4be2c841918 100644
--- a/engines/alcachofa/game-movie-adventure.cpp
+++ b/engines/alcachofa/game-movie-adventure.cpp
@@ -111,7 +111,7 @@ class GameMovieAdventure : public Game {
};
if (isInExemptions(exemptions) ||
- ((g_engine->gameDescription().flags & ADGF_DEMO) && isInExemptions(demoExemptions)))
+ ((g_engine->gameDescription().desc.flags & ADGF_DEMO) && isInExemptions(demoExemptions)))
debugC(1, kDebugGraphics, "Animation exemption triggered: %s", fileName.c_str());
else
Game::missingAnimation(fileName);
@@ -168,7 +168,7 @@ class GameMovieAdventure : public Game {
void missingSound(const String &fileName) override {
if (fileName == "CHAS" || fileName == "517")
return;
- if ((g_engine->gameDescription().flags & ADGF_DEMO) && (
+ if ((g_engine->gameDescription().desc.flags & ADGF_DEMO) && (
fileName == "M4996" ||
fileName == "T40"))
return;
@@ -177,13 +177,13 @@ class GameMovieAdventure : public Game {
bool isKnownBadVideo(int32 videoId) override {
return
- (videoId == 3 && (g_engine->gameDescription().flags & ADGF_DEMO)) || // problem with MPEG PS decoding
+ (videoId == 3 && (g_engine->gameDescription().desc.flags & ADGF_DEMO)) || // problem with MPEG PS decoding
Game::isKnownBadVideo(videoId);
}
void invalidVideo(int32 videoId, const char *context) override {
// for the one, known AVI problem, let's not block development
- if (videoId == 1 && g_engine->gameDescription().language != DE_DEU)
+ if (videoId == 1 && g_engine->gameDescription().desc.language != DE_DEU)
warning("Could not play video %d (%s) (WMV not supported)", videoId, context);
else
Game::invalidVideo(videoId, context);
diff --git a/engines/alcachofa/metaengine.cpp b/engines/alcachofa/metaengine.cpp
index 60af8263525..a8c57db2e06 100644
--- a/engines/alcachofa/metaengine.cpp
+++ b/engines/alcachofa/metaengine.cpp
@@ -69,7 +69,7 @@ const ADExtraGuiOptionsMap *AlcachofaMetaEngine::getAdvancedExtraGuiOptions() co
return Alcachofa::optionsList;
}
-Error AlcachofaMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+Error AlcachofaMetaEngine::createInstance(OSystem *syst, Engine **engine, const AlcachofaGameDescription *desc) const {
*engine = new Alcachofa::AlcachofaEngine(syst, desc);
return kNoError;
}
diff --git a/engines/alcachofa/metaengine.h b/engines/alcachofa/metaengine.h
index ada41267045..a01f695668c 100644
--- a/engines/alcachofa/metaengine.h
+++ b/engines/alcachofa/metaengine.h
@@ -22,7 +22,7 @@
#ifndef ALCACHOFA_METAENGINE_H
#define ALCACHOFA_METAENGINE_H
-#include "engines/advancedDetector.h"
+#include "alcachofa/detection.h"
namespace Alcachofa {
@@ -34,11 +34,11 @@ enum class EventAction {
}
-class AlcachofaMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
+class AlcachofaMetaEngine : public AdvancedMetaEngine<Alcachofa::AlcachofaGameDescription> {
public:
const char *getName() const override;
- Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+ Common::Error createInstance(OSystem *syst, Engine **engine, const Alcachofa::AlcachofaGameDescription *desc) const override;
/**
* Determine whether the engine supports the specified MetaEngine feature.
Commit: e99af42413b64f00c45a87a2ec0013b6556fc8fe
https://github.com/scummvm/scummvm/commit/e99af42413b64f00c45a87a2ec0013b6556fc8fe
Author: Helco (hermann.noll at hotmail.com)
Date: 2025-10-19T16:47:22+02:00
Commit Message:
ALCACHOFA: Add script translation tables for V3.0
Changed paths:
engines/alcachofa/alcachofa.h
engines/alcachofa/game-movie-adventure.cpp
engines/alcachofa/game.cpp
engines/alcachofa/game.h
engines/alcachofa/script-debug.h
engines/alcachofa/script.cpp
engines/alcachofa/script.h
engines/alcachofa/ui-objects.cpp
diff --git a/engines/alcachofa/alcachofa.h b/engines/alcachofa/alcachofa.h
index 06de0f30ab4..ea68e463690 100644
--- a/engines/alcachofa/alcachofa.h
+++ b/engines/alcachofa/alcachofa.h
@@ -111,6 +111,7 @@ public:
AlcachofaEngine(OSystem *syst, const AlcachofaGameDescription *gameDesc);
~AlcachofaEngine() override;
+ inline EngineVersion version() const { return gameDescription().engineVersion; }
inline bool isV1() const { return gameDescription().isVersionBetween(10, 19); }
inline bool isV2() const { return gameDescription().isVersionBetween(20, 29); }
inline bool isV3() const { return gameDescription().isVersionBetween(30, 39); }
diff --git a/engines/alcachofa/game-movie-adventure.cpp b/engines/alcachofa/game-movie-adventure.cpp
index 4be2c841918..7564f60d435 100644
--- a/engines/alcachofa/game-movie-adventure.cpp
+++ b/engines/alcachofa/game-movie-adventure.cpp
@@ -27,7 +27,190 @@ using namespace Common;
namespace Alcachofa {
-class GameMovieAdventure : public Game {
+static constexpr const ScriptOp kScriptOpMap[] = {
+ ScriptOp::Nop,
+ ScriptOp::Dup,
+ ScriptOp::PushAddr,
+ ScriptOp::PushValue,
+ ScriptOp::Deref,
+ ScriptOp::Crash, ///< would crash original engine by writing to read-only memory
+ ScriptOp::PopN,
+ ScriptOp::Store,
+ ScriptOp::Crash,
+ ScriptOp::Crash,
+ ScriptOp::LoadString,
+ ScriptOp::LoadString, ///< exactly the same as LoadString
+ ScriptOp::Crash,
+ ScriptOp::ScriptCall,
+ ScriptOp::KernelCall,
+ ScriptOp::JumpIfFalse,
+ ScriptOp::JumpIfTrue,
+ ScriptOp::Jump,
+ ScriptOp::Negate,
+ ScriptOp::BooleanNot,
+ ScriptOp::Mul,
+ ScriptOp::Crash,
+ ScriptOp::Crash,
+ ScriptOp::Add,
+ ScriptOp::Sub,
+ ScriptOp::Less,
+ ScriptOp::Greater,
+ ScriptOp::LessEquals,
+ ScriptOp::GreaterEquals,
+ ScriptOp::Equals,
+ ScriptOp::NotEquals,
+ ScriptOp::BitAnd,
+ ScriptOp::BitOr,
+ ScriptOp::Crash,
+ ScriptOp::Crash,
+ ScriptOp::Crash,
+ ScriptOp::Crash,
+ ScriptOp::ReturnValue
+};
+
+static constexpr const ScriptKernelTask kScriptKernelTaskMapV30[] = {
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::PlayVideo,
+ ScriptKernelTask::PlaySound,
+ ScriptKernelTask::PlayMusic,
+ ScriptKernelTask::StopMusic,
+ ScriptKernelTask::WaitForMusicToEnd,
+ ScriptKernelTask::ShowCenterBottomText,
+ ScriptKernelTask::StopAndTurn,
+ ScriptKernelTask::StopAndTurnMe,
+ ScriptKernelTask::ChangeCharacter,
+ ScriptKernelTask::SayText,
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::Go,
+ ScriptKernelTask::Put,
+ ScriptKernelTask::ChangeCharacterRoom,
+ ScriptKernelTask::KillProcesses,
+ ScriptKernelTask::On,
+ ScriptKernelTask::Off,
+ ScriptKernelTask::Pickup,
+ ScriptKernelTask::CharacterPickup,
+ ScriptKernelTask::Drop,
+ ScriptKernelTask::CharacterDrop,
+ ScriptKernelTask::Delay,
+ ScriptKernelTask::HadNoMousePressFor,
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::Fork,
+ ScriptKernelTask::Animate,
+ ScriptKernelTask::AnimateCharacter,
+ ScriptKernelTask::AnimateTalking,
+ ScriptKernelTask::ChangeRoom,
+ ScriptKernelTask::ToggleRoomFloor,
+ ScriptKernelTask::SetDialogLineReturn,
+ ScriptKernelTask::DialogMenu,
+ ScriptKernelTask::ClearInventory,
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::FadeType0,
+ ScriptKernelTask::FadeType1,
+ ScriptKernelTask::LerpWorldLodBias,
+ ScriptKernelTask::FadeType2,
+ ScriptKernelTask::SetActiveTextureSet,
+ ScriptKernelTask::SetMaxCamSpeedFactor,
+ ScriptKernelTask::WaitCamStopping,
+ ScriptKernelTask::CamFollow,
+ ScriptKernelTask::CamShake,
+ ScriptKernelTask::LerpCamXY,
+ ScriptKernelTask::LerpCamZ,
+ ScriptKernelTask::LerpCamScale,
+ ScriptKernelTask::LerpCamToObjectWithScale,
+ ScriptKernelTask::LerpCamToObjectResettingZ,
+ ScriptKernelTask::LerpCamRotation,
+ ScriptKernelTask::FadeIn,
+ ScriptKernelTask::FadeOut,
+ ScriptKernelTask::FadeIn2,
+ ScriptKernelTask::FadeOut2,
+ ScriptKernelTask::LerpCamToObjectKeepingZ
+};
+
+// in V3.1 there is the LerpCharacterLodBias and LerpCamXYZ tasks, no other differences
+
+static constexpr const ScriptKernelTask kScriptKernelTaskMapV31[] = {
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::PlayVideo,
+ ScriptKernelTask::PlaySound,
+ ScriptKernelTask::PlayMusic,
+ ScriptKernelTask::StopMusic,
+ ScriptKernelTask::WaitForMusicToEnd,
+ ScriptKernelTask::ShowCenterBottomText,
+ ScriptKernelTask::StopAndTurn,
+ ScriptKernelTask::StopAndTurnMe,
+ ScriptKernelTask::ChangeCharacter,
+ ScriptKernelTask::SayText,
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::Go,
+ ScriptKernelTask::Put,
+ ScriptKernelTask::ChangeCharacterRoom,
+ ScriptKernelTask::KillProcesses,
+ ScriptKernelTask::LerpCharacterLodBias,
+ ScriptKernelTask::On,
+ ScriptKernelTask::Off,
+ ScriptKernelTask::Pickup,
+ ScriptKernelTask::CharacterPickup,
+ ScriptKernelTask::Drop,
+ ScriptKernelTask::CharacterDrop,
+ ScriptKernelTask::Delay,
+ ScriptKernelTask::HadNoMousePressFor,
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::Fork,
+ ScriptKernelTask::Animate,
+ ScriptKernelTask::AnimateCharacter,
+ ScriptKernelTask::AnimateTalking,
+ ScriptKernelTask::ChangeRoom,
+ ScriptKernelTask::ToggleRoomFloor,
+ ScriptKernelTask::SetDialogLineReturn,
+ ScriptKernelTask::DialogMenu,
+ ScriptKernelTask::ClearInventory,
+ ScriptKernelTask::Nop,
+ ScriptKernelTask::FadeType0,
+ ScriptKernelTask::FadeType1,
+ ScriptKernelTask::LerpWorldLodBias,
+ ScriptKernelTask::FadeType2,
+ ScriptKernelTask::SetActiveTextureSet,
+ ScriptKernelTask::SetMaxCamSpeedFactor,
+ ScriptKernelTask::WaitCamStopping,
+ ScriptKernelTask::CamFollow,
+ ScriptKernelTask::CamShake,
+ ScriptKernelTask::LerpCamXY,
+ ScriptKernelTask::LerpCamZ,
+ ScriptKernelTask::LerpCamScale,
+ ScriptKernelTask::LerpCamToObjectWithScale,
+ ScriptKernelTask::LerpCamToObjectResettingZ,
+ ScriptKernelTask::LerpCamRotation,
+ ScriptKernelTask::FadeIn,
+ ScriptKernelTask::FadeOut,
+ ScriptKernelTask::FadeIn2,
+ ScriptKernelTask::FadeOut2,
+ ScriptKernelTask::LerpCamXYZ,
+ ScriptKernelTask::LerpCamToObjectKeepingZ
+};
+
+class GameWithVersion3 : public Game {
+public:
+ Point getResolution() override {
+ return Point(1024, 768);
+ }
+
+ static constexpr const char *kMapFiles[] = { // not really inherent to V3 but holds true for all V3 games
+ "MAPAS/MAPA5.EMC",
+ "MAPAS/MAPA4.EMC",
+ "MAPAS/MAPA3.EMC",
+ "MAPAS/MAPA2.EMC",
+ "MAPAS/MAPA1.EMC",
+ "MAPAS/GLOBAL.EMC",
+ nullptr
+ };
+ const char *const *getMapFiles() override {
+ return kMapFiles;
+ }
+
+ Span<const ScriptOp> getScriptOpMap() override {
+ return { kScriptOpMap, ARRAYSIZE(kScriptOpMap) };
+ }
+
void onLoadedGameFiles() override {
// this notifies the script whether we are a demo
if (g_engine->world().loadedMapCount() == 2)
@@ -54,13 +237,6 @@ class GameMovieAdventure : public Game {
return Game::shouldCharacterTrigger(character, action);
}
- bool shouldTriggerDoor(const Door *door) override {
- // An invalid door target, the character will go to the door and then ignore it (also in original engine)
- if (door->targetRoom() == "LABERINTO" && door->targetObject() == "a_LABERINTO_desde_LABERINTO_2")
- return false;
- return Game::shouldTriggerDoor(door);
- }
-
void onUserChangedCharacter() override {
// An original bug in room POBLADO_INDIO if filemon is bound and mortadelo enters the room
// the door A_PUENTE which was disabled is reenabled to allow mortadelo leaving
@@ -75,6 +251,94 @@ class GameMovieAdventure : public Game {
character->name().equalsIgnoreCase("MORTADELO_TREN"); // an original hard-coded special case
}
+ PointObject *unknownGoPutTarget(const Process &process, const char *action, const char *name) override {
+ if (scumm_stricmp(action, "put"))
+ return Game::unknownGoPutTarget(process, action, name);
+
+ if (!scumm_stricmp("A_Poblado_Indio", name)) {
+ // A_Poblado_Indio is a Door but is originally cast into a PointObject
+ // a pointer and the draw order is then interpreted as position and the character snapped onto the floor shape.
+ // Instead I just use the A_Poblado_Indio1 object which exists as counter-part for A_Poblado_Indio2 which should have been used
+ auto target = dynamic_cast<PointObject *>(
+ g_engine->world().getObjectByName(process.character(), "A_Poblado_Indio1"));
+ if (target == nullptr)
+ _message("Unknown put target A_Poblado_Indio1 during exemption for A_Poblado_Indio");
+ return target;
+ }
+
+ if (!scumm_stricmp("PUNTO_VENTANA", name)) {
+ // The object is in the previous, now inactive room.
+ // Luckily Mortadelo already is at that point so not further action required
+ return nullptr;
+ }
+
+ if (!scumm_stricmp("Puerta_Casa_Freddy_Intermedia", name)) {
+ // Another case of a door being cast into a PointObject
+ return nullptr;
+ }
+
+ return Game::unknownGoPutTarget(process, action, name);
+ }
+
+ void unknownAnimateCharacterObject(const char *name) override {
+ if (!scumm_stricmp(name, "COGE F DCH") || // original bug in MOTEL_ENTRADA
+ !scumm_stricmp(name, "CHIQUITO_IZQ"))
+ return;
+ Game::unknownAnimateCharacterObject(name);
+ }
+
+ void missingSound(const String &fileName) override {
+ if (fileName == "CHAS" || fileName == "517")
+ return;
+ Game::missingSound(fileName);
+ }
+};
+
+class GameMovieAdventureSpecialV30 : public GameWithVersion3 {
+public:
+ Span<const ScriptKernelTask> getScriptKernelTaskMap() override {
+ return { kScriptKernelTaskMapV30, ARRAYSIZE(kScriptKernelTaskMapV30) };
+ }
+
+ void missingAnimation(const String &fileName) override {
+ static const char *exemptions[] = {
+ "ANIMACION.AN0",
+ "PP_MORTA.AN0",
+ "ESTOMAGO.AN0",
+ "CREDITOS.AN0",
+ "HABITACION NEGRA.AN0",
+ nullptr
+ };
+
+ const auto isInExemptions = [&] (const char *const *const list) {
+ for (const char *const *exemption = list; *exemption != nullptr; exemption++) {
+ if (fileName.equalsIgnoreCase(*exemption))
+ return true;
+ }
+ return false;
+ };
+
+ if (isInExemptions(exemptions))
+ debugC(1, kDebugGraphics, "Animation exemption triggered: %s", fileName.c_str());
+ else
+ Game::missingAnimation(fileName);
+ }
+};
+
+class GameMovieAdventureSpecialV31 : public GameWithVersion3 {
+public:
+ Span<const ScriptKernelTask> getScriptKernelTaskMap() override {
+ return { kScriptKernelTaskMapV31, ARRAYSIZE(kScriptKernelTaskMapV31) };
+ }
+
+ bool shouldTriggerDoor(const Door *door) override {
+ // An invalid door target, the character will go to the door and then ignore it (also in original engine)
+ // this is a bug introduced in V3.1
+ if (door->targetRoom() == "LABERINTO" && door->targetObject() == "a_LABERINTO_desde_LABERINTO_2")
+ return false;
+ return Game::shouldTriggerDoor(door);
+ }
+
void missingAnimation(const String &fileName) override {
static const char *exemptions[] = {
"ANIMACION.AN0",
@@ -123,66 +387,28 @@ class GameMovieAdventure : public Game {
Game::unknownAnimateObject(name);
}
- PointObject *unknownGoPutTarget(const Process &process, const char *action, const char *name) override {
- if (scumm_stricmp(action, "put"))
- return Game::unknownGoPutTarget(process, action, name);
-
- if (!scumm_stricmp("A_Poblado_Indio", name)) {
- // A_Poblado_Indio is a Door but is originally cast into a PointObject
- // a pointer and the draw order is then interpreted as position and the character snapped onto the floor shape.
- // Instead I just use the A_Poblado_Indio1 object which exists as counter-part for A_Poblado_Indio2 which should have been used
- auto target = dynamic_cast<PointObject *>(
- g_engine->world().getObjectByName(process.character(), "A_Poblado_Indio1"));
- if (target == nullptr)
- _message("Unknown put target A_Poblado_Indio1 during exemption for A_Poblado_Indio");
- return target;
- }
-
- if (!scumm_stricmp("PUNTO_VENTANA", name)) {
- // The object is in the previous, now inactive room.
- // Luckily Mortadelo already is at that point so not further action required
- return nullptr;
- }
-
- if (!scumm_stricmp("Puerta_Casa_Freddy_Intermedia", name)) {
- // Another case of a door being cast into a PointObject
- return nullptr;
- }
-
- return Game::unknownGoPutTarget(process, action, name);
- }
-
void unknownSayTextCharacter(const char *name, int32 dialogId) override {
if (!scumm_stricmp(name, "OFELIA") && dialogId == 3737)
return;
Game::unknownSayTextCharacter(name, dialogId);
}
- void unknownAnimateCharacterObject(const char *name) override {
- if (!scumm_stricmp(name, "COGE F DCH") || // original bug in MOTEL_ENTRADA
- !scumm_stricmp(name, "CHIQUITO_IZQ"))
- return;
- Game::unknownAnimateCharacterObject(name);
- }
-
void missingSound(const String &fileName) override {
- if (fileName == "CHAS" || fileName == "517")
- return;
if ((g_engine->gameDescription().desc.flags & ADGF_DEMO) && (
fileName == "M4996" ||
fileName == "T40"))
return;
- Game::missingSound(fileName);
+ GameWithVersion3::missingSound(fileName);
}
bool isKnownBadVideo(int32 videoId) override {
return
- (videoId == 3 && (g_engine->gameDescription().desc.flags & ADGF_DEMO)) || // problem with MPEG PS decoding
+ (videoId == 3 && (g_engine->gameDescription().desc.flags & ADGF_DEMO)) || // The german trailer is WMV-encoded
Game::isKnownBadVideo(videoId);
}
void invalidVideo(int32 videoId, const char *context) override {
- // for the one, known AVI problem, let's not block development
+ // the second intro-video is DV-encoded in the spanish steam version
if (videoId == 1 && g_engine->gameDescription().desc.language != DE_DEU)
warning("Could not play video %d (%s) (WMV not supported)", videoId, context);
else
@@ -191,7 +417,10 @@ class GameMovieAdventure : public Game {
};
Game *Game::createForMovieAdventure() {
- return new GameMovieAdventure();
+ if (g_engine->version() == EngineVersion::V3_0)
+ return new GameMovieAdventureSpecialV30();
+ else
+ return new GameMovieAdventureSpecialV31();
}
}
diff --git a/engines/alcachofa/game.cpp b/engines/alcachofa/game.cpp
index b663a5380fc..1da96bcd901 100644
--- a/engines/alcachofa/game.cpp
+++ b/engines/alcachofa/game.cpp
@@ -114,18 +114,13 @@ void Game::unknownVariable(const char *name) {
}
void Game::unknownInstruction(const ScriptInstruction &instruction) {
- const char *type =
- instruction._op == ScriptOp::Crash5 || // these are defined in the game
- instruction._op == ScriptOp::Crash8 || // but implemented as crashes
- instruction._op == ScriptOp::Crash9 ||
- instruction._op == ScriptOp::Crash12 ||
- instruction._op == ScriptOp::Crash21 ||
- instruction._op == ScriptOp::Crash22 ||
- instruction._op == ScriptOp::Crash33 ||
- instruction._op == ScriptOp::Crash34 ||
- instruction._op == ScriptOp::Crash35 ||
- instruction._op == ScriptOp::Crash36
- ? "crash" : "invalid";
+ const char *type;
+ if (instruction._op < 0 || (uint32)instruction._op >= getScriptOpMap().size())
+ type = "out-of-bounds";
+ else if (getScriptOpMap()[instruction._op] == ScriptOp::Crash)
+ type = "crash"; // these are defined in the game, but implemented as write to null-pointer
+ else
+ type = "unimplemented"; // we forgot to implement them
_message("Script reached %s instruction: %d %d", type, (int)instruction._op, instruction._arg);
}
diff --git a/engines/alcachofa/game.h b/engines/alcachofa/game.h
index 483cf63e603..a18896bccb8 100644
--- a/engines/alcachofa/game.h
+++ b/engines/alcachofa/game.h
@@ -22,6 +22,8 @@
#ifndef ALCACHOFA_GAME_H
#define ALCACHOFA_GAME_H
+#include "alcachofa/script.h"
+
#include "common/textconsole.h"
#include "common/file.h"
@@ -48,6 +50,10 @@ public:
virtual ~Game() {}
virtual void onLoadedGameFiles();
+ virtual Common::Point getResolution() = 0;
+ virtual const char *const *getMapFiles() = 0; ///< Returns a nullptr-terminated list
+ virtual Common::Span<const ScriptOp> getScriptOpMap() = 0;
+ virtual Common::Span<const ScriptKernelTask> getScriptKernelTaskMap() = 0;
virtual bool doesRoomHaveBackground(const Room *room);
virtual void unknownRoomObject(const Common::String &type);
diff --git a/engines/alcachofa/script-debug.h b/engines/alcachofa/script-debug.h
index 573d502f4b4..f6e6d1fa807 100644
--- a/engines/alcachofa/script-debug.h
+++ b/engines/alcachofa/script-debug.h
@@ -30,14 +30,9 @@ static const char *const ScriptOpNames[] = {
"PushAddr",
"PushValue",
"Deref",
- "Crash5",
"PopN",
"Store",
- "Crash8",
- "Crash9",
"LoadString",
- "LoadString2",
- "Crash12",
"ScriptCall",
"KernelCall",
"JumpIfFalse",
@@ -46,8 +41,6 @@ static const char *const ScriptOpNames[] = {
"Negate",
"BooleanNot",
"Mul",
- "Crash21",
- "Crash22",
"Add",
"Sub",
"Less",
@@ -58,15 +51,13 @@ static const char *const ScriptOpNames[] = {
"NotEquals",
"BitAnd",
"BitOr",
- "Crash33",
- "Crash34",
- "Crash35",
- "Crash36",
- "Return"
+ "ReturnValue",
+ "ReturnVoid",
+ "Crash"
};
static const char *const KernelCallNames[] = {
- "<null>",
+ "Nop",
"PlayVideo",
"PlaySound",
"PlayMusic",
@@ -77,7 +68,6 @@ static const char *const KernelCallNames[] = {
"StopAndTurnMe",
"ChangeCharacter",
"SayText",
- "Nop10",
"Go",
"Put",
"ChangeCharacterRoom",
@@ -91,7 +81,6 @@ static const char *const KernelCallNames[] = {
"CharacterDrop",
"Delay",
"HadNoMousePressFor",
- "Nop24",
"Fork",
"Animate",
"AnimateCharacter",
@@ -101,7 +90,6 @@ static const char *const KernelCallNames[] = {
"SetDialogLineReturn",
"DialogMenu",
"ClearInventory",
- "Nop34",
"FadeType0",
"FadeType1",
"LerpWorldLodBias",
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index 6606971322d..e278d5c3bd3 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -40,7 +40,7 @@ enum ScriptDebugLevel {
};
ScriptInstruction::ScriptInstruction(ReadStream &stream)
- : _op((ScriptOp)stream.readSint32LE())
+ : _op(stream.readSint32LE())
, _arg(stream.readSint32LE()) {}
Script::Script() {
@@ -237,6 +237,7 @@ struct ScriptTask final : public Task {
handleReturnFromKernelCall(process().returnValue());
}
_isFirstExecution = _returnsFromKernelCall = false;
+ auto opMap = g_engine->game().getScriptOpMap();
while (true) {
if (_pc >= _script._instructions.size())
@@ -269,7 +270,11 @@ struct ScriptTask final : public Task {
}
}
- switch (instruction._op) {
+ if (instruction._op < 0 || (uint32)instruction._op >= opMap.size()) {
+ g_engine->game().unknownInstruction(instruction);
+ continue;
+ }
+ switch (opMap[instruction._op]) {
case ScriptOp::Nop: break;
case ScriptOp::Dup:
if (_stack.empty())
@@ -294,7 +299,6 @@ struct ScriptTask final : public Task {
pushNumber(value);
}break;
case ScriptOp::LoadString:
- case ScriptOp::LoadString2:
pushString(popNumber());
break;
case ScriptOp::ScriptCall:
@@ -302,7 +306,7 @@ struct ScriptTask final : public Task {
_pc = instruction._arg - 1;
break;
case ScriptOp::KernelCall: {
- TaskReturn kernelReturn = kernelCall((ScriptKernelTask)instruction._arg);
+ TaskReturn kernelReturn = kernelCall(instruction._arg);
if (kernelReturn.type() == TaskReturnType::Waiting) {
_returnsFromKernelCall = true;
return kernelReturn;
@@ -360,7 +364,7 @@ struct ScriptTask final : public Task {
case ScriptOp::BitOr:
pushNumber(popNumber() | popNumber()); //-V501
break;
- case ScriptOp::Return: {
+ case ScriptOp::ReturnValue: {
int32 returnValue = popNumber();
_pc = popInstruction();
if (_pc == UINT_MAX)
@@ -414,7 +418,9 @@ private:
void handleReturnFromKernelCall(int32 returnValue) {
// this is also original done, every KernelCall is followed by a PopN of the arguments
// only *after* the PopN the return value is pushed so that the following script can use it
- scumm_assert(_pc < _script._instructions.size() && _script._instructions[_pc]._op == ScriptOp::PopN);
+ scumm_assert(
+ _pc < _script._instructions.size() &&
+ g_engine->game().getScriptOpMap()[_script._instructions[_pc]._op] == ScriptOp::PopN);
popN(_script._instructions[_pc++]._arg);
pushNumber(returnValue);
}
@@ -540,10 +546,16 @@ private:
g_engine->player().activeCharacterKind() != process().character();
}
- TaskReturn kernelCall(ScriptKernelTask task) {
+ TaskReturn kernelCall(int32 taskI) {
+ const auto taskMap = g_engine->game().getScriptKernelTaskMap();
+ if (taskI < 0 || (uint32)taskI >= taskMap.size()) {
+ g_engine->game().unknownKernelTask(taskI);
+ return TaskReturn::finish(-1);
+ }
+ const auto task = taskMap[taskI];
+
debugC(SCRIPT_DEBUG_LVL_KERNELCALLS, kDebugScript, "%u: %5u Kernel %-25s",
process().pid(), _pc - 1, KernelCallNames[(int)task]);
-
switch (task) {
// sound/video
case ScriptKernelTask::PlayVideo:
@@ -923,12 +935,10 @@ private:
case ScriptKernelTask::FadeType2:
warning("STUB KERNEL CALL: FadeType2"); // Crossfade, unused from script
return TaskReturn::finish(0);
- case ScriptKernelTask::Nop10:
- case ScriptKernelTask::Nop24:
- case ScriptKernelTask::Nop34:
+ case ScriptKernelTask::Nop:
return TaskReturn::finish(0);
default:
- g_engine->game().unknownKernelTask((int)task);
+ g_engine->game().unknownKernelTask(taskI);
return TaskReturn::finish(0);
}
}
diff --git a/engines/alcachofa/script.h b/engines/alcachofa/script.h
index 8122ec2954a..d0672570ca4 100644
--- a/engines/alcachofa/script.h
+++ b/engines/alcachofa/script.h
@@ -33,20 +33,20 @@ namespace Alcachofa {
class Process;
+// the ScriptOp and ScriptKernelTask enums represent the *implemented* order
+// the specific Game instance maps the version-specific op codes to our order
+
enum class ScriptOp {
Nop,
Dup,
PushAddr,
+ PushDynAddr,
PushValue,
Deref,
- Crash5, ///< would crash original engine by writing to read-only memory
+ Pop1,
PopN,
Store,
- Crash8,
- Crash9,
LoadString,
- LoadString2, ///< exactly the same as LoadString
- Crash12,
ScriptCall,
KernelCall,
JumpIfFalse,
@@ -55,8 +55,6 @@ enum class ScriptOp {
Negate,
BooleanNot,
Mul,
- Crash21,
- Crash22,
Add,
Sub,
Less,
@@ -67,15 +65,14 @@ enum class ScriptOp {
NotEquals,
BitAnd,
BitOr,
- Crash33,
- Crash34,
- Crash35,
- Crash36,
- Return
+ ReturnValue,
+ ReturnVoid,
+ Crash
};
enum class ScriptKernelTask {
- PlayVideo = 1,
+ Nop = 0,
+ PlayVideo,
PlaySound,
PlayMusic,
StopMusic,
@@ -85,7 +82,6 @@ enum class ScriptKernelTask {
StopAndTurnMe,
ChangeCharacter,
SayText,
- Nop10,
Go,
Put,
ChangeCharacterRoom,
@@ -99,7 +95,6 @@ enum class ScriptKernelTask {
CharacterDrop,
Delay,
HadNoMousePressFor,
- Nop24,
Fork,
Animate,
AnimateCharacter,
@@ -109,7 +104,6 @@ enum class ScriptKernelTask {
SetDialogLineReturn,
DialogMenu,
ClearInventory,
- Nop34,
FadeType0,
FadeType1,
LerpWorldLodBias,
@@ -130,7 +124,11 @@ enum class ScriptKernelTask {
FadeIn2,
FadeOut2,
LerpCamXYZ,
- LerpCamToObjectKeepingZ
+ LerpCamToObjectKeepingZ,
+
+ SheriffTakesCharacter, ///< some special-case V1 tasks, unknown yet
+ ChangeDoor,
+ Disguise
};
enum class ScriptFlags {
@@ -148,7 +146,7 @@ inline bool operator & (ScriptFlags a, ScriptFlags b) {
struct ScriptInstruction {
ScriptInstruction(Common::ReadStream &stream);
- ScriptOp _op;
+ int32 _op; ///< int32 because it still has to be mapped using a game-specific translation table
int32 _arg;
};
diff --git a/engines/alcachofa/ui-objects.cpp b/engines/alcachofa/ui-objects.cpp
index 534115b1245..e0e17424048 100644
--- a/engines/alcachofa/ui-objects.cpp
+++ b/engines/alcachofa/ui-objects.cpp
@@ -161,7 +161,11 @@ EditBox::EditBox(Room *room, ReadStream &stream)
, i3(stream.readSint32LE())
, i4(stream.readSint32LE())
, i5(stream.readSint32LE())
- , _fontId(stream.readSint32LE()) {}
+ , _fontId(0) {
+
+ if (g_engine->version() == EngineVersion::V3_1)
+ _fontId = stream.readSint32LE();
+}
const char *CheckBox::typeName() const { return "CheckBox"; }
Commit: a94fdf73bff65bbaf78b3e6b09af3fc476af8290
https://github.com/scummvm/scummvm/commit/a94fdf73bff65bbaf78b3e6b09af3fc476af8290
Author: Helco (hermann.noll at hotmail.com)
Date: 2025-10-19T16:47:22+02:00
Commit Message:
ALCACHOFA: Reencode animation paths to UTF8
Changed paths:
engines/alcachofa/common.cpp
engines/alcachofa/common.h
engines/alcachofa/graphics.cpp
diff --git a/engines/alcachofa/common.cpp b/engines/alcachofa/common.cpp
index 6c963840a02..e2f62482cbf 100644
--- a/engines/alcachofa/common.cpp
+++ b/engines/alcachofa/common.cpp
@@ -59,6 +59,16 @@ float ease(float t, EasingType type) {
}
}
+String reencode(const String &string, CodePage from, CodePage to) {
+ // Some spanish releases contain special characters in paths but Path does not support U32String
+ // Instead we convert to UTF8 and let the filesystem backend choose the native target encoding
+
+ auto it = Common::find_if(string.begin(), string.end(), [] (const char v) { return v < 0; });
+ if (it == string.end())
+ return string; // no need to reencode
+ return string.decode(from).encode(to);
+}
+
FakeSemaphore::FakeSemaphore(const char *name, uint initialCount)
: _name(name)
, _counter(initialCount) {}
diff --git a/engines/alcachofa/common.h b/engines/alcachofa/common.h
index cd8da0fae88..1bd5b5f7bff 100644
--- a/engines/alcachofa/common.h
+++ b/engines/alcachofa/common.h
@@ -25,6 +25,7 @@
#include "common/rect.h"
#include "common/serializer.h"
#include "common/stream.h"
+#include "common/str-enc.h"
#include "common/stack.h"
#include "math/vector2d.h"
#include "math/vector3d.h"
@@ -118,6 +119,11 @@ int16 nextPowerOfTwo(int16 v);
float ease(float t, EasingType type);
+Common::String reencode(
+ const Common::String &string,
+ Common::CodePage from = Common::CodePage::kISO8859_1, // "Western European", used for the spanish special characters
+ Common::CodePage to = Common::CodePage::kUtf8);
+
Math::Vector3d as3D(const Math::Vector2d &v);
Math::Vector3d as3D(Common::Point p);
Math::Vector2d as2D(const Math::Vector3d &v);
diff --git a/engines/alcachofa/graphics.cpp b/engines/alcachofa/graphics.cpp
index 06992694b7c..9f3705d888a 100644
--- a/engines/alcachofa/graphics.cpp
+++ b/engines/alcachofa/graphics.cpp
@@ -88,6 +88,7 @@ void AnimationBase::load() {
}
if (_fileName.size() < 4 || scumm_strnicmp(_fileName.end() - 4, ".AN0", 4) != 0)
_fileName += ".AN0";
+ _fileName = reencode(_fileName);
fullPath += _fileName;
File file;
Commit: c489c0f061b0a82c45b7a965266a5326949f2321
https://github.com/scummvm/scummvm/commit/c489c0f061b0a82c45b7a965266a5326949f2321
Author: Helco (hermann.noll at hotmail.com)
Date: 2025-10-19T16:47:22+02:00
Commit Message:
ALCACHOFA: Replace dependencies on version-dependent script variables
Changed paths:
engines/alcachofa/camera.cpp
engines/alcachofa/game-movie-adventure.cpp
engines/alcachofa/game.cpp
engines/alcachofa/game.h
engines/alcachofa/global-ui.cpp
engines/alcachofa/graphics.cpp
engines/alcachofa/rooms.cpp
engines/alcachofa/script.cpp
engines/alcachofa/script.h
diff --git a/engines/alcachofa/camera.cpp b/engines/alcachofa/camera.cpp
index 5f9752717e9..4977bbb0ee6 100644
--- a/engines/alcachofa/camera.cpp
+++ b/engines/alcachofa/camera.cpp
@@ -113,7 +113,7 @@ void minmax(Vector3d &min, Vector3d &max, Vector3d val) {
Vector3d Camera::setAppliedCenter(Vector3d center) {
setupMatricesAround(center);
- if (g_engine->script().variable("EncuadrarCamara")) {
+ if (g_engine->game().shouldClipCamera()) {
const float screenW = g_system->getWidth(), screenH = g_system->getHeight();
Vector3d min, max;
min = max = transform2Dto3D(Vector3d(0, 0, _roomScale));
diff --git a/engines/alcachofa/game-movie-adventure.cpp b/engines/alcachofa/game-movie-adventure.cpp
index 7564f60d435..a9a5662fba3 100644
--- a/engines/alcachofa/game-movie-adventure.cpp
+++ b/engines/alcachofa/game-movie-adventure.cpp
@@ -211,6 +211,15 @@ public:
return { kScriptOpMap, ARRAYSIZE(kScriptOpMap) };
}
+ void updateScriptVariables() override {
+ Script &script = g_engine->script();
+ if (g_engine->input().wasAnyMousePressed()) // yes, this variable is never reset by the engine (only by script)
+ script.variable("SeHaPulsadoRaton") = 1;
+
+ script.variable("EstanAmbos") = g_engine->world().mortadelo().room() == g_engine->world().filemon().room();
+ script.variable("textoson") = g_engine->config().subtitles() ? 1 : 0;
+ }
+
void onLoadedGameFiles() override {
// this notifies the script whether we are a demo
if (g_engine->world().loadedMapCount() == 2)
@@ -300,6 +309,17 @@ public:
return { kScriptKernelTaskMapV30, ARRAYSIZE(kScriptKernelTaskMapV30) };
}
+ void updateScriptVariables() override {
+ GameWithVersion3::updateScriptVariables();
+
+ // in V3.0 there is no CalcularTiempoSinPulsarRaton variable to reset the timer
+ g_engine->script().setScriptTimer(g_engine->input().wasAnyMousePressed());
+ }
+
+ bool shouldClipCamera() override {
+ return true;
+ }
+
void missingAnimation(const String &fileName) override {
static const char *exemptions[] = {
"ANIMACION.AN0",
@@ -331,6 +351,27 @@ public:
return { kScriptKernelTaskMapV31, ARRAYSIZE(kScriptKernelTaskMapV31) };
}
+ void updateScriptVariables() override {
+ GameWithVersion3::updateScriptVariables();
+
+ Script &script = g_engine->script();
+ script.setScriptTimer(!script.variable("CalcularTiempoSinPulsarRaton"));
+ script.variable("modored") = 0; // this is signalling whether a network connection is established
+ }
+
+ bool shouldClipCamera() override {
+ return g_engine->script().variable("EncuadrarCamara") != 0;
+ }
+
+ void drawScreenStates() override {
+ if (int32 borderWidth = g_engine->script().variable("BordesNegros")) {
+ int16 width = g_system->getWidth();
+ int16 height = g_system->getHeight();
+ g_engine->drawQueue().add<BorderDrawRequest>(Rect(0, 0, width, borderWidth), kBlack);
+ g_engine->drawQueue().add<BorderDrawRequest>(Rect(0, height - borderWidth, width, height), kBlack);
+ }
+ }
+
bool shouldTriggerDoor(const Door *door) override {
// An invalid door target, the character will go to the door and then ignore it (also in original engine)
// this is a bug introduced in V3.1
diff --git a/engines/alcachofa/game.cpp b/engines/alcachofa/game.cpp
index 1da96bcd901..a69f6543798 100644
--- a/engines/alcachofa/game.cpp
+++ b/engines/alcachofa/game.cpp
@@ -37,6 +37,8 @@ Game::Game()
void Game::onLoadedGameFiles() {}
+void Game::drawScreenStates() {}
+
bool Game::doesRoomHaveBackground(const Room *room) {
return true;
}
diff --git a/engines/alcachofa/game.h b/engines/alcachofa/game.h
index a18896bccb8..6f258055afc 100644
--- a/engines/alcachofa/game.h
+++ b/engines/alcachofa/game.h
@@ -54,6 +54,9 @@ public:
virtual const char *const *getMapFiles() = 0; ///< Returns a nullptr-terminated list
virtual Common::Span<const ScriptOp> getScriptOpMap() = 0;
virtual Common::Span<const ScriptKernelTask> getScriptKernelTaskMap() = 0;
+ virtual void updateScriptVariables() = 0;
+ virtual bool shouldClipCamera() = 0;
+ virtual void drawScreenStates();
virtual bool doesRoomHaveBackground(const Room *room);
virtual void unknownRoomObject(const Common::String &type);
diff --git a/engines/alcachofa/global-ui.cpp b/engines/alcachofa/global-ui.cpp
index 7d9f7654697..7f7ab5740cc 100644
--- a/engines/alcachofa/global-ui.cpp
+++ b/engines/alcachofa/global-ui.cpp
@@ -254,12 +254,8 @@ void GlobalUI::drawScreenStates() {
auto &drawQueue = g_engine->drawQueue();
if (_isPermanentFaded)
drawQueue.add<FadeDrawRequest>(FadeType::ToBlack, 1.0f, -9);
- else if (int32 borderWidth = g_engine->script().variable("BordesNegros")) {
- int16 width = g_system->getWidth();
- int16 height = g_system->getHeight();
- drawQueue.add<BorderDrawRequest>(Rect(0, 0, width, borderWidth), kBlack);
- drawQueue.add<BorderDrawRequest>(Rect(0, height - borderWidth, width, height), kBlack);
- }
+ else
+ g_engine->game().drawScreenStates();
}
void GlobalUI::syncGame(Serializer &s) {
diff --git a/engines/alcachofa/graphics.cpp b/engines/alcachofa/graphics.cpp
index 9f3705d888a..b0fcb5c39d8 100644
--- a/engines/alcachofa/graphics.cpp
+++ b/engines/alcachofa/graphics.cpp
@@ -60,7 +60,7 @@ void IDebugRenderer::debugShape(const Shape &shape, Color color) {
}
AnimationBase::AnimationBase(String fileName, AnimationFolder folder)
- : _fileName(move(fileName))
+ : _fileName(reencode(fileName))
, _folder(folder) {}
AnimationBase::~AnimationBase() {
@@ -88,7 +88,6 @@ void AnimationBase::load() {
}
if (_fileName.size() < 4 || scumm_strnicmp(_fileName.end() - 4, ".AN0", 4) != 0)
_fileName += ".AN0";
- _fileName = reencode(_fileName);
fullPath += _fileName;
File file;
diff --git a/engines/alcachofa/rooms.cpp b/engines/alcachofa/rooms.cpp
index 31311874cf0..b20dc6ab5ba 100644
--- a/engines/alcachofa/rooms.cpp
+++ b/engines/alcachofa/rooms.cpp
@@ -164,7 +164,7 @@ void Room::draw() {
}
void Room::updateScripts() {
- g_engine->script().updateCommonVariables();
+ g_engine->game().updateScriptVariables();
if (!g_engine->scheduler().hasProcessWithName("ACTUALIZAR_" + _name))
g_engine->script().createProcess(MainCharacterKind::None, "ACTUALIZAR_" + _name, ScriptFlags::AllowMissing | ScriptFlags::IsBackground);
g_engine->scheduler().run();
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index e278d5c3bd3..54516675cdd 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -826,11 +826,13 @@ private:
// Camera tasks
case ScriptKernelTask::WaitCamStopping:
return TaskReturn::waitFor(g_engine->camera().waitToStop(process()));
- case ScriptKernelTask::CamFollow:
- g_engine->camera().setFollow(
- &g_engine->world().getMainCharacterByKind((MainCharacterKind)getNumberArg(0)),
- getNumberArg(1) != 0);
+ case ScriptKernelTask::CamFollow: {
+ WalkingCharacter *target = nullptr;
+ if (getNumberArg(0) != 0)
+ target = &g_engine->world().getMainCharacterByKind((MainCharacterKind)getNumberArg(0));
+ g_engine->camera().setFollow(target, getNumberArg(1) != 0);
return TaskReturn::finish(1);
+ }
case ScriptKernelTask::CamShake:
return TaskReturn::waitFor(g_engine->camera().shake(process(),
Vector2d(getNumberArg(1), getNumberArg(2)),
@@ -990,19 +992,12 @@ Process *Script::createProcess(MainCharacterKind character, const String &proced
return process;
}
-void Script::updateCommonVariables() {
- if (g_engine->input().wasAnyMousePressed()) // yes, this variable is never reset by the engine (only by script)
- variable("SeHaPulsadoRaton") = 1;
-
- if (variable("CalcularTiempoSinPulsarRaton")) {
- if (_scriptTimer == 0)
- _scriptTimer = g_engine->getMillis();
- } else
+void Script::setScriptTimer(bool reset) {
+ // Used for the V3 exclusive kernel task HadNoMousePressFor
+ if (reset)
_scriptTimer = 0;
-
- variable("EstanAmbos") = g_engine->world().mortadelo().room() == g_engine->world().filemon().room();
- variable("textoson") = g_engine->config().subtitles() ? 1 : 0;
- variable("modored") = 0; // this is signalling whether a network connection is established
+ else if (_scriptTimer == 0)
+ _scriptTimer = g_engine->getMillis();
}
}
diff --git a/engines/alcachofa/script.h b/engines/alcachofa/script.h
index d0672570ca4..e9cb9eb2846 100644
--- a/engines/alcachofa/script.h
+++ b/engines/alcachofa/script.h
@@ -155,7 +155,6 @@ public:
Script();
void syncGame(Common::Serializer &s);
- void updateCommonVariables();
int32 variable(const char *name) const;
int32 &variable(const char *name);
Process *createProcess(
@@ -175,6 +174,7 @@ public:
inline VariableNameIterator endVariables() const { return _variableNames.end(); }
inline bool hasVariable(const char *name) const { return _variableNames.contains(name); }
+ void setScriptTimer(bool reset);
private:
friend struct ScriptTask;
friend struct ScriptTimerTask;
More information about the Scummvm-git-logs
mailing list