[Scummvm-git-logs] scummvm master -> 2e00256424edea691a3831c07ed822c296649428
mduggan
noreply at scummvm.org
Thu Jun 18 09:25:57 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
2e00256424 ACCESS: Support multiple languages in Noct rerelease
Commit: 2e00256424edea691a3831c07ed822c296649428
https://github.com/scummvm/scummvm/commit/2e00256424edea691a3831c07ed822c296649428
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2026-06-18T18:57:23+10:00
Commit Message:
ACCESS: Support multiple languages in Noct rerelease
Changed paths:
engines/access/access.cpp
engines/access/access.h
engines/access/detection.cpp
engines/access/detection_tables.h
engines/access/metaengine.cpp
engines/access/noctropolis/noctropolis_comicviewer.cpp
engines/access/noctropolis/noctropolis_game.cpp
engines/access/noctropolis/noctropolis_game.h
engines/access/noctropolis/noctropolis_inventory.cpp
engines/access/noctropolis/noctropolis_resources.cpp
engines/access/noctropolis/noctropolis_resources.h
engines/access/scripts.cpp
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index 9fb4964b70a..04c92b2ddcd 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -122,6 +122,8 @@ AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
_stilScaleOff = 0;
ARRAYCLEAR(_countTbl);
+
+ _lang = Common::UNK_LANG;
}
AccessEngine::~AccessEngine() {
@@ -212,8 +214,7 @@ void AccessEngine::initialize() {
const SpriteResource *AccessEngine::getIcons() {
if (!_icons) {
- const char *fname = (getGameID() == kGameNoctropolis) ? "ICONS.AP" : "ICONS.LZ";
- Resource *iconData = _files->loadRawFile(fname);
+ Resource *iconData = _files->loadRawFile(getIconPath());
_icons = new SpriteResource(this, iconData);
delete iconData;
}
@@ -221,6 +222,11 @@ const SpriteResource *AccessEngine::getIcons() {
}
Common::Error AccessEngine::run() {
+ if (ConfMan.hasKey("language"))
+ _lang = Common::parseLanguage(ConfMan.get("language"));
+ else
+ _lang = getLanguage();
+
_res = Resources::init(this);
Common::U32String errorMessage;
if (!_res->load(errorMessage)) {
diff --git a/engines/access/access.h b/engines/access/access.h
index 0e2698252fc..6044f115658 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -147,6 +147,11 @@ private:
*/
SpriteResource *_icons;
+ /**
+ * Lang to use for resources.
+ */
+ Common::Language _lang;
+
/**
* Handles basic initialization
*/
@@ -201,6 +206,11 @@ protected:
*/
virtual void setupGame() = 0;
+ /**
+ * Get the path to the icons file
+ */
+ virtual Common::Path getIconPath() const { return Common::Path("ICONS.LZ"); }
+
public:
AnimationManager *_animation;
BubbleBox *_bubbleBox;
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp
index 9de6d795476..b73c1e2c5d8 100644
--- a/engines/access/detection.cpp
+++ b/engines/access/detection.cpp
@@ -65,6 +65,30 @@ public:
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
+
+ DetectedGame toDetectedGame(const ADDetectedGame &adGame, ADDetectedGameExtraInfo *extraInfo) const override {
+ static const Common::Language NOCTROPOLIS_RERELEASE_LANGS[] = {
+ Common::EN_ANY,
+ Common::FR_FRA,
+ Common::DE_DEU,
+ Common::ES_ESP,
+ };
+ DetectedGame game = AdvancedMetaEngineDetection::toDetectedGame(adGame);
+
+ const Access::AccessGameDescription *desc = reinterpret_cast<const Access::AccessGameDescription *>(adGame.desc);
+ assert(desc);
+
+ if (desc && (desc->features & Access::FEATURE_NOCT_MULTI_LANG)) {
+ // The AdvancedDetector model only allows specifying a single supported
+ // game language. The Noctropolis re-release supports multiple languages.
+ for (const auto lang: NOCTROPOLIS_RERELEASE_LANGS) {
+ game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(lang));
+ }
+ }
+
+ return game;
+ }
+
};
diff --git a/engines/access/detection_tables.h b/engines/access/detection_tables.h
index cf9398ab7a1..b9513ac7d0f 100644
--- a/engines/access/detection_tables.h
+++ b/engines/access/detection_tables.h
@@ -21,6 +21,8 @@
namespace Access {
+static const uint FEATURE_NOCT_MULTI_LANG = 1;
+
static const AccessGameDescription gameDescriptions[] = {
{
// Amazon Guardians of Eden - Floppy English
@@ -163,7 +165,7 @@ static const AccessGameDescription gameDescriptions[] = {
},
{
- // Noctropolis - sum of this file is the same in all known verisons
+ // Noctropolis - original release
{
"noctropolis",
nullptr,
@@ -179,13 +181,13 @@ static const AccessGameDescription gameDescriptions[] = {
},
{
- // Noctropolis - GOG/Steam version
+ // Noctropolis - original release, German
{
"noctropolis",
- "Rerelease",
+ nullptr,
AD_ENTRY2s("dark/scene01.ap", "3a154bf58e10cd7ace14cab1bf5adf4a", 147954,
- "dark/scene13.ap", "0d400713ed30e692d63af4d28ba42c5e", 327980),
- Common::EN_ANY,
+ "dark/scene13.ap", "261c65ea702c6088ab3ed6e39e217d64", 328430),
+ Common::DE_DEU,
Common::kPlatformWindows,
ADGF_TESTING,
GUIO1(GUIO_NONE)
@@ -194,6 +196,22 @@ static const AccessGameDescription gameDescriptions[] = {
0
},
+ {
+ // Noctropolis - GOG/Steam version (multi-language support)
+ {
+ "noctropolis",
+ "Rerelease",
+ AD_ENTRY2s("dark/scene01.ap", "3a154bf58e10cd7ace14cab1bf5adf4a", 147954,
+ "dark/scene13.ap", "0d400713ed30e692d63af4d28ba42c5e", 327980),
+ Common::UNK_LANG,
+ Common::kPlatformWindows,
+ ADGF_TESTING,
+ GUIO1(GUIO_GAMEOPTIONS1)
+ },
+ kGameNoctropolis,
+ FEATURE_NOCT_MULTI_LANG
+ },
+
{ AD_TABLE_END_MARKER, 0, 0 }
};
diff --git a/engines/access/metaengine.cpp b/engines/access/metaengine.cpp
index 4da9f8dedb9..309663aa331 100644
--- a/engines/access/metaengine.cpp
+++ b/engines/access/metaengine.cpp
@@ -41,6 +41,7 @@
#include "common/translation.h"
#define MAX_SAVES 99
+#define GAMEOPTION_OGG_MUSIC GUIO_GAMEOPTIONS1
namespace Access {
@@ -65,7 +66,7 @@ bool AccessEngine::isDemo() const {
}
Common::Language AccessEngine::getLanguage() const {
- return _gameDescription->desc.language;
+ return _lang;
}
Common::Platform AccessEngine::getPlatform() const {
@@ -74,6 +75,22 @@ Common::Platform AccessEngine::getPlatform() const {
} // End of namespace Access
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_OGG_MUSIC,
+ {
+ _s("Use 'high definition' OGG music"),
+ _s("Use the OGG audio from the re-release instead of original MIDI tracks"),
+ "ogg_music",
+ true,
+ 0,
+ 0
+ }
+ },
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+
class AccessMetaEngine : public AdvancedMetaEngine<Access::AccessGameDescription> {
public:
const char *getName() const override {
@@ -88,6 +105,11 @@ public:
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
Common::KeymapArray initKeymaps(const char *target) const override;
+
+ const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
+ return optionsList;
+ }
+
};
bool AccessMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -201,7 +223,6 @@ SaveStateDescriptor AccessMetaEngine::querySaveMetaInfos(const char *target, int
return SaveStateDescriptor();
}
-
Common::KeymapArray AccessMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
using namespace Access;
diff --git a/engines/access/noctropolis/noctropolis_comicviewer.cpp b/engines/access/noctropolis/noctropolis_comicviewer.cpp
index 30bc311df63..757c5631760 100644
--- a/engines/access/noctropolis/noctropolis_comicviewer.cpp
+++ b/engines/access/noctropolis/noctropolis_comicviewer.cpp
@@ -20,6 +20,7 @@
*/
#include "access/noctropolis/noctropolis_comicviewer.h"
+#include "access/noctropolis/noctropolis_resources.h"
namespace Access {
@@ -72,7 +73,7 @@ void ComicViewer::run(const ComicResource *comic) {
PageResult ComicViewer::runPage(const ComicPage *page) {
PageResult result = kPageResultNone;
- Common::Path pagePath(page->filename);
+ Common::Path pagePath = ((NoctropolisResources *)_vm->_res)->translatePath(page->filename);
if (!_vm->_files->existFile(pagePath)) {
// Happens in Demo 2 - no comic files
@@ -82,7 +83,8 @@ PageResult ComicViewer::runPage(const ComicPage *page) {
_vm->_files->loadScreen(pagePath);
- Resource *bubbleData = _vm->_files->loadRawFile("COMDATA/comic.ap");
+ Common::Path bubbleDataPath = ((NoctropolisResources *)_vm->_res)->translatePath("DARK/COMDATA/comic.ap");
+ Resource *bubbleData = _vm->_files->loadRawFile(bubbleDataPath);
_bubbleSprites = new SpriteResource(_vm, bubbleData);
delete bubbleData;
diff --git a/engines/access/noctropolis/noctropolis_game.cpp b/engines/access/noctropolis/noctropolis_game.cpp
index 8e040bad117..eecb61287b8 100644
--- a/engines/access/noctropolis/noctropolis_game.cpp
+++ b/engines/access/noctropolis/noctropolis_game.cpp
@@ -72,6 +72,11 @@ void NoctropolisEngine::initObjects() {
}
}
+Common::Path NoctropolisEngine::getIconPath() const {
+ return ((NoctropolisResources *)_res)->translatePath("DARK/ICONS.AP");
+}
+
+
void NoctropolisEngine::setupGame() {
_timers.clear();
for (int i = 0; i < 32; ++i) {
diff --git a/engines/access/noctropolis/noctropolis_game.h b/engines/access/noctropolis/noctropolis_game.h
index badb490bc83..8ddf2729e70 100644
--- a/engines/access/noctropolis/noctropolis_game.h
+++ b/engines/access/noctropolis/noctropolis_game.h
@@ -106,6 +106,11 @@ protected:
*/
Common::Error synchronize(Common::Serializer &s) override;
+ /**
+ * Get the path to the icons file
+ */
+ Common::Path getIconPath() const override;
+
private:
void doIntro();
void doFlashLogo();
diff --git a/engines/access/noctropolis/noctropolis_inventory.cpp b/engines/access/noctropolis/noctropolis_inventory.cpp
index 98b780cafc6..39a7d155614 100644
--- a/engines/access/noctropolis/noctropolis_inventory.cpp
+++ b/engines/access/noctropolis/noctropolis_inventory.cpp
@@ -20,6 +20,7 @@
*/
#include "access/noctropolis/noctropolis_inventory.h"
+#include "access/noctropolis/noctropolis_resources.h"
#include "access/access.h"
#include "access/resources.h"
#include "access/asurface.h"
@@ -60,8 +61,8 @@ int NoctropolisInventory::displayInv() {
g_system->warpMouse(warpMouseX, warpMouseY);
}
- // TODO: Maybe move/load these globally?
- Resource *iconData = _vm->_files->loadRawFile("INV.AP");
+ Common::Path path = ((NoctropolisResources *)_vm->_res)->translatePath("DARK/INV.AP");
+ Resource *iconData = _vm->_files->loadRawFile(path);
SpriteResource *inventorySprites = new SpriteResource(_vm, iconData);
delete iconData;
diff --git a/engines/access/noctropolis/noctropolis_resources.cpp b/engines/access/noctropolis/noctropolis_resources.cpp
index 43739415fd3..c3a1c708af0 100644
--- a/engines/access/noctropolis/noctropolis_resources.cpp
+++ b/engines/access/noctropolis/noctropolis_resources.cpp
@@ -1866,19 +1866,15 @@ static int _langOffset(Common::Language lang) {
void NoctropolisResources::load(Common::SeekableReadStream &s) {
// Note: *don't* call the base class here. Noctropolis doesn't have data in access.dat.
-
- // TODO: For non-EN variants we want to use something other than DARK/ as the path.
for (int i = 0; i < ARRAYSIZE(NOCT_FILES_1); i++) {
- Common::Path filename = Common::Path(NOCT_FILES_1[i]).getLastComponent();
- FILENAMES.push_back(filename);
+ FILENAMES.push_back(translatePath(NOCT_FILES_1[i]));
}
// TODO: These last few files are maybe only ever used from hard-coded points,
// so maybe we can just hard-code the names in those places and avoid this hack?
while (FILENAMES.size() < 256 - ARRAYSIZE(NOCT_FILES_2))
FILENAMES.push_back(Common::Path());
for (int i = 0; i < ARRAYSIZE(NOCT_FILES_2); i++) {
- Common::Path filename = Common::Path(NOCT_FILES_2[i]).getLastComponent();
- FILENAMES.push_back(filename);
+ FILENAMES.push_back(translatePath(NOCT_FILES_2[i]));
}
_fontChaleteu = new NoctropolisFont(0x66, 11, 1, 0xe2, CHALETEU_OFFSETS, CHALETEU_DATA);
@@ -2022,6 +2018,26 @@ void NoctropolisResources::load(Common::SeekableReadStream &s) {
}
}
+Common::Path NoctropolisResources::translatePath(const char *rawPath) const {
+ Common::String path_prefix;
+ switch (_vm->getLanguage()) {
+ case Common::FR_FRA: path_prefix = "FR/"; break;
+ case Common::DE_DEU: path_prefix = "DE/"; break;
+ case Common::ES_ESP: path_prefix = "ES/"; break;
+ default: break;
+ }
+
+ Common::String path = path_prefix + rawPath;
+ if (_vm->isDemo())
+ path.replace(0, 4, "DEMO"); // replace DARK with DEMO.
+
+ if (!path_prefix.empty() && !SearchMan.hasFile(Common::Path(path)))
+ path = path.substr(path_prefix.size());
+
+ return Common::Path(path);
+}
+
+
int NoctropolisResources::menuAt(int16 x, int16 y) const {
for (int i = 0; i < (int)_menus.size(); i++) {
if (Polygon::pointInside(_menus[i], x, y))
diff --git a/engines/access/noctropolis/noctropolis_resources.h b/engines/access/noctropolis/noctropolis_resources.h
index d496ab309a9..d3c2e3c6e72 100644
--- a/engines/access/noctropolis/noctropolis_resources.h
+++ b/engines/access/noctropolis/noctropolis_resources.h
@@ -74,6 +74,8 @@ public:
const ComicResource *getLastComicResource() const;
const ComicResource *getSpecialComicResource() const;
+ Common::Path translatePath(const char *rawPath) const;
+
int menuAt(int16 x, int16 y) const;
private:
diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp
index 1d9ed34f795..ceb4f757ef3 100644
--- a/engines/access/scripts.cpp
+++ b/engines/access/scripts.cpp
@@ -1532,7 +1532,8 @@ void Scripts::cmdDispAbout_v3() {
int selectedItem = -2;
bool needRedraw = true;
- Resource *spriteData = _vm->_files->loadRawFile("ASK.AP");
+ Common::Path path = ((Noctropolis::NoctropolisResources *)_vm->_res)->translatePath("DARK/ASK.AP");
+ Resource *spriteData = _vm->_files->loadRawFile(path);
SpriteResource *askSprites = new SpriteResource(_vm, spriteData);
delete spriteData;
More information about the Scummvm-git-logs
mailing list