[Scummvm-git-logs] scummvm master -> 72decc28bf3d034998d44edb868da37715247c15

Helco noreply at scummvm.org
Thu Jun 25 17:42:51 UTC 2026


This automated email contains information about 11 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
88a2c567c8 ALCACHOFA: V2: Fix room bounds with non-standard background scale
4bd9f74c23 ALCACHOFA: Shortcut empty object queries in scripts
d2af44ad1a ALCACHOFA: V2: Fix cam lerp to stationary characters
f5dcfd6337 ALCACHOFA: CORVINO: Fix camera follow after scripted room change
b2fa206e23 ALCACHOFA: CORVINO: Fix script edge-cases
e3de8c573f ALCACHOFA: V2: Fix camera jitter when clicking during walking
0ccd114857 ALCACHOFA: V2: Enable KillProcesses kernel task
367b10ae5f ALCACHOFA: V2: Add kernel task WaitForMouseClick
d9b408ae0c ALCACHOFA: CORVINO: Fix telephone conversation in PRIMER_PLANO_TELEFONO
1217dd6903 ALCACHOFA: V2: Enable texture filtering
72decc28bf ALCACHOFA: V2: Improve animation path fallbacks


Commit: 88a2c567c885375b27a9e66da852a846049198f5
    https://github.com/scummvm/scummvm/commit/88a2c567c885375b27a9e66da852a846049198f5
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:55+02:00

Commit Message:
ALCACHOFA: V2: Fix room bounds with non-standard background scale

This only happens in CORVINO/BALONES in EXTERIOR_ESTADIO which is why it was not noticed before.

Changed paths:
    engines/alcachofa/camera.cpp


diff --git a/engines/alcachofa/camera.cpp b/engines/alcachofa/camera.cpp
index 4c17e3160e3..4aa2e8c620a 100644
--- a/engines/alcachofa/camera.cpp
+++ b/engines/alcachofa/camera.cpp
@@ -253,7 +253,7 @@ void CameraV2::setRoomBounds(Graphic &background) {
 	Point bgSize = background.animation().imageSize(0);
 	float scaleFactor = background.scale() / (float)kBaseScale;
 	Point screenSize(g_system->getWidth(), g_system->getHeight());
-	_roomMin = as2D(background.topLeft() + screenSize / 2) * scaleFactor;
+	_roomMin = as2D(background.topLeft()) * scaleFactor + as2D(screenSize / 2);
 	_roomMax = _roomMin + as2D(bgSize - screenSize) * scaleFactor;
 	_roomScale = 0;
 }


Commit: 4bd9f74c23b7e5941396e2c0f7099fbc2c74d11e
    https://github.com/scummvm/scummvm/commit/4bd9f74c23b7e5941396e2c0f7099fbc2c74d11e
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:55+02:00

Commit Message:
ALCACHOFA: Shortcut empty object queries in scripts

Changed paths:
    engines/alcachofa/script.cpp


diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index e4cbfc1fd52..4d817431105 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -654,6 +654,8 @@ private:
 	template<class TObject = ObjectBase>
 	TObject *getObjectArg(uint argI) {
 		const char *const name = getStringArg(argI);
+		if (!*name)
+			return nullptr;
 		auto *object = g_engine->world().getObjectByName(process().character(), name);
 		return dynamic_cast<TObject *>(object);
 	}


Commit: d2af44ad1ad7ab032ee6a9af9b4b8134c491383c
    https://github.com/scummvm/scummvm/commit/d2af44ad1ad7ab032ee6a9af9b4b8134c491383c
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: V2: Fix cam lerp to stationary characters

Changed paths:
    engines/alcachofa/script.cpp


diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index 4d817431105..588307e5981 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -662,14 +662,21 @@ private:
 
 	const Point kInvalidPoint = { INT16_MIN, INT16_MIN };
 	Point getCamLerpTargetArg(const char *action, uint argI) {
-		auto *pointObject = getObjectArg<PointObject>(argI);
+		auto *object = getObjectArg<ObjectBase>(argI);
+
+		auto *pointObject = dynamic_cast<PointObject *>(object);
 		if (pointObject != nullptr)
 			return pointObject->position();
 
 		// in V2 a main character (we can reduce to walking character) can be used instead
-		auto *character = getObjectArg<WalkingCharacter>(argI);
-		if (character != nullptr)
-			return character->position();
+		auto *walkingChar = dynamic_cast<WalkingCharacter *>(object);
+		if (walkingChar != nullptr)
+			return walkingChar->position();
+
+		// in corvino it might even be just a regular stationary character
+		auto stationaryChar = dynamic_cast<Character *>(object);
+		if (stationaryChar != nullptr)
+			return stationaryChar->interactionPoint();
 
 		pointObject = g_engine->game().unknownCamLerpTarget(action, getStringArg(argI));
 		return pointObject == nullptr ? kInvalidPoint : pointObject->position();


Commit: f5dcfd6337c074b2eceafff9858bcb873dd6315e
    https://github.com/scummvm/scummvm/commit/f5dcfd6337c074b2eceafff9858bcb873dd6315e
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: CORVINO: Fix camera follow after scripted room change

More specifically, if a script snaps the camera and then changes the displayed room room without explicitly following the main character again.
We just enable the camera follow after the next user interaction.

Changed paths:
    engines/alcachofa/game-objects.cpp


diff --git a/engines/alcachofa/game-objects.cpp b/engines/alcachofa/game-objects.cpp
index eee8e4b2fb7..786c5b810d5 100644
--- a/engines/alcachofa/game-objects.cpp
+++ b/engines/alcachofa/game-objects.cpp
@@ -1049,6 +1049,10 @@ void MainCharacter::walkToMouse() {
 			targetPos = tmpPath[0];
 	}
 
+	// this camera follow is not original, but fixes a bug in CORVINO and should be
+	// indempotent for all other games and situations as it only affects user interaction
+	g_engine->camera().setFollow(this);
+
 	const uint minDistance = (uint)(50 * _graphicNormal.depthScale());
 	if (_sourcePos.sqrDist(targetPos) > minDistance * minDistance)
 		walkTo(targetPos);


Commit: b2fa206e236f70e921929e400f22858d85b87e52
    https://github.com/scummvm/scummvm/commit/b2fa206e236f70e921929e400f22858d85b87e52
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: CORVINO: Fix script edge-cases

1. An invalid door target in ENFERMERIA
2. A mispelled item ID I_ELECTROCHOCK
3. A lower-case character name

Changed paths:
    engines/alcachofa/game-v2.cpp
    engines/alcachofa/script.h


diff --git a/engines/alcachofa/game-v2.cpp b/engines/alcachofa/game-v2.cpp
index 76c7b92227f..36d3614e3c6 100644
--- a/engines/alcachofa/game-v2.cpp
+++ b/engines/alcachofa/game-v2.cpp
@@ -383,6 +383,22 @@ public:
 			return;
 		return GameWithVersion2::missingAnimation(fileName);
 	}
