diff options
author | Eugene Sandulenko | 2016-10-15 13:51:00 +0200 |
---|---|---|
committer | GitHub | 2016-10-15 13:51:00 +0200 |
commit | af2027ddd19b7ac14b3671e80fd6eca1a2a6b12d (patch) | |
tree | add20a37863a6feee1e5778b93cfa28c1969b7a9 /engines/chewy | |
parent | e928198a722f076f6ed87c90c9799b5855c7b946 (diff) | |
parent | 53de49a052426151a1afb1de0b6843d1b8127b9b (diff) | |
download | scummvm-rg350-af2027ddd19b7ac14b3671e80fd6eca1a2a6b12d.tar.gz scummvm-rg350-af2027ddd19b7ac14b3671e80fd6eca1a2a6b12d.tar.bz2 scummvm-rg350-af2027ddd19b7ac14b3671e80fd6eca1a2a6b12d.zip |
Merge pull request #838 from bluegr/chewy
Chewy: Esc from F5. New WIP engine.
Diffstat (limited to 'engines/chewy')
-rw-r--r-- | engines/chewy/chewy.cpp | 128 | ||||
-rw-r--r-- | engines/chewy/chewy.h | 87 | ||||
-rw-r--r-- | engines/chewy/configure.engine | 3 | ||||
-rw-r--r-- | engines/chewy/console.cpp | 238 | ||||
-rw-r--r-- | engines/chewy/console.h | 54 | ||||
-rw-r--r-- | engines/chewy/cursor.cpp | 107 | ||||
-rw-r--r-- | engines/chewy/cursor.h | 54 | ||||
-rw-r--r-- | engines/chewy/detection.cpp | 151 | ||||
-rw-r--r-- | engines/chewy/events.cpp | 63 | ||||
-rw-r--r-- | engines/chewy/events.h | 51 | ||||
-rw-r--r-- | engines/chewy/graphics.cpp | 145 | ||||
-rw-r--r-- | engines/chewy/graphics.h | 53 | ||||
-rw-r--r-- | engines/chewy/module.mk | 22 | ||||
-rw-r--r-- | engines/chewy/resource.cpp | 314 | ||||
-rw-r--r-- | engines/chewy/resource.h | 184 | ||||
-rw-r--r-- | engines/chewy/scene.cpp | 59 | ||||
-rw-r--r-- | engines/chewy/scene.h | 45 | ||||
-rw-r--r-- | engines/chewy/sound.cpp | 257 | ||||
-rw-r--r-- | engines/chewy/sound.h | 81 | ||||
-rw-r--r-- | engines/chewy/text.cpp | 214 | ||||
-rw-r--r-- | engines/chewy/text.h | 113 | ||||
-rw-r--r-- | engines/chewy/video/cfo_decoder.cpp | 319 | ||||
-rw-r--r-- | engines/chewy/video/cfo_decoder.h | 74 |
23 files changed, 2816 insertions, 0 deletions
diff --git a/engines/chewy/chewy.cpp b/engines/chewy/chewy.cpp new file mode 100644 index 0000000000..75243ccfd0 --- /dev/null +++ b/engines/chewy/chewy.cpp @@ -0,0 +1,128 @@ +/* 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 "common/config-manager.h" +#include "common/error.h" +#include "common/events.h" +#include "common/system.h" +#include "graphics/palette.h" + +#include "engines/engine.h" +#include "engines/util.h" + +#include "chewy/chewy.h" +#include "chewy/console.h" +#include "chewy/cursor.h" +#include "chewy/events.h" +#include "chewy/graphics.h" +#include "chewy/resource.h" +#include "chewy/scene.h" +#include "chewy/sound.h" +#include "chewy/text.h" + +namespace Chewy { + +ChewyEngine::ChewyEngine(OSystem *syst, const ChewyGameDescription *gameDesc) + : Engine(syst), + _gameDescription(gameDesc), + _rnd("chewy") { + + const Common::FSNode gameDataDir(ConfMan.get("path")); + + SearchMan.addSubDirectoryMatching(gameDataDir, "back"); + SearchMan.addSubDirectoryMatching(gameDataDir, "cut"); + SearchMan.addSubDirectoryMatching(gameDataDir, "err"); + SearchMan.addSubDirectoryMatching(gameDataDir, "misc"); + SearchMan.addSubDirectoryMatching(gameDataDir, "room"); + SearchMan.addSubDirectoryMatching(gameDataDir, "sound"); + SearchMan.addSubDirectoryMatching(gameDataDir, "txt"); +} + +ChewyEngine::~ChewyEngine() { + delete _events; + delete _text; + delete _sound; + delete _cursor; + delete _scene; + delete _graphics; + delete _console; +} + +void ChewyEngine::initialize() { + _console = new Console(this); + _cursor = new Cursor(this); + _graphics = new Graphics(this); + _scene = new Scene(this); + _sound = new Sound(_mixer); + _text = new Text(); + _events = new Events(this, _graphics, _console); + + _curCursor = 0; + _elapsedFrames = 0; + _videoNum = -1; +} + +Common::Error ChewyEngine::run() { + // Initialize backend + //initGraphics(640, 480, true); + initGraphics(320, 200, false); + + initialize(); + + /*for (uint i = 0; i < 161; i++) { + debug("Video %d", i); + _graphics->playVideo(i); + }*/ + + //_graphics->playVideo(0); + + _scene->change(0); + //_sound->playSpeech(1); + //_sound->playSound(1); + //_sound->playMusic(2); + + // Run a dummy loop + while (!shouldQuit()) { + _events->processEvents(); + + _console->onFrame(); + + // Cursor animation + if (_elapsedFrames % 30 == 0) + _cursor->animateCursor(); + + if (_videoNum >= 0) { + _graphics->playVideo(_videoNum); + _scene->draw(); + _videoNum = -1; + } + + g_system->updateScreen(); + g_system->delayMillis(10); + + _elapsedFrames++; + } + + return Common::kNoError; +} + +} // End of namespace Chewy diff --git a/engines/chewy/chewy.h b/engines/chewy/chewy.h new file mode 100644 index 0000000000..6ebeff833e --- /dev/null +++ b/engines/chewy/chewy.h @@ -0,0 +1,87 @@ +/* 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 CHEWY_CHEWY_H +#define CHEWY_CHEWY_H + + +#include "common/scummsys.h" +#include "common/file.h" +#include "common/util.h" +#include "common/str.h" +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "common/random.h" + +#include "engines/engine.h" + +namespace Chewy { + +struct ChewyGameDescription; +class Console; +class Cursor; +class Events; +class Graphics; +class Scene; +class Sound; +class Text; + +class ChewyEngine : public Engine { +public: + ChewyEngine(OSystem *syst, const ChewyGameDescription *gameDesc); + virtual ~ChewyEngine(); + + int getGameType() const; + uint32 getFeatures() const; + Common::Language getLanguage() const; + Common::Platform getPlatform() const; + + const ChewyGameDescription *_gameDescription; + Common::RandomSource _rnd; + + void setPlayVideo(uint num) { _videoNum = num; } + + Graphics *_graphics; + Cursor *_cursor; + Scene *_scene; + Sound *_sound; + Text *_text; + +protected: + // Engine APIs + virtual Common::Error run(); + virtual bool hasFeature(EngineFeature f) const; + + void initialize(); + void shutdown(); + + Console *_console; + Events *_events; + + uint _curCursor; + uint _elapsedFrames; + int _videoNum; +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/configure.engine b/engines/chewy/configure.engine new file mode 100644 index 0000000000..f9f7ffd101 --- /dev/null +++ b/engines/chewy/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine chewy "Chewy: Esc from F5" no diff --git a/engines/chewy/console.cpp b/engines/chewy/console.cpp new file mode 100644 index 0000000000..cb2d5e21c1 --- /dev/null +++ b/engines/chewy/console.cpp @@ -0,0 +1,238 @@ +/* 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 "gui/debugger.h" + +#include "chewy/chewy.h" +#include "chewy/console.h" +#include "chewy/graphics.h" +#include "chewy/resource.h" +#include "chewy/sound.h" +#include "chewy/text.h" + +namespace Chewy { + +Console::Console(ChewyEngine *vm) : GUI::Debugger(), _vm(vm) { + registerCmd("dump", WRAP_METHOD(Console, Cmd_Dump)); + registerCmd("dump_bg", WRAP_METHOD(Console, Cmd_DumpBg)); + registerCmd("draw", WRAP_METHOD(Console, Cmd_Draw)); + registerCmd("play_sound", WRAP_METHOD(Console, Cmd_PlaySound)); + registerCmd("play_speech", WRAP_METHOD(Console, Cmd_PlaySpeech)); + registerCmd("play_music", WRAP_METHOD(Console, Cmd_PlayMusic)); + registerCmd("play_video", WRAP_METHOD(Console, Cmd_PlayVideo)); + registerCmd("video_info", WRAP_METHOD(Console, Cmd_VideoInfo)); + registerCmd("error_message", WRAP_METHOD(Console, Cmd_ErrorMessage)); + registerCmd("dialog", WRAP_METHOD(Console, Cmd_Dialog)); + registerCmd("text", WRAP_METHOD(Console, Cmd_Text)); +} + +Console::~Console() { +} + +bool Console::Cmd_Dump(int argc, const char **argv) { + if (argc < 4) { + debugPrintf("Usage: dump <file> <resource number> <dump file name>\n"); + return true; + } + + Common::String filename = argv[1]; + int resNum = atoi(argv[2]); + Common::String dumpFilename = argv[3]; + + Resource *res = new Resource(filename); + Chunk *chunk = res->getChunk(resNum); + byte *data = res->getChunkData(resNum); + uint32 size = chunk->size; + + Common::DumpFile outFile; + outFile.open(dumpFilename); + outFile.write(data, size); + outFile.flush(); + outFile.close(); + + delete[] data; + delete res; + + return true; +} + +bool Console::Cmd_DumpBg(int argc, const char **argv) { + if (argc < 4) { + debugPrintf("Usage: dump_bg <file> <resource number> <dump file name>\n"); + return true; + } + + Common::String filename = argv[1]; + int resNum = atoi(argv[2]); + Common::String dumpFilename = argv[3]; + + BackgroundResource *res = new BackgroundResource(filename); + TBFChunk *image = res->getImage(resNum); + + Common::DumpFile outFile; + outFile.open(dumpFilename); + outFile.write(image->data, image->size); + outFile.flush(); + outFile.close(); + + delete[] image->data; + delete image; + delete res; + + return true; +} + + +bool Console::Cmd_Draw(int argc, const char **argv) { + if (argc < 3) { + debugPrintf("Usage: draw <file> <resource number>\n"); + return true; + } + + Common::String filename = argv[1]; + int resNum = atoi(argv[2]); + + _vm->_graphics->drawImage(filename, resNum); + + return false; +} + +bool Console::Cmd_PlaySound(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Usage: play_sound <number>\n"); + return true; + } + + int resNum = atoi(argv[1]); + _vm->_sound->playSound(resNum); + + return true; +} + +bool Console::Cmd_PlaySpeech(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Usage: play_speech <number>\n"); + return true; + } + + int resNum = atoi(argv[1]); + _vm->_sound->playSpeech(resNum); + + return true; +} + +bool Console::Cmd_PlayMusic(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Usage: play_music <number>\n"); + return true; + } + + int resNum = atoi(argv[1]); + _vm->_sound->playMusic(resNum); + + return true; +} + +bool Console::Cmd_PlayVideo(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Usage: play_video <number>\n"); + return true; + } + + int resNum = atoi(argv[1]); + _vm->setPlayVideo(resNum); + + return false; +} + +bool Console::Cmd_VideoInfo(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Usage: video_info <number>\n"); + return true; + } + + int resNum = atoi(argv[1]); + VideoResource *res = new VideoResource("cut.tap"); + VideoChunk *header = res->getVideoHeader(resNum); + debugPrintf("Size: %d, %d x %d, %d frames, %d ms frame delay, first frame at %d\n", header->size, header->width, header->height, header->frameCount, header->frameDelay, header->firstFrameOffset); + delete header; + delete res; + + return true; +} + +bool Console::Cmd_ErrorMessage(int argc, const char **argv) { + if (argc < 3) { + debugPrintf("Usage: error_message <file> <message number>\n"); + return true; + } + + Common::String filename = argv[1]; + int resNum = atoi(argv[2]); + + ErrorMessage *res = new ErrorMessage(filename); + Common::String str = res->getErrorMessage(resNum); + this->debugPrintf("Error message: %s\n", str.c_str()); + delete res; + + return true; +} + +bool Console::Cmd_Dialog(int argc, const char **argv) { + if (argc < 3) { + debugPrintf("Usage: dialog <dialog> <entry>\n"); + return true; + } + + int dialogNum = atoi(argv[1]); + int entryNum = atoi(argv[2]); + uint cur = 0; + TextEntryList *d = _vm->_text->getDialog(dialogNum, entryNum); + + for (TextEntryList::iterator it = d->begin(); it != d->end(); ++it) { + this->debugPrintf("Entry %d: speech %d, text '%s'\n", cur, (*it).speechId, (*it).text.c_str()); + } + + d->clear(); + delete d; + + return true; +} + +bool Console::Cmd_Text(int argc, const char **argv) { + if (argc < 3) { + debugPrintf("Usage: text <dialog> <entry>\n"); + return true; + } + + int dialogNum = atoi(argv[1]); + int entryNum = atoi(argv[2]); + TextEntry *d = _vm->_text->getText(dialogNum, entryNum); + + debugPrintf("Speech %d, text '%s'\n", d->speechId, d->text.c_str()); + + delete d; + + return true; +} + +} // End of namespace Chewy diff --git a/engines/chewy/console.h b/engines/chewy/console.h new file mode 100644 index 0000000000..4953480644 --- /dev/null +++ b/engines/chewy/console.h @@ -0,0 +1,54 @@ +/* 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 CHEWY_CONSOLE_H +#define CHEWY_CONSOLE_H + +#include "gui/debugger.h" + +namespace Chewy { + +class ChewyEngine; + +class Console : public GUI::Debugger { +public: + Console(ChewyEngine *vm); + virtual ~Console(void); + +private: + ChewyEngine *_vm; + + bool Cmd_Dump(int argc, const char **argv); + bool Cmd_DumpBg(int argc, const char **argv); + bool Cmd_Draw(int argc, const char **argv); + bool Cmd_PlaySound(int argc, const char **argv); + bool Cmd_PlaySpeech(int argc, const char **argv); + bool Cmd_PlayMusic(int argc, const char **argv); + bool Cmd_PlayVideo(int argc, const char **argv); + bool Cmd_VideoInfo(int argc, const char **argv); + bool Cmd_ErrorMessage(int argc, const char **argv); + bool Cmd_Dialog(int argc, const char **argv); + bool Cmd_Text(int argc, const char **argv); +}; + +} // End of namespace Chewy +#endif diff --git a/engines/chewy/cursor.cpp b/engines/chewy/cursor.cpp new file mode 100644 index 0000000000..18e001f05f --- /dev/null +++ b/engines/chewy/cursor.cpp @@ -0,0 +1,107 @@ +/* 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 "common/system.h" +#include "common/events.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +#include "chewy/cursor.h" +#include "chewy/resource.h" + +namespace Chewy { + +const byte _cursorFrames[] = { + 4, 1, 1, 1, // walk + 4, 1, 1, 1, // pick up / use + 1, 1, 1, 1, 1, + 4, 1, 1, 1, // look + 4, 1, 1, 1, // talk + 4, 1, 1, 1, // open + 1, + 1, 1, 1, 1, // left, right, up, down + 1, // save + 1, + 5, 1, 1, 1, 1, + 1, + 1, // use (inventory) + 1, // look (inventory) + 1 // gun +}; + +Cursor::Cursor(ChewyEngine *vm) : _vm(vm) { + _curCursor = 0; + _curCursorFrame = 0; + _cursorSprites = new SpriteResource("cursor.taf"); +} + +Cursor::~Cursor() { + delete _cursorSprites; +} + +void Cursor::setCursor(uint num, bool newCursor) { + TAFChunk *cursor = _cursorSprites->getSprite(num); + if (newCursor) + _curCursor = num; + + CursorMan.replaceCursor(cursor->data, cursor->width, cursor->height, 0, 0, 0); + + delete[] cursor->data; + delete cursor; +} + +void Cursor::showCursor() { + CursorMan.showMouse(true); +} + +void Cursor::hideCursor() { + CursorMan.showMouse(false); +} + +void Cursor::animateCursor() { + if (_cursorFrames[_curCursor] > 1) { + _curCursorFrame++; + + if (_curCursorFrame >= _cursorFrames[_curCursor]) + _curCursorFrame = 0; + + setCursor(_curCursor + _curCursorFrame, false); + } +} + +void Cursor::nextCursor() { + uint maxCursors = ARRAYSIZE(_cursorFrames); + + if (_cursorFrames[_curCursor] > 0) + _curCursor += _cursorFrames[_curCursor]; + else + _curCursor++; + + if (_curCursor >= maxCursors) + _curCursor = 0; + + _curCursorFrame = 0; + setCursor(_curCursor); +} + +} // End of namespace Chewy diff --git a/engines/chewy/cursor.h b/engines/chewy/cursor.h new file mode 100644 index 0000000000..1ab75d0997 --- /dev/null +++ b/engines/chewy/cursor.h @@ -0,0 +1,54 @@ +/* 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 CHEWY_CURSOR_H +#define CHEWY_CURSOR_H + +#include "chewy/chewy.h" + +namespace Chewy { + +class SpriteResource; +class Font; + +class Cursor { +public: + Cursor(ChewyEngine *vm); + virtual ~Cursor(); + + void setCursor(uint num, bool newCursor = true); + void showCursor(); + void hideCursor(); + void animateCursor(); + void nextCursor(); + +private: + ChewyEngine *_vm; + + uint _curCursor; + uint _curCursorFrame; + SpriteResource *_cursorSprites; +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/detection.cpp b/engines/chewy/detection.cpp new file mode 100644 index 0000000000..835a4358fa --- /dev/null +++ b/engines/chewy/detection.cpp @@ -0,0 +1,151 @@ +/* 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 "common/savefile.h" +#include "common/system.h" +#include "base/plugins.h" + +#include "engines/advancedDetector.h" + +#include "chewy/chewy.h" + + +namespace Chewy { + +struct ChewyGameDescription { + ADGameDescription desc; +}; + +uint32 ChewyEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +Common::Language ChewyEngine::getLanguage() const { + return _gameDescription->desc.language; +} + +} + +static const PlainGameDescriptor chewyGames[] = { + {"chewy", "Chewy: Esc from F5"}, + {0, 0} +}; + +static const char *directoryGlobs[] = { + "txt", + 0 +}; + +namespace Chewy { + +static const ChewyGameDescription gameDescriptions[] = { + + { + { + "chewy", + 0, + AD_ENTRY1s("atds.tap", "e6050c144dd4f23d79ea4f89a8ef306e", 218857), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + }, + + { AD_TABLE_END_MARKER } +}; + +} // End of namespace Chewy + +class ChewyMetaEngine : public AdvancedMetaEngine { +public: + ChewyMetaEngine() : AdvancedMetaEngine(Chewy::gameDescriptions, sizeof(Chewy::ChewyGameDescription), chewyGames) { + _maxScanDepth = 2; + _directoryGlobs = directoryGlobs; + _singleId = "chewy"; + } + + virtual const char *getName() const { + return "Chewy Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Chewy Engine New Generation Software (C) 1995"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + SaveStateList listSaves(const char *target) const; + virtual int getMaximumSaveSlot() const; + void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; +}; + +bool ChewyMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate) || + (f == kSavesSupportPlayTime); +} + +bool Chewy::ChewyEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); +} + +bool ChewyMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + const Chewy::ChewyGameDescription *gd = (const Chewy::ChewyGameDescription *)desc; + if (gd) { + *engine = new Chewy::ChewyEngine(syst, gd); + } + return gd != 0; +} + +SaveStateList ChewyMetaEngine::listSaves(const char *target) const { + SaveStateList saveList; + + return saveList; +} + +int ChewyMetaEngine::getMaximumSaveSlot() const { + return 999; +} + +void ChewyMetaEngine::removeSaveState(const char *target, int slot) const { +} + +SaveStateDescriptor ChewyMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + + return SaveStateDescriptor(); +} // End of namespace Chewy + +#if PLUGIN_ENABLED_DYNAMIC(CHEWY) + REGISTER_PLUGIN_DYNAMIC(CHEWY, PLUGIN_TYPE_ENGINE, ChewyMetaEngine); +#else + REGISTER_PLUGIN_STATIC(CHEWY, PLUGIN_TYPE_ENGINE, ChewyMetaEngine); +#endif diff --git a/engines/chewy/events.cpp b/engines/chewy/events.cpp new file mode 100644 index 0000000000..6675fea392 --- /dev/null +++ b/engines/chewy/events.cpp @@ -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. + * + */ + +#include "common/system.h" +#include "common/events.h" + +#include "chewy/chewy.h" +#include "chewy/console.h" +#include "chewy/cursor.h" +#include "chewy/events.h" +#include "chewy/graphics.h" + +namespace Chewy { + +Events::Events(ChewyEngine *vm, Graphics *graphics, Console *console) : + _vm(vm), _graphics(graphics), _console(console) { + + _eventManager = g_system->getEventManager(); +} + +void Events::processEvents() { + while (_eventManager->pollEvent(_event)) { + if (_event.type == Common::EVENT_KEYDOWN) { + switch (_event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: + _vm->quitGame(); + break; + case Common::KEYCODE_SPACE: + _vm->_cursor->nextCursor(); + break; + case Common::KEYCODE_d: + if (_event.kbd.flags & Common::KBD_CTRL) + _console->attach(); + break; + default: + break; + } + } else if (_event.type == Common::EVENT_RBUTTONUP) { + _vm->_cursor->nextCursor(); + } + } +} + +} // End of namespace Chewy diff --git a/engines/chewy/events.h b/engines/chewy/events.h new file mode 100644 index 0000000000..fb2ab408e8 --- /dev/null +++ b/engines/chewy/events.h @@ -0,0 +1,51 @@ +/* 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 CHEWY_EVENTS_H +#define CHEWY_EVENTS_H + +#include "common/events.h" + +namespace Chewy { + +class ChewyEngine; +class Graphics; +class Console; + +class Events { +public: + Events(ChewyEngine *vm, Graphics *graphics, Console *console); + virtual ~Events() {} + + void processEvents(); + +private: + Common::Event _event; + Common::EventManager *_eventManager; + ChewyEngine *_vm; + Graphics *_graphics; + Console *_console; +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/graphics.cpp b/engines/chewy/graphics.cpp new file mode 100644 index 0000000000..07a3abe435 --- /dev/null +++ b/engines/chewy/graphics.cpp @@ -0,0 +1,145 @@ +/* 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 "common/system.h" +#include "common/events.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +#include "chewy/cursor.h" +#include "chewy/graphics.h" +#include "chewy/resource.h" +#include "chewy/text.h" +#include "chewy/video/cfo_decoder.h" + +namespace Chewy { + +Graphics::Graphics(ChewyEngine *vm) : _vm(vm) { + _font = nullptr; +} + +Graphics::~Graphics() { + delete _font; +} + +void Graphics::drawSprite(Common::String filename, int spriteNum, uint x, uint y) { + SpriteResource *res = new SpriteResource(filename); + TAFChunk *sprite = res->getSprite(spriteNum); + + drawTransparent(x, y, sprite->data, sprite->width, sprite->height, 0); + g_system->updateScreen(); + + delete[] sprite->data; + delete sprite; + delete res; +} + +void Graphics::drawImage(Common::String filename, int imageNum) { + BackgroundResource *res = new BackgroundResource(filename); + TBFChunk *image = res->getImage(imageNum); + + g_system->getPaletteManager()->setPalette(image->palette, 0, 256); + g_system->copyRectToScreen(image->data, image->width, 0, 0, image->width, image->height); + g_system->updateScreen(); + + delete[] image->data; + delete image; + delete res; +} + +void Graphics::loadFont(Common::String filename) { + _font = new Font(filename); +} + +void Graphics::drawTransparent(uint16 x, uint16 y, byte *data, uint16 width, uint16 height, byte transparentColor) { + ::Graphics::Surface *screen = g_system->lockScreen(); + for (uint curX = 0; curX < width; curX++) { + for (uint curY = 0; curY < height; curY++) { + byte *src = data + (curY * width) + curX; + byte *dst = (byte *)screen->getBasePtr(curX + x, curY + y); + if (*src != transparentColor) + *dst = *src; + } + } + g_system->unlockScreen(); +} + +void Graphics::drawText(Common::String text, uint x, uint y) { + ::Graphics::Surface *textSurface = _font->getLine(text); + + drawTransparent(x, y, (byte *)textSurface->getPixels(), textSurface->pitch, textSurface->h, 0xFF); + + textSurface->free(); + delete textSurface; +} + +void Graphics::playVideo(uint num) { + CfoDecoder *cfoDecoder = new CfoDecoder(_vm->_sound); + VideoResource *videoResource = new VideoResource("cut.tap"); + Common::SeekableReadStream *videoStream = videoResource->getVideoStream(num); + + if (!cfoDecoder->loadStream(videoStream)) { + delete videoResource; + delete cfoDecoder; + return; + } + + uint16 x = (g_system->getWidth() - cfoDecoder->getWidth()) / 2; + uint16 y = (g_system->getHeight() - cfoDecoder->getHeight()) / 2; + bool skipVideo = false; + byte curPalette[256 * 3]; + + g_system->getPaletteManager()->grabPalette(curPalette, 0, 256); + _vm->_cursor->hideCursor(); + + cfoDecoder->start(); + + while (!_vm->shouldQuit() && !cfoDecoder->endOfVideo() && !skipVideo) { + if (cfoDecoder->needsUpdate()) { + const ::Graphics::Surface *frame = cfoDecoder->decodeNextFrame(); + if (frame) { + g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); + + if (cfoDecoder->hasDirtyPalette()) + g_system->getPaletteManager()->setPalette(cfoDecoder->getPalette(), 0, 256); + + g_system->updateScreen(); + } + } + + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } + + g_system->delayMillis(10); + } + + cfoDecoder->close(); + + g_system->getPaletteManager()->setPalette(curPalette, 0, 256); + _vm->_cursor->showCursor(); +} + +} // End of namespace Chewy diff --git a/engines/chewy/graphics.h b/engines/chewy/graphics.h new file mode 100644 index 0000000000..a260311df5 --- /dev/null +++ b/engines/chewy/graphics.h @@ -0,0 +1,53 @@ +/* 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 CHEWY_GRAPHICS_H +#define CHEWY_GRAPHICS_H + +#include "chewy/chewy.h" + +namespace Chewy { + +class SpriteResource; +class Font; + +class Graphics { +public: + Graphics(ChewyEngine *vm); + virtual ~Graphics(); + + void drawImage(Common::String filename, int imageNum); + void drawSprite(Common::String filename, int spriteNum, uint x, uint y); + void playVideo(uint num); + void loadFont(Common::String filename); + void drawText(Common::String text, uint x, uint y); + +private: + void drawTransparent(uint16 x, uint16 y, byte *data, uint16 width, uint16 height, byte transparentColor); + + ChewyEngine *_vm; + Font *_font; +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/module.mk b/engines/chewy/module.mk new file mode 100644 index 0000000000..5752e28adf --- /dev/null +++ b/engines/chewy/module.mk @@ -0,0 +1,22 @@ +MODULE := engines/chewy + +MODULE_OBJS = \ + chewy.o \ + cursor.o \ + console.o \ + detection.o \ + events.o \ + graphics.o \ + resource.o \ + scene.o \ + sound.o \ + text.o \ + video/cfo_decoder.o + +# This module can be built as a plugin +ifeq ($(ENABLE_CHEWY), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/chewy/resource.cpp b/engines/chewy/resource.cpp new file mode 100644 index 0000000000..e112d98cdb --- /dev/null +++ b/engines/chewy/resource.cpp @@ -0,0 +1,314 @@ +/* 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 "common/debug.h" +#include "common/stream.h" +#include "common/substream.h" +#include "common/textconsole.h" +#include "graphics/pixelformat.h" +#include "graphics/surface.h" + +#include "chewy/chewy.h" +#include "chewy/resource.h" + +namespace Chewy { + +// Resource files - TODO: +// ====================== +// back/episode1.gep +// cut/blende.rnd +// misc/exit.eib +// misc/inventar.iib +// misc/inventar.sib +// room/test.rdi +// txt/diah.adh +// txt/inv_st.s and txt/room_st.s (inventory/room control bytes) +// txt/inv_use.idx + +Resource::Resource(Common::String filename) { + const uint32 headerGeneric = MKTAG('N', 'G', 'S', '\0'); + const uint32 headerTxtDec = MKTAG('T', 'C', 'F', '\0'); + const uint32 headerTxtEnc = MKTAG('T', 'C', 'F', '\1'); + const uint32 headerSprite = MKTAG('T', 'A', 'F', '\0'); + + filename.toLowercase(); + _stream.open(filename); + + uint32 header = _stream.readUint32BE(); + bool isText = (header == headerTxtDec || header == headerTxtEnc); + bool isSprite = (header == headerSprite); + + if (header != headerGeneric && !isSprite && !isText) + error("Invalid resource - %s", filename.c_str()); + + if (isText) { + _resType = kResourceTCF; + _encrypted = (header == headerTxtEnc); + } else if (isSprite) { + initSprite(filename); + return; + } else { + _resType = (ResourceType)_stream.readUint16LE(); + _encrypted = false; + } + + if (filename == "atds.tap") + _encrypted = true; + + _chunkCount = _stream.readUint16LE(); + + for (uint i = 0; i < _chunkCount; i++) { + Chunk cur; + cur.size = _stream.readUint32LE(); + + if (!isText) + cur.type = (ResourceType)_stream.readUint16LE(); + else + cur.num = _stream.readUint16LE(); + + cur.pos = _stream.pos(); + + _stream.skip(cur.size); + _chunkList.push_back(cur); + } +} + +Resource::~Resource() { + _chunkList.clear(); + _stream.close(); +} + +uint32 Resource::getChunkCount() const { + return _chunkList.size(); +} + +Chunk *Resource::getChunk(uint num) { + assert(num < _chunkList.size()); + + return &_chunkList[num]; +} + +byte *Resource::getChunkData(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + byte *data = new byte[chunk->size]; + + _stream.seek(chunk->pos, SEEK_SET); + _stream.read(data, chunk->size); + if (_encrypted) + decrypt(data, chunk->size); + + return data; +} + +void Resource::initSprite(Common::String filename) { + uint32 nextSpriteOffset; + + // TAF (sprite) resources are much different than the rest, so we have a + // separate initializer for them here + + _resType = kResourceTAF; + _encrypted = false; + /*screenMode = */_stream.readUint16LE(); + _chunkCount = _stream.readUint16LE(); + _stream.skip(4); // total size of all sprites + _stream.skip(3 * 256); // palette + nextSpriteOffset = _stream.readUint32LE(); + _stream.skip(2 + 1); // correction table, padding + if ((int32)nextSpriteOffset != _stream.pos()) + error("Invalid sprite resource - %s", filename.c_str()); + + for (uint i = 0; i < _chunkCount; i++) { + Chunk cur; + + cur.pos = _stream.pos(); + cur.type = kResourceTAF; + + _stream.skip(2 + 2 + 2); // compression flag, width, height + nextSpriteOffset = _stream.readUint32LE(); + uint32 spriteImageOffset = _stream.readUint32LE(); + _stream.skip(1); // padding + + if ((int32)spriteImageOffset != _stream.pos()) + error("Invalid sprite resource - %s", filename.c_str()); + + cur.size = nextSpriteOffset - cur.pos - 15; // 15 = sizeof(TAFChunk) + + _stream.skip(cur.size); + _chunkList.push_back(cur); + } +} + +void Resource::unpackRLE(byte *buffer, uint32 compressedSize, uint32 uncompressedSize) { + // Compressed images are packed using a very simple RLE compression + byte count; + byte value; + uint32 outPos = 0; + + for (uint i = 0; i < (compressedSize) / 2 && outPos < uncompressedSize; i++) { + count = _stream.readByte(); + value = _stream.readByte(); + for (byte j = 0; j < count; j++) { + buffer[outPos++] = value; + } + } +} + +void Resource::decrypt(byte *data, uint32 size) { + byte *c = data; + + for (uint i = 0; i < size; i++) { + *c = -(*c); + ++c; + } +} + +TAFChunk *SpriteResource::getSprite(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + TAFChunk *taf = new TAFChunk(); + + _stream.seek(chunk->pos, SEEK_SET); + + taf->compressionFlag = _stream.readUint16LE(); + taf->width = _stream.readUint16LE(); + taf->height = _stream.readUint16LE(); + _stream.skip(4 + 4 + 1); // nextSpriteOffset, spriteImageOffset, padding + + taf->data = new byte[taf->width * taf->height]; + + if (!taf->compressionFlag) + _stream.read(taf->data, chunk->size); + else + unpackRLE(taf->data, chunk->size, taf->width * taf->height); + + return taf; +} + +TBFChunk *BackgroundResource::getImage(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + TBFChunk *tbf = new TBFChunk(); + + _stream.seek(chunk->pos, SEEK_SET); + + if (_stream.readUint32BE() != MKTAG('T', 'B', 'F', '\0')) + error("Corrupt TBF resource"); + + tbf->screenMode = _stream.readUint16LE(); + tbf->compressionFlag = _stream.readUint16LE(); + tbf->size = _stream.readUint32LE(); + tbf->width = _stream.readUint16LE(); + tbf->height = _stream.readUint16LE(); + for (int j = 0; j < 3 * 256; j++) + tbf->palette[j] = (_stream.readByte() << 2) & 0xff; + + tbf->data = new byte[tbf->size]; + + if (!tbf->compressionFlag) + _stream.read(tbf->data, chunk->size); + else + unpackRLE(tbf->data, chunk->size, tbf->size); + + return tbf; +} + +SoundChunk *SoundResource::getSound(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + SoundChunk *sound = new SoundChunk(); + + _stream.seek(chunk->pos, SEEK_SET); + + // Voice files are split in blocks, so reassemble them here + byte blocksRemaining; + uint32 totalLength = 0; + uint32 blockSize; + + // Find the total length of the voice file + do { + blocksRemaining = _stream.readByte(); + + byte b1 = _stream.readByte(); + byte b2 = _stream.readByte(); + byte b3 = _stream.readByte(); + blockSize = b1 + (b2 << 8) + (b3 << 16); + + totalLength += blockSize; + _stream.skip(blockSize); + } while (blocksRemaining > 1); + + // Read the voice data + sound->size = totalLength; + sound->data = new byte[totalLength]; + byte *ptr = sound->data; + + _stream.seek(chunk->pos, SEEK_SET); + + do { + blocksRemaining = _stream.readByte(); + + byte b1 = _stream.readByte(); + byte b2 = _stream.readByte(); + byte b3 = _stream.readByte(); + blockSize = b1 + (b2 << 8) + (b3 << 16); + + _stream.read(ptr, blockSize); + ptr += blockSize; + } while (blocksRemaining > 1); + + return sound; +} + +VideoChunk *VideoResource::getVideoHeader(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + VideoChunk *vid = new VideoChunk(); + + _stream.seek(chunk->pos, SEEK_SET); + + if (_stream.readUint32BE() != MKTAG('C', 'F', 'O', '\0')) + error("Corrupt video resource"); + + vid->size = _stream.readUint32LE(); // always 0 + vid->frameCount = _stream.readUint16LE(); + vid->width = _stream.readUint16LE(); + vid->height = _stream.readUint16LE(); + vid->frameDelay = _stream.readUint32LE(); + vid->firstFrameOffset = _stream.readUint32LE(); // always 22 + + return vid; +} + +Common::SeekableReadStream *VideoResource::getVideoStream(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + return new Common::SeekableSubReadStream(&_stream, chunk->pos, chunk->pos + chunk->size); +} + +} // End of namespace Chewy diff --git a/engines/chewy/resource.h b/engines/chewy/resource.h new file mode 100644 index 0000000000..abccc9680d --- /dev/null +++ b/engines/chewy/resource.h @@ -0,0 +1,184 @@ +/* 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 CHEWY_RESOURCE_H +#define CHEWY_RESOURCE_H + + +#include "common/scummsys.h" +#include "common/file.h" +#include "common/util.h" +#include "common/str.h" +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "common/random.h" +#include "common/stream.h" +#include "graphics/surface.h" + +namespace Chewy { + +enum ResourceType { + kResourcePCX = 0, // unused + kResourceTBF = 1, // background art, contained in TGPs + kResourceTAF = 2, + kResourceTFF = 3, + kResourceVOC = 4, // speech and SFX, contained in TVPs + kResourceTPF = 5, // unused + kResourceTMF = 6, // music, similar to a MOD file, contained in details.tap + kResourceMOD = 7, // unused + kResourceRAW = 8, // unused + kResourceLBM = 9, // unused + kResourceRDI = 10, + kResourceTXT = 11, + kResourceIIB = 12, + kResourceSIB = 13, + kResourceEIB = 14, + kResourceATS = 15, // unused + kResourceSAA = 16, // unused + kResourceFLC = 17, // unused + kResourceAAD = 18, // unused + kResourceADS = 19, // unused + kResourceADH = 20, // used in txt/diah.adh + kResourceTGP = 21, // container for background art, used in back/comic.tgp, back/episode1.tgp and back/gbook.tgp + kResourceTVP = 22, // container for speech, used in sound/speech.tvp + kResourceTTP = 23, // unused + kResourceTAP = 24, // container for sound effects, music and cutscenes, used in sound/details.tap and cut/cut.tap + kResourceCFO = 25, // unused + kResourceTCF = 26 // error messages, used in err/err_e.tcf (English) and err/err_d.tcf (German) +}; + +// Generic chunk header +struct Chunk { + uint32 size; + uint16 num; // same as the type below, used in chunks where the type is substituted with count + ResourceType type; + uint32 pos; // position of the actual data +}; + +// TBF (background) chunk header +struct TBFChunk { + // TBF chunk header + // ID (TBF, followed by a zero) + uint16 screenMode; + uint16 compressionFlag; + uint32 size; + uint16 width; + uint16 height; + byte palette[3 * 256]; + byte *data; +}; + +// TAF (sprite) image data chunk header - 15 bytes +struct TAFChunk { + uint16 compressionFlag; + uint16 width; + uint16 height; + // 4 bytes next sprite offset + // 4 bytes sprite image offset + // 1 byte padding + byte *data; +}; + +// Sound chunk header +struct SoundChunk { + uint32 size; + byte *data; +}; + +// Video chunk header +struct VideoChunk { + // ID (CFA, followed by a zero) + uint32 size; + uint16 frameCount; + uint16 width; + uint16 height; + uint32 frameDelay; // in ms + uint32 firstFrameOffset; +}; + +enum VideoFrameType { + kVideoFrameNormal = 0xF1FA, + kVideoFrameCustom = 0xFAF1 +}; + +typedef Common::Array<Chunk> ChunkList; +typedef Common::Array<TBFChunk> TBFChunkList; + +class Resource { +public: + Resource(Common::String filename); + virtual ~Resource(); + + ResourceType getType() const { return _resType; } + uint32 getChunkCount() const; + Chunk *getChunk(uint num); + virtual byte *getChunkData(uint num); + +protected: + void initSprite(Common::String filename); + void unpackRLE(byte *buffer, uint32 compressedSize, uint32 uncompressedSize); + void decrypt(byte *data, uint32 size); + + Common::File _stream; + uint16 _chunkCount; + ResourceType _resType; + bool _encrypted; + + ChunkList _chunkList; +}; + +class SpriteResource : public Resource { +public: + SpriteResource(Common::String filename) : Resource(filename) {} + virtual ~SpriteResource() {} + + TAFChunk *getSprite(uint num); +}; + +class BackgroundResource : public Resource { +public: + BackgroundResource(Common::String filename) : Resource(filename) {} + virtual ~BackgroundResource() {} + + TBFChunk *getImage(uint num); +}; + +class SoundResource : public Resource { +public: + SoundResource(Common::String filename) : Resource(filename) {} + virtual ~SoundResource() {} + + SoundChunk *getSound(uint num); +}; + +class VideoResource : public Resource { +public: + VideoResource(Common::String filename) : Resource(filename) {} + virtual ~VideoResource() {} + + VideoChunk *getVideoHeader(uint num); + Common::SeekableReadStream *getVideoStream(uint num); +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/scene.cpp b/engines/chewy/scene.cpp new file mode 100644 index 0000000000..03e4332f85 --- /dev/null +++ b/engines/chewy/scene.cpp @@ -0,0 +1,59 @@ +/* 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 "common/system.h" +#include "common/events.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +#include "chewy/cursor.h" +#include "chewy/graphics.h" +#include "chewy/scene.h" +#include "chewy/resource.h" +#include "chewy/text.h" +#include "chewy/video/cfo_decoder.h" + +namespace Chewy { + +Scene::Scene(ChewyEngine *vm) : _vm(vm) { +} + +Scene::~Scene() { +} + +void Scene::change(uint scene) { + _curScene = scene; + _vm->_cursor->setCursor(0); + _vm->_cursor->showCursor(); + + draw(); +} + +void Scene::draw() { + _vm->_graphics->drawImage("episode1.tgp", _curScene); + _vm->_graphics->drawSprite("det1.taf", 0, 200, 100); + _vm->_graphics->loadFont("6x8.tff"); + _vm->_graphics->drawText("This is a test", 200, 80); +} + +} // End of namespace Chewy diff --git a/engines/chewy/scene.h b/engines/chewy/scene.h new file mode 100644 index 0000000000..37601d057b --- /dev/null +++ b/engines/chewy/scene.h @@ -0,0 +1,45 @@ +/* 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 CHEWY_SCENE_H +#define CHEWY_SCENE_H + +#include "chewy/chewy.h" + +namespace Chewy { + +class Scene { +public: + Scene(ChewyEngine *vm); + virtual ~Scene(); + + void change(uint scene); + void draw(); + +private: + ChewyEngine *_vm; + uint _curScene; +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/sound.cpp b/engines/chewy/sound.cpp new file mode 100644 index 0000000000..36f2d63073 --- /dev/null +++ b/engines/chewy/sound.cpp @@ -0,0 +1,257 @@ +/* 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 "audio/audiostream.h" +#include "audio/mixer.h" +#include "audio/decoders/raw.h" +#include "common/system.h" + +#include "chewy/resource.h" +#include "chewy/sound.h" + +namespace Chewy { + +Sound::Sound(Audio::Mixer *mixer) { + _mixer = mixer; + _speechRes = new SoundResource("speech.tvp"); + _soundRes = new SoundResource("details.tap"); +} + +Sound::~Sound() { + delete _soundRes; + delete _speechRes; +} + +void Sound::playSound(int num, bool loop, uint channel) { + SoundChunk *sound = _soundRes->getSound(num); + byte *data = (byte *)malloc(sound->size); + memcpy(data, sound->data, sound->size); + + playSound(data, sound->size, loop, channel); + + delete[] sound->data; + delete sound; +} + +void Sound::playSound(byte *data, uint32 size, bool loop, uint channel, DisposeAfterUse::Flag dispose) { + Audio::AudioStream *stream = Audio::makeLoopingAudioStream( + Audio::makeRawStream(data, + size, 22050, Audio::FLAG_UNSIGNED, + dispose), + loop ? 0 : 1); + + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[channel], stream); +} + +void Sound::pauseSound(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->pauseHandle(_soundHandle[channel], true); +} + +void Sound::resumeSound(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->pauseHandle(_soundHandle[channel], false); +} + +void Sound::stopSound(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->stopHandle(_soundHandle[channel]); +} + +bool Sound::isSoundActive(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + return _mixer->isSoundHandleActive(_soundHandle[channel]); +} + +void Sound::setSoundVolume(uint volume) { + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume); +} + +void Sound::setSoundChannelVolume(uint channel, uint volume) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->setChannelVolume(_soundHandle[channel], volume); +} + +void Sound::setSoundChannelBalance(uint channel, uint balance) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->setChannelBalance(_soundHandle[channel], balance); +} + +void Sound::playMusic(int num, bool loop) { + uint32 musicNum = _soundRes->getChunkCount() - 1 - num; + Chunk *chunk = _soundRes->getChunk(musicNum); + byte *data = _soundRes->getChunkData(musicNum); + + playMusic(data, chunk->size, loop); + + delete[] data; + delete chunk; +} + +void Sound::playMusic(byte *data, uint32 size, bool loop, DisposeAfterUse::Flag dispose) { + byte *modData = nullptr; + uint32 modSize; + + // TODO: TMF music files are similar to MOD files. With the following + // incorrect implementation, the PCM parts of these files can be played + warning("The current music playing implementation is wrong"); + modSize = size; + modData = (byte *)malloc(modSize); + memcpy(modData, data, size); + //convertTMFToMod(data, size, modData, modSize); + + Audio::AudioStream *stream = Audio::makeLoopingAudioStream( + Audio::makeRawStream(modData, + modSize, 22050, Audio::FLAG_UNSIGNED, + dispose), + loop ? 0 : 1); + + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, stream); +} + +void Sound::pauseMusic() { + _mixer->pauseHandle(_musicHandle, true); +} + +void Sound::resumeMusic() { + _mixer->pauseHandle(_musicHandle, false); +} + +void Sound::stopMusic() { + _mixer->stopHandle(_musicHandle); +} + +bool Sound::isMusicActive() { + return _mixer->isSoundHandleActive(_musicHandle); +} + +void Sound::setMusicVolume(uint volume) { + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); +} + +void Sound::playSpeech(int num) { + SoundChunk *sound = _speechRes->getSound(num); + byte *data = (byte *)malloc(sound->size); + memcpy(data, sound->data, sound->size); + + Audio::AudioStream *stream = Audio::makeLoopingAudioStream( + Audio::makeRawStream(data, + sound->size, 22050, Audio::FLAG_UNSIGNED, + DisposeAfterUse::YES), + 1); + + _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream); + + delete[] sound->data; + delete sound; +} + +void Sound::pauseSpeech() { + _mixer->pauseHandle(_speechHandle, true); +} + +void Sound::resumeSpeech() { + _mixer->pauseHandle(_speechHandle, false); +} + +void Sound::stopSpeech() { + _mixer->stopHandle(_speechHandle); +} + +bool Sound::isSpeechActive() { + return _mixer->isSoundHandleActive(_speechHandle); +} + +void Sound::setSpeechVolume(uint volume) { + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume); +} + +void Sound::stopAll() { + _mixer->stopAll(); +} + +void Sound::convertTMFToMod(byte *tmfData, uint32 tmfSize, byte *modData, uint32 &modSize) { + // Convert the TMF stream back to a regular Protracker MOD stream + const int maxInstruments = 31; + // Extra bytes needed: 20 bytes song name, 31 * 22 instrument names, 4 magic bytes "M.K." + modSize = tmfSize + 20 + maxInstruments * 22 + 4; + modData = (byte *)malloc(modSize); + byte *tmfPtr = tmfData; + byte *modPtr = modData; + + const byte songName[20] = { + 'S', 'C', 'U', 'M', 'M', + 'V', 'M', ' ', 'M', 'O', + 'D', 'U', 'L', 'E', '\0', + '\0', '\0', '\0', '\0', '\0' + }; + const byte instrumentName[22] = { + 'S', 'C', 'U', 'M', 'M', + 'V', 'M', ' ', 'I', 'N', + 'S', 'T', 'R', 'U', 'M', + 'E', 'N', 'T', '\0', '\0', + '\0', '\0' + }; + + if (READ_BE_UINT32(tmfPtr) != MKTAG('T', 'M', 'F', '\0')) + error("Corrupt TMF resource"); + tmfPtr += 4; + + memcpy(modPtr, songName, 20); + modPtr += 20; + + byte fineTune, instVolume; + uint16 repeatPoint, repeatLength, sampleLength; + + for (int i = 0; i < maxInstruments; i++) { + fineTune = *tmfPtr++; + instVolume = *tmfPtr++; + repeatPoint = READ_BE_UINT16(tmfPtr); tmfPtr += 2; + repeatLength = READ_BE_UINT16(tmfPtr); tmfPtr += 2; + sampleLength = READ_BE_UINT16(tmfPtr); tmfPtr += 2; + + // Instrument name + memcpy(modPtr, instrumentName, 18); modPtr += 18; + *modPtr++ = ' '; + *modPtr++ = i / 10; + *modPtr++ = i % 10; + *modPtr++ = '\0'; + + WRITE_BE_UINT16(modPtr, sampleLength / 2); modPtr += 2; + *modPtr++ = fineTune; + *modPtr++ = instVolume; + WRITE_BE_UINT16(modPtr, repeatPoint / 2); modPtr += 2; + WRITE_BE_UINT16(modPtr, repeatLength / 2); modPtr += 2; + } + + *modPtr++ = *tmfPtr++; // song length + *modPtr++ = *tmfPtr++; // undef + memcpy(modPtr, tmfPtr, 128); + modPtr += 128; + tmfPtr += 128; + WRITE_BE_UINT32(modPtr, MKTAG('M', '.', 'K', '.')); modPtr += 4; + // TODO: 31 bytes instrument positions + + // TODO: notes +} + +} // End of namespace Chewy diff --git a/engines/chewy/sound.h b/engines/chewy/sound.h new file mode 100644 index 0000000000..a39cf5db67 --- /dev/null +++ b/engines/chewy/sound.h @@ -0,0 +1,81 @@ +/* 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 CHEWY_SOUND_H +#define CHEWY_SOUND_H + +#include "audio/mixer.h" +#include "chewy/chewy.h" + +namespace Chewy { + +class SoundResource; + +#define MAX_SOUND_EFFECTS 14 + +class Sound { +public: + Sound(Audio::Mixer *mixer); + virtual ~Sound(); + + void playSound(int num, bool loop = false, uint channel = 0); + void playSound(byte *data, uint32 size, bool loop = false, uint channel = 0, DisposeAfterUse::Flag dispose = DisposeAfterUse::YES); + void pauseSound(uint channel); + void resumeSound(uint channel); + void stopSound(uint channel); + bool isSoundActive(uint channel); + void setSoundVolume(uint volume); + void setSoundChannelVolume(uint channel, uint volume); + void setSoundChannelBalance(uint channel, uint balance); + + void playMusic(int num, bool loop = false); + void playMusic(byte *data, uint32 size, bool loop = false, DisposeAfterUse::Flag dispose = DisposeAfterUse::YES); + void pauseMusic(); + void resumeMusic(); + void stopMusic(); + bool isMusicActive(); + void setMusicVolume(uint volume); + + void playSpeech(int num); + void pauseSpeech(); + void resumeSpeech(); + void stopSpeech(); + bool isSpeechActive(); + void setSpeechVolume(uint volume); + + void stopAll(); + +private: + Audio::Mixer *_mixer; + Audio::SoundHandle _soundHandle[MAX_SOUND_EFFECTS]; + Audio::SoundHandle _musicHandle; + Audio::SoundHandle _speechHandle; + + SoundResource *_speechRes; + SoundResource *_soundRes; + + void convertTMFToMod(byte *tmfData, uint32 tmfSize, byte *modData, uint32 &modSize); +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/text.cpp b/engines/chewy/text.cpp new file mode 100644 index 0000000000..fcf07a684b --- /dev/null +++ b/engines/chewy/text.cpp @@ -0,0 +1,214 @@ +/* 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 "common/rect.h" +#include "common/system.h" + +#include "chewy/resource.h" +#include "chewy/text.h" + +namespace Chewy { + +Text::Text() : Resource("atds.tap") { +} + +Text::~Text() { +} + +TextEntryList *Text::getDialog(uint dialogNum, uint entryNum) { + if (dialogNum >= kADSTextMax) + error("getDialog(): Invalid entry number requested, %d (max %d)", dialogNum, kADSTextMax - 1); + + TextEntryList *l = new TextEntryList(); + + byte *data = getChunkData(dialogNum); + byte *ptr = data; + + ptr += 2; // entry number + ptr += 2; // number of persons + ptr += 2; // automove count + ptr += 2; // cursor number + ptr += 13; // misc data + + for (uint i = 0; i <= entryNum; i++) { + do { + TextEntry curDialog; + ptr++; // current entry + ptr += 2; + curDialog.speechId = READ_LE_UINT16(ptr) - VOICE_OFFSET; ptr += 2; + + do { + curDialog.text += *ptr++; + + if (*ptr == 0 && *(ptr + 1) != kEndText) { + // TODO: Split lines + *ptr = ' '; + } + } while (*ptr != kEndText); + + if (i == entryNum) + l->push_back(curDialog); + + } while (*(ptr + 1) != kEndEntry); + + ptr += 2; // kEndText, kEndEntry + + if (*ptr == kEndBlock) // not found + break; + } + + delete[] data; + + return l; +} + +TextEntry *Text::getText(uint dialogNum, uint entryNum) { + if (dialogNum < kADSTextMax) + error("getText(): Invalid entry number requested, %d (min %d)", dialogNum, kADSTextMax); + + TextEntry *d = new TextEntry(); + bool isText = (dialogNum >= kADSTextMax && dialogNum < kADSTextMax + kATSTextMax); + bool isAutoDialog = (dialogNum >= kADSTextMax + kATSTextMax && dialogNum < kADSTextMax + kATSTextMax + kAADTextMax); + //bool isInvText = (dialogNum >= kADSTextMax + kATSTextMax + kAADTextMax && dialogNum < kADSTextMax + kATSTextMax + kAADTextMax + kINVTextMax); + + byte *data = getChunkData(dialogNum); + byte *ptr = data; + + if (isAutoDialog) + ptr += 3; + + for (uint i = 0; i <= entryNum; i++) { + ptr += 13; + d->speechId = READ_LE_UINT16(ptr) - VOICE_OFFSET; ptr += 2; + + do { + if (i == entryNum) + d->text += *ptr++; + else + ptr++; + + if (*ptr == 0 && *(ptr + 1) != kEndText) { + // TODO: Split lines + *ptr = ' '; + } + } while (*ptr); + + if (*(ptr + 1) != kEndText || *(ptr + 2) != kEndChunk) + error("Invalid text resource - %d", dialogNum); + + if (!isText) + ptr += 3; // 0, kEndText, kEndChunk + if (isAutoDialog) + ptr += 3; + + if (i == entryNum) { + // Found + delete[] data; + return d; + } + } + + // Not found + delete[] data; + delete d; + + return nullptr; +} + +Font::Font(Common::String filename) { + const uint32 headerFont = MKTAG('T', 'F', 'F', '\0'); + Common::File stream; + + stream.open(filename); + + uint32 header = stream.readUint32BE(); + + if (header != headerFont) + error("Invalid resource - %s", filename.c_str()); + + stream.skip(4); // total memory + _count = stream.readUint16LE(); + _first = stream.readUint16LE(); + _last = stream.readUint16LE(); + _width = stream.readUint16LE(); + _height = stream.readUint16LE(); + + _fontSurface.create(_width * _count, _height, ::Graphics::PixelFormat::createFormatCLUT8()); + + byte cur; + int bitIndex = 7; + byte *p; + + cur = stream.readByte(); + + for (uint n = 0; n < _count; n++) { + for (uint y = 0; y < _height; y++) { + p = (byte *)_fontSurface.getBasePtr(n * _width, y); + + for (uint x = n * _width; x < n * _width + _width; x++) { + *p++ = (cur & (1 << bitIndex)) ? 0 : 0xFF; + + bitIndex--; + if (bitIndex < 0) { + bitIndex = 7; + cur = stream.readByte(); + } + } + } + } +} + +Font::~Font() { + _fontSurface.free(); +} + +::Graphics::Surface *Font::getLine(const Common::String &text) { + ::Graphics::Surface *line = new ::Graphics::Surface(); + line->create(text.size() * _width, _height, ::Graphics::PixelFormat::createFormatCLUT8()); + + for (uint i = 0; i < text.size(); i++) { + uint x = (text[i] - _first) * _width; + line->copyRectToSurface(_fontSurface, i * _width, 0, Common::Rect(x, 0, x + _width, _height)); + } + + return line; +} + +Common::String ErrorMessage::getErrorMessage(uint num) { + assert(num < _chunkList.size()); + + Chunk *chunk = &_chunkList[num]; + Common::String str; + byte *data = new byte[chunk->size]; + + _stream.seek(chunk->pos, SEEK_SET); + _stream.read(data, chunk->size); + if (_encrypted) + decrypt(data, chunk->size); + + str = (char *)data; + delete[] data; + + return str; +} + +} // End of namespace Chewy diff --git a/engines/chewy/text.h b/engines/chewy/text.h new file mode 100644 index 0000000000..a082de6a98 --- /dev/null +++ b/engines/chewy/text.h @@ -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. + * + */ + +#ifndef CHEWY_TEXT_H +#define CHEWY_TEXT_H + +#include "common/list.h" +#include "chewy/chewy.h" +#include "chewy/resource.h" + +namespace Chewy { + +/** + * Game texts are contained in txt/atds.tap, and contain the following (in that order): + * ADS (Adventure Dialog System) - dialogs, 500 entries max + * ATS (Adventure Text System) - text descriptions, 100 entries max + * AAD (Adventure Auto Dialog System) - automatic dialogs, 100 entries max + * INV - inventory text descriptions, 100 entries max + * USE - use action texts, 100 entries max + */ +enum MaxTextTypes { + kADSTextMax = 500, // 0 - 499 + kATSTextMax = 100, // 500 - 599 + kAADTextMax = 100, // 600 - 699 + kINVTextMax = 100, // 700 - 799 + kUSETextMax = 100 // 800 - 899 +}; + +/** + * Markers for text entries + */ +enum TextEntryMarkers { + kEndRow = 0x00, + kEndBlock = 0x0b, + kEndEntry = 0x0c, + kEndText = 0x0d, + kEndChunk = 0x0e + // There's also 0x0f, block end, which we don't use +}; + +#define VOICE_OFFSET 20 + +struct TextEntry { + uint16 speechId; + Common::String text; +}; + +typedef Common::List<TextEntry> TextEntryList; + + +class Text : public Resource { +public: + Text(); + virtual ~Text(); + + /** + * Gets a list of lines for a specific dialog entry + */ + TextEntryList *getDialog(uint dialogNum, uint entryNum); + + /** + * Gets a line of text of the following types: + * - text (ATS) - 500 - 599 + * - auto dialog (AAD) - 600 - 699 + * - inventory text (INV) - 700 - 799 + * - use text (USE) - 800 - 899 + */ + TextEntry *getText(uint dialogNum, uint entryNum); +}; + +class ErrorMessage : public Resource { +public: + ErrorMessage(Common::String filename) : Resource(filename) {} + virtual ~ErrorMessage() {} + + Common::String getErrorMessage(uint num); +}; + +class Font { +public: + Font(Common::String filename); + virtual ~Font(); + + ::Graphics::Surface *getLine(const Common::String &text); + +private: + uint16 _count, _first, _last, _width, _height; + + ::Graphics::Surface _fontSurface; +}; + +} // End of namespace Chewy + +#endif diff --git a/engines/chewy/video/cfo_decoder.cpp b/engines/chewy/video/cfo_decoder.cpp new file mode 100644 index 0000000000..0d8fcd7083 --- /dev/null +++ b/engines/chewy/video/cfo_decoder.cpp @@ -0,0 +1,319 @@ +/* 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 "common/events.h" +#include "common/system.h" +#include "engines/engine.h" +#include "graphics/palette.h" +#include "video/flic_decoder.h" + +#include "chewy/sound.h" +#include "chewy/video/cfo_decoder.h" + +namespace Chewy { + +enum CustomSubChunk { + kChunkFadeIn = 0, // unused + kChunkFadeOut = 1, + kChunkLoadMusic = 2, + kChunkLoadRaw = 3, // unused + kChunkLoadVoc = 4, + kChunkPlayMusic = 5, + kChunkPlaySeq = 6, // unused + kChunkPlayPattern = 7, // unused + kChunkStopMusic = 8, + kChunkWaitMusicEnd = 9, + kChunkSetMusicVolume = 10, + kChunkSetLoopMode = 11, // unused + kChunkPlayRaw = 12, // unused + kChunkPlayVoc = 13, + kChunkSetSoundVolume = 14, + kChunkSetChannelVolume = 15, + kChunkFreeSoundEffect = 16, + kChunkMusicFadeIn = 17, // unused + kChunkMusicFadeOut = 18, + kChunkSetBalance = 19, + kChunkSetSpeed = 20, // unused + kChunkClearScreen = 21 +}; + +bool CfoDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + if (stream->readUint32BE() != MKTAG('C', 'F', 'O', '\0')) + error("Corrupt video resource"); + + stream->readUint32LE(); // always 0 + + uint16 frameCount = stream->readUint16LE(); + uint16 width = stream->readUint16LE(); + uint16 height = stream->readUint16LE(); + + addTrack(new CfoVideoTrack(stream, frameCount, width, height, _sound)); + return true; +} + +CfoDecoder::CfoVideoTrack::CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Sound *sound) : + Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, true), _sound(sound) { + readHeader(); + + for (int i = 0; i < MAX_SOUND_EFFECTS; i++) { + _soundEffects[i] = nullptr; + _soundEffectSize[i] = 0; + } + + _musicData = nullptr; + _musicSize = 0; +} + +CfoDecoder::CfoVideoTrack::~CfoVideoTrack() { + _sound->stopAll(); + + for (int i = 0; i < MAX_SOUND_EFFECTS; i++) { + delete[] _soundEffects[i]; + } + + delete[] _musicData; +} + +void CfoDecoder::CfoVideoTrack::readHeader() { + _frameDelay = _startFrameDelay = _fileStream->readUint32LE(); + _offsetFrame1 = _fileStream->readUint32LE(); + _offsetFrame2 = 0; // doesn't exist, as CFO videos aren't rewindable + + _fileStream->seek(_offsetFrame1); +} + +#define FRAME_TYPE 0xF1FA +#define CUSTOM_FRAME_TYPE 0xFAF1 + +const ::Graphics::Surface *CfoDecoder::CfoVideoTrack::decodeNextFrame() { + uint16 frameType; + + // Read chunk + /*uint32 frameSize =*/ _fileStream->readUint32LE(); + frameType = _fileStream->readUint16LE(); + + switch (frameType) { + case FRAME_TYPE: + handleFrame(); + break; + case CUSTOM_FRAME_TYPE: + handleCustomFrame(); + break; + default: + error("CfoDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType); + break; + } + + _curFrame++; + _nextFrameStartTime += _frameDelay; + + return _surface; +} + +#define FLI_SETPAL 4 +#define FLI_SS2 7 +#define FLI_BRUN 15 +#define FLI_COPY 16 +#define PSTAMP 18 + +void CfoDecoder::CfoVideoTrack::handleFrame() { + uint16 chunkCount = _fileStream->readUint16LE(); + + // Read subchunks + for (uint32 i = 0; i < chunkCount; ++i) { + uint32 frameSize = _fileStream->readUint32LE(); + uint16 frameType = _fileStream->readUint16LE(); + uint8 *data = new uint8[frameSize - 6]; + _fileStream->read(data, frameSize - 6); + + switch (frameType) { + case FLI_SETPAL: + unpackPalette(data); + _dirtyPalette = true; + break; + case FLI_SS2: + decodeDeltaFLC(data); + break; + case FLI_BRUN: + decodeByteRun(data); + break; + case FLI_COPY: + copyFrame(data); + break; + case PSTAMP: + /* PSTAMP - skip for now */ + break; + default: + error("CfoDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType); + break; + } + + delete[] data; + } +} + +void CfoDecoder::CfoVideoTrack::handleCustomFrame() { + uint16 chunkCount = _fileStream->readUint16LE(); + + uint16 number, channel, volume, repeat, balance; + + // Read subchunks + for (uint32 i = 0; i < chunkCount; ++i) { + uint32 frameSize = _fileStream->readUint32LE(); + uint16 frameType = _fileStream->readUint16LE(); + + switch (frameType) { + case kChunkFadeIn: + error("Unused chunk kChunkFadeIn found"); + break; + case kChunkFadeOut: + // Used in video 0 + _fileStream->skip(2); // delay, unused + fadeOut(); + break; + case kChunkLoadMusic: + // Used in videos 0, 18, 34, 71 + _musicSize = frameSize; + _musicData = new byte[frameSize]; + _fileStream->read(_musicData, frameSize); + break; + case kChunkLoadRaw: + error("Unused chunk kChunkLoadRaw found"); + break; + case kChunkLoadVoc: + number = _fileStream->readUint16LE(); + assert(number < MAX_SOUND_EFFECTS); + delete[] _soundEffects[number]; + + _soundEffectSize[number] = frameSize - 2; + _soundEffects[number] = new byte[frameSize - 2]; + _fileStream->read(_soundEffects[number], frameSize - 2); + break; + case kChunkPlayMusic: + // Used in videos 0, 18, 34, 71 + _sound->playMusic(_musicData, _musicSize, false, DisposeAfterUse::NO); + break; + case kChunkPlaySeq: + error("Unused chunk kChunkPlaySeq found"); + break; + case kChunkPlayPattern: + error("Unused chunk kChunkPlayPattern found"); + break; + case kChunkStopMusic: + _sound->stopMusic(); + + // Game videos do not restart music after stopping it + delete[] _musicData; + _musicSize = 0; + break; + case kChunkWaitMusicEnd: + do { + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) {} // ignore events + g_system->updateScreen(); + g_system->delayMillis(10); + } while (_sound->isMusicActive()); + break; + case kChunkSetMusicVolume: + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + _sound->setMusicVolume(volume); + break; + case kChunkSetLoopMode: + error("Unused chunk kChunkSetLoopMode found"); + break; + case kChunkPlayRaw: + error("Unused chunk kChunkPlayRaw found"); + break; + case kChunkPlayVoc: + number = _fileStream->readUint16LE(); + channel = _fileStream->readUint16LE(); + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + repeat = _fileStream->readUint16LE(); + assert(number < MAX_SOUND_EFFECTS); + + _sound->setSoundVolume(volume); + _sound->playSound(_soundEffects[number], _soundEffectSize[number], repeat, channel, DisposeAfterUse::NO); + break; + case kChunkSetSoundVolume: + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + _sound->setSoundVolume(volume); + break; + case kChunkSetChannelVolume: + channel = _fileStream->readUint16LE(); + volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; + + _sound->setSoundChannelVolume(channel, volume); + break; + case kChunkFreeSoundEffect: + number = _fileStream->readUint16LE(); + assert(number < MAX_SOUND_EFFECTS); + + delete[] _soundEffects[number]; + _soundEffects[number] = nullptr; + break; + case kChunkMusicFadeIn: + error("Unused chunk kChunkMusicFadeIn found"); + break; + case kChunkMusicFadeOut: + // Used in videos 0, 71 + warning("kChunkMusicFadeOut"); + // TODO + _fileStream->skip(frameSize); + break; + case kChunkSetBalance: + channel = _fileStream->readUint16LE(); + balance = (_fileStream->readUint16LE() * 2) - 127; + _sound->setSoundChannelBalance(channel, balance); + break; + case kChunkSetSpeed: + error("Unused chunk kChunkSetSpeed found"); + break; + case kChunkClearScreen: + g_system->fillScreen(0); + break; + default: + error("Unknown subchunk: %d", frameType); + break; + } + } +} + +void CfoDecoder::CfoVideoTrack::fadeOut() { + for (int j = 0; j < 64; j++) { + for (int i = 0; i < 256; i++) { + if (_palette[i * 3 + 0] > 0) + --_palette[i * 3 + 0]; + if (_palette[i * 3 + 1] > 0) + --_palette[i * 3 + 1]; + if (_palette[i * 3 + 2] > 0) + --_palette[i * 3 + 2]; + } + + g_system->getPaletteManager()->setPalette(_palette, 0, 256); + g_system->updateScreen(); + g_system->delayMillis(10); + } +} + +} // End of namespace Chewy diff --git a/engines/chewy/video/cfo_decoder.h b/engines/chewy/video/cfo_decoder.h new file mode 100644 index 0000000000..1495821674 --- /dev/null +++ b/engines/chewy/video/cfo_decoder.h @@ -0,0 +1,74 @@ +/* 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 CHEWY_VIDEO_CFO_DECODER_H +#define CHEWY_VIDEO_CFO_DECODER_H + +#include "graphics/surface.h" +#include "video/flic_decoder.h" + +namespace Chewy { + +#define MAX_SOUND_EFFECTS 14 + +class Sound; + +// A FLIC decoder, with a modified header and additional custom frames +class CfoDecoder : public Video::FlicDecoder { +public: + CfoDecoder(Sound *sound) : Video::FlicDecoder(), _sound(sound) {} + virtual ~CfoDecoder() {} + + bool loadStream(Common::SeekableReadStream *stream); + +private: + Sound *_sound; + + class CfoVideoTrack : public Video::FlicDecoder::FlicVideoTrack { + public: + CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Sound *sound); + virtual ~CfoVideoTrack(); + + void readHeader(); + + bool isRewindable() const { return false; } + bool rewind() { return false; } + + const ::Graphics::Surface *decodeNextFrame(); + + private: + void handleFrame(); + void handleCustomFrame(); + void fadeOut(); + + Sound *_sound; + + byte *_soundEffects[MAX_SOUND_EFFECTS]; + uint32 _soundEffectSize[MAX_SOUND_EFFECTS]; + byte *_musicData; + uint32 _musicSize; + }; +}; + +} // End of namespace Chewy + +#endif |