diff options
-rw-r--r-- | engines/glk/detection.cpp | 9 | ||||
-rw-r--r-- | engines/glk/hugo/detection.cpp | 113 | ||||
-rw-r--r-- | engines/glk/hugo/detection.h | 63 | ||||
-rw-r--r-- | engines/glk/hugo/detection_tables.h | 56 | ||||
-rw-r--r-- | engines/glk/hugo/hugo.cpp | 46 | ||||
-rw-r--r-- | engines/glk/hugo/hugo.h | 67 | ||||
-rw-r--r-- | engines/glk/hugo/hugo_types.h | 136 | ||||
-rw-r--r-- | engines/glk/module.mk | 2 |
8 files changed, 492 insertions, 0 deletions
diff --git a/engines/glk/detection.cpp b/engines/glk/detection.cpp index 193d439ba9..fe2ea0bdea 100644 --- a/engines/glk/detection.cpp +++ b/engines/glk/detection.cpp @@ -28,6 +28,8 @@ #include "glk/frotz/frotz.h" #include "glk/glulxe/detection.h" #include "glk/glulxe/glulxe.h" +#include "glk/hugo/detection.h" +#include "glk/hugo/hugo.h" #include "glk/magnetic/detection.h" #include "glk/magnetic/magnetic.h" #include "glk/scott/detection.h" @@ -114,6 +116,7 @@ Common::Error GlkMetaEngine::createInstance(OSystem *syst, Engine **engine) cons else if ((*engine = create<Glk::Scott::ScottMetaEngine, Glk::Scott::Scott>(syst, gameDesc)) != nullptr) {} #ifndef RELEASE_BUILD else if ((*engine = create<Glk::Alan2::Alan2MetaEngine, Glk::Alan2::Alan2>(syst, gameDesc)) != nullptr) {} + else if ((*engine = create<Glk::Hugo::HugoMetaEngine, Glk::Hugo::Hugo>(syst, gameDesc)) != nullptr) {} else if ((*engine = create<Glk::Magnetic::MagneticMetaEngine, Glk::Magnetic::Magnetic>(syst, gameDesc)) != nullptr) {} else if ((td = Glk::TADS::TADSMetaEngine::findGame(gameDesc._gameId.c_str()))._description) { if (td._options & Glk::TADS::OPTION_TADS3) @@ -158,6 +161,7 @@ PlainGameList GlkMetaEngine::getSupportedGames() const { Glk::Scott::ScottMetaEngine::getSupportedGames(list); #ifndef RELEASE_BUILD Glk::Alan2::Alan2MetaEngine::getSupportedGames(list); + Glk::Hugo::HugoMetaEngine::getSupportedGames(list); Glk::Magnetic::MagneticMetaEngine::getSupportedGames(list); Glk::TADS::TADSMetaEngine::getSupportedGames(list); #endif @@ -179,6 +183,9 @@ PlainGameDescriptor GlkMetaEngine::findGame(const char *gameId) const { gd = Glk::Alan2::Alan2MetaEngine::findGame(gameId); if (gd._description) return gd; + gd = Glk::Hugo::HugoMetaEngine::findGame(gameId); + if (gd._description) return gd; + gd = Glk::Magnetic::MagneticMetaEngine::findGame(gameId); if (gd._description) return gd; @@ -199,6 +206,7 @@ DetectedGames GlkMetaEngine::detectGames(const Common::FSList &fslist) const { #ifndef RELEASE_BUILD Glk::Alan2::Alan2MetaEngine::detectGames(fslist, detectedGames); + Glk::Hugo::HugoMetaEngine::detectGames(fslist, detectedGames); Glk::Magnetic::MagneticMetaEngine::detectGames(fslist, detectedGames); Glk::TADS::TADSMetaEngine::detectGames(fslist, detectedGames); #endif @@ -214,6 +222,7 @@ void GlkMetaEngine::detectClashes() const { #ifndef RELEASE_BUILD Glk::Alan2::Alan2MetaEngine::detectClashes(map); + Glk::Hugo::HugoMetaEngine::detectClashes(map); Glk::Magnetic::MagneticMetaEngine::detectClashes(map); Glk::TADS::TADSMetaEngine::detectClashes(map); #endif diff --git a/engines/glk/hugo/detection.cpp b/engines/glk/hugo/detection.cpp new file mode 100644 index 0000000000..6a8203be4e --- /dev/null +++ b/engines/glk/hugo/detection.cpp @@ -0,0 +1,113 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "glk/hugo/detection.h" +#include "glk/hugo/detection_tables.h" +#include "common/debug.h" +#include "common/file.h" +#include "common/md5.h" +#include "engines/game.h" + +namespace Glk { +namespace Hugo { + +void HugoMetaEngine::getSupportedGames(PlainGameList &games) { + for (const PlainGameDescriptor *pd = HUGO_GAME_LIST; pd->gameId; ++pd) { + games.push_back(*pd); + } +} + +GameDescriptor HugoMetaEngine::findGame(const char *gameId) { + for (const PlainGameDescriptor *pd = HUGO_GAME_LIST; pd->gameId; ++pd) { + if (!strcmp(gameId, pd->gameId)) + return *pd; + } + + return PlainGameDescriptor(); +} + +bool HugoMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) { + const char *const EXTENSIONS[] = { ".mag", ".rsc", nullptr }; + + // Loop through the files of the folder + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + // Check for a recognised filename + if (file->isDirectory()) + continue; + Common::String filename = file->getName(); + bool hasExt = false; + for (const char *const *ext = &EXTENSIONS[0]; *ext && !hasExt; ++ext) + hasExt = filename.hasSuffixIgnoreCase(*ext); + if (!hasExt) + continue; + + // Open up the file and calculate the md5 + Common::File gameFile; + if (!gameFile.open(*file)) + continue; + if (gameFile.readUint32BE() != MKTAG('M', 'a', 'S', 'c')) { + gameFile.close(); + continue; + } + + gameFile.seek(0); + Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000); + size_t filesize = gameFile.size(); + gameFile.close(); + + // Check for known games + const HugoGameDescription *p = HUGO_GAMES; + while (p->_gameId && (md5 != p->_md5 || filesize != p->_filesize)) + ++p; + + DetectedGame gd; + if (!p->_gameId) { + if (gDebugLevel > 0) { + // Print an entry suitable for putting into the detection_tables.h + debug("ENTRY0(\"%s\", \"%s\", %u),", filename.c_str(), md5.c_str(), (uint)filesize); + } + + const PlainGameDescriptor &desc = HUGO_GAME_LIST[0]; + gd = DetectedGame(desc.gameId, desc.description, Common::UNK_LANG, Common::kPlatformUnknown); + } else { + PlainGameDescriptor gameDesc = findGame(p->_gameId); + gd = DetectedGame(p->_gameId, gameDesc.description, p->_language, Common::kPlatformUnknown, p->_extra); + gd.setGUIOptions(GUIO4(GUIO_NOSPEECH, GUIO_NOSFX, GUIO_NOMUSIC, GUIO_NOSUBTITLES)); + } + + gd.addExtraEntry("filename", filename); + gameList.push_back(gd); + } + + return !gameList.empty(); +} + +void HugoMetaEngine::detectClashes(Common::StringMap &map) { + for (const PlainGameDescriptor *pd = HUGO_GAME_LIST; pd->gameId; ++pd) { + if (map.contains(pd->gameId)) + error("Duplicate game Id found - %s", pd->gameId); + map[pd->gameId] = ""; + } +} + +} // End of namespace Hugo +} // End of namespace Glk diff --git a/engines/glk/hugo/detection.h b/engines/glk/hugo/detection.h new file mode 100644 index 0000000000..221a2ede8b --- /dev/null +++ b/engines/glk/hugo/detection.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GLK_HUGO_DETECTION +#define GLK_HUGO_DETECTION + +#include "common/fs.h" +#include "common/hash-str.h" +#include "engines/game.h" +#include "glk/detection.h" + +namespace Glk { +namespace Hugo { + +/** + * Meta engine for Hugo interpreter + */ +class HugoMetaEngine { +public: + /** + * Get a list of supported games + */ + static void getSupportedGames(PlainGameList &games); + + /** + * Returns a game description for the given game Id, if it's supported + */ + static GameDescriptor findGame(const char *gameId); + + /** + * Detect supported games + */ + static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList); + + /** + * Check for game Id clashes with other sub-engines + */ + static void detectClashes(Common::StringMap &map); +}; + +} // End of namespace Hugo +} // End of namespace Glk + +#endif diff --git a/engines/glk/hugo/detection_tables.h b/engines/glk/hugo/detection_tables.h new file mode 100644 index 0000000000..8afe7c156c --- /dev/null +++ b/engines/glk/hugo/detection_tables.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "engines/game.h" +#include "common/gui_options.h" +#include "common/language.h" + +namespace Glk { +namespace Hugo { + +/** + * Game description + */ +struct HugoGameDescription { + const char *const _gameId; + const char *const _extra; + const char *const _md5; + size_t _filesize; + Common::Language _language; +}; + +const PlainGameDescriptor HUGO_GAME_LIST[] = { + { "hugo", "Hugo IF Game" }, + + { nullptr, nullptr } +}; + +#define ENTRY0(ID, MD5, FILESIZE) { ID, nullptr, MD5, FILESIZE, Common::EN_ANY } +#define ENTRY1(ID, EXTRA, MD5, FILESIZE) { ID, EXTRA, MD5, FILESIZE, Common::EN_ANY } +#define TABLE_END_MARKER { nullptr, nullptr, nullptr, 0, Common::EN_ANY } + +const HugoGameDescription HUGO_GAMES[] = { + TABLE_END_MARKER +}; + +} // End of namespace Hugo +} // End of namespace Glk diff --git a/engines/glk/hugo/hugo.cpp b/engines/glk/hugo/hugo.cpp new file mode 100644 index 0000000000..5945d81d83 --- /dev/null +++ b/engines/glk/hugo/hugo.cpp @@ -0,0 +1,46 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "glk/hugo/hugo.h" + +namespace Glk { +namespace Hugo { + +Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc) { +} + +void Hugo::runGame() { + +} + +Common::Error Hugo::loadGameData(strid_t file) { + // TODO + return Common::kNoError; +} + +Common::Error Hugo::saveGameData(strid_t file, const Common::String &desc) { + // TODO + return Common::kNoError; +} + +} // End of namespace Hugo +} // End of namespace Glk diff --git a/engines/glk/hugo/hugo.h b/engines/glk/hugo/hugo.h new file mode 100644 index 0000000000..7032bbad9f --- /dev/null +++ b/engines/glk/hugo/hugo.h @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GLK_HUGO_HUGO +#define GLK_HUGO_HUGO + +#include "common/scummsys.h" +#include "glk/glk_api.h" +#include "glk/hugo/hugo_types.h" + +namespace Glk { +namespace Hugo { + +/** + * Hugo game interpreter + */ +class Hugo : public GlkAPI { +public: + /** + * Constructor + */ + Hugo(OSystem *syst, const GlkGameDescription &gameDesc); + + /** + * Run the game + */ + void runGame(); + + /** + * Returns the running interpreter type + */ + virtual InterpreterType getInterpreterType() const override { return INTERPRETER_HUGO; } + + /** + * Load a savegame from the passed stream + */ + virtual Common::Error loadGameData(strid_t file) override; + + /** + * Save the game to the passed stream + */ + virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override; +}; + +} // End of namespace Hugo +} // End of namespace Glk + +#endif diff --git a/engines/glk/hugo/hugo_types.h b/engines/glk/hugo/hugo_types.h new file mode 100644 index 0000000000..19e5396967 --- /dev/null +++ b/engines/glk/hugo/hugo_types.h @@ -0,0 +1,136 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GLK_HUGO_TYPES +#define GLK_HUGO_TYPES + +#include "common/scummsys.h" + +namespace Glk { +namespace Hugo { + +#define MAX_HINTS 260 +#define MAX_HCONTENTS 30000 + +#define MAX_POSITIONS 20 +#define MAX_ANIMS 200 +#define MAX_FRAMES 20 +#define MAX_STRING_SIZE 0xFF00 +#define MAX_PICTURE_SIZE 0xC800 +#define MAX_MUSIC_SIZE 0x4E20 +#define MAX_HITEMS 25 + +struct lookup { + int16 flag; + int16 count; + + lookup() : flag(0), count(0) {} +}; + +struct picture { + byte * data; + uint32 data_size; + uint16 width; + uint16 height; + uint16 wbytes; + uint16 plane_step; + byte *mask; + + picture() : data(nullptr), data_size(0), width(0), height(0), wbytes(0), plane_step(0), + mask(nullptr) {} +}; + +/** + * Hugo animated pictures support + * + * Note: Some of the pictures for Wonderland and the Collection Volume 1 games + * are animations. To detect these, pass a pointer to a type8 as the is_anim + * argument to ms_extract(). + * + * There are two types of animated images, however almost all images are type1. + * A type1 image consists of four main elements: + * 1) A static picture which is loaded straight at the beginning + * 2) A set of frames with a mask. These frames are just "small pictures", which + * are coded like the normal static pictures. The image mask determines + * how the frame is removed after it has been displayed. A mask is exactly + * 1/8 the size of the image and holds 1 bit per pixel, saying "remove pixel" + * or leave pixel set when frame gets removed. It might be a good idea to check + * your system documentation for masking operations as your system might be + * able to use this mask data directly. + * 3) Positioning tables. These hold animation sequences consisting of commands + * like "Draw frame 12 at (123,456)" + * 4) A playback script, which determines how to use the positioning tables. + * These scripts are handled inside Hugo, so no need to worry about. + * However, details can be found in the ms_animate() function. + * + * A type2 image is like a type1 image, but it does not have a static + * picture, nor does it have frame masking. It just consists of frames. + * + * How to support animations? + * After getting is_anim == 1 you should call ms_animate() immediately, and at + * regular intervals until ms_animate() returns 0. An appropriate interval + * between calls is about 100 milliseconds. + * Each call to ms_animate() will fill in the arguments with the address + * and size of an array of ms_position structures (see below), each of + * which holds an an animation frame number and x and y co-ordinates. To + * display the animation, decode all the animation frames (discussed below) + * from a single call to ms_animate() and display each one over the main picture. + * If your port does not support animations, define NO_ANIMATION. + */ +struct ms_position { + int16 x, y; + int16 number; + + ms_position() : x(0), y(0), number(0) {} +}; + +/** + * Hugo Windows hint support + * + * The windowed Hugo Scolls games included online hints. To add support + * for the hints to your hugo port, you should implement the ms_showhints + * function. It retrieves a pointer to an array of ms_hint structs + * The root element is always hints[0]. The elcount determines the number + * of items in this topic. You probably want to display those in some kind + * of list interface. The content pointer points to the actual description of + * the items, separated by '\0' terminators. The nodetype is 1 if the items are + * "folders" and 2 if the items are hints. Hints should be displayed one after + * another. For "folder" items, the links array holds the index of the hint in + * the array which is to be displayed on selection. One hint block has exactly + * one type. The parent element determines the "back" target. + */ +struct ms_hint { + uint16 elcount; + uint16 nodetype; + byte *content; + uint16 links[MAX_HITEMS]; + uint16 parent; + + ms_hint() : elcount(0), nodetype(0), content(nullptr), parent(0) { + Common::fill(&links[0], &links[MAX_HITEMS], 0); + } +}; + +} // End of namespace Hugo +} // End of namespace Glk + +#endif diff --git a/engines/glk/module.mk b/engines/glk/module.mk index f8367c7208..ea85350958 100644 --- a/engines/glk/module.mk +++ b/engines/glk/module.mk @@ -71,6 +71,8 @@ MODULE_OBJS := \ glulxe/serial.o \ glulxe/string.o \ glulxe/vm.o \ + hugo/detection.o \ + hugo/hugo.o \ magnetic/detection.o \ magnetic/emu.o \ magnetic/graphics.o \ |