+
+	void unknownDropItem(const char *name) override {
+		// an original bug, the item will just stay in the inventory unusable
+		if (scumm_stricmp(name, "I_ELECTROCHOCK") == 0)
+			return;
+		return GameWithVersion2::unknownDropItem(name);
+	}
+
+	bool shouldTriggerDoor(const Door *door) override {
+		// an original bug, a door left active to a non-existant target
+		// probably the room layout was different during development
+		if (door->name().equalsIgnoreCase("a_SALA_DE_TROFEOS_desde_ENFERMERIA"))
+			return false;
+
+		return GameWithVersion2::shouldTriggerDoor(door);
+	}
 };
 
 class GameCorvino : public GameWithVersion2_1 {
diff --git a/engines/alcachofa/script.h b/engines/alcachofa/script.h
index c324825b21b..3d571c242dc 100644
--- a/engines/alcachofa/script.h
+++ b/engines/alcachofa/script.h
@@ -183,7 +183,8 @@ private:
 	friend struct ScriptTask;
 	friend struct ScriptTimerTask;
 	Common::HashMap<Common::String, uint32> _variableNames;
-	Common::HashMap<Common::String, uint32> _procedures;
+	Common::HashMap<Common::String, uint32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>
+		_procedures; // In CORVINO there are some mixed-case character names but upper-case procedures
 	Common::Array<ScriptInstruction> _instructions;
 	Common::Array<int32> _variables;
 	Common::SpanOwner<Common::Span<char>> _strings;


Commit: e3de8c573f042e498de0a31f686c03f9bc5da917
    https://github.com/scummvm/scummvm/commit/e3de8c573f042e498de0a31f686c03f9bc5da917
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: V2: Fix camera jitter when clicking during walking

Changed paths:
    engines/alcachofa/camera.h
    engines/alcachofa/game-objects.cpp


diff --git a/engines/alcachofa/camera.h b/engines/alcachofa/camera.h
index 4c4b93d3af6..7230b531ba0 100644
--- a/engines/alcachofa/camera.h
+++ b/engines/alcachofa/camera.h
@@ -92,6 +92,8 @@ public:
 	void syncGame(Common::Serializer &s) override;
 	void lerpOrSet(Common::Point target, int32 mode);
 
+	WalkingCharacter *followTarget() const { return _followTarget; }
+
 	Task *disguise(Process &process, int32 duration);
 
 protected:
diff --git a/engines/alcachofa/game-objects.cpp b/engines/alcachofa/game-objects.cpp
index 786c5b810d5..6247d5ed273 100644
--- a/engines/alcachofa/game-objects.cpp
+++ b/engines/alcachofa/game-objects.cpp
@@ -1051,7 +1051,9 @@ void MainCharacter::walkToMouse() {
 
 	// this camera follow is not original, but fixes a bug in CORVINO and should be
 	// indempotent for all other games and situations as it only affects user interaction
-	g_engine->camera().setFollow(this);
+	// we still need to check to prevent the camera jumping when it already follows us
+	if (g_engine->isV2() && g_engine->cameraV1().followTarget() != this)
+		g_engine->camera().setFollow(this);
 
 	const uint minDistance = (uint)(50 * _graphicNormal.depthScale());
 	if (_sourcePos.sqrDist(targetPos) > minDistance * minDistance)


Commit: 0ccd114857a8cf00c2a2a70c3a4a9e0b3246dcf6
    https://github.com/scummvm/scummvm/commit/0ccd114857a8cf00c2a2a70c3a4a9e0b3246dcf6
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: V2: Enable KillProcesses kernel task

Changed paths:
    engines/alcachofa/game-v2.cpp
    engines/alcachofa/script.h


diff --git a/engines/alcachofa/game-v2.cpp b/engines/alcachofa/game-v2.cpp
index 36d3614e3c6..7828a5d50c1 100644
--- a/engines/alcachofa/game-v2.cpp
+++ b/engines/alcachofa/game-v2.cpp
@@ -107,7 +107,7 @@ static constexpr const ScriptKernelTask kScriptKernelTaskMap[] = {
 	ScriptKernelTask::AnimateTalking,
 	ScriptKernelTask::ClearInventory,
 	ScriptKernelTask::WaitForMouseClick,
-	ScriptKernelTask::ResetCharacter
+	ScriptKernelTask::KillProcesses
 };
 
 class GameWithVersion2 : public Game {
diff --git a/engines/alcachofa/script.h b/engines/alcachofa/script.h
index 3d571c242dc..c5e84aaab18 100644
--- a/engines/alcachofa/script.h
+++ b/engines/alcachofa/script.h
@@ -129,8 +129,7 @@ enum class ScriptKernelTask {
 	LerpCamXYZ,
 	LerpCamToObjectKeepingZ,
 	Disguise,
-	WaitForMouseClick, // only V2.1
-	ResetCharacter     // only V2.1
+	WaitForMouseClick // only V2.1
 };
 
 enum class ScriptFlags {


Commit: 367b10ae5fdef3f3dcfad7f1b4ffe5c1379db043
    https://github.com/scummvm/scummvm/commit/367b10ae5fdef3f3dcfad7f1b4ffe5c1379db043
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: V2: Add kernel task WaitForMouseClick

Changed paths:
    engines/alcachofa/input.cpp
    engines/alcachofa/script.cpp


diff --git a/engines/alcachofa/input.cpp b/engines/alcachofa/input.cpp
index 6ac957052ef..d29e04c1c7a 100644
--- a/engines/alcachofa/input.cpp
+++ b/engines/alcachofa/input.cpp
@@ -118,6 +118,10 @@ struct WaitForInputTask final : public Task {
 		do {
 			TASK_YIELD(1);
 		} while(!g_engine->input().wasAnyMousePressed());
+
+		// as script task this is run before room updates
+		// preventing the click to be reused in room interaction
+		g_engine->input().nextFrame();
 		TASK_END;
 	}
 
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index 588307e5981..b9b64310836 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -745,6 +745,8 @@ private:
 			auto duration = g_engine->isV1() ? 60 : getNumberArg(0);
 			return TaskReturn::waitFor(new ScriptTimerTask(process(), duration));
 		}
+		case ScriptKernelTask::WaitForMouseClick:
+			return TaskReturn::waitFor(g_engine->input().waitForInput(process()));
 		case ScriptKernelTask::Fork:
 			g_engine->scheduler().createProcess<ScriptTask>(process().character(), *this);
 			return TaskReturn::finish(0); // 0 means this is the forking process


Commit: d9b408ae0c9e1c6cdfd5a0c3563e54d9c36543ef
    https://github.com/scummvm/scummvm/commit/d9b408ae0c9e1c6cdfd5a0c3563e54d9c36543ef
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: CORVINO: Fix telephone conversation in PRIMER_PLANO_TELEFONO

Changed paths:
    engines/alcachofa/game-v2.cpp
    engines/alcachofa/script.cpp


diff --git a/engines/alcachofa/game-v2.cpp b/engines/alcachofa/game-v2.cpp
index 7828a5d50c1..6851b42ace1 100644
--- a/engines/alcachofa/game-v2.cpp
+++ b/engines/alcachofa/game-v2.cpp
@@ -366,6 +366,13 @@ public:
 
 class GameWithVersion2_1 : public GameWithVersion2 {
 public:
+	void onLoadedGameFiles() override {
+		GameWithVersion2::onLoadedGameFiles();
+
+		auto &script = g_engine->script();
+		script.fixNestedMenuPop(25096); // Filemon using phone in PRIMER_PLANO_TELEFONO
+	}
+
 	Path getVideoPath(int32 videoId) override {
 		return Path(String::format("Data/DATA%02d.BIN", videoId));
 	}
@@ -384,6 +391,21 @@ public:
 		return GameWithVersion2::missingAnimation(fileName);
 	}
 
+	void missingSound(const Common::String &fileName) override {
+		// seems like in the last level, they didnt test anymore? Many missing sounds in the same area
+		if (fileName == "Sonidos/2147" ||
+			fileName == "Sonidos/2148" ||
+			fileName == "Sonidos/2149" ||
+			fileName == "Sonidos/2150" ||
+			fileName == "Sonidos/2151" ||
+			fileName == "Sonidos/2159" ||
+			fileName == "Sonidos/2160" ||
+			fileName == "Sonidos/2161" ||
+			fileName == "Sonidos/2162")
+			return;
+		GameWithVersion2::missingSound(fileName);
+	}
+
 	void unknownDropItem(const char *name) override {
 		// an original bug, the item will just stay in the inventory unusable
 		if (scumm_stricmp(name, "I_ELECTROCHOCK") == 0)
@@ -404,6 +426,8 @@ public:
 class GameCorvino : public GameWithVersion2_1 {
 public:
 	void onLoadedGameFiles() override {
+		GameWithVersion2_1::onLoadedGameFiles();
+
 		g_engine->script().variable("EsJuegoCompleto") = 0;
 	}
 
@@ -424,6 +448,8 @@ public:
 	}
 
 	void onLoadedGameFiles() override {
+		GameWithVersion2_1::onLoadedGameFiles();
+
 		g_engine->script().variable("EsJuegoCompleto") = 1;
 	}
 
@@ -439,6 +465,8 @@ public:
 	}
 
 	void onLoadedGameFiles() override {
+		GameWithVersion2_1::onLoadedGameFiles();
+
 		g_engine->script().variable("EsJuegoCompleto") = 2;
 	}
 
diff --git a/engines/alcachofa/script.cpp b/engines/alcachofa/script.cpp
index b9b64310836..2ad7b9c8c21 100644
--- a/engines/alcachofa/script.cpp
+++ b/engines/alcachofa/script.cpp
@@ -1204,6 +1204,8 @@ void Script::fixNestedMenuPop(uint32 pc) {
 	 *   secta-win-es
 	 *   escarabajo-win-es
 	 *   moscu-win-es
+	 *   corvino-win-es
+	 *   mamelucos-win-es
 	 */
 	scumm_assert(pc < _instructions.size());
 	auto &instr = _instructions[pc];


Commit: 1217dd690302df6f33cfc23258479dd4067aa0fb
    https://github.com/scummvm/scummvm/commit/1217dd690302df6f33cfc23258479dd4067aa0fb
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: V2: Enable texture filtering

Changed paths:
    engines/alcachofa/game-v2.cpp


diff --git a/engines/alcachofa/game-v2.cpp b/engines/alcachofa/game-v2.cpp
index 6851b42ace1..cceb66a66fb 100644
--- a/engines/alcachofa/game-v2.cpp
+++ b/engines/alcachofa/game-v2.cpp
@@ -177,7 +177,7 @@ public:
 	}
 
 	bool shouldFilterTexturesByDefault() override {
-		return false;
+		return true;
 	}
 
 	bool shouldClipCamera() override {


Commit: 72decc28bf3d034998d44edb868da37715247c15
    https://github.com/scummvm/scummvm/commit/72decc28bf3d034998d44edb868da37715247c15
Author: Helco (hermann.noll at hotmail.com)
Date: 2026-06-25T19:39:56+02:00

Commit Message:
ALCACHOFA: V2: Improve animation path fallbacks

Changed paths:
    engines/alcachofa/game-v2.cpp
    engines/alcachofa/game.cpp
    engines/alcachofa/game.h
    engines/alcachofa/graphics.cpp


diff --git a/engines/alcachofa/game-v2.cpp b/engines/alcachofa/game-v2.cpp
index cceb66a66fb..ce1827d9109 100644
--- a/engines/alcachofa/game-v2.cpp
+++ b/engines/alcachofa/game-v2.cpp
@@ -171,6 +171,12 @@ public:
 			kind == MainCharacterKind::Mortadelo ? "PistaMorta" : "PistaFile");
 	}
 
+	bool shouldMusicLoop() override {
+		// The credits cutscene is slightly longer than the
+		// so we just disable looping and keep the last couple seconds quiet
+		return !g_engine->player().currentRoom()->name().equalsIgnoreCase("CREDITOS");
+	}
+
 	bool hasMortadeloVoice(const Character *character) override {
 		return Game::hasMortadeloVoice(character) ||
 			character->name().equalsIgnoreCase("MORTA_ATADO");
@@ -212,26 +218,48 @@ public:
 		return !room->name().equalsIgnoreCase("Global");
 	}
 
-	String reencodePath(const String &path) override {
-		if (!_hasMessedUpEncoding)
-			return Game::reencodePath(path);
-
-		// Some of the Steam releases have wrong characters due to a messed up UTF8 conversion
-		U32String u32String = path.decode(Common::CodePage::kISO8859_1);
-		for (uint i = 0; i < u32String.size(); i++) {
-			const auto ch = u32String[i];
-			if (ch == 0xC1) // Á -> ╡
-				u32String[i] = 0x2561;
-			else if (ch == 0xD3) // Ó -> α
-				u32String[i] = 0x03B1;
-			else if (ch == 0xCD) // Í -> ╓
-				u32String[i] = 0x2553;
-		}
-		return u32String.encode();
+	String alternativeAnimationName(const String &path, int variant) override {
+		U32String u32String = path.decode(Common::CodePage::kUtf8);
+		bool hasChanges = false;
+		if (variant == 0) {
+			// SearchMan cannot find case-insensitive with non-ascii special characters
+			// (e.g. "autógrafo" is not found by "AUTÓGRAFO")
+			for (uint i = 0; i < u32String.size(); i++) {
+				const auto ch = u32String[i];
+				if (ch == 0xC1) {
+					u32String[i] = 0xE1; // Á -> á
+					hasChanges = true;
+				} else if (ch == 0xD3) {
+					u32String[i] = 0xF3; // Ó -> ó
+					hasChanges = true;
+				} else if (ch == 0xCD) {
+					u32String[i] = 0xED; // Í -> í
+					hasChanges = true;
+				} else if (ch == 0xD1) {
+					u32String[i] = 0xF1; // Ñ -> ñ
+					hasChanges = true;
+				}
+			}
+			return hasChanges ? u32String.encode() : String();
+		} else if (variant == 1) {
+			// Some of the Steam releases have wrong characters due to a messed up UTF8 conversion
+			for (uint i = 0; i < u32String.size(); i++) {
+				const auto ch = u32String[i];
+				if (ch == 0xC1) { // Á -> ╡
+					u32String[i] = 0x2561;
+					hasChanges = true;
+				} else if (ch == 0xD3) { // Ó -> α
+					u32String[i] = 0x03B1;
+					hasChanges = true;
+				} else if (ch == 0xCD) { // Í -> ╓
+					u32String[i] = 0x2553;
+					hasChanges = true;
+				}
+			}
+			return hasChanges ? u32String.encode() : String();
+		} else
+			return String();
 	}
-
-protected:
-	bool _hasMessedUpEncoding = false;
 };
 
 class GameWithVersion2_0 : public GameWithVersion2 {
@@ -258,12 +286,6 @@ public:
 			return Game::unknownCamLerpTarget(action, name);
 		return nullptr;
 	}
-
-	bool shouldMusicLoop() override {
-		// The credits cutscene is slightly longer than the
-		// so we just disable looping and keep the last couple seconds quiet
-		return !g_engine->player().currentRoom()->name().equalsIgnoreCase("CREDITOS");
-	}
 };
 
 static constexpr const char *kMapFilesSecta[] = {
@@ -343,10 +365,6 @@ public:
 
 class GameEscarabajo : public GameWithVersion2_0 {
 public:
-	GameEscarabajo() {
-		_hasMessedUpEncoding = !SearchMan.hasFile(Path(reencode("Animaciones/M\xC1SCARA MUSEO_RECEPCI\xD3N.ANI")));
-	}
-
 	void onLoadedGameFiles() override {
 		g_engine->script().variable("EsJuegoCompleto") = 2;
 	}
@@ -373,10 +391,6 @@ public:
 		script.fixNestedMenuPop(25096); // Filemon using phone in PRIMER_PLANO_TELEFONO
 	}
 
-	Path getVideoPath(int32 videoId) override {
-		return Path(String::format("Data/DATA%02d.BIN", videoId));
-	}
-
 	char getTextFileKey() override {
 		return static_cast<char>(0x60);
 	}
@@ -435,6 +449,10 @@ public:
 		return kMapFilesCorvino;
 	}
 
+	Path getVideoPath(int32 videoId) override {
+		return Path(String::format("Data/DATA%02d.BIN", videoId));
+	}
+
 	bool isKnownBadVideo(int32 videoId) override {
 		// These use DV codec in the steam release
 		return videoId < 2;
@@ -443,10 +461,6 @@ public:
 
 class GameBalones : public GameWithVersion2_1 {
 public:
-	GameBalones() {
-		_hasMessedUpEncoding = !SearchMan.hasFile(Path(reencode("Animaciones/aut\xD3grafo.ani")));
-	}
-
 	void onLoadedGameFiles() override {
 		GameWithVersion2_1::onLoadedGameFiles();
 
@@ -456,14 +470,42 @@ public:
 	const char *const *getMapFiles() override {
 		return kMapFilesBalones;
 	}
+
+	Path getVideoPath(int32 videoId) override {
+		return Path(String::format("Bin/DATA%02d.BIN", videoId));
+	}
+
+	void missingAnimation(const Common::String &filename) override {
+		if (filename.equalsIgnoreCase("DOCE EUROS.ANI") ||
+			filename.equalsIgnoreCase("ASPIRADORA_MANGUERA.ANI") ||
+			filename.equalsIgnoreCase("ASPIRADORA.ANI") ||
+			filename.equalsIgnoreCase("ASPIRADOR.ANI") ||
+			filename.equalsIgnoreCase("CABEZA.ANI") ||
+			filename.equalsIgnoreCase("CANICAS.ANI") ||
+			filename.equalsIgnoreCase("HUEVO.ANI") ||
+			filename.equalsIgnoreCase("NAVAJA.ANI") ||
+			filename.equalsIgnoreCase("PALANCA.ANI") ||
+			filename.equalsIgnoreCase("PELUCA MOJADA.ANI") ||
+			filename.equalsIgnoreCase("PERA.ANI") ||
+			filename.equalsIgnoreCase("PERA CON PITORRO.ANI") ||
+			filename.equalsIgnoreCase("PILA.ANI") ||
+			filename.equalsIgnoreCase("PINCEL.ANI") ||
+			filename.equalsIgnoreCase("PINCEL CON COSA REPUGNANTE.ANI") ||
+			filename.equalsIgnoreCase("PINCEL SIN CEL.ANI") ||
+			filename.equalsIgnoreCase("PELO.ANI") ||
+			filename.equalsIgnoreCase("PELO RESINA.ANI") ||
+			filename.equalsIgnoreCase("PINTAU\xC3\x91""AS.ANI") ||
+			filename.equalsIgnoreCase("TARJETA CRÉDITO.ANI") ||
+			filename.equalsIgnoreCase("MANGUERA.ANI") ||
+			filename.equalsIgnoreCase("VENTILADOR.ANI") ||
+			filename.equalsIgnoreCase("BISO\xC3\x91\xC3\x89.ANI"))
+			return;
+		GameWithVersion2_1::missingAnimation(filename);
+	}
 };
 
 class GameMamelucos : public GameWithVersion2_1 {
 public:
-	GameMamelucos() {
-		_hasMessedUpEncoding = !SearchMan.hasFile(Path(reencode("Animaciones/EST\xC1TICOS FILEM\xD3N.ANI")));
-	}
-
 	void onLoadedGameFiles() override {
 		GameWithVersion2_1::onLoadedGameFiles();
 
@@ -473,6 +515,10 @@ public:
 	const char *const *getMapFiles() override {
 		return kMapFilesMamelucos;
 	}
+
+	Path getVideoPath(int32 videoId) override {
+		return Path(String::format("Bin/DATA%02d.BIN", videoId));
+	}
 };
 
 Game *Game::createForSecta() {
diff --git a/engines/alcachofa/game.cpp b/engines/alcachofa/game.cpp
index 3e5b1562caf..62e4362b540 100644
--- a/engines/alcachofa/game.cpp
+++ b/engines/alcachofa/game.cpp
@@ -153,6 +153,10 @@ PointObject *Game::unknownGoPutTarget(const Process &process, const char *action
 	return nullptr;
 }
 
+String Game::alternativeAnimationName(const String &fileName, int variant) {
+	return {};
+}
+
 void Game::missingAnimation(const String &fileName) {
 	_message("Could not open animation %s", fileName.c_str());
 }
diff --git a/engines/alcachofa/game.h b/engines/alcachofa/game.h
index 1fa369e3dac..d8c9976c5bd 100644
--- a/engines/alcachofa/game.h
+++ b/engines/alcachofa/game.h
@@ -117,6 +117,7 @@ public:
 	virtual void unknownScriptProcedure(const Common::String &procedure);
 	virtual void unknownMenuAction(int32 actionId);
 
+	virtual Common::String alternativeAnimationName(const Common::String &fileName, int variant);
 	virtual void missingAnimation(const Common::String &fileName);
 	virtual void missingSound(const Common::String &fileName);
 	virtual void invalidSNDFormat(uint format, uint channels, uint freq, uint bps);
diff --git a/engines/alcachofa/graphics.cpp b/engines/alcachofa/graphics.cpp
index b1e1cd48ad4..f50a95e10e1 100644
--- a/engines/alcachofa/graphics.cpp
+++ b/engines/alcachofa/graphics.cpp
@@ -156,6 +156,60 @@ AnimationBase::~AnimationBase() {
 	freeImages();
 }
 
+static void openAnimationFile(File *file, String name, AnimationFolder folder) {
+	// for real file paths we have to apply the folder and do a couple fallback
+	const char *extension = g_engine->isV3() ? ".AN0" : ".ANI";
+	String fullPath;
+	const auto getFullPath = [&] (AnimationFolder folder) {
+		switch (folder) {
+		case AnimationFolder::Animations:
+			fullPath = "Animaciones/";
+			break;
+		case AnimationFolder::Masks:
+			fullPath = "Mascaras/";
+			break;
+		case AnimationFolder::Backgrounds:
+			fullPath = "Fondos/";
+			break;
+		default:
+			assert(false && "Invalid AnimationFolder");
+			break;
+		}
+		fullPath += name;
+		if (!name.hasSuffixIgnoreCase(extension))
+			fullPath += extension;
+	};
+
+	// the canonical path
+	getFullPath(folder);
+	if (file->open(fullPath.c_str()))
+		return;
+
+	// an original fallback to a different folder
+	getFullPath(AnimationFolder::Masks);
+	if (file->open(fullPath.c_str()))
+		return;
+
+	// some V2 games has many different variants of messed up encodings
+	String originalName = name;
+	int variant = 0;
+	do {
+		name = g_engine->game().alternativeAnimationName(originalName, variant++);
+		if (name.empty())
+			return;
+
+		// with the original folder
+		getFullPath(folder);
+		if (file->open(fullPath.c_str()))
+			return;
+
+		// and the original Masks fallback again
+		getFullPath(AnimationFolder::Masks);
+		if (file->open(fullPath.c_str()))
+			return;
+	} while (true);
+}
+
 void AnimationBase::load() {
 	if (_isLoaded)
 		return;
@@ -170,38 +224,11 @@ void AnimationBase::load() {
 		} else
 			rawStream = g_engine->world().openFileRef(_fileRef);
 	} else {
-		// for real file paths we have to apply the folder and do some fallback
-		const char *extension = g_engine->isV3() ? ".AN0" : ".ANI";
-		String fullPath;
-		const auto getFullPath = [&] (AnimationFolder folder) {
-			switch (folder) {
-			case AnimationFolder::Animations:
-				fullPath = "Animaciones/";
-				break;
-			case AnimationFolder::Masks:
-				fullPath = "Mascaras/";
-				break;
-			case AnimationFolder::Backgrounds:
-				fullPath = "Fondos/";
-				break;
-			default:
-				assert(false && "Invalid AnimationFolder");
-				break;
-			}
-			fullPath += _fileRef._path;
-			if (!_fileRef._path.hasSuffixIgnoreCase(extension))
-				fullPath += extension;
-		};
-		getFullPath(_folder);
-
 		File *file = new File();
-		if (!file->open(fullPath.c_str())) {
-			// original fallback
-			getFullPath(AnimationFolder::Masks);
-			if (!file->open(fullPath.c_str())) {
-				delete file;
-				file = nullptr;
-			}
+		openAnimationFile(file, _fileRef._path, _folder);
+		if (!file->isOpen()) {
+			delete file;
+			file = nullptr;
 		}
 		rawStream.reset(file);
 	}




More information about the Scummvm-git-logs mailing list