aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/chewy/chewy.cpp128
-rw-r--r--engines/chewy/chewy.h87
-rw-r--r--engines/chewy/configure.engine3
-rw-r--r--engines/chewy/console.cpp238
-rw-r--r--engines/chewy/console.h54
-rw-r--r--engines/chewy/cursor.cpp107
-rw-r--r--engines/chewy/cursor.h54
-rw-r--r--engines/chewy/detection.cpp151
-rw-r--r--engines/chewy/events.cpp63
-rw-r--r--engines/chewy/events.h51
-rw-r--r--engines/chewy/graphics.cpp145
-rw-r--r--engines/chewy/graphics.h53
-rw-r--r--engines/chewy/module.mk22
-rw-r--r--engines/chewy/resource.cpp314
-rw-r--r--engines/chewy/resource.h184
-rw-r--r--engines/chewy/scene.cpp59
-rw-r--r--engines/chewy/scene.h45
-rw-r--r--engines/chewy/sound.cpp257
-rw-r--r--engines/chewy/sound.h81
-rw-r--r--engines/chewy/text.cpp214
-rw-r--r--engines/chewy/text.h113
-rw-r--r--engines/chewy/video/cfo_decoder.cpp319
-rw-r--r--engines/chewy/video/cfo_decoder.h74
-rw-r--r--video/flic_decoder.cpp148
-rw-r--r--video/flic_decoder.h18
25 files changed, 2903 insertions, 79 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
diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp
index 994f47cea8..a1976e2729 100644
--- a/video/flic_decoder.cpp
+++ b/video/flic_decoder.cpp
@@ -85,19 +85,10 @@ void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
((FlicVideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch);
}
-FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height) {
+FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader) {
_fileStream = stream;
_frameCount = frameCount;
- _fileStream->readUint16LE(); // flags
- // Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word)
- // the frame delay is the FLIC "speed", in milliseconds.
- _frameDelay = _startFrameDelay = _fileStream->readUint32LE();
-
- _fileStream->seek(80);
- _offsetFrame1 = _fileStream->readUint32LE();
- _offsetFrame2 = _fileStream->readUint32LE();
-
_surface = new Graphics::Surface();
_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
_palette = new byte[3 * 256];
@@ -108,8 +99,8 @@ FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream,
_nextFrameStartTime = 0;
_atRingFrame = false;
- // Seek to the first frame
- _fileStream->seek(_offsetFrame1);
+ if (!skipHeader)
+ readHeader();
}
FlicDecoder::FlicVideoTrack::~FlicVideoTrack() {
@@ -120,6 +111,20 @@ FlicDecoder::FlicVideoTrack::~FlicVideoTrack() {
delete _surface;
}
+void FlicDecoder::FlicVideoTrack::readHeader() {
+ _fileStream->readUint16LE(); // flags
+ // Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word)
+ // the frame delay is the FLIC "speed", in milliseconds.
+ _frameDelay = _startFrameDelay = _fileStream->readUint32LE();
+
+ _fileStream->seek(80);
+ _offsetFrame1 = _fileStream->readUint32LE();
+ _offsetFrame2 = _fileStream->readUint32LE();
+
+ // Seek to the first frame
+ _fileStream->seek(_offsetFrame1);
+}
+
bool FlicDecoder::FlicVideoTrack::endOfTrack() const {
return getCurFrame() >= getFrameCount() - 1;
}
@@ -158,76 +163,18 @@ Graphics::PixelFormat FlicDecoder::FlicVideoTrack::getPixelFormat() const {
const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() {
// Read chunk
- uint32 frameSize = _fileStream->readUint32LE();
+ /*uint32 frameSize = */ _fileStream->readUint32LE();
uint16 frameType = _fileStream->readUint16LE();
- uint16 chunkCount = 0;
switch (frameType) {
case FRAME_TYPE:
- {
- chunkCount = _fileStream->readUint16LE();
- // Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
- // the frame delay is the FLIC "speed", in milliseconds.
- uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds
- if (newFrameDelay > 0)
- _frameDelay = newFrameDelay;
-
- _fileStream->readUint16LE(); // reserved, always 0
- uint16 newWidth = _fileStream->readUint16LE();
- uint16 newHeight = _fileStream->readUint16LE();
-
- if ((newWidth != 0) || (newHeight != 0)) {
- if (newWidth == 0)
- newWidth = _surface->w;
- if (newHeight == 0)
- newHeight = _surface->h;
-
- _surface->free();
- delete _surface;
- _surface = new Graphics::Surface();
- _surface->create(newWidth, newHeight, Graphics::PixelFormat::createFormatCLUT8());
- }
- }
+ handleFrame();
break;
default:
error("FlicDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType);
break;
}
- // Read subchunks
- if (frameType == FRAME_TYPE) {
- for (uint32 i = 0; i < chunkCount; ++i) {
- frameSize = _fileStream->readUint32LE();
- 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("FlicDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType);
- break;
- }
-
- delete[] data;
- }
- }
-
_curFrame++;
_nextFrameStartTime += _frameDelay;
@@ -240,6 +187,63 @@ const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() {
return _surface;
}
+void FlicDecoder::FlicVideoTrack::handleFrame() {
+ uint16 chunkCount = _fileStream->readUint16LE();
+ // Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
+ // the frame delay is the FLIC "speed", in milliseconds.
+ uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds
+ if (newFrameDelay > 0)
+ _frameDelay = newFrameDelay;
+
+ _fileStream->readUint16LE(); // reserved, always 0
+ uint16 newWidth = _fileStream->readUint16LE();
+ uint16 newHeight = _fileStream->readUint16LE();
+
+ if ((newWidth != 0) || (newHeight != 0)) {
+ if (newWidth == 0)
+ newWidth = _surface->w;
+ if (newHeight == 0)
+ newHeight = _surface->h;
+
+ _surface->free();
+ delete _surface;
+ _surface = new Graphics::Surface();
+ _surface->create(newWidth, newHeight, Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ // 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("FlicDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType);
+ break;
+ }
+
+ delete[] data;
+ }
+}
+
void FlicDecoder::FlicVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
for (int y = (*it).top; y < (*it).bottom; ++y) {
diff --git a/video/flic_decoder.h b/video/flic_decoder.h
index 1769e1ed2e..445e474b87 100644
--- a/video/flic_decoder.h
+++ b/video/flic_decoder.h
@@ -42,6 +42,7 @@ namespace Video {
* Decoder for FLIC videos.
*
* Video decoder used in engines:
+ * - chewy
* - tucker
*/
class FlicDecoder : public VideoDecoder {
@@ -49,21 +50,23 @@ public:
FlicDecoder();
virtual ~FlicDecoder();
- bool loadStream(Common::SeekableReadStream *stream);
+ virtual bool loadStream(Common::SeekableReadStream *stream);
const Common::List<Common::Rect> *getDirtyRects() const;
void clearDirtyRects();
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
-private:
+protected:
class FlicVideoTrack : public VideoTrack {
public:
- FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height);
+ FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader = false);
~FlicVideoTrack();
+ virtual void readHeader();
+
bool endOfTrack() const;
- bool isRewindable() const { return true; }
- bool rewind();
+ virtual bool isRewindable() const { return true; }
+ virtual bool rewind();
uint16 getWidth() const;
uint16 getHeight() const;
@@ -71,7 +74,8 @@ private:
int getCurFrame() const { return _curFrame; }
int getFrameCount() const { return _frameCount; }
uint32 getNextFrameStartTime() const { return _nextFrameStartTime; }
- const Graphics::Surface *decodeNextFrame();
+ virtual const Graphics::Surface *decodeNextFrame();
+ virtual void handleFrame();
const byte *getPalette() const { _dirtyPalette = false; return _palette; }
bool hasDirtyPalette() const { return _dirtyPalette; }
@@ -79,7 +83,7 @@ private:
void clearDirtyRects() { _dirtyRects.clear(); }
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
- private:
+ protected:
Common::SeekableReadStream *_fileStream;
Graphics::Surface *_surface;