aboutsummaryrefslogtreecommitdiff
path: root/engines/gob/pregob
diff options
context:
space:
mode:
Diffstat (limited to 'engines/gob/pregob')
-rw-r--r--engines/gob/pregob/gctfile.cpp306
-rw-r--r--engines/gob/pregob/gctfile.h149
-rw-r--r--engines/gob/pregob/onceupon/abracadabra.cpp137
-rw-r--r--engines/gob/pregob/onceupon/abracadabra.h61
-rw-r--r--engines/gob/pregob/onceupon/babayaga.cpp137
-rw-r--r--engines/gob/pregob/onceupon/babayaga.h61
-rw-r--r--engines/gob/pregob/onceupon/brokenstrings.h60
-rw-r--r--engines/gob/pregob/onceupon/chargenchild.cpp117
-rw-r--r--engines/gob/pregob/onceupon/chargenchild.h60
-rw-r--r--engines/gob/pregob/onceupon/onceupon.cpp1904
-rw-r--r--engines/gob/pregob/onceupon/onceupon.h344
-rw-r--r--engines/gob/pregob/onceupon/palettes.h411
-rw-r--r--engines/gob/pregob/onceupon/parents.cpp217
-rw-r--r--engines/gob/pregob/onceupon/parents.h94
-rw-r--r--engines/gob/pregob/onceupon/stork.cpp234
-rw-r--r--engines/gob/pregob/onceupon/stork.h103
-rw-r--r--engines/gob/pregob/onceupon/title.cpp117
-rw-r--r--engines/gob/pregob/onceupon/title.h55
-rw-r--r--engines/gob/pregob/pregob.cpp351
-rw-r--r--engines/gob/pregob/pregob.h194
-rw-r--r--engines/gob/pregob/seqfile.cpp384
-rw-r--r--engines/gob/pregob/seqfile.h193
-rw-r--r--engines/gob/pregob/txtfile.cpp232
-rw-r--r--engines/gob/pregob/txtfile.h91
24 files changed, 6012 insertions, 0 deletions
diff --git a/engines/gob/pregob/gctfile.cpp b/engines/gob/pregob/gctfile.cpp
new file mode 100644
index 0000000000..08c32cda76
--- /dev/null
+++ b/engines/gob/pregob/gctfile.cpp
@@ -0,0 +1,306 @@
+/* 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/random.h"
+#include "common/stream.h"
+
+#include "gob/surface.h"
+#include "gob/video.h"
+
+#include "gob/pregob/gctfile.h"
+
+namespace Gob {
+
+GCTFile::Chunk::Chunk() : type(kChunkTypeNone) {
+}
+
+
+GCTFile::GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd) : _rnd(&rnd),
+ _areaLeft(0), _areaTop(0), _areaRight(0), _areaBottom(0), _currentItem(0xFFFF) {
+
+ load(gct);
+}
+
+GCTFile::~GCTFile() {
+}
+
+void GCTFile::load(Common::SeekableReadStream &gct) {
+ gct.skip(4); // Required buffer size
+ gct.skip(2); // Unknown
+
+ // Read the selector and line counts for each item
+ const uint16 itemCount = gct.readUint16LE();
+ _items.resize(itemCount);
+
+ for (Items::iterator i = _items.begin(); i != _items.end(); ++i) {
+ const uint16 selector = gct.readUint16LE();
+ const uint16 lineCount = gct.readUint16LE();
+
+ i->selector = selector;
+ i->lines.resize(lineCount);
+ }
+
+ // Read all item lines
+ for (Items::iterator i = _items.begin(); i != _items.end(); ++i) {
+ for (Lines::iterator l = i->lines.begin(); l != i->lines.end(); ++l) {
+ const uint16 lineSize = gct.readUint16LE();
+
+ readLine(gct, *l, lineSize);
+ }
+ }
+
+ if (gct.err())
+ error("GCTFile::load(): Failed reading GCT");
+}
+
+void GCTFile::readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const {
+ line.chunks.push_back(Chunk());
+
+ while (lineSize > 0) {
+ byte c = gct.readByte();
+ lineSize--;
+
+ if (c == 0) {
+ // Command byte
+
+ if (lineSize == 0)
+ break;
+
+ byte cmd = gct.readByte();
+ lineSize--;
+
+ // Line end command
+ if (cmd == 0)
+ break;
+
+ // Item reference command
+ if (cmd == 1) {
+ if (lineSize < 2) {
+ warning("GCTFile::readLine(): Item reference command is missing parameters");
+ break;
+ }
+
+ const uint32 itemRef = gct.readUint16LE();
+ lineSize -= 2;
+
+ line.chunks.push_back(Chunk());
+ line.chunks.back().type = kChunkTypeItem;
+ line.chunks.back().item = itemRef;
+
+ line.chunks.push_back(Chunk());
+ continue;
+ }
+
+ warning("GCTFile::readLine(): Invalid command 0x%02X", cmd);
+ break;
+ }
+
+ // Text
+ line.chunks.back().type = kChunkTypeString;
+ line.chunks.back().text += (char)c;
+ }
+
+ // Skip bytes we didn't read (because of errors)
+ gct.skip(lineSize);
+
+ // Remove empty chunks from the end of the list
+ while (!line.chunks.empty() && (line.chunks.back().type == kChunkTypeNone))
+ line.chunks.pop_back();
+}
+
+uint16 GCTFile::getLineCount(uint item) const {
+ if (item >= _items.size())
+ return 0;
+
+ return _items[item].lines.size();
+}
+
+void GCTFile::selectLine(uint item, uint16 line) {
+ if ((item >= _items.size()) && (item != kSelectorAll) && (item != kSelectorRandom))
+ return;
+
+ _items[item].selector = line;
+}
+
+void GCTFile::setText(uint item, uint16 line, const Common::String &text) {
+ if ((item >= _items.size()) || (line >= _items[item].lines.size()))
+ return;
+
+ _items[item].lines[line].chunks.clear();
+ _items[item].lines[line].chunks.push_back(Chunk());
+
+ _items[item].lines[line].chunks.back().type = kChunkTypeString;
+ _items[item].lines[line].chunks.back().text = text;
+}
+
+void GCTFile::setText(uint item, const Common::String &text) {
+ if (item >= _items.size())
+ return;
+
+ _items[item].selector = 0;
+
+ _items[item].lines.resize(1);
+
+ setText(item, 0, text);
+}
+
+void GCTFile::reset() {
+ _currentItem = 0xFFFF;
+ _currentText.clear();
+}
+
+Common::String GCTFile::getLineText(const Line &line) const {
+ Common::String text;
+
+ // Go over all chunks in this line
+ for (Chunks::const_iterator c = line.chunks.begin(); c != line.chunks.end(); ++c) {
+ // A chunk is either a direct string, or a reference to another item
+
+ if (c->type == kChunkTypeItem) {
+ Common::List<Common::String> lines;
+
+ getItemText(c->item, lines);
+ if (lines.empty())
+ continue;
+
+ if (lines.size() > 1)
+ warning("GCTFile::getLineText(): Referenced item has multiple lines");
+
+ text += lines.front();
+ } else if (c->type == kChunkTypeString)
+ text += c->text;
+ }
+
+ return text;
+}
+
+void GCTFile::getItemText(uint item, Common::List<Common::String> &text) const {
+ text.clear();
+
+ if ((item >= _items.size()) || _items[item].lines.empty())
+ return;
+
+ uint16 line = _items[item].selector;
+
+ // Draw all lines
+ if (line == kSelectorAll) {
+ for (Lines::const_iterator l = _items[item].lines.begin(); l != _items[item].lines.end(); ++l)
+ text.push_back(getLineText(*l));
+
+ return;
+ }
+
+ // Draw random line
+ if (line == kSelectorRandom)
+ line = _rnd->getRandomNumber(_items[item].lines.size() - 1);
+
+ if (line >= _items[item].lines.size())
+ return;
+
+ text.push_back(getLineText(_items[item].lines[line]));
+}
+
+void GCTFile::setArea(int16 left, int16 top, int16 right, int16 bottom) {
+ trashBuffer();
+
+ _hasArea = false;
+
+ const int16 width = right - left + 1;
+ const int16 height = bottom - top + 1;
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ _areaLeft = left;
+ _areaTop = top;
+ _areaRight = right;
+ _areaBottom = bottom;
+
+ _hasArea = true;
+
+ resizeBuffer(width, height);
+}
+
+bool GCTFile::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ return restoreScreen(dest, left, top, right, bottom);
+}
+
+bool GCTFile::fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ left = _areaLeft;
+ top = _areaTop;
+ right = _areaRight;
+ bottom = _areaBottom;
+
+ if (!hasSavedBackground())
+ saveScreen(dest, left, top, right, bottom);
+
+ dest.fillRect(left, top, right, bottom, color);
+
+ return true;
+}
+
+bool GCTFile::finished() const {
+ return (_currentItem != 0xFFFF) && _currentText.empty();
+}
+
+bool GCTFile::draw(Surface &dest, uint16 item, const Font &font, uint8 color,
+ int16 &left, int16 &top, int16 &right, int16 &bottom) {
+
+ if ((item >= _items.size()) || !_hasArea)
+ return false;
+
+ left = _areaLeft;
+ top = _areaTop;
+ right = _areaRight;
+ bottom = _areaBottom;
+
+ const int16 width = right - left + 1;
+ const int16 height = bottom - top + 1;
+
+ const uint lineCount = height / font.getCharHeight();
+ if (lineCount == 0)
+ return false;
+
+ if (!hasSavedBackground())
+ saveScreen(dest, left, top, right, bottom);
+
+ if (item != _currentItem) {
+ _currentItem = item;
+
+ getItemText(_currentItem, _currentText);
+ }
+
+ if (_currentText.empty())
+ return false;
+
+ int16 y = top;
+ for (uint i = 0; (i < lineCount) && !_currentText.empty(); i++, y += font.getCharHeight()) {
+ const Common::String &line = _currentText.front();
+ const int16 x = left + ((width - (line.size() * font.getCharWidth())) / 2);
+
+ font.drawString(line, x, y, color, 0, true, dest);
+ _currentText.pop_front();
+ }
+
+ return true;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/gctfile.h b/engines/gob/pregob/gctfile.h
new file mode 100644
index 0000000000..ed6351b7a8
--- /dev/null
+++ b/engines/gob/pregob/gctfile.h
@@ -0,0 +1,149 @@
+/* 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 GOB_PREGOB_GCTFILE_H
+#define GOB_PREGOB_GCTFILE_H
+
+#include "common/str.h"
+#include "common/array.h"
+#include "common/list.h"
+
+#include "gob/backbuffer.h"
+
+namespace Common {
+ class RandomSource;
+ class SeekableReadStream;
+}
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class GCTFile : public BackBuffer {
+public:
+ static const uint16 kSelectorAll = 0xFFFE; ///< Print all lines.
+ static const uint16 kSelectorRandom = 0xFFFF; ///< Print a random line.
+
+
+ GCTFile(Common::SeekableReadStream &gct, Common::RandomSource &rnd);
+ ~GCTFile();
+
+ /** Return the number of lines in an item. */
+ uint16 getLineCount(uint item) const;
+
+ /** Set the area the text will be printed in. */
+ void setArea(int16 left, int16 top, int16 right, int16 bottom);
+
+ /** Set which line of this item should be printed. */
+ void selectLine(uint item, uint16 line);
+
+ /** Change the text of an items' line. */
+ void setText(uint item, uint16 line, const Common::String &text);
+ /** Change the item into one one line and set that line's text. */
+ void setText(uint item, const Common::String &text);
+
+ /** Reset the item drawing state. */
+ void reset();
+
+ /** Clear the drawn text, restoring the original content. */
+ bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Fill the text area with a color. */
+ bool fill(Surface &dest, uint8 color, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Draw an item onto the surface, until all text has been drawn or the area is filled. */
+ bool draw(Surface &dest, uint16 item, const Font &font, uint8 color,
+ int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Did we draw all text? */
+ bool finished() const;
+
+private:
+ /** The type of a chunk. */
+ enum ChunkType {
+ kChunkTypeNone = 0, ///< Do nothing.
+ kChunkTypeString , ///< A direct string.
+ kChunkTypeItem ///< A reference to an item to print instead.
+ };
+
+ /** A chunk in an item text line. */
+ struct Chunk {
+ ChunkType type; ///< The type of the chunk.
+
+ Common::String text; ///< Text to print.
+
+ int item; ///< Item to print instead.
+
+ Chunk();
+ };
+
+ typedef Common::List<Chunk> Chunks;
+
+ /** A line in an item. */
+ struct Line {
+ Chunks chunks; ///< The chunks that make up the line.
+ };
+
+ typedef Common::Array<Line> Lines;
+
+ /** A GCT item. */
+ struct Item {
+ Lines lines; ///< The text lines in the item
+ uint16 selector; ///< Which line to print.
+ };
+
+ typedef Common::Array<Item> Items;
+
+
+ Common::RandomSource *_rnd;
+
+ Items _items; ///< All GCT items.
+
+ // The area on which to print
+ bool _hasArea;
+ int16 _areaLeft;
+ int16 _areaTop;
+ int16 _areaRight;
+ int16 _areaBottom;
+
+ /** Index of the current item we're drawing. */
+ uint16 _currentItem;
+ /** Text left to draw. */
+ Common::List<Common::String> _currentText;
+
+
+ // -- Loading helpers --
+
+ void load(Common::SeekableReadStream &gct);
+ void readLine(Common::SeekableReadStream &gct, Line &line, uint16 lineSize) const;
+
+
+ // -- Draw helpers --
+
+ Common::String getLineText(const Line &line) const;
+ void getItemText(uint item, Common::List<Common::String> &text) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_GCTFILE_H
diff --git a/engines/gob/pregob/onceupon/abracadabra.cpp b/engines/gob/pregob/onceupon/abracadabra.cpp
new file mode 100644
index 0000000000..2cf6855ef8
--- /dev/null
+++ b/engines/gob/pregob/onceupon/abracadabra.cpp
@@ -0,0 +1,137 @@
+/* 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/textconsole.h"
+
+#include "gob/gob.h"
+
+#include "gob/pregob/onceupon/abracadabra.h"
+
+static const uint8 kCopyProtectionColors[7] = {
+ 14, 11, 13, 1, 7, 12, 2
+};
+
+static const uint8 kCopyProtectionShapes[7 * 20] = {
+ 3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3,
+ 0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4,
+ 0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3,
+ 1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1,
+ 4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4,
+ 4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2,
+ 3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4
+};
+
+static const uint8 kCopyProtectionObfuscate[4] = {
+ 1, 0, 2, 3
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const OnceUpon::MenuButton Abracadabra::kAnimalsButtons = {
+ true, 131, 127, 183, 164, 193, 0, 243, 35, 132, 128, 0
+};
+
+const OnceUpon::MenuButton Abracadabra::kAnimalButtons[] = {
+ {false, 37, 89, 95, 127, 37, 89, 95, 127, 131, 25, 0},
+ {false, 114, 65, 172, 111, 114, 65, 172, 111, 131, 25, 1},
+ {false, 186, 72, 227, 96, 186, 72, 227, 96, 139, 25, 2},
+ {false, 249, 87, 282, 112, 249, 87, 282, 112, 143, 25, 3},
+ {false, 180, 102, 234, 138, 180, 102, 234, 138, 133, 25, 4},
+ {false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5},
+ {false, 113, 151, 171, 176, 113, 151, 171, 176, 131, 25, 6},
+ {false, 114, 122, 151, 150, 114, 122, 151, 150, 141, 25, 7},
+ {false, 36, 136, 94, 176, 36, 136, 94, 176, 131, 25, 8},
+ {false, 243, 123, 295, 155, 243, 123, 295, 155, 136, 25, 9}
+};
+
+const char *Abracadabra::kAnimalNames[] = {
+ "loup",
+ "drag",
+ "arai",
+ "crap",
+ "crab",
+ "mous",
+ "saut",
+ "guep",
+ "rhin",
+ "scor"
+};
+
+// The houses where the stork can drop a bundle
+const OnceUpon::MenuButton Abracadabra::kStorkHouses[] = {
+ {false, 16, 80, 87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady
+ {false, 61, 123, 96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers
+ {false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut , Woodcutters
+ {false, 229, 91, 304, 188, 0, 0, 0, 0, 0, 0, 3} // Palace , King & Queen
+};
+
+// The stork bundle drop parameters
+const Stork::BundleDrop Abracadabra::kStorkBundleDrops[] = {
+ { 14, 65, 127, true },
+ { 14, 76, 152, true },
+ { 14, 204, 137, true },
+ { 11, 275, 179, false }
+};
+
+// Parameters for the stork section.
+const OnceUpon::StorkParam Abracadabra::kStorkParam = {
+ "present.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops
+};
+
+
+Abracadabra::Abracadabra(GobEngine *vm) : OnceUpon(vm) {
+}
+
+Abracadabra::~Abracadabra() {
+}
+
+void Abracadabra::run() {
+ init();
+
+ // Copy protection
+ bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
+ if (_vm->shouldQuit() || !correctCP)
+ return;
+
+ // Show the intro
+ showIntro();
+ if (_vm->shouldQuit())
+ return;
+
+ // Handle the start menu
+ doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
+ if (_vm->shouldQuit())
+ return;
+
+ // Play the actual game
+ playGame();
+}
+
+const OnceUpon::StorkParam &Abracadabra::getStorkParameters() const {
+ return kStorkParam;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/abracadabra.h b/engines/gob/pregob/onceupon/abracadabra.h
new file mode 100644
index 0000000000..8048213f5f
--- /dev/null
+++ b/engines/gob/pregob/onceupon/abracadabra.h
@@ -0,0 +1,61 @@
+/* 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 GOB_PREGOB_ONCEUPON_ABRACADABRA_H
+#define GOB_PREGOB_ONCEUPON_ABRACADABRA_H
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class Abracadabra : public OnceUpon {
+public:
+ Abracadabra(GobEngine *vm);
+ ~Abracadabra();
+
+ void run();
+
+protected:
+ const StorkParam &getStorkParameters() const;
+
+private:
+ /** Definition of the menu button that leads to the animal names screen. */
+ static const MenuButton kAnimalsButtons;
+
+ /** Definition of the buttons that make up the animals in the animal names screen. */
+ static const MenuButton kAnimalButtons[];
+ /** File prefixes for the name of each animal. */
+ static const char *kAnimalNames[];
+
+ // Parameters for the stork section.
+ static const MenuButton kStorkHouses[];
+ static const Stork::BundleDrop kStorkBundleDrops[];
+ static const struct StorkParam kStorkParam;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_ABRACADABRA_H
diff --git a/engines/gob/pregob/onceupon/babayaga.cpp b/engines/gob/pregob/onceupon/babayaga.cpp
new file mode 100644
index 0000000000..ef56b9dd0b
--- /dev/null
+++ b/engines/gob/pregob/onceupon/babayaga.cpp
@@ -0,0 +1,137 @@
+/* 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/textconsole.h"
+
+#include "gob/gob.h"
+
+#include "gob/pregob/onceupon/babayaga.h"
+
+static const uint8 kCopyProtectionColors[7] = {
+ 14, 11, 13, 1, 7, 12, 2
+};
+
+static const uint8 kCopyProtectionShapes[7 * 20] = {
+ 0, 0, 1, 2, 1, 1, 2, 4, 3, 1, 4, 2, 4, 4, 2, 4, 1, 2, 3, 3,
+ 3, 1, 0, 3, 1, 3, 4, 2, 4, 4, 3, 2, 0, 2, 0, 1, 2, 0, 1, 4,
+ 1, 0, 2, 3, 4, 2, 3, 2, 2, 0, 0, 0, 4, 2, 3, 4, 4, 0, 4, 1,
+ 0, 2, 0, 4, 2, 4, 4, 2, 3, 0, 1, 1, 1, 1, 3, 0, 4, 2, 3, 4,
+ 3, 4, 3, 0, 1, 2, 0, 2, 2, 0, 2, 4, 0, 3, 4, 1, 1, 4, 1, 3,
+ 4, 2, 1, 1, 1, 1, 4, 3, 4, 2, 3, 0, 0, 3, 0, 2, 3, 0, 2, 4,
+ 4, 2, 4, 3, 0, 4, 0, 2, 3, 1, 4, 1, 3, 1, 0, 0, 2, 1, 3, 2
+};
+
+static const uint8 kCopyProtectionObfuscate[4] = {
+ 0, 1, 2, 3
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const OnceUpon::MenuButton BabaYaga::kAnimalsButtons = {
+ true, 131, 127, 183, 164, 193, 0, 245, 37, 131, 127, 0
+};
+
+const OnceUpon::MenuButton BabaYaga::kAnimalButtons[] = {
+ {false, 34, 84, 92, 127, 34, 84, 92, 127, 131, 25, 0},
+ {false, 114, 65, 172, 111, 114, 65, 172, 111, 131, 25, 1},
+ {false, 186, 72, 227, 96, 186, 72, 227, 96, 139, 25, 2},
+ {false, 249, 87, 282, 112, 249, 87, 282, 112, 143, 25, 3},
+ {false, 180, 97, 234, 138, 180, 97, 234, 138, 133, 25, 4},
+ {false, 197, 145, 242, 173, 197, 145, 242, 173, 137, 25, 5},
+ {false, 113, 156, 171, 176, 113, 156, 171, 176, 131, 25, 6},
+ {false, 114, 127, 151, 150, 114, 127, 151, 150, 141, 25, 7},
+ {false, 36, 136, 94, 176, 36, 136, 94, 176, 131, 25, 8},
+ {false, 245, 123, 293, 155, 245, 123, 293, 155, 136, 25, 9}
+};
+
+const char *BabaYaga::kAnimalNames[] = {
+ "vaut",
+ "drag",
+ "arai",
+ "gren",
+ "fauc",
+ "abei",
+ "serp",
+ "tort",
+ "sang",
+ "rena"
+};
+
+// The houses where the stork can drop a bundle
+const OnceUpon::MenuButton BabaYaga::kStorkHouses[] = {
+ {false, 16, 80, 87, 125, 0, 0, 0, 0, 0, 0, 0}, // Castle , Lord & Lady
+ {false, 61, 123, 96, 149, 0, 0, 0, 0, 0, 0, 1}, // Cottage, Farmers
+ {false, 199, 118, 226, 137, 0, 0, 0, 0, 0, 0, 2}, // Hut , Woodcutters
+ {false, 229, 91, 304, 188, 0, 0, 0, 0, 0, 0, 3} // Palace , King & Queen
+};
+
+// The stork bundle drop parameters
+const Stork::BundleDrop BabaYaga::kStorkBundleDrops[] = {
+ { 14, 35, 129, true },
+ { 14, 70, 148, true },
+ { 14, 206, 136, true },
+ { 11, 260, 225, false }
+};
+
+// Parameters for the stork section.
+const OnceUpon::StorkParam BabaYaga::kStorkParam = {
+ "present2.cmp", ARRAYSIZE(kStorkHouses), kStorkHouses, kStorkBundleDrops
+};
+
+
+BabaYaga::BabaYaga(GobEngine *vm) : OnceUpon(vm) {
+}
+
+BabaYaga::~BabaYaga() {
+}
+
+void BabaYaga::run() {
+ init();
+
+ // Copy protection
+ bool correctCP = doCopyProtection(kCopyProtectionColors, kCopyProtectionShapes, kCopyProtectionObfuscate);
+ if (_vm->shouldQuit() || !correctCP)
+ return;
+
+ // Show the intro
+ showIntro();
+ if (_vm->shouldQuit())
+ return;
+
+ // Handle the start menu
+ doStartMenu(&kAnimalsButtons, ARRAYSIZE(kAnimalButtons), kAnimalButtons, kAnimalNames);
+ if (_vm->shouldQuit())
+ return;
+
+ // Play the actual game
+ playGame();
+}
+
+const OnceUpon::StorkParam &BabaYaga::getStorkParameters() const {
+ return kStorkParam;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/babayaga.h b/engines/gob/pregob/onceupon/babayaga.h
new file mode 100644
index 0000000000..0241f78f4e
--- /dev/null
+++ b/engines/gob/pregob/onceupon/babayaga.h
@@ -0,0 +1,61 @@
+/* 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 GOB_PREGOB_ONCEUPON_BABAYAGA_H
+#define GOB_PREGOB_ONCEUPON_BABAYAGA_H
+
+#include "gob/pregob/onceupon/onceupon.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+class BabaYaga : public OnceUpon {
+public:
+ BabaYaga(GobEngine *vm);
+ ~BabaYaga();
+
+ void run();
+
+protected:
+ const StorkParam &getStorkParameters() const;
+
+private:
+ /** Definition of the menu button that leads to the animal names screen. */
+ static const MenuButton kAnimalsButtons;
+
+ /** Definition of the buttons that make up the animals in the animal names screen. */
+ static const MenuButton kAnimalButtons[];
+ /** File prefixes for the name of each animal. */
+ static const char *kAnimalNames[];
+
+ // Parameters for the stork section.
+ static const MenuButton kStorkHouses[];
+ static const Stork::BundleDrop kStorkBundleDrops[];
+ static const struct StorkParam kStorkParam;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_BABAYAGA_H
diff --git a/engines/gob/pregob/onceupon/brokenstrings.h b/engines/gob/pregob/onceupon/brokenstrings.h
new file mode 100644
index 0000000000..89acb1c6bd
--- /dev/null
+++ b/engines/gob/pregob/onceupon/brokenstrings.h
@@ -0,0 +1,60 @@
+/* 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 GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
+#define GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
+
+struct BrokenString {
+ const char *wrong;
+ const char *correct;
+};
+
+struct BrokenStringLanguage {
+ const BrokenString *strings;
+ uint count;
+};
+
+static const BrokenString kBrokenStringsGerman[] = {
+ { "Zeichungen von Kaki," , "Zeichnungen von Kaki," },
+ { "die es in seine Wachtr\204ume", "die es in seine Tagtr\204ume" },
+ { " Spielerfahrung" , " Spielerfahren" },
+ { " Fortgeschrittene" , " Fortgeschritten" },
+ { "die Vespe" , "die Wespe" },
+ { "das Rhinoceros" , "das Rhinozeros" },
+ { "die Heusschrecke" , "die Heuschrecke" },
+ { "Das, von Drachen gebrachte" , "Das vom Drachen gebrachte" },
+ { "Am Waldesrand es sieht" , "Am Waldesrand sieht es" },
+ { " das Kind den Palast." , "das Kind den Palast." },
+ { "Am Waldessaum sieht" , "Am Waldesrand sieht" },
+ { "tipp auf ESC!" , "dr\201cke ESC!" },
+ { "Wohin fliegt der Drachen?" , "Wohin fliegt der Drache?" }
+};
+
+static const BrokenStringLanguage kBrokenStrings[kLanguageCount] = {
+ { 0, 0 }, // French
+ { kBrokenStringsGerman, ARRAYSIZE(kBrokenStringsGerman) }, // German
+ { 0, 0 }, // English
+ { 0, 0 }, // Spanish
+ { 0, 0 }, // Italian
+};
+
+#endif // GOB_PREGOB_ONCEUPON_BROKENSTRINGS_H
diff --git a/engines/gob/pregob/onceupon/chargenchild.cpp b/engines/gob/pregob/onceupon/chargenchild.cpp
new file mode 100644
index 0000000000..ba099e4937
--- /dev/null
+++ b/engines/gob/pregob/onceupon/chargenchild.cpp
@@ -0,0 +1,117 @@
+/* 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 "gob/surface.h"
+#include "gob/anifile.h"
+
+#include "gob/pregob/onceupon/chargenchild.h"
+
+enum Animation {
+ kAnimWalkLeft = 0,
+ kAnimWalkRight = 1,
+ kAnimJumpLeft = 2,
+ kAnimJumpRight = 3,
+ kAnimTapFoot = 14
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+CharGenChild::CharGenChild(const ANIFile &ani) : ANIObject(ani) {
+ setPosition(265, 110);
+ setAnimation(kAnimWalkLeft);
+ setVisible(true);
+ setPause(false);
+}
+
+CharGenChild::~CharGenChild() {
+}
+
+void CharGenChild::advance() {
+ bool wasLastFrame = lastFrame();
+
+ ANIObject::advance();
+
+ int16 x, y, left, top, width, height;
+ getPosition(x, y);
+ getFramePosition(left, top);
+ getFrameSize(width, height);
+
+ const int16 right = left + width - 1;
+
+ switch (getAnimation()) {
+ case kAnimWalkLeft:
+ if (left <= 147)
+ setAnimation(kAnimWalkRight);
+ break;
+
+ case kAnimWalkRight:
+ if (right >= 290) {
+ setAnimation(kAnimJumpLeft);
+
+ setPosition(x, y - 14);
+ }
+ break;
+
+ case kAnimJumpLeft:
+ if (wasLastFrame) {
+ setAnimation(kAnimTapFoot);
+
+ setPosition(x, y - 10);
+ }
+ break;
+
+ case kAnimTapFoot:
+ if (wasLastFrame) {
+ setAnimation(kAnimJumpRight);
+
+ setPosition(x, y + 10);
+ }
+ break;
+
+ case kAnimJumpRight:
+ if (wasLastFrame) {
+ setAnimation(kAnimWalkLeft);
+
+ setPosition(x, y + 14);
+ }
+ break;
+ }
+}
+
+CharGenChild::Sound CharGenChild::shouldPlaySound() const {
+ const uint16 anim = getAnimation();
+ const uint16 frame = getFrame();
+
+ if (((anim == kAnimWalkLeft) || (anim == kAnimWalkRight)) && ((frame == 1) || (frame == 6)))
+ return kSoundWalk;
+
+ if (((anim == kAnimJumpLeft) || (anim == kAnimJumpRight)) && (frame == 0))
+ return kSoundJump;
+
+ return kSoundNone;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/chargenchild.h b/engines/gob/pregob/onceupon/chargenchild.h
new file mode 100644
index 0000000000..3b09ef112a
--- /dev/null
+++ b/engines/gob/pregob/onceupon/chargenchild.h
@@ -0,0 +1,60 @@
+/* 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 GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
+#define GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
+
+#include "common/system.h"
+
+#include "gob/aniobject.h"
+
+namespace Gob {
+
+class Surface;
+class ANIFile;
+
+namespace OnceUpon {
+
+/** The child running around on the character generator screen. */
+class CharGenChild : public ANIObject {
+public:
+ enum Sound {
+ kSoundNone = 0,
+ kSoundWalk ,
+ kSoundJump
+ };
+
+ CharGenChild(const ANIFile &ani);
+ ~CharGenChild();
+
+ /** Advance the animation to the next frame. */
+ void advance();
+
+ /** Should we play a sound right now? */
+ Sound shouldPlaySound() const;
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_CHARGENCHILD_H
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
new file mode 100644
index 0000000000..e4c2df34c0
--- /dev/null
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -0,0 +1,1904 @@
+/* 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 "gob/gob.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "gob/dataio.h"
+#include "gob/surface.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+#include "gob/anifile.h"
+#include "gob/aniobject.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/txtfile.h"
+#include "gob/pregob/gctfile.h"
+
+#include "gob/pregob/onceupon/onceupon.h"
+#include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/title.h"
+#include "gob/pregob/onceupon/parents.h"
+#include "gob/pregob/onceupon/chargenchild.h"
+
+static const uint kLanguageCount = 5;
+
+static const uint kCopyProtectionHelpStringCount = 3;
+
+static const char *kCopyProtectionHelpStrings[Gob::OnceUpon::OnceUpon::kLanguageCount][kCopyProtectionHelpStringCount] = {
+ { // French
+ "Consulte le livret des animaux, rep\212re la",
+ "page correspondant \205 la couleur de l\'\202cran",
+ "et clique le symbole associ\202 \205 l\'animal affich\202.",
+ },
+ { // German
+ "Suche im Tieralbum die Seite, die der Farbe auf",
+ "dem Bildschirm entspricht und klicke auf das",
+ "Tiersymbol.",
+ },
+ { // English
+ "Consult the book of animals, find the page",
+ "corresponding to the colour of screen and click",
+ "the symbol associated with the animal displayed.",
+ },
+ { // Spanish
+ "Consulta el libro de los animales, localiza la ",
+ "p\240gina que corresponde al color de la pantalla.",
+ "Cliquea el s\241mbolo asociado al animal que aparece.",
+ },
+ { // Italian
+ "Guarda il libretto degli animali, trova la",
+ "pagina che corrisponde al colore dello schermo,",
+ "clicca il simbolo associato all\'animale presentato",
+ }
+};
+
+static const char *kCopyProtectionWrongStrings[Gob::OnceUpon::OnceUpon::kLanguageCount] = {
+ "Tu t\'es tromp\202, dommage...", // French
+ "Schade, du hast dich geirrt." , // German
+ "You are wrong, what a pity!" , // English
+ "Te equivocas, l\240stima..." , // Spanish
+ "Sei Sbagliato, peccato..." // Italian
+};
+
+static const uint kCopyProtectionShapeCount = 5;
+
+static const int16 kCopyProtectionShapeCoords[kCopyProtectionShapeCount][6] = {
+ { 0, 51, 26, 75, 60, 154},
+ { 28, 51, 58, 81, 96, 151},
+ { 60, 51, 94, 79, 136, 152},
+ { 96, 51, 136, 71, 180, 155},
+ {140, 51, 170, 77, 228, 153}
+};
+
+enum ClownAnimation {
+ kClownAnimationClownCheer = 0,
+ kClownAnimationClownStand = 1,
+ kClownAnimationClownCry = 6
+};
+
+// 12 seconds delay for one area full of GCT text
+static const uint32 kGCTDelay = 12000;
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const OnceUpon::MenuButton OnceUpon::kMainMenuDifficultyButton[] = {
+ {false, 29, 18, 77, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyBeginner},
+ {false, 133, 18, 181, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyIntermediate},
+ {false, 241, 18, 289, 57, 0, 0, 0, 0, 0, 0, (int)kDifficultyAdvanced},
+};
+
+const OnceUpon::MenuButton OnceUpon::kSectionButtons[] = {
+ {false, 27, 121, 91, 179, 0, 0, 0, 0, 0, 0, 0},
+ { true, 95, 121, 159, 179, 4, 1, 56, 49, 100, 126, 2},
+ { true, 163, 121, 227, 179, 64, 1, 120, 49, 168, 126, 6},
+ { true, 231, 121, 295, 179, 128, 1, 184, 49, 236, 126, 10}
+};
+
+const OnceUpon::MenuButton OnceUpon::kIngameButtons[] = {
+ {true, 108, 83, 139, 116, 0, 0, 31, 34, 108, 83, 0},
+ {true, 144, 83, 175, 116, 36, 0, 67, 34, 144, 83, 1},
+ {true, 180, 83, 211, 116, 72, 0, 103, 34, 180, 83, 2}
+};
+
+const OnceUpon::MenuButton OnceUpon::kAnimalNamesBack = {
+ true, 19, 13, 50, 46, 36, 0, 67, 34, 19, 13, 1
+};
+
+const OnceUpon::MenuButton OnceUpon::kLanguageButtons[] = {
+ {true, 43, 80, 93, 115, 0, 55, 50, 90, 43, 80, 0},
+ {true, 132, 80, 182, 115, 53, 55, 103, 90, 132, 80, 1},
+ {true, 234, 80, 284, 115, 106, 55, 156, 90, 234, 80, 2},
+ {true, 43, 138, 93, 173, 159, 55, 209, 90, 43, 138, 3},
+ {true, 132, 138, 182, 173, 212, 55, 262, 90, 132, 138, 4},
+ {true, 234, 138, 284, 173, 265, 55, 315, 90, 234, 138, 2}
+};
+
+const char *OnceUpon::kSound[kSoundCount] = {
+ "diamant.snd", // kSoundClick
+ "cigogne.snd", // kSoundStork
+ "saute.snd" // kSoundJump
+};
+
+const OnceUpon::SectionFunc OnceUpon::kSectionFuncs[kSectionCount] = {
+ &OnceUpon::sectionStork,
+ &OnceUpon::sectionChapter1,
+ &OnceUpon::sectionParents,
+ &OnceUpon::sectionChapter2,
+ &OnceUpon::sectionForest0,
+ &OnceUpon::sectionChapter3,
+ &OnceUpon::sectionEvilCastle,
+ &OnceUpon::sectionChapter4,
+ &OnceUpon::sectionForest1,
+ &OnceUpon::sectionChapter5,
+ &OnceUpon::sectionBossFight,
+ &OnceUpon::sectionChapter6,
+ &OnceUpon::sectionForest2,
+ &OnceUpon::sectionChapter7,
+ &OnceUpon::sectionEnd
+};
+
+
+OnceUpon::ScreenBackup::ScreenBackup() : palette(-1), changedCursor(false), cursorVisible(false) {
+ screen = new Surface(320, 200, 1);
+}
+
+OnceUpon::ScreenBackup::~ScreenBackup() {
+ delete screen;
+}
+
+
+OnceUpon::OnceUpon(GobEngine *vm) : PreGob(vm), _openedArchives(false),
+ _jeudak(0), _lettre(0), _plettre(0), _glettre(0) {
+
+}
+
+OnceUpon::~OnceUpon() {
+ deinit();
+}
+
+void OnceUpon::init() {
+ deinit();
+
+ // Open data files
+
+ bool hasSTK1 = _vm->_dataIO->openArchive("stk1.stk", true);
+ bool hasSTK2 = _vm->_dataIO->openArchive("stk2.stk", true);
+ bool hasSTK3 = _vm->_dataIO->openArchive("stk3.stk", true);
+
+ if (!hasSTK1 || !hasSTK2 || !hasSTK3)
+ error("OnceUpon::OnceUpon(): Failed to open archives");
+
+ _openedArchives = true;
+
+ // Open fonts
+
+ _jeudak = _vm->_draw->loadFont("jeudak.let");
+ _lettre = _vm->_draw->loadFont("lettre.let");
+ _plettre = _vm->_draw->loadFont("plettre.let");
+ _glettre = _vm->_draw->loadFont("glettre.let");
+
+ if (!_jeudak || !_lettre || !_plettre || !_glettre)
+ error("OnceUpon::OnceUpon(): Failed to fonts (%d, %d, %d, %d)",
+ _jeudak != 0, _lettre != 0, _plettre != 0, _glettre != 0);
+
+ // Verify the language
+
+ if (_vm->_global->_language == kLanguageAmerican)
+ _vm->_global->_language = kLanguageBritish;
+
+ if ((_vm->_global->_language >= kLanguageCount))
+ error("We do not support the language \"%s\".\n"
+ "If you are certain that your game copy includes this language,\n"
+ "please contact the ScummVM team with details about this version.\n"
+ "Thanks", _vm->getLangDesc(_vm->_global->_language));
+
+ // Load all our sounds and init the screen
+
+ loadSounds(kSound, kSoundCount);
+ initScreen();
+
+ // We start with an invalid palette
+ _palette = -1;
+
+ // No quit requested at start
+ _quit = false;
+
+ // We start with no selected difficulty and at section 0
+ _difficulty = kDifficultyCount;
+ _section = 0;
+
+ // Default name
+ _name = "Nemo";
+
+ // Default character properties
+ _house = 0;
+ _head = 0;
+ _colorHair = 0;
+ _colorJacket = 0;
+ _colorTrousers = 0;
+}
+
+void OnceUpon::deinit() {
+ // Free sounds
+ freeSounds();
+
+ // Free fonts
+
+ delete _jeudak;
+ delete _lettre;
+ delete _plettre;
+ delete _glettre;
+
+ _jeudak = 0;
+ _lettre = 0;
+ _plettre = 0;
+ _glettre = 0;
+
+ // Close archives
+
+ if (_openedArchives) {
+ _vm->_dataIO->closeArchive(true);
+ _vm->_dataIO->closeArchive(true);
+ _vm->_dataIO->closeArchive(true);
+ }
+
+ _openedArchives = false;
+}
+
+void OnceUpon::setGamePalette(uint palette) {
+ if (palette >= kPaletteCount)
+ return;
+
+ _palette = palette;
+
+ setPalette(kGamePalettes[palette], kPaletteSize);
+}
+
+void OnceUpon::setGameCursor() {
+ Surface cursor(320, 16, 1);
+
+ // Set the default game cursor
+ _vm->_video->drawPackedSprite("icon.cmp", cursor);
+ setCursor(cursor, 105, 0, 120, 15, 0, 0);
+}
+
+void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+ int16 x, int16 y) const {
+
+ // A special way of drawing something:
+ // Draw every other line "downwards", wait a bit after each line
+ // Then, draw the remaining lines "upwards" and again wait a bit after each line.
+
+ if (_vm->shouldQuit())
+ return;
+
+ const int16 width = right - left + 1;
+ const int16 height = bottom - top + 1;
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ // Draw the even lines downwards
+ for (int16 i = 0; i < height; i += 2) {
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+ _vm->_draw->blitInvalidated();
+
+ _vm->_util->longDelay(1);
+ }
+
+ // Draw the odd lines upwards
+ for (int16 i = (height & 1) ? height : (height - 1); i >= 0; i -= 2) {
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->_draw->_backSurface->blit(src, left, top + i, right, top + i, x, y + i);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, y + i, x + width - 1, y + 1);
+ _vm->_draw->blitInvalidated();
+
+ _vm->_util->longDelay(1);
+ }
+}
+
+void OnceUpon::backupScreen(ScreenBackup &backup, bool setDefaultCursor) {
+ // Backup the screen and palette
+ backup.screen->blit(*_vm->_draw->_backSurface);
+ backup.palette = _palette;
+
+ // Backup the cursor
+
+ backup.cursorVisible = isCursorVisible();
+
+ backup.changedCursor = false;
+ if (setDefaultCursor) {
+ backup.changedCursor = true;
+
+ addCursor();
+ setGameCursor();
+ }
+}
+
+void OnceUpon::restoreScreen(ScreenBackup &backup) {
+ if (_vm->shouldQuit())
+ return;
+
+ // Restore the screen
+ _vm->_draw->_backSurface->blit(*backup.screen);
+ _vm->_draw->forceBlit();
+
+ // Restore the palette
+ if (backup.palette >= 0)
+ setGamePalette(backup.palette);
+
+ // Restore the cursor
+
+ if (!backup.cursorVisible)
+ hideCursor();
+
+ if (backup.changedCursor)
+ removeCursor();
+
+ backup.changedCursor = false;
+}
+
+void OnceUpon::fixTXTStrings(TXTFile &txt) const {
+ TXTFile::LineArray &lines = txt.getLines();
+ for (uint i = 0; i < lines.size(); i++)
+ lines[i].text = fixString(lines[i].text);
+}
+
+#include "gob/pregob/onceupon/brokenstrings.h"
+Common::String OnceUpon::fixString(const Common::String &str) const {
+ const BrokenStringLanguage &broken = kBrokenStrings[_vm->_global->_language];
+
+ for (uint i = 0; i < broken.count; i++) {
+ if (str == broken.strings[i].wrong)
+ return broken.strings[i].correct;
+ }
+
+ return str;
+}
+
+enum ClownAnimation {
+ kClownAnimationStand = 0,
+ kClownAnimationCheer = 1,
+ kClownAnimationCry = 2
+};
+
+const PreGob::AnimProperties OnceUpon::kClownAnimations[] = {
+ { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 0, 0, ANIObject::kModeOnce , true, false, false, 0, 0},
+ { 6, 0, ANIObject::kModeOnce , true, false, false, 0, 0}
+};
+
+enum CopyProtectionState {
+ kCPStateSetup, // Set up the screen
+ kCPStateWaitUser, // Waiting for the user to pick a shape
+ kCPStateWaitClown, // Waiting for the clown animation to finish
+ kCPStateFinish // Finishing
+};
+
+bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]) {
+ fadeOut();
+ setPalette(kCopyProtectionPalette, kPaletteSize);
+
+ // Load the copy protection sprites
+ Surface sprites[2] = {Surface(320, 200, 1), Surface(320, 200, 1)};
+
+ _vm->_video->drawPackedSprite("grille1.cmp", sprites[0]);
+ _vm->_video->drawPackedSprite("grille2.cmp", sprites[1]);
+
+ // Load the clown animation
+ ANIFile ani (_vm, "grille.ani", 320);
+ ANIList anims;
+
+ loadAnims(anims, ani, 1, &kClownAnimations[kClownAnimationStand]);
+
+ // Set the copy protection cursor
+ setCursor(sprites[1], 5, 110, 20, 134, 3, 0);
+
+ // We start with 2 tries left, not having a correct answer and the copy protection not set up yet
+ CopyProtectionState state = kCPStateSetup;
+
+ uint8 triesLeft = 2;
+ int8 animalShape = -1;
+ bool hasCorrect = false;
+
+ while (!_vm->shouldQuit() && (state != kCPStateFinish)) {
+ clearAnim(anims);
+
+ // Set up the screen
+ if (state == kCPStateSetup) {
+ animalShape = cpSetup(colors, shapes, obfuscate, sprites);
+
+ setAnim(*anims[0], kClownAnimations[kClownAnimationStand]);
+ state = kCPStateWaitUser;
+ }
+
+ drawAnim(anims);
+
+ // If we're waiting for the clown and he finished, evaluate if we're finished
+ if (!anims[0]->isVisible() && (state == kCPStateWaitClown))
+ state = (hasCorrect || (--triesLeft == 0)) ? kCPStateFinish : kCPStateSetup;
+
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ checkInput(mouseX, mouseY, mouseButtons);
+
+ if (state == kCPStateWaitUser) {
+ // Look if we clicked a shaped and got it right
+
+ int8 guessedShape = -1;
+ if (mouseButtons == kMouseButtonsLeft)
+ guessedShape = cpFindShape(mouseX, mouseY);
+
+ if (guessedShape >= 0) {
+ hasCorrect = guessedShape == animalShape;
+ animalShape = -1;
+
+ setAnim(*anims[0], kClownAnimations[hasCorrect ? kClownAnimationCheer : kClownAnimationCry]);
+ state = kCPStateWaitClown;
+ }
+ }
+ }
+
+ freeAnims(anims);
+
+ fadeOut();
+ hideCursor();
+ clearScreen();
+
+ // Display the "You are wrong" screen
+ if (!hasCorrect)
+ cpWrong();
+
+ return hasCorrect;
+}
+
+int8 OnceUpon::cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4],
+ const Surface sprites[2]) {
+
+ fadeOut();
+ hideCursor();
+
+ // Get a random animal and animal color
+ int8 animalColor = _vm->_util->getRandom(7);
+ while ((colors[animalColor] == 1) || (colors[animalColor] == 7) || (colors[animalColor] == 11))
+ animalColor = _vm->_util->getRandom(7);
+
+ int8 animal = _vm->_util->getRandom(20);
+
+ int8 animalShape = shapes[animalColor * 20 + animal];
+ if (animal < 4)
+ animal = obfuscate[animal];
+
+ // Get the position of the animal sprite
+ int16 animalLeft = (animal % 4) * 80;
+ int16 animalTop = (animal / 4) * 50;
+
+ uint8 sprite = 0;
+ if (animalTop >= 200) {
+ animalTop -= 200;
+ sprite = 1;
+ }
+
+ int16 animalRight = animalLeft + 80 - 1;
+ int16 animalBottom = animalTop + 50 - 1;
+
+ // Fill with the animal color
+ _vm->_draw->_backSurface->fill(colors[animalColor]);
+
+ // Print the help line strings
+ for (uint i = 0; i < kCopyProtectionHelpStringCount; i++) {
+ const char * const helpString = kCopyProtectionHelpStrings[_vm->_global->_language][i];
+
+ const int x = 160 - (strlen(helpString) * _plettre->getCharWidth()) / 2;
+ const int y = i * 10 + 5;
+
+ _plettre->drawString(helpString, x, y, 8, 0, true, *_vm->_draw->_backSurface);
+ }
+
+ // White rectangle with black border
+ _vm->_draw->_backSurface->fillRect( 93, 43, 226, 134, 15);
+ _vm->_draw->_backSurface->drawRect( 92, 42, 227, 135, 0);
+
+ // Draw the animal in the animal color
+ _vm->_draw->_backSurface->fillRect(120, 63, 199, 112, colors[animalColor]);
+ _vm->_draw->_backSurface->blit(sprites[sprite], animalLeft, animalTop, animalRight, animalBottom, 120, 63, 0);
+
+ // Draw the shapes
+ for (uint i = 0; i < kCopyProtectionShapeCount; i++) {
+ const int16 * const coords = kCopyProtectionShapeCoords[i];
+
+ _vm->_draw->_backSurface->blit(sprites[1], coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], 0);
+ }
+
+ _vm->_draw->forceBlit();
+
+ return animalShape;
+}
+
+int8 OnceUpon::cpFindShape(int16 x, int16 y) const {
+ // Look through all shapes and check if the coordinates are inside one of them
+ for (uint i = 0; i < kCopyProtectionShapeCount; i++) {
+ const int16 * const coords = kCopyProtectionShapeCoords[i];
+
+ const int16 left = coords[4];
+ const int16 top = coords[5];
+ const int16 right = coords[4] + (coords[2] - coords[0] + 1) - 1;
+ const int16 bottom = coords[5] + (coords[3] - coords[1] + 1) - 1;
+
+ if ((x >= left) && (x <= right) && (y >= top) && (y <= bottom))
+ return i;
+ }
+
+ return -1;
+}
+
+void OnceUpon::cpWrong() {
+ // Display the "You are wrong" string, centered
+
+ const char * const wrongString = kCopyProtectionWrongStrings[_vm->_global->_language];
+ const int wrongX = 160 - (strlen(wrongString) * _plettre->getCharWidth()) / 2;
+
+ _vm->_draw->_backSurface->clear();
+ _plettre->drawString(wrongString, wrongX, 100, 15, 0, true, *_vm->_draw->_backSurface);
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ waitInput();
+
+ fadeOut();
+ clearScreen();
+}
+
+void OnceUpon::showIntro() {
+ // Show all intro parts
+
+ // "Loading"
+ showWait(10);
+ if (_vm->shouldQuit())
+ return;
+
+ // Quote about fairy tales
+ showQuote();
+ if (_vm->shouldQuit())
+ return;
+
+ // Once Upon A Time title
+ showTitle();
+ if (_vm->shouldQuit())
+ return;
+
+ // Game title screen
+ showChapter(0);
+ if (_vm->shouldQuit())
+ return;
+
+ // "Loading"
+ showWait(17);
+}
+
+void OnceUpon::showWait(uint palette) {
+ // Show the loading floppy
+
+ fadeOut();
+ clearScreen();
+ setGamePalette(palette);
+
+ Surface wait(320, 43, 1);
+
+ _vm->_video->drawPackedSprite("wait.cmp", wait);
+ _vm->_draw->_backSurface->blit(wait, 0, 0, 72, 33, 122, 84);
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+}
+
+void OnceUpon::showQuote() {
+ // Show the quote about fairytales
+
+ fadeOut();
+ clearScreen();
+ setGamePalette(11);
+
+ static const Font *fonts[3] = { _plettre, _glettre, _plettre };
+
+ TXTFile *quote = loadTXT(getLocFile("gene.tx"), TXTFile::kFormatStringPositionColorFont);
+ quote->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts));
+ delete quote;
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ waitInput();
+
+ fadeOut();
+}
+
+const PreGob::AnimProperties OnceUpon::kTitleAnimation = {
+ 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0
+};
+
+void OnceUpon::showTitle() {
+ fadeOut();
+ setGamePalette(10);
+
+ Title title(_vm);
+ title.play();
+}
+
+void OnceUpon::showChapter(int chapter) {
+ // Display the intro text to a chapter
+
+ fadeOut();
+ clearScreen();
+ setGamePalette(11);
+
+ // Parchment background
+ _vm->_video->drawPackedSprite("parch.cmp", *_vm->_draw->_backSurface);
+
+ static const Font *fonts[3] = { _plettre, _glettre, _plettre };
+
+ const Common::String chapterFile = getLocFile(Common::String::format("gene%d.tx", chapter));
+
+ TXTFile *gameTitle = loadTXT(chapterFile, TXTFile::kFormatStringPositionColorFont);
+ gameTitle->draw(*_vm->_draw->_backSurface, fonts, ARRAYSIZE(fonts));
+ delete gameTitle;
+
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ waitInput();
+
+ fadeOut();
+}
+
+void OnceUpon::showByeBye() {
+ fadeOut();
+ hideCursor();
+ clearScreen();
+ setGamePalette(1);
+
+ _plettre->drawString("Bye Bye....", 140, 80, 2, 0, true, *_vm->_draw->_backSurface);
+ _vm->_draw->forceBlit();
+
+ fadeIn();
+
+ _vm->_util->longDelay(1000);
+
+ fadeOut();
+}
+
+void OnceUpon::doStartMenu(const MenuButton *animalsButton, uint animalCount,
+ const MenuButton *animalButtons, const char * const *animalNames) {
+ clearScreen();
+
+ // Wait until we clicked on of the difficulty buttons and are ready to start playing
+ while (!_vm->shouldQuit()) {
+ MenuAction action = handleStartMenu(animalsButton);
+ if (action == kMenuActionPlay)
+ break;
+
+ // If we pressed the "listen to animal names" button, handle that screen
+ if (action == kMenuActionAnimals)
+ handleAnimalNames(animalCount, animalButtons, animalNames);
+ }
+}
+
+OnceUpon::MenuAction OnceUpon::handleStartMenu(const MenuButton *animalsButton) {
+ ScreenBackup screenBackup;
+ backupScreen(screenBackup, true);
+
+ fadeOut();
+ setGamePalette(17);
+ drawStartMenu(animalsButton);
+ showCursor();
+ fadeIn();
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+ if (key == kKeyEscape)
+ // ESC -> Quit
+ return kMenuActionQuit;
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ playSound(kSoundClick);
+
+ // If we clicked on a difficulty button, show the selected difficulty and start the game
+ int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY);
+ if (diff >= 0) {
+ _difficulty = (Difficulty)diff;
+ action = kMenuActionPlay;
+
+ drawStartMenu(animalsButton);
+ _vm->_util->longDelay(1000);
+ }
+
+ if (animalsButton && (checkButton(animalsButton, 1, mouseX, mouseY) != -1))
+ action = kMenuActionAnimals;
+
+ }
+
+ fadeOut();
+ restoreScreen(screenBackup);
+
+ return action;
+}
+
+OnceUpon::MenuAction OnceUpon::handleMainMenu() {
+ ScreenBackup screenBackup;
+ backupScreen(screenBackup, true);
+
+ fadeOut();
+ setGamePalette(17);
+ drawMainMenu();
+ showCursor();
+ fadeIn();
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+ if (key == kKeyEscape)
+ // ESC -> Quit
+ return kMenuActionQuit;
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ playSound(kSoundClick);
+
+ // If we clicked on a difficulty button, change the current difficulty level
+ int diff = checkButton(kMainMenuDifficultyButton, ARRAYSIZE(kMainMenuDifficultyButton), mouseX, mouseY);
+ if ((diff >= 0) && (diff != (int)_difficulty)) {
+ _difficulty = (Difficulty)diff;
+
+ drawMainMenu();
+ }
+
+ // If we clicked on a section button, restart the game from this section
+ int section = checkButton(kSectionButtons, ARRAYSIZE(kSectionButtons), mouseX, mouseY);
+ if ((section >= 0) && (section <= _section)) {
+ _section = section;
+ action = kMenuActionRestart;
+ }
+
+ }
+
+ fadeOut();
+ restoreScreen(screenBackup);
+
+ return action;
+}
+
+OnceUpon::MenuAction OnceUpon::handleIngameMenu() {
+ ScreenBackup screenBackup;
+ backupScreen(screenBackup, true);
+
+ drawIngameMenu();
+ showCursor();
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+ if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight))
+ // ESC or right mouse button -> Dismiss the menu
+ action = kMenuActionPlay;
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ int button = checkButton(kIngameButtons, ARRAYSIZE(kIngameButtons), mouseX, mouseY);
+ if (button == 0)
+ action = kMenuActionQuit;
+ else if (button == 1)
+ action = kMenuActionMainMenu;
+ else if (button == 2)
+ action = kMenuActionPlay;
+
+ }
+
+ clearIngameMenu(*screenBackup.screen);
+ restoreScreen(screenBackup);
+
+ return action;
+}
+
+void OnceUpon::drawStartMenu(const MenuButton *animalsButton) {
+ // Draw the background
+ _vm->_video->drawPackedSprite("menu2.cmp", *_vm->_draw->_backSurface);
+
+ // Draw the "Listen to animal names" button
+ if (animalsButton) {
+ Surface elements(320, 38, 1);
+ _vm->_video->drawPackedSprite("elemenu.cmp", elements);
+ _vm->_draw->_backSurface->fillRect(animalsButton->left , animalsButton->top,
+ animalsButton->right, animalsButton->bottom, 0);
+ drawButton(*_vm->_draw->_backSurface, elements, *animalsButton);
+ }
+
+ // Highlight the current difficulty
+ drawMenuDifficulty();
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::drawMainMenu() {
+ // Draw the background
+ _vm->_video->drawPackedSprite("menu.cmp", *_vm->_draw->_backSurface);
+
+ // Highlight the current difficulty
+ drawMenuDifficulty();
+
+ // Draw the section buttons
+ Surface elements(320, 200, 1);
+ _vm->_video->drawPackedSprite("elemenu.cmp", elements);
+
+ for (uint i = 0; i < ARRAYSIZE(kSectionButtons); i++) {
+ const MenuButton &button = kSectionButtons[i];
+
+ if (!button.needDraw)
+ continue;
+
+ if (_section >= (int)button.id)
+ drawButton(*_vm->_draw->_backSurface, elements, button);
+ }
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::drawIngameMenu() {
+ Surface menu(320, 34, 1);
+ _vm->_video->drawPackedSprite("icon.cmp", menu);
+
+ // Draw the menu in a special way, button by button
+ for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+ const MenuButton &button = kIngameButtons[i];
+
+ drawLineByLine(menu, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom,
+ button.dstX, button.dstY);
+ }
+
+ _vm->_draw->forceBlit();
+ _vm->_video->retrace();
+}
+
+void OnceUpon::drawMenuDifficulty() {
+ if (_difficulty == kDifficultyCount)
+ return;
+
+ TXTFile *difficulties = loadTXT(getLocFile("diffic.tx"), TXTFile::kFormatStringPositionColor);
+
+ // Draw the difficulty name
+ difficulties->draw((uint) _difficulty, *_vm->_draw->_backSurface, &_plettre, 1);
+
+ // Draw a border around the current difficulty
+ drawButtonBorder(kMainMenuDifficultyButton[_difficulty], difficulties->getLines()[_difficulty].color);
+
+ delete difficulties;
+}
+
+void OnceUpon::clearIngameMenu(const Surface &background) {
+ if (_vm->shouldQuit())
+ return;
+
+ // Find the area encompassing the whole ingame menu
+
+ int16 left = 0x7FFF;
+ int16 top = 0x7FFF;
+ int16 right = 0x0000;
+ int16 bottom = 0x0000;
+
+ for (uint i = 0; i < ARRAYSIZE(kIngameButtons); i++) {
+ const MenuButton &button = kIngameButtons[i];
+
+ if (!button.needDraw)
+ continue;
+
+ left = MIN<int16>(left , button.dstX);
+ top = MIN<int16>(top , button.dstY);
+ right = MAX<int16>(right , button.dstX + (button.srcRight - button.srcLeft + 1) - 1);
+ bottom = MAX<int16>(bottom, button.dstY + (button.srcBottom - button.srcTop + 1) - 1);
+ }
+
+ if ((left > right) || (top > bottom))
+ return;
+
+ // Clear it line by line
+ drawLineByLine(background, left, top, right, bottom, left, top);
+}
+
+OnceUpon::MenuAction OnceUpon::doIngameMenu() {
+ // Show the ingame menu
+ MenuAction action = handleIngameMenu();
+
+ if ((action == kMenuActionQuit) || _vm->shouldQuit()) {
+
+ // User pressed the quit button, or quit ScummVM
+ _quit = true;
+ action = kMenuActionQuit;
+
+ } else if (action == kMenuActionPlay) {
+
+ // User pressed the return to game button
+ action = kMenuActionPlay;
+
+ } else if (kMenuActionMainMenu) {
+
+ // User pressed the return to main menu button
+ action = handleMainMenu();
+ }
+
+ return action;
+}
+
+OnceUpon::MenuAction OnceUpon::doIngameMenu(int16 &key, MouseButtons &mouseButtons) {
+ if ((key != kKeyEscape) && (mouseButtons != kMouseButtonsRight))
+ return kMenuActionNone;
+
+ key = 0;
+ mouseButtons = kMouseButtonsNone;
+
+ MenuAction action = doIngameMenu();
+ if (action == kMenuActionPlay)
+ action = kMenuActionNone;
+
+ return action;
+}
+
+int OnceUpon::checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue) const {
+ // Look through all buttons, and return the ID of the button we're in
+
+ for (uint i = 0; i < count; i++) {
+ const MenuButton &button = buttons[i];
+
+ if ((x >= button.left) && (x <= button.right) && (y >= button.top) && (y <= button.bottom))
+ return (int)button.id;
+ }
+
+ // We're in none of these buttons, return the fail value
+ return failValue;
+}
+
+void OnceUpon::drawButton(Surface &dest, const Surface &src, const MenuButton &button, int transp) const {
+ dest.blit(src, button.srcLeft, button.srcTop, button.srcRight, button.srcBottom, button.dstX, button.dstY, transp);
+}
+
+void OnceUpon::drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp) const {
+ for (uint i = 0; i < count; i++) {
+ const MenuButton &button = buttons[i];
+
+ if (!button.needDraw)
+ continue;
+
+ drawButton(dest, src, button, transp);
+ }
+}
+
+void OnceUpon::drawButtonBorder(const MenuButton &button, uint8 color) {
+ _vm->_draw->_backSurface->drawRect(button.left, button.top, button.right, button.bottom, color);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, button.left, button.top, button.right, button.bottom);
+}
+
+enum AnimalNamesState {
+ kANStateChoose, // We're in the animal chooser
+ kANStateNames, // We're in the language chooser
+ kANStateFinish // We're finished
+};
+
+void OnceUpon::handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names) {
+ fadeOut();
+ clearScreen();
+ setGamePalette(19);
+
+ bool cursorVisible = isCursorVisible();
+
+ // Set the cursor
+ addCursor();
+ setGameCursor();
+
+ anSetupChooser();
+
+ int8 _animal = -1;
+
+ AnimalNamesState state = kANStateChoose;
+ while (!_vm->shouldQuit() && (state != kANStateFinish)) {
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ checkInput(mouseX, mouseY, mouseButtons);
+
+ // If we moused over an animal button, draw a border around it
+ int animal = checkButton(buttons, count, mouseX, mouseY);
+ if ((state == kANStateChoose) && (animal != _animal)) {
+ // Erase the old border
+ if (_animal >= 0)
+ drawButtonBorder(buttons[_animal], 15);
+
+ _animal = animal;
+
+ // Draw the new border
+ if (_animal >= 0)
+ drawButtonBorder(buttons[_animal], 10);
+ }
+
+ if (mouseButtons != kMouseButtonsLeft)
+ continue;
+
+ playSound(kSoundClick);
+
+ // We clicked on a language button, play the animal name
+ int language = checkButton(kLanguageButtons, ARRAYSIZE(kLanguageButtons), mouseX, mouseY);
+ if ((state == kANStateNames) && (language >= 0))
+ anPlayAnimalName(names[_animal], language);
+
+ // We clicked on an animal
+ if ((state == kANStateChoose) && (_animal >= 0)) {
+ anSetupNames(buttons[_animal]);
+
+ state = kANStateNames;
+ }
+
+ // If we clicked on the back button, go back
+ if (checkButton(&kAnimalNamesBack, 1, mouseX, mouseY) != -1) {
+ if (state == kANStateNames) {
+ anSetupChooser();
+
+ state = kANStateChoose;
+ } else if (state == kANStateChoose)
+ state = kANStateFinish;
+ }
+ }
+
+ fadeOut();
+
+ // Restore the cursor
+ if (!cursorVisible)
+ hideCursor();
+ removeCursor();
+}
+
+void OnceUpon::anSetupChooser() {
+ fadeOut();
+
+ _vm->_video->drawPackedSprite("dico.cmp", *_vm->_draw->_backSurface);
+
+ // Draw the back button
+ Surface menu(320, 34, 1);
+ _vm->_video->drawPackedSprite("icon.cmp", menu);
+ drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack);
+
+ // "Choose an animal"
+ TXTFile *choose = loadTXT(getLocFile("choisi.tx"), TXTFile::kFormatStringPosition);
+ choose->draw(*_vm->_draw->_backSurface, &_plettre, 1, 14);
+ delete choose;
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::anSetupNames(const MenuButton &animal) {
+ fadeOut();
+
+ Surface background(320, 200, 1);
+
+ _vm->_video->drawPackedSprite("dico.cmp", background);
+
+ // Draw the background and clear what we don't need
+ _vm->_draw->_backSurface->blit(background);
+ _vm->_draw->_backSurface->fillRect(19, 19, 302, 186, 15);
+
+ // Draw the back button
+ Surface menu(320, 34, 1);
+ _vm->_video->drawPackedSprite("icon.cmp", menu);
+ drawButton(*_vm->_draw->_backSurface, menu, kAnimalNamesBack);
+
+ // Draw the animal
+ drawButton(*_vm->_draw->_backSurface, background, animal);
+
+ // Draw the language buttons
+ Surface elements(320, 200, 1);
+ _vm->_video->drawPackedSprite("elemenu.cmp", elements);
+ drawButtons(*_vm->_draw->_backSurface, elements, kLanguageButtons, ARRAYSIZE(kLanguageButtons));
+
+ // Draw the language names
+ _plettre->drawString("Fran\207ais", 43, 70, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("Deutsch" , 136, 70, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("English" , 238, 70, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("Italiano" , 43, 128, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("Espa\244ol" , 136, 128, 10, 15, true, *_vm->_draw->_backSurface);
+ _plettre->drawString("English" , 238, 128, 10, 15, true, *_vm->_draw->_backSurface);
+
+ _vm->_draw->forceBlit();
+}
+
+void OnceUpon::anPlayAnimalName(const Common::String &animal, uint language) {
+ // Sound file to play
+ Common::String soundFile = animal + "_" + kLanguageSuffixLong[language] + ".snd";
+
+ // Get the name of the animal
+ TXTFile *names = loadTXT(animal + ".anm", TXTFile::kFormatString);
+ Common::String name = names->getLines()[language].text;
+ delete names;
+
+ // It should be centered on the screen
+ const int nameX = 160 - (name.size() * _plettre->getCharWidth()) / 2;
+
+ // Backup the screen surface
+ Surface backup(162, 23, 1);
+ backup.blit(*_vm->_draw->_backSurface, 78, 123, 239, 145, 0, 0);
+
+ // Draw the name border
+ Surface nameBorder(162, 23, 1);
+ _vm->_video->drawPackedSprite("mot.cmp", nameBorder);
+ _vm->_draw->_backSurface->blit(nameBorder, 0, 0, 161, 22, 78, 123);
+
+ // Print the animal name
+ _plettre->drawString(name, nameX, 129, 10, 0, true, *_vm->_draw->_backSurface);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
+
+ playSoundFile(soundFile);
+
+ // Restore the screen
+ _vm->_draw->_backSurface->blit(backup, 0, 0, 161, 22, 78, 123);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 78, 123, 239, 145);
+}
+
+void OnceUpon::playGame() {
+ while (!_vm->shouldQuit() && !_quit) {
+ // Play a section and advance to the next section if we finished it
+ if (playSection())
+ _section = MIN(_section + 1, kSectionCount - 1);
+ }
+
+ // If we quit through the game and not through ScummVM, show the "Bye Bye" screen
+ if (!_vm->shouldQuit())
+ showByeBye();
+}
+
+bool OnceUpon::playSection() {
+ if ((_section < 0) || (_section >= ARRAYSIZE(kSectionFuncs))) {
+ _quit = true;
+ return false;
+ }
+
+ return (this->*kSectionFuncs[_section])();
+}
+
+const PreGob::AnimProperties OnceUpon::kSectionStorkAnimations[] = {
+ { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 2, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 3, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 4, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 5, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 7, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {17, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {16, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {15, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}
+};
+
+enum StorkState {
+ kStorkStateWaitUser,
+ kStorkStateWaitBundle,
+ kStorkStateFinish
+};
+
+bool OnceUpon::sectionStork() {
+ fadeOut();
+ hideCursor();
+ setGamePalette(0);
+ setGameCursor();
+
+ const StorkParam &param = getStorkParameters();
+
+ Surface backdrop(320, 200, 1);
+
+ // Draw the frame
+ _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+
+ // Draw the backdrop
+ _vm->_video->drawPackedSprite(param.backdrop, backdrop);
+ _vm->_draw->_backSurface->blit(backdrop, 0, 0, 288, 175, 16, 12);
+
+ // "Where does the stork go?"
+ TXTFile *whereStork = loadTXT(getLocFile("ouva.tx"), TXTFile::kFormatStringPositionColor);
+ whereStork->draw(*_vm->_draw->_backSurface, &_plettre, 1);
+
+ // Where the stork actually goes
+ GCTFile *thereStork = loadGCT(getLocFile("choix.gc"));
+ thereStork->setArea(17, 18, 303, 41);
+
+ ANIFile ani(_vm, "present.ani", 320);
+ ANIList anims;
+
+ Stork *stork = new Stork(_vm, ani);
+
+ loadAnims(anims, ani, ARRAYSIZE(kSectionStorkAnimations), kSectionStorkAnimations);
+ anims.push_back(stork);
+
+ drawAnim(anims);
+
+ _vm->_draw->forceBlit();
+
+ int8 storkSoundWait = 0;
+
+ StorkState state = kStorkStateWaitUser;
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (state != kStorkStateFinish)) {
+ // Play the stork sound
+ if (--storkSoundWait == 0)
+ playSound(kSoundStork);
+ if (storkSoundWait <= 0)
+ storkSoundWait = 50 - _vm->_util->getRandom(30);
+
+ // Check if the bundle landed
+ if ((state == kStorkStateWaitBundle) && stork->hasBundleLanded())
+ state = kStorkStateFinish;
+
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+ action = doIngameMenu(key, mouseButtons);
+ if (action != kMenuActionNone) {
+ state = kStorkStateFinish;
+ break;
+ }
+
+ clearAnim(anims);
+
+ if (mouseButtons == kMouseButtonsLeft) {
+ stopSound();
+ playSound(kSoundClick);
+
+ int house = checkButton(param.houses, param.houseCount, mouseX, mouseY);
+ if ((state == kStorkStateWaitUser) && (house >= 0)) {
+
+ _house = house;
+
+ stork->dropBundle(param.drops[house]);
+ state = kStorkStateWaitBundle;
+
+ // Remove the "Where does the stork go?" text
+ int16 left, top, right, bottom;
+ if (whereStork->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ // Print the text where the stork actually goes
+ thereStork->selectLine(3, house); // The house
+ thereStork->selectLine(4, house); // The house's inhabitants
+ if (thereStork->draw(*_vm->_draw->_backSurface, 2, *_plettre, 10, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ }
+ }
+
+ drawAnim(anims);
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+ }
+
+ freeAnims(anims);
+ delete thereStork;
+ delete whereStork;
+
+ fadeOut();
+ hideCursor();
+
+ // Didn't complete the section
+ if (action != kMenuActionNone)
+ return false;
+
+ // Move on to the character generator
+
+ CharGenAction charGenAction = kCharGenRestart;
+ while (charGenAction == kCharGenRestart)
+ charGenAction = characterGenerator();
+
+ // Did we successfully create a character?
+ return charGenAction == kCharGenDone;
+}
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHeadButtons[] = {
+ {true, 106, 146, 152, 180, 0, 0, 47, 34, 106, 146, 0},
+ {true, 155, 146, 201, 180, 49, 0, 96, 34, 155, 146, 1},
+ {true, 204, 146, 250, 180, 98, 0, 145, 34, 204, 146, 2},
+ {true, 253, 146, 299, 180, 147, 0, 194, 34, 253, 146, 3}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHeads[] = {
+ {true, 0, 0, 0, 0, 29, 4, 68, 31, 40, 51, 0},
+ {true, 0, 0, 0, 0, 83, 4, 113, 31, 45, 51, 1},
+ {true, 0, 0, 0, 0, 132, 4, 162, 31, 45, 51, 2},
+ {true, 0, 0, 0, 0, 182, 4, 211, 31, 45, 51, 3}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenHairButtons[] = {
+ {true, 105, 55, 124, 70, 271, 1, 289, 15, 105, 55, 0x04},
+ {true, 105, 74, 124, 89, 271, 20, 289, 34, 105, 74, 0x07}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenJacketButtons[] = {
+ {true, 105, 90, 124, 105, 271, 39, 289, 53, 105, 90, 0x06},
+ {true, 105, 109, 124, 124, 271, 58, 289, 72, 105, 109, 0x02}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenTrousersButtons[] = {
+ {true, 105, 140, 124, 155, 271, 77, 289, 91, 105, 140, 0x01},
+ {true, 105, 159, 124, 174, 271, 96, 289, 110, 105, 159, 0x03}
+};
+
+const OnceUpon::MenuButton OnceUpon::kCharGenNameEntry[] = {
+ {true, 0, 0, 0, 0, 0, 38, 54, 48, 140, 145, 0},
+ {true, 0, 0, 0, 0, 106, 38, 159, 48, 195, 145, 0},
+ {true, 0, 0, 0, 0, 0, 105, 54, 121, 140, 156, 0},
+ {true, 0, 0, 0, 0, 106, 105, 159, 121, 195, 156, 0}
+};
+
+enum CharGenState {
+ kCharGenStateHead = 0, // Choose a head
+ kCharGenStateHair , // Choose hair color
+ kCharGenStateJacket , // Choose jacket color
+ kCharGenStateTrousers , // Choose trousers color
+ kCharGenStateName , // Choose name
+ kCharGenStateSure , // "Are you sure?"
+ kCharGenStateStoryName , // "We're going to tell the story of $NAME"
+ kCharGenStateFinish // Finished
+};
+
+void OnceUpon::charGenSetup(uint stage) {
+ Surface choix(320, 200, 1), elchoix(320, 200, 1), paperDoll(65, 137, 1);
+
+ _vm->_video->drawPackedSprite("choix.cmp" , choix);
+ _vm->_video->drawPackedSprite("elchoix.cmp", elchoix);
+
+ paperDoll.blit(choix, 200, 0, 264, 136, 0, 0);
+
+ GCTFile *text = loadGCT(getLocFile("choix.gc"));
+ text->setArea(17, 18, 303, 41);
+ text->setText(9, _name);
+
+ // Background
+ _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+ _vm->_draw->_backSurface->fillRect(16, 50, 303, 187, 5);
+
+ // Character sprite frame
+ _vm->_draw->_backSurface->blit(choix, 0, 38, 159, 121, 140, 54);
+
+ // Recolor the paper doll parts
+ if (_colorHair != 0xFF)
+ elchoix.recolor(0x0C, _colorHair);
+
+ if (_colorJacket != 0xFF)
+ paperDoll.recolor(0x0A, _colorJacket);
+
+ if (_colorTrousers != 0xFF)
+ paperDoll.recolor(0x09, _colorTrousers);
+
+ _vm->_draw->_backSurface->blit(paperDoll, 32, 51);
+
+ // Paper doll head
+ if (_head != 0xFF)
+ drawButton(*_vm->_draw->_backSurface, elchoix, kCharGenHeads[_head], 0);
+
+ if (stage == kCharGenStateHead) {
+ // Head buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons));
+
+ // "Choose a head"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 5, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateHair) {
+ // Hair color buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons));
+
+ // "What color is the hair?"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 6, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateJacket) {
+ // Jacket color buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons));
+
+ // "What color is the jacket?"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 7, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateTrousers) {
+ // Trousers color buttons
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons));
+
+ // "What color are the trousers?"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 8, *_plettre, 10, left, top, right, bottom);
+
+ } else if (stage == kCharGenStateName) {
+ // Name entry field
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry));
+
+ // "Enter name"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 10, *_plettre, 10, left, top, right, bottom);
+
+ charGenDrawName();
+ } else if (stage == kCharGenStateSure) {
+ // Name entry field
+ drawButtons(*_vm->_draw->_backSurface, choix, kCharGenNameEntry, ARRAYSIZE(kCharGenNameEntry));
+
+ // "Are you sure?"
+ TXTFile *sure = loadTXT(getLocFile("estu.tx"), TXTFile::kFormatStringPositionColor);
+ sure->draw(*_vm->_draw->_backSurface, &_plettre, 1);
+ delete sure;
+
+ charGenDrawName();
+ } else if (stage == kCharGenStateStoryName) {
+
+ // "We're going to tell the story of $NAME"
+ int16 left, top, right, bottom;
+ text->draw(*_vm->_draw->_backSurface, 11, *_plettre, 10, left, top, right, bottom);
+ }
+
+ delete text;
+}
+
+bool OnceUpon::enterString(Common::String &name, int16 key, uint maxLength, const Font &font) {
+ if (key == 0)
+ return true;
+
+ if (key == kKeyBackspace) {
+ name.deleteLastChar();
+ return true;
+ }
+
+ if (key == kKeySpace)
+ key = ' ';
+
+ if ((key >= ' ') && (key <= 0xFF)) {
+ if (name.size() >= maxLength)
+ return false;
+
+ if (!font.hasChar(key))
+ return false;
+
+ name += (char) key;
+ return true;
+ }
+
+ return false;
+}
+
+void OnceUpon::charGenDrawName() {
+ _vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1);
+
+ const int16 nameY = 151 + ((166 - 151 + 1 - _plettre->getCharHeight()) / 2);
+ const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2);
+
+ _plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface);
+
+ const int16 cursorLeft = nameX + _name.size() * _plettre->getCharWidth();
+ const int16 cursorTop = nameY;
+ const int16 cursorRight = cursorLeft + _plettre->getCharWidth() - 1;
+ const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1;
+
+ _vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166);
+}
+
+OnceUpon::CharGenAction OnceUpon::characterGenerator() {
+ fadeOut();
+ hideCursor();
+ setGameCursor();
+
+ showWait(1);
+
+ _name.clear();
+
+ _head = 0xFF;
+ _colorHair = 0xFF;
+ _colorJacket = 0xFF;
+ _colorTrousers = 0xFF;
+
+ CharGenState state = kCharGenStateHead;
+ charGenSetup(state);
+
+ ANIFile ani(_vm, "ba.ani", 320);
+
+ ani.recolor(0x0F, 0x0C);
+ ani.recolor(0x0E, 0x0A);
+ ani.recolor(0x08, 0x09);
+
+ CharGenChild *child = new CharGenChild(ani);
+
+ ANIList anims;
+ anims.push_back(child);
+
+ fadeOut();
+ _vm->_draw->forceBlit();
+
+ CharGenAction action = kCharGenRestart;
+ while (!_vm->shouldQuit() && (state != kCharGenStateFinish)) {
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+ MenuAction menuAction = doIngameMenu(key, mouseButtons);
+ if (menuAction != kMenuActionNone) {
+ state = kCharGenStateFinish;
+ action = kCharGenAbort;
+ break;
+ }
+
+ clearAnim(anims);
+
+ if (state == kCharGenStateStoryName) {
+ if ((mouseButtons != kMouseButtonsNone) || (key != 0)) {
+ state = kCharGenStateFinish;
+ action = kCharGenDone;
+ break;
+ }
+ }
+
+ if (state == kCharGenStateSure) {
+ // Not sure => restart
+ if ((key == 'N') || (key == 'n')) { // No / Nein / Non
+ state = kCharGenStateFinish;
+ action = kCharGenRestart;
+ break;
+ }
+
+ if ((key == 'Y') || (key == 'y') || // Yes
+ (key == 'J') || (key == 'j') || // Ja
+ (key == 'S') || (key == 's') || // Si
+ (key == 'O') || (key == 'o')) { // Oui
+
+ state = kCharGenStateStoryName;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+ }
+
+ if (state == kCharGenStateName) {
+ if (enterString(_name, key, 14, *_plettre)) {
+ _vm->_draw->_backSurface->fillRect(147, 151, 243, 166, 1);
+
+ const int16 nameY = 151 + ((166 - 151 + 1 - _plettre->getCharHeight()) / 2);
+ const int16 nameX = 147 + ((243 - 147 + 1 - (15 * _plettre->getCharWidth ())) / 2);
+
+ _plettre->drawString(_name, nameX, nameY, 10, 0, true, *_vm->_draw->_backSurface);
+
+ const int16 cursorLeft = nameX + _name.size() * _plettre->getCharWidth();
+ const int16 cursorTop = nameY;
+ const int16 cursorRight = cursorLeft + _plettre->getCharWidth() - 1;
+ const int16 cursorBottom = cursorTop + _plettre->getCharHeight() - 1;
+
+ _vm->_draw->_backSurface->fillRect(cursorLeft, cursorTop, cursorRight, cursorBottom, 10);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 151, 243, 166);
+ }
+
+ if ((key == kKeyReturn) && !_name.empty()) {
+ _name.trim();
+ _name.setChar(Util::toCP850Upper(_name[0]), 0);
+
+ state = kCharGenStateSure;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+ }
+
+ if (mouseButtons == kMouseButtonsLeft) {
+ stopSound();
+ playSound(kSoundClick);
+
+ int trousers = checkButton(kCharGenTrousersButtons, ARRAYSIZE(kCharGenTrousersButtons), mouseX, mouseY);
+ if ((state == kCharGenStateTrousers) && (trousers >= 0)) {
+ _colorTrousers = trousers;
+
+ ani.recolor(0x09, _colorTrousers);
+
+ state = kCharGenStateName;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+
+ int jacket = checkButton(kCharGenJacketButtons, ARRAYSIZE(kCharGenJacketButtons), mouseX, mouseY);
+ if ((state == kCharGenStateJacket) && (jacket >= 0)) {
+ _colorJacket = jacket;
+
+ ani.recolor(0x0A, _colorJacket);
+
+ state = kCharGenStateTrousers;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+
+ int hair = checkButton(kCharGenHairButtons, ARRAYSIZE(kCharGenHairButtons), mouseX, mouseY);
+ if ((state == kCharGenStateHair) && (hair >= 0)) {
+ _colorHair = hair;
+
+ ani.recolor(0x0C, _colorHair);
+
+ state = kCharGenStateJacket;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+
+ int head = checkButton(kCharGenHeadButtons, ARRAYSIZE(kCharGenHeadButtons), mouseX, mouseY);
+ if ((state == kCharGenStateHead) && (head >= 0)) {
+ _head = head;
+
+ state = kCharGenStateHair;
+ charGenSetup(state);
+ _vm->_draw->forceBlit();
+ }
+ }
+
+ drawAnim(anims);
+
+ // Play the child sounds
+ CharGenChild::Sound childSound = child->shouldPlaySound();
+ if (childSound == CharGenChild::kSoundWalk) {
+ beep(50, 10);
+ } else if (childSound == CharGenChild::kSoundJump) {
+ stopSound();
+ playSound(kSoundJump);
+ }
+
+ showCursor();
+ fadeIn();
+
+ endFrame(true);
+ }
+
+ fadeOut();
+ hideCursor();
+
+ freeAnims(anims);
+
+ if (_vm->shouldQuit())
+ return kCharGenAbort;
+
+ return action;
+}
+
+bool OnceUpon::sectionChapter1() {
+ showChapter(1);
+ return true;
+}
+
+bool OnceUpon::sectionParents() {
+ fadeOut();
+ setGamePalette(14);
+ clearScreen();
+
+ const Common::String seq = ((_house == 1) || (_house == 2)) ? "parents.seq" : "parents2.seq";
+ const Common::String gct = getLocFile("mefait.gc");
+
+ Parents parents(_vm, seq, gct, _name, _house, *_plettre, kGamePalettes[14], kGamePalettes[13], kPaletteSize);
+ parents.play();
+
+ warning("OnceUpon::sectionParents(): TODO: Item search");
+ return true;
+}
+
+bool OnceUpon::sectionChapter2() {
+ showChapter(2);
+ return true;
+}
+
+bool OnceUpon::sectionForest0() {
+ warning("OnceUpon::sectionForest0(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter3() {
+ showChapter(3);
+ return true;
+}
+
+bool OnceUpon::sectionEvilCastle() {
+ warning("OnceUpon::sectionEvilCastle(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter4() {
+ showChapter(4);
+ return true;
+}
+
+bool OnceUpon::sectionForest1() {
+ warning("OnceUpon::sectionForest1(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter5() {
+ showChapter(5);
+ return true;
+}
+
+bool OnceUpon::sectionBossFight() {
+ warning("OnceUpon::sectionBossFight(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter6() {
+ showChapter(6);
+ return true;
+}
+
+bool OnceUpon::sectionForest2() {
+ warning("OnceUpon::sectionForest2(): TODO");
+ return true;
+}
+
+bool OnceUpon::sectionChapter7() {
+ showChapter(7);
+ return true;
+}
+
+const PreGob::AnimProperties OnceUpon::kSectionEndAnimations[] = {
+ { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ { 9, 0, ANIObject::kModeContinuous, true, false, false, 0, 0},
+ {11, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}
+};
+
+bool OnceUpon::sectionEnd() {
+ fadeOut();
+ setGamePalette(9);
+
+ _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface);
+
+ Surface endBackground(320, 200, 1);
+ _vm->_video->drawPackedSprite("fin.cmp", endBackground);
+
+ _vm->_draw->_backSurface->blit(endBackground, 0, 0, 288, 137, 16, 50);
+
+ GCTFile *endText = loadGCT(getLocFile("final.gc"));
+ endText->setArea(17, 18, 303, 41);
+ endText->setText(1, _name);
+
+ ANIFile ani(_vm, "fin.ani", 320);
+ ANIList anims;
+
+ loadAnims(anims, ani, ARRAYSIZE(kSectionEndAnimations), kSectionEndAnimations);
+ drawAnim(anims);
+
+ _vm->_draw->forceBlit();
+
+ uint32 textStartTime = 0;
+
+ MenuAction action = kMenuActionNone;
+ while (!_vm->shouldQuit() && (action == kMenuActionNone)) {
+ // Check user input
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ int16 key = checkInput(mouseX, mouseY, mouseButtons);
+
+ action = doIngameMenu(key, mouseButtons);
+ if (action != kMenuActionNone)
+ break;
+
+ clearAnim(anims);
+
+ // Pressed a key or mouse button => Skip to next area-full of text
+ if ((mouseButtons == kMouseButtonsLeft) || (key != 0))
+ textStartTime = 0;
+
+ // Draw the next area-full of text
+ uint32 now = _vm->_util->getTimeKey();
+ if (!endText->finished() && ((textStartTime == 0) || (now >= (textStartTime + kGCTDelay)))) {
+ textStartTime = now;
+
+ int16 left, top, right, bottom;
+ if (endText->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ if (endText->draw(*_vm->_draw->_backSurface, 0, *_plettre, 10, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ }
+
+ drawAnim(anims);
+ fadeIn();
+
+ endFrame(true);
+ }
+
+ freeAnims(anims);
+ delete endText;
+
+ // Restart requested
+ if (action == kMenuActionRestart)
+ return false;
+
+ // Last scene. Even if we didn't explicitly request a quit, the game ends here
+ _quit = true;
+ return false;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h
new file mode 100644
index 0000000000..66ef877618
--- /dev/null
+++ b/engines/gob/pregob/onceupon/onceupon.h
@@ -0,0 +1,344 @@
+/* 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 GOB_PREGOB_ONCEUPON_ONCEUPON_H
+#define GOB_PREGOB_ONCEUPON_ONCEUPON_H
+
+#include "common/system.h"
+#include "common/str.h"
+
+#include "gob/pregob/pregob.h"
+
+#include "gob/pregob/onceupon/stork.h"
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class ANIObject;
+
+namespace OnceUpon {
+
+class OnceUpon : public PreGob {
+public:
+ /** Number of languages we support. */
+ static const uint kLanguageCount = 5;
+
+
+ OnceUpon(GobEngine *vm);
+ ~OnceUpon();
+
+
+protected:
+ /** A description of a menu button. */
+ struct MenuButton {
+ bool needDraw; ///< Does the button need drawing?
+
+ int16 left; ///< Left coordinate of the button.
+ int16 top; ///< Top coordinate of the button.
+ int16 right; ///< Right coordinate of the button.
+ int16 bottom; ///< Bottom coordinate of the button.
+
+ int16 srcLeft; ///< Left coordinate of the button's sprite.
+ int16 srcTop; ///< Top coordinate of the button's sprite.
+ int16 srcRight; ///< Right coordinate of the button's sprite.
+ int16 srcBottom; ///< Right coordinate of the button's sprite.
+
+ int16 dstX; ///< Destination X coordinate of the button's sprite.
+ int16 dstY; ///< Destination Y coordinate of the button's sprite.
+
+ uint id; ///< The button's ID.
+ };
+
+ /** Parameters for the stork section. */
+ struct StorkParam {
+ const char *backdrop; ///< Backdrop image file.
+
+ uint houseCount; ///< Number of houses.
+ const MenuButton *houses; ///< House button definitions.
+
+ const Stork::BundleDrop *drops; ///< The bundle drop parameters.
+ };
+
+ void init();
+ void deinit();
+
+ /** Handle the copy protection.
+ *
+ * @param colors Colors the copy protection animals can be.
+ * @param shapes The shape that's the correct answer for each animal in each color.
+ * @param obfuscate Extra obfuscate table. correctShape = shapes[colors][obfuscate[animal]].
+ * @return true if the user guessed the correct shape, false otherwise.
+ */
+ bool doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20], const uint8 obfuscate[4]);
+
+ /** Show the intro. */
+ void showIntro();
+
+ /** Handle the start menu.
+ *
+ * @param animalsButton Definition of the menu button that leads to the animal names screen. Can be 0.
+ * @param animalCount Number of animals in the animal names screen.
+ * @param animalButtons Definition of the buttons that make up the animals in the animal names screen.
+ * @param animalNames File prefixes for the name of each animal.
+ */
+ void doStartMenu(const MenuButton *animalsButton, uint animalCount,
+ const MenuButton *animalButtons, const char * const *animalNames);
+
+ /** Play the game proper. */
+ void playGame();
+
+
+ /** Return the parameters for the stork section. */
+ virtual const StorkParam &getStorkParameters() const = 0;
+
+
+private:
+ /** All actions a user can request in a menu. */
+ enum MenuAction {
+ kMenuActionNone = 0, ///< No action.
+ kMenuActionAnimals , ///< Do the animal names.
+ kMenuActionPlay , ///< Play the game.
+ kMenuActionRestart , ///< Restart the section.
+ kMenuActionMainMenu, ///< Go to the main menu.
+ kMenuActionQuit ///< Quit the game.
+ };
+
+ /** Difficulty levels. */
+ enum Difficulty {
+ kDifficultyBeginner = 0,
+ kDifficultyIntermediate = 1,
+ kDifficultyAdvanced = 2,
+ kDifficultyCount
+ };
+
+ /** The different sounds common in the game. */
+ enum Sound {
+ kSoundClick = 0,
+ kSoundStork ,
+ kSoundJump ,
+ kSoundCount
+ };
+
+ /** Action the character generation wants us to take. */
+ enum CharGenAction {
+ kCharGenDone = 0, ///< Created a character, move on.
+ kCharGenAbort , ///< Aborted the character generation.
+ kCharGenRestart ///< Restart the character generation.
+ };
+
+ /** A complete screen backup. */
+ struct ScreenBackup {
+ Surface *screen; ///< Screen contents.
+ int palette; ///< Screen palette.
+
+ bool changedCursor; ///< Did we change the cursor?
+ bool cursorVisible; ///< Was the cursor visible?
+
+ ScreenBackup();
+ ~ScreenBackup();
+ };
+
+
+ /** The number of game sections. */
+ static const int kSectionCount = 15;
+
+ static const MenuButton kMainMenuDifficultyButton[]; ///< Difficulty buttons.
+ static const MenuButton kSectionButtons[]; ///< Section buttons.
+
+ static const MenuButton kIngameButtons[]; ///< Ingame menu buttons.
+
+ static const MenuButton kAnimalNamesBack; ///< "Back" button in the animal names screens.
+ static const MenuButton kLanguageButtons[]; ///< Language buttons in the animal names screen.
+
+ static const MenuButton kSectionStorkHouses[];
+
+ static const MenuButton kCharGenHeadButtons[];
+ static const MenuButton kCharGenHeads[];
+ static const MenuButton kCharGenHairButtons[];
+ static const MenuButton kCharGenJacketButtons[];
+ static const MenuButton kCharGenTrousersButtons[];
+ static const MenuButton kCharGenNameEntry[];
+
+ /** All general game sounds we know about. */
+ static const char *kSound[kSoundCount];
+
+
+ static const AnimProperties kClownAnimations[];
+ static const AnimProperties kTitleAnimation;
+ static const AnimProperties kSectionStorkAnimations[];
+ static const AnimProperties kSectionEndAnimations[];
+
+
+ /** Function pointer type for a section handler. */
+ typedef bool (OnceUpon::*SectionFunc)();
+ /** Section handler function. */
+ static const SectionFunc kSectionFuncs[kSectionCount];
+
+
+ /** Did we open the game archives? */
+ bool _openedArchives;
+
+ // Fonts
+ Font *_jeudak;
+ Font *_lettre;
+ Font *_plettre;
+ Font *_glettre;
+
+ /** The current palette. */
+ int _palette;
+
+ bool _quit; ///< Did the user request a normal game quit?
+
+ Difficulty _difficulty; ///< The current difficulty.
+ int _section; ///< The current game section.
+
+ Common::String _name; ///< The name of the child.
+
+ uint8 _house;
+
+ uint8 _head;
+ uint8 _colorHair;
+ uint8 _colorJacket;
+ uint8 _colorTrousers;
+
+
+ // -- General helpers --
+
+ void setGamePalette(uint palette); ///< Set a game palette.
+ void setGameCursor(); ///< Set the default game cursor.
+
+ /** Draw this sprite in a fancy, animated line-by-line way. */
+ void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom,
+ int16 x, int16 y) const;
+
+ /** Backup the screen contents. */
+ void backupScreen(ScreenBackup &backup, bool setDefaultCursor = false);
+ /** Restore the screen contents with a previously made backup. */
+ void restoreScreen(ScreenBackup &backup);
+
+ Common::String fixString(const Common::String &str) const; ///< Fix a string if necessary.
+ void fixTXTStrings(TXTFile &txt) const; ///< Fix all strings in a TXT.
+
+
+ // -- Copy protection helpers --
+
+ /** Set up the copy protection. */
+ int8 cpSetup(const uint8 colors[7], const uint8 shapes[7 * 20],
+ const uint8 obfuscate[4], const Surface sprites[2]);
+ /** Find the shape under these coordinates. */
+ int8 cpFindShape(int16 x, int16 y) const;
+ /** Display the "You are wrong" screen. */
+ void cpWrong();
+
+
+ // -- Show different game screens --
+
+ void showWait(uint palette = 0xFFFF); ///< Show the wait / loading screen.
+ void showQuote(); ///< Show the quote about fairytales.
+ void showTitle(); ///< Show the Once Upon A Time title.
+ void showChapter(int chapter); ///< Show a chapter intro text.
+ void showByeBye(); ///< Show the "bye bye" screen.
+
+ /** Handle the "listen to animal names" part. */
+ void handleAnimalNames(uint count, const MenuButton *buttons, const char * const *names);
+
+
+ // -- Menu helpers --
+
+ MenuAction handleStartMenu(const MenuButton *animalsButton); ///< Handle the start menu.
+ MenuAction handleMainMenu(); ///< Handle the main menu.
+ MenuAction handleIngameMenu(); ///< Handle the ingame menu.
+
+ void drawStartMenu(const MenuButton *animalsButton); ///< Draw the start menu.
+ void drawMainMenu(); ///< Draw the main menu.
+ void drawIngameMenu(); ///< Draw the ingame menu.
+
+ /** Draw the difficulty label. */
+ void drawMenuDifficulty();
+
+ /** Clear the ingame menu in an animated way. */
+ void clearIngameMenu(const Surface &background);
+
+ /** Handle the whole ingame menu. */
+ MenuAction doIngameMenu();
+ /** Handle the whole ingame menu if ESC or right mouse button was pressed. */
+ MenuAction doIngameMenu(int16 &key, MouseButtons &mouseButtons);
+
+
+ // -- Menu button helpers --
+
+ /** Find the button under these coordinates. */
+ int checkButton(const MenuButton *buttons, uint count, int16 x, int16 y, int failValue = -1) const;
+
+ /** Draw a menu button. */
+ void drawButton (Surface &dest, const Surface &src, const MenuButton &button, int transp = -1) const;
+ /** Draw multiple menu buttons. */
+ void drawButtons(Surface &dest, const Surface &src, const MenuButton *buttons, uint count, int transp = -1) const;
+
+ /** Draw a border around a button. */
+ void drawButtonBorder(const MenuButton &button, uint8 color);
+
+
+ // -- Animal names helpers --
+
+ /** Set up the animal chooser. */
+ void anSetupChooser();
+ /** Set up the language chooser for one animal. */
+ void anSetupNames(const MenuButton &animal);
+ /** Play / Display the name of an animal in one language. */
+ void anPlayAnimalName(const Common::String &animal, uint language);
+
+
+ // -- Game sections --
+
+ bool playSection();
+
+ bool sectionStork();
+ bool sectionChapter1();
+ bool sectionParents();
+ bool sectionChapter2();
+ bool sectionForest0();
+ bool sectionChapter3();
+ bool sectionEvilCastle();
+ bool sectionChapter4();
+ bool sectionForest1();
+ bool sectionChapter5();
+ bool sectionBossFight();
+ bool sectionChapter6();
+ bool sectionForest2();
+ bool sectionChapter7();
+ bool sectionEnd();
+
+ CharGenAction characterGenerator();
+ void charGenSetup(uint stage);
+ void charGenDrawName();
+
+ static bool enterString(Common::String &name, int16 key, uint maxLength, const Font &font);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_ONCEUPON_H
diff --git a/engines/gob/pregob/onceupon/palettes.h b/engines/gob/pregob/onceupon/palettes.h
new file mode 100644
index 0000000000..952581041c
--- /dev/null
+++ b/engines/gob/pregob/onceupon/palettes.h
@@ -0,0 +1,411 @@
+/* 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 GOB_PREGOB_ONCEUPON_PALETTES_H
+#define GOB_PREGOB_ONCEUPON_PALETTES_H
+
+static const int kPaletteSize = 16;
+static const uint kPaletteCount = 20;
+
+static const byte kCopyProtectionPalette[3 * kPaletteSize] = {
+ 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x19,
+ 0x00, 0x3F, 0x00,
+ 0x00, 0x2A, 0x2A,
+ 0x2A, 0x00, 0x00,
+ 0x2A, 0x00, 0x2A,
+ 0x2A, 0x15, 0x00,
+ 0x00, 0x19, 0x12,
+ 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x3F,
+ 0x15, 0x3F, 0x15,
+ 0x00, 0x20, 0x3F,
+ 0x3F, 0x00, 0x00,
+ 0x3F, 0x00, 0x20,
+ 0x3F, 0x3F, 0x00,
+ 0x3F, 0x3F, 0x3F
+};
+
+static const byte kGamePalettes[kPaletteCount][3 * kPaletteSize] = {
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x3C,
+ 0x1C, 0x28, 0x00,
+ 0x10, 0x18, 0x00,
+ 0x1C, 0x1C, 0x20,
+ 0x14, 0x14, 0x14,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x14, 0x20, 0x04,
+ 0x3C, 0x2C, 0x00,
+ 0x02, 0x00, 0x18,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x38, 0x20, 0x3C,
+ 0x2C, 0x10, 0x30,
+ 0x20, 0x08, 0x28,
+ 0x14, 0x00, 0x1C,
+ 0x20, 0x20, 0x38,
+ 0x18, 0x18, 0x2C,
+ 0x10, 0x10, 0x24,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x20, 0x20,
+ 0x24, 0x14, 0x14,
+ 0x1C, 0x10, 0x10,
+ 0x14, 0x0C, 0x0C,
+ 0x1C, 0x1C, 0x1C,
+ 0x18, 0x18, 0x18,
+ 0x10, 0x10, 0x10,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x1C,
+ 0x10, 0x1C, 0x10,
+ 0x10, 0x14, 0x0C,
+ 0x1C, 0x1C, 0x3C,
+ 0x24, 0x24, 0x3C,
+ 0x18, 0x18, 0x24,
+ 0x10, 0x10, 0x18,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3F, 0x26, 0x3F,
+ 0x36, 0x1C, 0x36,
+ 0x2C, 0x12, 0x2A,
+ 0x27, 0x0C, 0x24,
+ 0x22, 0x07, 0x1E,
+ 0x1D, 0x03, 0x18,
+ 0x16, 0x00, 0x10,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3A,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3F, 0x39, 0x26,
+ 0x38, 0x34, 0x1C,
+ 0x30, 0x2F, 0x13,
+ 0x27, 0x29, 0x0C,
+ 0x1D, 0x22, 0x07,
+ 0x14, 0x1B, 0x03,
+ 0x0C, 0x14, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3A,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x24, 0x3C, 0x3C,
+ 0x1C, 0x34, 0x38,
+ 0x14, 0x2C, 0x30,
+ 0x0C, 0x20, 0x2C,
+ 0x08, 0x18, 0x28,
+ 0x04, 0x10, 0x20,
+ 0x00, 0x08, 0x1C,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x24,
+ 0x38, 0x24, 0x1C,
+ 0x30, 0x1C, 0x14,
+ 0x28, 0x18, 0x0C,
+ 0x20, 0x10, 0x04,
+ 0x1C, 0x0C, 0x00,
+ 0x14, 0x08, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x34, 0x24,
+ 0x38, 0x2C, 0x1C,
+ 0x30, 0x24, 0x14,
+ 0x2C, 0x1C, 0x10,
+ 0x30, 0x30, 0x3C,
+ 0x1C, 0x1C, 0x38,
+ 0x0C, 0x0C, 0x38,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0C,
+ 0x02, 0x03, 0x14,
+ 0x07, 0x07, 0x1D,
+ 0x0E, 0x0E, 0x25,
+ 0x17, 0x17, 0x2E,
+ 0x21, 0x22, 0x36,
+ 0x2F, 0x2F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3B, 0x0D,
+ 0x3A, 0x31, 0x0A,
+ 0x35, 0x28, 0x07,
+ 0x30, 0x21, 0x04,
+ 0x2B, 0x19, 0x02,
+ 0x26, 0x12, 0x01,
+ 0x16, 0x0B, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00,
+ 0x21, 0x01, 0x00,
+ 0x2A, 0x02, 0x00,
+ 0x33, 0x03, 0x00,
+ 0x3D, 0x06, 0x00,
+ 0x2A, 0x19, 0x05,
+ 0x15, 0x14, 0x14,
+ 0x22, 0x1F, 0x1E,
+ 0x2F, 0x2C, 0x28,
+ 0x3F, 0x3C, 0x29,
+ 0x3F, 0x38, 0x0B,
+ 0x3B, 0x30, 0x0A,
+ 0x37, 0x29, 0x08,
+ 0x33, 0x23, 0x07,
+ 0x2F, 0x1D, 0x06
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x1C, 0x38,
+ 0x34, 0x30, 0x28,
+ 0x2C, 0x24, 0x1C,
+ 0x24, 0x18, 0x10,
+ 0x1C, 0x10, 0x08,
+ 0x14, 0x04, 0x04,
+ 0x10, 0x00, 0x00,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x1C, 0x38,
+ 0x34, 0x30, 0x28,
+ 0x2C, 0x24, 0x1C,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x1A, 0x30, 0x37,
+ 0x14, 0x28, 0x31,
+ 0x10, 0x20, 0x2C,
+ 0x0C, 0x19, 0x27,
+ 0x08, 0x12, 0x21,
+ 0x05, 0x0C, 0x1C,
+ 0x03, 0x07, 0x16,
+ 0x01, 0x03, 0x11,
+ 0x00, 0x00, 0x0C,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x34, 0x30, 0x34,
+ 0x30, 0x24, 0x30,
+ 0x28, 0x1C, 0x28,
+ 0x24, 0x14, 0x24,
+ 0x1C, 0x0C, 0x1C,
+ 0x18, 0x08, 0x18,
+ 0x14, 0x04, 0x14,
+ 0x0C, 0x04, 0x0C,
+ 0x08, 0x00, 0x08,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x2C, 0x24, 0x0C,
+ 0x34, 0x34, 0x28,
+ 0x2C, 0x2C, 0x1C,
+ 0x24, 0x24, 0x10,
+ 0x1C, 0x18, 0x08,
+ 0x14, 0x14, 0x08,
+ 0x10, 0x10, 0x04,
+ 0x0C, 0x0C, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x38,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x14, 0x28, 0x31,
+ 0x10, 0x20, 0x2C,
+ 0x0C, 0x19, 0x27,
+ 0x08, 0x12, 0x21,
+ 0x05, 0x0C, 0x1C,
+ 0x03, 0x07, 0x16,
+ 0x01, 0x03, 0x11,
+ 0x00, 0x3C, 0x00,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x1C,
+ 0x10, 0x1C, 0x10,
+ 0x10, 0x14, 0x0C,
+ 0x1C, 0x1C, 0x3C,
+ 0x24, 0x24, 0x3C,
+ 0x18, 0x18, 0x24,
+ 0x10, 0x10, 0x18,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ },
+ {
+ 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x1C,
+ 0x10, 0x1C, 0x10,
+ 0x10, 0x14, 0x0C,
+ 0x1C, 0x1C, 0x3C,
+ 0x24, 0x24, 0x3C,
+ 0x18, 0x18, 0x24,
+ 0x10, 0x10, 0x18,
+ 0x14, 0x20, 0x04,
+ 0x00, 0x00, 0x24,
+ 0x3C, 0x3C, 0x3C,
+ 0x00, 0x00, 0x00,
+ 0x3C, 0x2C, 0x00,
+ 0x3C, 0x18, 0x00,
+ 0x3C, 0x04, 0x00,
+ 0x1C, 0x00, 0x00
+ }
+};
+
+#endif // GOB_PREGOB_ONCEUPON_PALETTES_H
diff --git a/engines/gob/pregob/onceupon/parents.cpp b/engines/gob/pregob/onceupon/parents.cpp
new file mode 100644
index 0000000000..cdaee6a38d
--- /dev/null
+++ b/engines/gob/pregob/onceupon/parents.cpp
@@ -0,0 +1,217 @@
+/* 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 "gob/gob.h"
+#include "gob/global.h"
+#include "gob/dataio.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/gctfile.h"
+
+#include "gob/pregob/onceupon/palettes.h"
+#include "gob/pregob/onceupon/parents.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+const char *Parents::kSound[kSoundCount] = {
+ "rire.snd", // kSoundCackle
+ "tonn.snd" // kSoundThunder
+};
+
+// So that every GCT line is displayed for 12 seconds
+const uint16 Parents::kLoop[kLoopCount][3] = {
+ { 72, 77, 33},
+ {105, 109, 38},
+ {141, 145, 38},
+ {446, 454, 23},
+ {456, 464, 23},
+ {466, 474, 23},
+ {476, 484, 23}
+};
+
+
+Parents::Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct,
+ const Common::String &childName, uint8 house, const Font &font,
+ const byte *normalPalette, const byte *brightPalette, uint paletteSize) :
+ SEQFile(vm, seq),
+ _gct(0), _house(house), _font(&font),
+ _paletteSize(paletteSize), _normalPalette(normalPalette), _brightPalette(brightPalette) {
+
+ // Load sounds
+ for (int i = 0; i < kSoundCount; i++)
+ _vm->_sound->sampleLoad(&_sounds[i], SOUND_SND, kSound[i]);
+
+ // Load GCT
+ Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gct);
+ if (gctStream) {
+ _gct = new GCTFile(*gctStream, _vm->_rnd);
+
+ delete gctStream;
+ } else
+ error("Parents::Parents(): Failed to open \"%s\"", gct.c_str());
+
+ _gct->setArea(17, 18, 303, 41);
+ _gct->setText(1, childName);
+
+ _gct->selectLine(2, _house);
+ _gct->selectLine(4, _house);
+
+ for (uint i = 0; i < kLoopCount; i++)
+ _loopID[i] = addLoop(kLoop[i][0], kLoop[i][1], kLoop[i][2]);
+}
+
+Parents::~Parents() {
+ delete _gct;
+}
+
+void Parents::play() {
+ _currentLoop = 0;
+
+ SEQFile::play(true, 496, 15);
+
+ // After playback, fade out
+ if (!_vm->shouldQuit())
+ _vm->_palAnim->fade(0, 0, 0);
+}
+
+void Parents::handleFrameEvent() {
+ switch (getFrame()) {
+ case 0:
+ // On fame 0, fade in
+ _vm->_draw->forceBlit();
+ _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+ break;
+
+ case 4:
+ drawGCT(0);
+ break;
+
+ case 55:
+ drawGCT(3, 0);
+ break;
+
+ case 79:
+ drawGCT(_house + 5, 1);
+ break;
+
+ case 110:
+ drawGCT(_house + 9, 2);
+ break;
+
+ case 146:
+ drawGCT(17);
+ break;
+
+ case 198:
+ drawGCT(13);
+ break;
+
+ case 445:
+ drawGCT(14, 3);
+ break;
+
+ case 455:
+ drawGCT(18, 4);
+ break;
+
+ case 465:
+ drawGCT(19, 5);
+ break;
+
+ case 475:
+ drawGCT(20, 6);
+ break;
+
+ case 188:
+ case 228:
+ case 237:
+ case 257:
+ case 275:
+ case 426:
+ lightningEffect();
+ break;
+
+ case 203:
+ case 243:
+ case 252:
+ case 272:
+ case 290:
+ case 441:
+ playSound(kSoundThunder);
+ break;
+
+ case 340:
+ playSound(kSoundCackle);
+ break;
+ }
+}
+
+void Parents::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) {
+ if ((key == kKeyEscape) || (mouseButtons == kMouseButtonsRight))
+ abortPlay();
+
+ if (((key == kKeySpace) || (mouseButtons == kMouseButtonsLeft)) && (_currentLoop < kLoopCount))
+ skipLoop(_loopID[_currentLoop]);
+}
+
+void Parents::playSound(Sound sound) {
+ _vm->_sound->blasterStop(0);
+ _vm->_sound->blasterPlay(&_sounds[sound], 0, 0);
+}
+
+void Parents::lightningEffect() {
+ for (int i = 0; (i < 5) && !_vm->shouldQuit(); i++) {
+
+ setPalette(_brightPalette, _paletteSize);
+ _vm->_util->delay(5);
+
+ setPalette(_normalPalette, _paletteSize);
+ _vm->_util->delay(5);
+ }
+}
+
+void Parents::setPalette(const byte *palette, uint size) {
+ memcpy(_vm->_draw->_vgaPalette, palette, 3 * size);
+
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+ _vm->_video->retrace();
+}
+
+void Parents::drawGCT(uint item, uint loop) {
+ int16 left, top, right, bottom;
+ if (_gct->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ if (_gct->draw(*_vm->_draw->_backSurface, item, *_font, 10, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ _currentLoop = loop;
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/parents.h b/engines/gob/pregob/onceupon/parents.h
new file mode 100644
index 0000000000..f5c8307b73
--- /dev/null
+++ b/engines/gob/pregob/onceupon/parents.h
@@ -0,0 +1,94 @@
+/* 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 GOB_PREGOB_ONCEUPON_PARENTS_H
+#define GOB_PREGOB_ONCEUPON_PARENTS_H
+
+#include "gob/sound/sounddesc.h"
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+class Font;
+
+class GCTFile;
+
+namespace OnceUpon {
+
+/** The home / parents animation sequence. */
+class Parents : public SEQFile {
+public:
+ Parents(GobEngine *vm, const Common::String &seq, const Common::String &gct,
+ const Common::String &childName, uint8 house, const Font &font,
+ const byte *normalPalette, const byte *brightPalette, uint paletteSize);
+ ~Parents();
+
+ void play();
+
+protected:
+ void handleFrameEvent();
+ void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons);
+
+private:
+ static const uint kLoopCount = 7;
+
+ static const uint16 kLoop[kLoopCount][3];
+
+ enum Sound {
+ kSoundCackle = 0,
+ kSoundThunder ,
+ kSoundCount
+ };
+
+ static const char *kSound[kSoundCount];
+
+
+ uint8 _house;
+
+ const Font *_font;
+
+ uint _paletteSize;
+ const byte *_normalPalette;
+ const byte *_brightPalette;
+
+ SoundDesc _sounds[kSoundCount];
+
+ GCTFile *_gct;
+
+ uint _loopID[kLoopCount];
+ uint _currentLoop;
+
+
+ void lightningEffect();
+
+ void playSound(Sound sound);
+ void setPalette(const byte *palette, uint size);
+
+ void drawGCT(uint item, uint loop = 0xFFFF);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_PARENTS_H
diff --git a/engines/gob/pregob/onceupon/stork.cpp b/engines/gob/pregob/onceupon/stork.cpp
new file mode 100644
index 0000000000..3c38037d08
--- /dev/null
+++ b/engines/gob/pregob/onceupon/stork.cpp
@@ -0,0 +1,234 @@
+/* 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/str.h"
+
+#include "gob/gob.h"
+#include "gob/surface.h"
+#include "gob/anifile.h"
+#include "gob/video.h"
+
+#include "gob/pregob/onceupon/stork.h"
+
+enum Animation {
+ kAnimFlyNearWithBundle = 9,
+ kAnimFlyFarWithBundle = 12,
+ kAnimFlyNearWithoutBundle = 10,
+ kAnimFlyFarWithoutBundle = 13,
+ kAnimBundleNear = 11,
+ kAnimBundleFar = 14
+};
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Stork::Stork(GobEngine *vm, const ANIFile &ani) : ANIObject(ani), _shouldDrop(false) {
+ _frame = new Surface(320, 200, 1);
+ vm->_video->drawPackedSprite("cadre.cmp", *_frame);
+
+ _bundle = new ANIObject(ani);
+
+ _bundle->setVisible(false);
+ _bundle->setPause(true);
+
+ setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80);
+}
+
+Stork::~Stork() {
+ delete _frame;
+
+ delete _bundle;
+}
+
+bool Stork::hasBundleLanded() const {
+ if (!_shouldDrop || !_bundle->isVisible() || _bundle->isPaused())
+ return false;
+
+ int16 x, y, width, height;
+ _bundle->getFramePosition(x, y);
+ _bundle->getFrameSize(width, height);
+
+ return (y + height) >= _bundleDrop.landY;
+}
+
+void Stork::dropBundle(const BundleDrop &drop) {
+ if (_shouldDrop)
+ return;
+
+ _shouldDrop = true;
+ _bundleDrop = drop;
+}
+
+bool Stork::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0x0000;
+ bottom = 0x0000;
+
+ bool drawn = ANIObject::draw(dest, left, top, right, bottom);
+ if (drawn) {
+ // Left frame edge
+ if (left <= 15)
+ dest.blit(*_frame, left, top, MIN<int16>(15, right), bottom, left, top);
+
+ // Right frame edge
+ if (right >= 304)
+ dest.blit(*_frame, MAX<int16>(304, left), top, right, bottom, MAX<int16>(304, left), top);
+ }
+
+ int16 bLeft, bTop, bRight, bBottom;
+ if (_bundle->draw(dest, bLeft, bTop, bRight, bBottom)) {
+ // Bottom frame edge
+ if (bBottom >= 188)
+ dest.blit(*_frame, bLeft, MAX<int16>(188, bTop), bRight, bBottom, bLeft, MAX<int16>(188, bTop));
+
+ left = MIN(left , bLeft );
+ top = MIN(top , bTop );
+ right = MAX(right , bRight );
+ bottom = MAX(bottom, bBottom);
+
+ drawn = true;
+ }
+
+ return drawn;
+}
+
+bool Stork::clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0x0000;
+ bottom = 0x0000;
+
+ bool cleared = _bundle->clear(dest, left, top, right, bottom);
+
+ int16 sLeft, sTop, sRight, sBottom;
+ if (ANIObject::clear(dest, sLeft, sTop, sRight, sBottom)) {
+ left = MIN(left , sLeft );
+ top = MIN(top , sTop );
+ right = MAX(right , sRight );
+ bottom = MAX(bottom, sBottom);
+
+ cleared = true;
+ }
+
+ return cleared;
+}
+
+void Stork::advance() {
+ _bundle->advance();
+
+ ANIObject::advance();
+
+ int16 curX, curY, curWidth, curHeight;
+ getFramePosition(curX, curY, 0);
+ getFrameSize(curWidth, curHeight, 0);
+
+ const int16 curRight = curX + curWidth - 1;
+
+ int16 nextX, nextY, nextWidth, nextHeight;
+ getFramePosition(nextX, nextY, 1);
+ getFrameSize(nextWidth, nextHeight, 1);
+
+ const int16 nextRight = nextX + nextWidth - 1;
+
+ switch (_state) {
+ case kStateFlyNearWithBundle:
+ if (curX >= 330)
+ setState(kStateFlyFarWithBundle, kAnimFlyFarWithBundle, 330);
+
+ if ((curRight <= _bundleDrop.dropX) &&
+ (nextRight >= _bundleDrop.dropX) && _shouldDrop && !_bundleDrop.dropWhileFar)
+ dropBundle(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle);
+
+ break;
+
+ case kStateFlyFarWithBundle:
+ if (curX <= -80)
+ setState(kStateFlyNearWithBundle, kAnimFlyNearWithBundle, -80);
+
+ if ((curX >= _bundleDrop.dropX) &&
+ (nextX <= _bundleDrop.dropX) && _shouldDrop && _bundleDrop.dropWhileFar)
+ dropBundle(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle);
+
+ break;
+
+ case kStateFlyNearWithoutBundle:
+ if (curX >= 330)
+ setState(kStateFlyFarWithoutBundle, kAnimFlyFarWithoutBundle, 330);
+ break;
+
+ case kStateFlyFarWithoutBundle:
+ if (curX <= -80)
+ setState(kStateFlyNearWithoutBundle, kAnimFlyNearWithoutBundle, -80);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Stork::dropBundle(State state, uint16 anim) {
+ setState(state, anim);
+
+ int16 x, y, width, height;
+ getFramePosition(x, y);
+ getFrameSize(width, height);
+
+ _bundle->setAnimation(_bundleDrop.anim);
+ _bundle->setPause(false);
+ _bundle->setVisible(true);
+
+ int16 bWidth, bHeight;
+ _bundle->getFrameSize(bWidth, bHeight);
+
+ // Drop position
+ x = _bundleDrop.dropX;
+ y = y + height - bHeight;
+
+ // If the stork is flying near (from left to right), drop the bundle at the right edge
+ if (!_bundleDrop.dropWhileFar)
+ x = x - bWidth;
+
+ _bundle->setPosition(x, y);
+}
+
+void Stork::setState(State state, uint16 anim) {
+ setAnimation(anim);
+ setVisible(true);
+ setPause(false);
+
+ _state = state;
+}
+
+void Stork::setState(State state, uint16 anim, int16 x) {
+ setState(state, anim);
+ setPosition();
+
+ int16 pX, pY;
+ getPosition(pX, pY);
+ setPosition( x, pY);
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/stork.h b/engines/gob/pregob/onceupon/stork.h
new file mode 100644
index 0000000000..756f5258c7
--- /dev/null
+++ b/engines/gob/pregob/onceupon/stork.h
@@ -0,0 +1,103 @@
+/* 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 GOB_PREGOB_ONCEUPON_STORK_H
+#define GOB_PREGOB_ONCEUPON_STORK_H
+
+#include "common/system.h"
+
+#include "gob/aniobject.h"
+
+namespace Common {
+ class String;
+}
+
+namespace Gob {
+
+class GobEngine;
+
+class Surface;
+class ANIFile;
+
+namespace OnceUpon {
+
+/** The stork in Baba Yaga / dragon in Abracadabra. */
+class Stork : public ANIObject {
+public:
+ /** Information on how to drop the bundle. */
+ struct BundleDrop {
+ int16 anim; ///< Animation of the bundle floating down
+
+ int16 dropX; ///< X position the stork drops the bundle
+ int16 landY; ///< Y position the bundle lands
+
+ bool dropWhileFar; ///< Does the stork drop the bundle while far instead of near?
+ };
+
+ Stork(GobEngine *vm, const ANIFile &ani);
+ ~Stork();
+
+ /** Has the bundle landed? */
+ bool hasBundleLanded() const;
+
+ /** Drop the bundle. */
+ void dropBundle(const BundleDrop &drop);
+
+ /** Draw the current frame onto the surface and return the affected rectangle. */
+ bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+ /** Draw the current frame from the surface and return the affected rectangle. */
+ bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ /** Advance the animation to the next frame. */
+ void advance();
+
+private:
+ enum State {
+ kStateFlyNearWithBundle = 0,
+ kStateFlyFarWithBundle ,
+ kStateFlyNearWithoutBundle ,
+ kStateFlyFarWithoutBundle
+ };
+
+
+ GobEngine *_vm;
+
+ Surface *_frame;
+ ANIObject *_bundle;
+
+ State _state;
+
+ bool _shouldDrop;
+ BundleDrop _bundleDrop;
+
+
+ void setState(State state, uint16 anim);
+ void setState(State state, uint16 anim, int16 x);
+
+ void dropBundle(State state, uint16 anim);
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_STORK_H
diff --git a/engines/gob/pregob/onceupon/title.cpp b/engines/gob/pregob/onceupon/title.cpp
new file mode 100644
index 0000000000..5163ff6822
--- /dev/null
+++ b/engines/gob/pregob/onceupon/title.cpp
@@ -0,0 +1,117 @@
+/* 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 "gob/gob.h"
+#include "gob/global.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/onceupon/title.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+Title::Title(GobEngine *vm) : SEQFile(vm, "ville.seq") {
+}
+
+Title::~Title() {
+}
+
+void Title::play() {
+ SEQFile::play(true, 0xFFFF, 15);
+
+ // After playback, fade out and stop the music
+ if (!_vm->shouldQuit())
+ _vm->_palAnim->fade(0, 0, 0);
+
+ stopMusic();
+}
+
+void Title::handleFrameEvent() {
+ // On fame 0, start the music and fade in
+ if (getFrame() == 0) {
+ playMusic();
+
+ _vm->_draw->forceBlit();
+ _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+ }
+}
+
+void Title::playMusic() {
+ // Look at what platform this is and play the appropriate music type
+
+ if (_vm->getPlatform() == Common::kPlatformPC)
+ playMusicDOS();
+ else if (_vm->getPlatform() == Common::kPlatformAmiga)
+ playMusicAmiga();
+ else if (_vm->getPlatform() == Common::kPlatformAtariST)
+ playMusicAtariST();
+}
+
+void Title::playMusicDOS() {
+ // Play an AdLib track
+
+ _vm->_sound->adlibLoadTBR("babayaga.tbr");
+ _vm->_sound->adlibLoadMDY("babayaga.mdy");
+ _vm->_sound->adlibSetRepeating(-1);
+ _vm->_sound->adlibPlay();
+}
+
+void Title::playMusicAmiga() {
+ // Play a Protracker track
+
+ _vm->_sound->protrackerPlay("mod.babayaga");
+}
+
+void Title::playMusicAtariST() {
+ // Play a Soundblaster composition
+
+ static const int16 titleMusic[21] = { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, -1};
+ static const char * const titleFiles[ 3] = {"baba1.snd", "baba2.snd", "baba3.snd"};
+
+ for (uint i = 0; i < ARRAYSIZE(titleFiles); i++)
+ _vm->_sound->sampleLoad(_vm->_sound->sampleGetBySlot(i), SOUND_SND, titleFiles[i]);
+
+ _vm->_sound->blasterPlayComposition(titleMusic, 0);
+ _vm->_sound->blasterRepeatComposition(-1);
+}
+
+void Title::stopMusic() {
+ // Just stop everything
+
+ _vm->_sound->adlibSetRepeating(0);
+ _vm->_sound->blasterRepeatComposition(0);
+
+ _vm->_sound->adlibStop();
+ _vm->_sound->blasterStopComposition();
+ _vm->_sound->protrackerStop();
+
+ for (int i = 0; i < ::Gob::Sound::kSoundsCount; i++)
+ _vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(i));
+}
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/onceupon/title.h b/engines/gob/pregob/onceupon/title.h
new file mode 100644
index 0000000000..5e7ef76d40
--- /dev/null
+++ b/engines/gob/pregob/onceupon/title.h
@@ -0,0 +1,55 @@
+/* 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 GOB_PREGOB_ONCEUPON_TITLE_H
+#define GOB_PREGOB_ONCEUPON_TITLE_H
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+namespace OnceUpon {
+
+/** The Once Upon A Time title animation sequence. */
+class Title : public SEQFile {
+public:
+ Title(GobEngine *vm);
+ ~Title();
+
+ void play();
+
+protected:
+ void handleFrameEvent();
+
+private:
+ void playMusic(); ///< Play the title music.
+ void playMusicDOS(); ///< Play the title music of the DOS version.
+ void playMusicAmiga(); ///< Play the title music of the Amiga version.
+ void playMusicAtariST(); ///< Play the title music of the Atari ST version.
+ void stopMusic(); ///< Stop the title music.
+};
+
+} // End of namespace OnceUpon
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_ONCEUPON_TITLE_H
diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp
new file mode 100644
index 0000000000..54eb3c6795
--- /dev/null
+++ b/engines/gob/pregob/pregob.cpp
@@ -0,0 +1,351 @@
+/* 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 "graphics/cursorman.h"
+
+#include "gob/gob.h"
+#include "gob/global.h"
+#include "gob/util.h"
+#include "gob/surface.h"
+#include "gob/dataio.h"
+#include "gob/palanim.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+#include "gob/aniobject.h"
+
+#include "gob/sound/sound.h"
+
+#include "gob/pregob/pregob.h"
+#include "gob/pregob/gctfile.h"
+
+
+namespace Gob {
+
+const char PreGob::kLanguageSuffixShort[5] = { 't', 'g', 'a', 'e', 'i'};
+const char *PreGob::kLanguageSuffixLong [5] = {"fr", "al", "an", "it", "es"};
+
+
+PreGob::PreGob(GobEngine *vm) : _vm(vm), _fadedOut(false) {
+}
+
+PreGob::~PreGob() {
+}
+
+void PreGob::fadeOut() {
+ if (_fadedOut || _vm->shouldQuit())
+ return;
+
+ // Fade to black
+ _vm->_palAnim->fade(0, 0, 0);
+
+ _fadedOut = true;
+}
+
+void PreGob::fadeIn() {
+ if (!_fadedOut || _vm->shouldQuit())
+ return;
+
+ // Fade to palette
+ _vm->_draw->blitInvalidated();
+ _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+
+ _fadedOut = false;
+}
+
+void PreGob::clearScreen() {
+ _vm->_draw->_backSurface->clear();
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+ _vm->_draw->blitInvalidated();
+ _vm->_video->retrace();
+}
+
+void PreGob::initScreen() {
+ _vm->_util->setFrameRate(15);
+
+ _fadedOut = true;
+
+ _vm->_draw->initScreen();
+
+ _vm->_draw->_backSurface->clear();
+ _vm->_util->clearPalette();
+
+ _vm->_draw->forceBlit();
+ _vm->_video->retrace();
+
+ _vm->_util->processInput();
+}
+
+void PreGob::setPalette(const byte *palette, uint16 size) {
+ memcpy(_vm->_draw->_vgaPalette, palette, 3 * size);
+
+ // If we didn't fade out prior, immediately set the palette
+ if (!_fadedOut)
+ _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
+}
+
+void PreGob::addCursor() {
+ CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
+}
+
+void PreGob::removeCursor() {
+ CursorMan.popCursor();
+}
+
+void PreGob::setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY) {
+ CursorMan.replaceCursor(sprite.getData(), sprite.getWidth(), sprite.getHeight(), hotspotX, hotspotY, 0);
+}
+
+void PreGob::setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
+ int16 hotspotX, int16 hotspotY) {
+
+ const int width = right - left + 1;
+ const int height = bottom - top + 1;
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ Surface cursor(width, height, 1);
+
+ cursor.blit(sprite, left, top, right, bottom, 0, 0);
+
+ setCursor(cursor, hotspotX, hotspotX);
+}
+
+void PreGob::showCursor() {
+ CursorMan.showMouse(true);
+
+ _vm->_draw->_showCursor = 4;
+}
+
+void PreGob::hideCursor() {
+ CursorMan.showMouse(false);
+
+ _vm->_draw->_showCursor = 0;
+}
+
+bool PreGob::isCursorVisible() const {
+ return CursorMan.isVisible();
+}
+
+void PreGob::loadSounds(const char * const *sounds, uint soundCount) {
+ freeSounds();
+
+ _sounds.resize(soundCount);
+
+ for (uint i = 0; i < soundCount; i++)
+ loadSound(_sounds[i], sounds[i]);
+}
+
+void PreGob::freeSounds() {
+ _sounds.clear();
+}
+
+bool PreGob::loadSound(SoundDesc &sound, const Common::String &file) const {
+ return _vm->_sound->sampleLoad(&sound, SOUND_SND, file.c_str());
+}
+
+void PreGob::playSound(uint sound, int16 frequency, int16 repCount) {
+ if (sound >= _sounds.size())
+ return;
+
+ _vm->_sound->blasterPlay(&_sounds[sound], repCount, frequency);
+}
+
+void PreGob::stopSound() {
+ _vm->_sound->blasterStop(0);
+}
+
+void PreGob::playSoundFile(const Common::String &file, int16 frequency, int16 repCount, bool interruptible) {
+ stopSound();
+
+ SoundDesc sound;
+ if (!loadSound(sound, file))
+ return;
+
+ _vm->_sound->blasterPlay(&sound, repCount, frequency);
+
+ _vm->_util->forceMouseUp();
+
+ bool finished = false;
+ while (!_vm->shouldQuit() && !finished && _vm->_sound->blasterPlayingSound()) {
+ endFrame(true);
+
+ finished = hasInput();
+ }
+
+ _vm->_util->forceMouseUp();
+
+ stopSound();
+}
+
+void PreGob::beep(int16 frequency, int32 length) {
+ _vm->_sound->speakerOn(frequency, length);
+}
+
+void PreGob::endFrame(bool doInput) {
+ _vm->_draw->blitInvalidated();
+ _vm->_util->waitEndFrame();
+
+ if (doInput)
+ _vm->_util->processInput();
+}
+
+int16 PreGob::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
+ _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
+ _vm->_util->forceMouseUp();
+
+ return _vm->_util->checkKey();
+}
+
+int16 PreGob::waitInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
+ bool finished = false;
+
+ int16 key = 0;
+ while (!_vm->shouldQuit() && !finished) {
+ endFrame(true);
+
+ key = checkInput(mouseX, mouseY, mouseButtons);
+
+ finished = (mouseButtons != kMouseButtonsNone) || (key != 0);
+ }
+
+ return key;
+}
+
+int16 PreGob::waitInput() {
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ return waitInput(mouseX, mouseY, mouseButtons);
+}
+
+bool PreGob::hasInput() {
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+
+ return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone);
+}
+
+void PreGob::clearAnim(ANIObject &anim) {
+ int16 left, top, right, bottom;
+
+ if (anim.clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+}
+
+void PreGob::drawAnim(ANIObject &anim) {
+ int16 left, top, right, bottom;
+
+ if (anim.draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ anim.advance();
+}
+
+void PreGob::redrawAnim(ANIObject &anim) {
+ clearAnim(anim);
+ drawAnim(anim);
+}
+
+void PreGob::clearAnim(const ANIList &anims) {
+ for (int i = (anims.size() - 1); i >= 0; i--)
+ clearAnim(*anims[i]);
+}
+
+void PreGob::drawAnim(const ANIList &anims) {
+ for (ANIList::const_iterator a = anims.begin(); a != anims.end(); ++a)
+ drawAnim(**a);
+}
+
+void PreGob::redrawAnim(const ANIList &anims) {
+ clearAnim(anims);
+ drawAnim(anims);
+}
+
+void PreGob::loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const {
+ freeAnims(anims);
+
+ anims.resize(count);
+ for (uint i = 0; i < count; i++) {
+ anims[i] = new ANIObject(ani);
+
+ setAnim(*anims[i], props[i]);
+ }
+}
+
+void PreGob::freeAnims(ANIList &anims) const {
+ for (ANIList::iterator a = anims.begin(); a != anims.end(); ++a)
+ delete *a;
+
+ anims.clear();
+}
+
+void PreGob::setAnim(ANIObject &anim, const AnimProperties &props) const {
+ anim.setAnimation(props.animation);
+ anim.setFrame(props.frame);
+ anim.setMode(props.mode);
+ anim.setPause(props.paused);
+ anim.setVisible(props.visible);
+
+ if (props.hasPosition)
+ anim.setPosition(props.x, props.y);
+ else
+ anim.setPosition();
+}
+
+Common::String PreGob::getLocFile(const Common::String &file) const {
+ if (_vm->_global->_language >= ARRAYSIZE(kLanguageSuffixShort))
+ return file;
+
+ return file + kLanguageSuffixShort[_vm->_global->_language];
+}
+
+TXTFile *PreGob::loadTXT(const Common::String &txtFile, TXTFile::Format format) const {
+ Common::SeekableReadStream *txtStream = _vm->_dataIO->getFile(txtFile);
+ if (!txtStream)
+ error("PreGob::loadTXT(): Failed to open \"%s\"", txtFile.c_str());
+
+ TXTFile *txt = new TXTFile(*txtStream, format);
+
+ delete txtStream;
+
+ fixTXTStrings(*txt);
+
+ return txt;
+}
+
+void PreGob::fixTXTStrings(TXTFile &txt) const {
+}
+
+GCTFile *PreGob::loadGCT(const Common::String &gctFile) const {
+ Common::SeekableReadStream *gctStream = _vm->_dataIO->getFile(gctFile);
+ if (!gctStream)
+ error("PreGob::loadGCT(): Failed to open \"%s\"", gctFile.c_str());
+
+ GCTFile *gct = new GCTFile(*gctStream, _vm->_rnd);
+
+ delete gctStream;
+
+ return gct;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
new file mode 100644
index 0000000000..632f85b88e
--- /dev/null
+++ b/engines/gob/pregob/pregob.h
@@ -0,0 +1,194 @@
+/* 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 GOB_PREGOB_PREGOB_H
+#define GOB_PREGOB_PREGOB_H
+
+#include "common/str.h"
+#include "common/array.h"
+
+#include "gob/util.h"
+#include "gob/aniobject.h"
+
+#include "gob/sound/sounddesc.h"
+
+#include "gob/pregob/txtfile.h"
+
+namespace Gob {
+
+class GobEngine;
+class Surface;
+
+class GCTFile;
+
+class PreGob {
+public:
+ PreGob(GobEngine *vm);
+ virtual ~PreGob();
+
+ virtual void run() = 0;
+
+ struct AnimProperties {
+ uint16 animation;
+ uint16 frame;
+
+ ANIObject::Mode mode;
+
+ bool visible;
+ bool paused;
+
+ bool hasPosition;
+ int16 x;
+ int16 y;
+ };
+
+protected:
+ typedef Common::Array<ANIObject *> ANIList;
+
+ static const char kLanguageSuffixShort[5];
+ static const char *kLanguageSuffixLong [5];
+
+
+ GobEngine *_vm;
+
+
+ // -- Graphics --
+
+ /** Initialize the game screen. */
+ void initScreen();
+
+ void fadeOut(); ///< Fade to black.
+ void fadeIn(); ///< Fade to the current palette.
+
+ void clearScreen();
+
+ /** Change the palette.
+ *
+ * @param palette The palette to change to.
+ * @param size Size of the palette in colors.
+ */
+ void setPalette(const byte *palette, uint16 size); ///< Change the palette
+
+ /** Add a new cursor that can be manipulated to the stack. */
+ void addCursor();
+ /** Remove the top-most cursor from the stack. */
+ void removeCursor();
+
+ /** Set the current cursor. */
+ void setCursor(Surface &sprite, int16 hotspotX, int16 hotspotY);
+ /** Set the current cursor. */
+ void setCursor(Surface &sprite, int16 left, int16 top, int16 right, int16 bottom,
+ int16 hotspotX, int16 hotspotY);
+
+ /** Show the cursor. */
+ void showCursor();
+ /** Hide the cursor. */
+ void hideCursor();
+
+ /** Is the cursor currently visible? */
+ bool isCursorVisible() const;
+
+ /** Remove an animation from the screen. */
+ void clearAnim(ANIObject &anim);
+ /** Draw an animation to the screen, advancing it. */
+ void drawAnim(ANIObject &anim);
+ /** Clear and draw an animation to the screen, advancing it. */
+ void redrawAnim(ANIObject &anim);
+
+ /** Remove animations from the screen. */
+ void clearAnim(const ANIList &anims);
+ /** Draw animations to the screen, advancing them. */
+ void drawAnim(const ANIList &anims);
+ /** Clear and draw animations to the screen, advancing them. */
+ void redrawAnim(const ANIList &anims);
+
+ void loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const;
+ void freeAnims(ANIList &anims) const;
+
+ void setAnim(ANIObject &anim, const AnimProperties &props) const;
+
+ /** Wait for the frame to end, handling screen updates and optionally update input. */
+ void endFrame(bool doInput);
+
+
+ // -- Sound --
+
+ /** Load all sounds that can be played interactively in the game. */
+ void loadSounds(const char * const *sounds, uint soundCount);
+ /** Free all loaded sound. */
+ void freeSounds();
+
+ /** Play a loaded sound. */
+ void playSound(uint sound, int16 frequency = 0, int16 repCount = 0);
+ /** Stop all sound playback. */
+ void stopSound();
+
+ /** Play a sound until it ends or is interrupted by a keypress. */
+ void playSoundFile(const Common::String &file, int16 frequency = 0, int16 repCount = 0, bool interruptible = true);
+
+ /** Beep the PC speaker. */
+ void beep(int16 frequency, int32 length);
+
+
+ // -- Input --
+
+ /** Check mouse and keyboard input. */
+ int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+ /** Wait for mouse or keyboard input. */
+ int16 waitInput (int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
+ /** Wait for mouse or keyboard input, but don't care about what was done with the mouse. */
+ int16 waitInput();
+ /** Did we have mouse or keyboard input? */
+ bool hasInput();
+
+
+ // -- TXT helpers --
+
+ /** Get the name of a localized file. */
+ Common::String getLocFile(const Common::String &file) const;
+ /** Open a TXT file. */
+ TXTFile *loadTXT(const Common::String &txtFile, TXTFile::Format format) const;
+
+ /** Called by loadTXT() to fix strings within the TXT file. */
+ virtual void fixTXTStrings(TXTFile &txt) const;
+
+
+ // -- GCT helpers --
+
+ GCTFile *loadGCT(const Common::String &gctFile) const;
+
+
+private:
+ /** Did we fade out? */
+ bool _fadedOut;
+
+ /** All loaded sounds. */
+ Common::Array<SoundDesc> _sounds;
+
+
+ /** Load a sound file. */
+ bool loadSound(SoundDesc &sound, const Common::String &file) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_PREGOB_H
diff --git a/engines/gob/pregob/seqfile.cpp b/engines/gob/pregob/seqfile.cpp
new file mode 100644
index 0000000000..91973bbb85
--- /dev/null
+++ b/engines/gob/pregob/seqfile.cpp
@@ -0,0 +1,384 @@
+/* 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/str.h"
+#include "common/stream.h"
+
+#include "gob/gob.h"
+#include "gob/dataio.h"
+#include "gob/draw.h"
+#include "gob/decfile.h"
+#include "gob/anifile.h"
+#include "gob/aniobject.h"
+
+#include "gob/pregob/seqfile.h"
+
+namespace Gob {
+
+SEQFile::SEQFile(GobEngine *vm, const Common::String &fileName) : _vm(vm) {
+ for (uint i = 0; i < kObjectCount; i++)
+ _objects[i].object = 0;
+
+ Common::SeekableReadStream *seq = _vm->_dataIO->getFile(Util::setExtension(fileName, ".SEQ"));
+ if (!seq) {
+ warning("SEQFile::SEQFile(): No such file \"%s\"", fileName.c_str());
+ return;
+ }
+
+ load(*seq);
+
+ delete seq;
+}
+
+SEQFile::~SEQFile() {
+ for (uint i = 0; i < kObjectCount; i++)
+ delete _objects[i].object;
+
+ for (Backgrounds::iterator b = _backgrounds.begin(); b != _backgrounds.end(); ++b)
+ delete *b;
+
+ for (Animations::iterator a = _animations.begin(); a != _animations.end(); ++a)
+ delete *a;
+}
+
+void SEQFile::load(Common::SeekableReadStream &seq) {
+ const uint16 decCount = (uint16)seq.readByte() + 1;
+ const uint16 aniCount = (uint16)seq.readByte() + 1;
+
+ // Load backgrounds
+ _backgrounds.reserve(decCount);
+ for (uint i = 0; i < decCount; i++) {
+ const Common::String dec = Util::readString(seq, 13);
+
+ if (!_vm->_dataIO->hasFile(dec)) {
+ warning("SEQFile::load(): No such background \"%s\"", dec.c_str());
+ return;
+ }
+
+ _backgrounds.push_back(new DECFile(_vm, dec, 320, 200));
+ }
+
+ // Load animations
+ _animations.reserve(aniCount);
+ for (uint i = 0; i < aniCount; i++) {
+ const Common::String ani = Util::readString(seq, 13);
+
+ if (!_vm->_dataIO->hasFile(ani)) {
+ warning("SEQFile::load(): No such animation \"%s\"", ani.c_str());
+ return;
+ }
+
+ _animations.push_back(new ANIFile(_vm, ani));
+ }
+
+ _frameRate = seq.readUint16LE();
+
+ // Load background change keys
+
+ const uint16 bgKeyCount = seq.readUint16LE();
+ _bgKeys.resize(bgKeyCount);
+
+ for (uint16 i = 0; i < bgKeyCount; i++) {
+ const uint16 frame = seq.readUint16LE();
+ const uint16 index = seq.readUint16LE();
+
+ _bgKeys[i].frame = frame;
+ _bgKeys[i].background = index < _backgrounds.size() ? _backgrounds[index] : 0;
+ }
+
+ // Load animation keys for all 4 objects
+
+ for (uint i = 0; i < kObjectCount; i++) {
+ const uint16 animKeyCount = seq.readUint16LE();
+ _animKeys.reserve(_animKeys.size() + animKeyCount);
+
+ for (uint16 j = 0; j < animKeyCount; j++) {
+ _animKeys.push_back(AnimationKey());
+
+ const uint16 frame = seq.readUint16LE();
+ const uint16 index = seq.readUint16LE();
+
+ uint16 animation;
+ const ANIFile *ani = findANI(index, animation);
+
+ _animKeys.back().object = i;
+ _animKeys.back().frame = frame;
+ _animKeys.back().ani = ani;
+ _animKeys.back().animation = animation;
+ _animKeys.back().x = seq.readSint16LE();
+ _animKeys.back().y = seq.readSint16LE();
+ _animKeys.back().order = seq.readSint16LE();
+ }
+ }
+
+}
+
+const ANIFile *SEQFile::findANI(uint16 index, uint16 &animation) {
+ animation = 0xFFFF;
+
+ // 0xFFFF = remove animation
+ if (index == 0xFFFF)
+ return 0;
+
+ for (Animations::const_iterator a = _animations.begin(); a != _animations.end(); ++a) {
+ if (index < (*a)->getAnimationCount()) {
+ animation = index;
+ return *a;
+ }
+
+ index -= (*a)->getAnimationCount();
+ }
+
+ return 0;
+}
+
+void SEQFile::play(bool abortable, uint16 endFrame, uint16 frameRate) {
+ if (_bgKeys.empty() && _animKeys.empty())
+ // Nothing to do
+ return;
+
+ // Init
+
+ _frame = 0;
+ _abortPlay = false;
+
+ for (uint i = 0; i < kObjectCount; i++) {
+ delete _objects[i].object;
+
+ _objects[i].object = 0;
+ _objects[i].order = 0;
+ }
+
+ for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l)
+ l->currentLoop = 0;
+
+ // Set the frame rate
+
+ int16 frameRateBack = _vm->_util->getFrameRate();
+
+ if (frameRate == 0)
+ frameRate = _frameRate;
+
+ _vm->_util->setFrameRate(frameRate);
+
+ _abortable = abortable;
+
+ while (!_vm->shouldQuit() && !_abortPlay) {
+ // Handle the frame contents
+ playFrame();
+
+ // Handle extra frame events
+ handleFrameEvent();
+
+ // Wait for the frame to end
+ _vm->_draw->blitInvalidated();
+ _vm->_util->waitEndFrame();
+
+ // Handle input
+
+ _vm->_util->processInput();
+
+ int16 key = _vm->_util->checkKey();
+
+ int16 mouseX, mouseY;
+ MouseButtons mouseButtons;
+ _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
+ _vm->_util->forceMouseUp();
+
+ handleInput(key, mouseX, mouseY, mouseButtons);
+
+ // Loop
+
+ bool looped = false;
+ for (Loops::iterator l = _loops.begin(); l != _loops.end(); ++l) {
+ if ((l->endFrame == _frame) && (l->currentLoop < l->loopCount)) {
+ _frame = l->startFrame;
+
+ l->currentLoop++;
+ looped = true;
+ }
+ }
+
+ // If we didn't loop, advance the frame and look if we should end here
+
+ if (!looped) {
+ _frame++;
+ if (_frame >= endFrame)
+ break;
+ }
+ }
+
+ // Restore the frame rate
+ _vm->_util->setFrameRate(frameRateBack);
+}
+
+void SEQFile::playFrame() {
+ // Remove the current animation frames
+ clearAnims();
+
+ // Handle background keys, directly updating the background
+ for (BackgroundKeys::const_iterator b = _bgKeys.begin(); b != _bgKeys.end(); ++b) {
+ if (!b->background || (b->frame != _frame))
+ continue;
+
+ b->background->draw(*_vm->_draw->_backSurface);
+
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
+ }
+
+ // Handle the animation keys, updating the objects
+ for (AnimationKeys::const_iterator a = _animKeys.begin(); a != _animKeys.end(); ++a) {
+ if (a->frame != _frame)
+ continue;
+
+ Object &object = _objects[a->object];
+
+ delete object.object;
+ object.object = 0;
+
+ // No valid animation => remove
+ if ((a->animation == 0xFFFF) || !a->ani)
+ continue;
+
+ // Change the animation
+
+ object.object = new ANIObject(*a->ani);
+
+ object.object->setAnimation(a->animation);
+ object.object->setPosition(a->x, a->y);
+ object.object->setVisible(true);
+ object.object->setPause(false);
+
+ object.order = a->order;
+ }
+
+ // Draw the animations
+ drawAnims();
+}
+
+// NOTE: This is really not at all efficient. However, since there's only a
+// small number of objects, it should matter. We really do need a stable
+// sort, though, so Common::sort() is out.
+SEQFile::Objects SEQFile::getOrderedObjects() {
+ int16 minOrder = (int16)0x7FFF;
+ int16 maxOrder = (int16)0x8000;
+
+ Objects objects;
+
+ // Find the span of order values
+ for (uint i = 0; i < kObjectCount; i++) {
+ if (!_objects[i].object)
+ continue;
+
+ minOrder = MIN(minOrder, _objects[i].order);
+ maxOrder = MAX(maxOrder, _objects[i].order);
+ }
+
+ // Stably sort the objects by order value
+ for (int16 o = minOrder; o <= maxOrder; o++)
+ for (uint i = 0; i < kObjectCount; i++)
+ if (_objects[i].object && (_objects[i].order == o))
+ objects.push_back(_objects[i]);
+
+ return objects;
+}
+
+void SEQFile::clearAnims() {
+ Objects objects = getOrderedObjects();
+
+ // Remove the animation frames, in reverse drawing order
+ for (Objects::iterator o = objects.reverse_begin(); o != objects.end(); --o) {
+ int16 left, top, right, bottom;
+
+ if (o->object->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+ }
+}
+
+void SEQFile::drawAnims() {
+ Objects objects = getOrderedObjects();
+
+ // Draw the animation frames and advance the animation
+ for (Objects::iterator o = objects.begin(); o != objects.end(); ++o) {
+ int16 left, top, right, bottom;
+
+ if (o->object->draw(*_vm->_draw->_backSurface, left, top, right, bottom))
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
+
+ o->object->advance();
+ }
+}
+
+uint16 SEQFile::getFrame() const {
+ return _frame;
+}
+
+void SEQFile::seekFrame(uint16 frame) {
+ _frame = frame;
+}
+
+uint SEQFile::addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount) {
+ _loops.resize(_loops.size() + 1);
+
+ _loops.back().startFrame = startFrame;
+ _loops.back().endFrame = endFrame;
+ _loops.back().loopCount = loopCount;
+ _loops.back().currentLoop = 0;
+ _loops.back().empty = false;
+
+ return _loops.size() - 1;
+}
+
+void SEQFile::skipLoop(uint loopID) {
+ if (loopID >= _loops.size())
+ return;
+
+ _loops[loopID].currentLoop = 0xFFFF;
+}
+
+void SEQFile::delLoop(uint loopID) {
+ if (loopID >= _loops.size())
+ return;
+
+ _loops[loopID].empty = true;
+
+ cleanLoops();
+}
+
+void SEQFile::cleanLoops() {
+ while (!_loops.empty() && _loops.back().empty)
+ _loops.pop_back();
+}
+
+void SEQFile::abortPlay() {
+ _abortPlay = true;
+}
+
+void SEQFile::handleFrameEvent() {
+}
+
+void SEQFile::handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons) {
+ if (_abortable && ((key != 0) || (mouseButtons != kMouseButtonsNone)))
+ abortPlay();
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/seqfile.h b/engines/gob/pregob/seqfile.h
new file mode 100644
index 0000000000..5e12962ef9
--- /dev/null
+++ b/engines/gob/pregob/seqfile.h
@@ -0,0 +1,193 @@
+/* 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 GOB_PREGOB_SEQFILE_H
+#define GOB_PREGOB_SEQFILE_H
+
+#include "common/system.h"
+#include "common/array.h"
+#include "common/list.h"
+
+#include "gob/util.h"
+
+namespace Common {
+ class String;
+ class SeekableReadStream;
+}
+
+namespace Gob {
+
+class GobEngine;
+
+class DECFile;
+class ANIFile;
+class ANIObject;
+
+/** A SEQ file, describing a complex animation sequence.
+ *
+ * Used in early hardcoded gob games.
+ * The principle is similar to the Mult class (see mult.h), but instead
+ * of depending on all the externally loaded animations, backgrounds and
+ * objects, a SEQ file references animation and background directly by
+ * filename.
+ */
+class SEQFile {
+public:
+ SEQFile(GobEngine *vm, const Common::String &fileName);
+ virtual ~SEQFile();
+
+ /** Play the SEQ.
+ *
+ * @param abortable If true, end playback on any user input.
+ * @param endFrame The frame on where to end, or 0xFFFF for infinite playback.
+ * @param frameRate The frame rate at which to play the SEQ, or 0 for playing at
+ * the speed the SEQ itself wants to.
+ */
+ void play(bool abortable = true, uint16 endFrame = 0xFFFF, uint16 frameRate = 0);
+
+
+protected:
+ GobEngine *_vm;
+
+
+ /** Returns the current frame number. */
+ uint16 getFrame() const;
+
+ /** Seek to a specific frame. */
+ void seekFrame(uint16 frame);
+
+ /** Add a frame loop. */
+ uint addLoop(uint16 startFrame, uint16 endFrame, uint16 loopCount);
+
+ /** Skip a frame loop. */
+ void skipLoop(uint loopID);
+
+ /** Delete a frame loop. */
+ void delLoop(uint loopID);
+
+ /** Ends SEQ playback. */
+ void abortPlay();
+
+ /** Callback for special frame events. */
+ virtual void handleFrameEvent();
+ /** Callback for special user input handling. */
+ virtual void handleInput(int16 key, int16 mouseX, int16 mouseY, MouseButtons mouseButtons);
+
+
+private:
+ /** Number of animation objects that are visible at the same time. */
+ static const uint kObjectCount = 4;
+
+ /** A key for changing the background. */
+ struct BackgroundKey {
+ uint16 frame; ///< Frame the change is to happen.
+
+ const DECFile *background; ///< The background to use.
+ };
+
+ /** A key for playing an object animation. */
+ struct AnimationKey {
+ uint object; ///< The object this key belongs to.
+
+ uint16 frame; ///< Frame the change is to happen.
+
+ const ANIFile *ani; ///< The ANI to use.
+
+ uint16 animation; ///< The animation to use.
+
+ int16 x; ///< X position of the animation.
+ int16 y; ///< Y position of the animation.
+
+ int16 order; ///< Used to determine in which order to draw the objects.
+ };
+
+ /** A managed animation object. */
+ struct Object {
+ ANIObject *object; ///< The actual animation object.
+
+ int16 order; ///< The current drawing order.
+ };
+
+ /** A frame loop. */
+ struct Loop {
+ uint16 startFrame;
+ uint16 endFrame;
+
+ uint16 loopCount;
+ uint16 currentLoop;
+
+ bool empty;
+ };
+
+ typedef Common::Array<DECFile *> Backgrounds;
+ typedef Common::Array<ANIFile *> Animations;
+
+ typedef Common::Array<BackgroundKey> BackgroundKeys;
+ typedef Common::Array<AnimationKey> AnimationKeys;
+
+ typedef Common::List<Object> Objects;
+
+ typedef Common::Array<Loop> Loops;
+
+
+ uint16 _frame; ///< The current frame.
+ bool _abortPlay; ///< Was the end of the playback requested?
+
+ uint16 _frameRate;
+
+ Backgrounds _backgrounds; ///< All backgrounds in this SEQ.
+ Animations _animations; ///< All animations in this SEQ.
+
+ BackgroundKeys _bgKeys; ///< The background change keyframes.
+ AnimationKeys _animKeys; ///< The animation change keyframes.
+
+ Object _objects[kObjectCount]; ///< The managed animation objects.
+
+ Loops _loops;
+
+ /** Whether the playback should be abortable by user input. */
+ bool _abortable;
+
+
+ // -- Loading helpers --
+
+ void load(Common::SeekableReadStream &seq);
+
+ const ANIFile *findANI(uint16 index, uint16 &animation);
+
+ // -- Playback helpers --
+
+ void playFrame();
+
+ /** Get a list of objects ordered by drawing order. */
+ Objects getOrderedObjects();
+
+ void clearAnims(); ///< Remove all animation frames.
+ void drawAnims(); ///< Draw the animation frames.
+
+ /** Look if we can compact the loop array. */
+ void cleanLoops();
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_SEQFILE_H
diff --git a/engines/gob/pregob/txtfile.cpp b/engines/gob/pregob/txtfile.cpp
new file mode 100644
index 0000000000..3ff0d4b039
--- /dev/null
+++ b/engines/gob/pregob/txtfile.cpp
@@ -0,0 +1,232 @@
+/* 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/stream.h"
+
+#include "gob/draw.h"
+
+#include "gob/pregob/txtfile.h"
+
+namespace Gob {
+
+TXTFile::TXTFile(Common::SeekableReadStream &txt, Format format) {
+ load(txt, format);
+}
+
+TXTFile::~TXTFile() {
+}
+
+TXTFile::LineArray &TXTFile::getLines() {
+ return _lines;
+}
+
+void TXTFile::load(Common::SeekableReadStream &txt, Format format) {
+ if (format == kFormatStringPositionColorFont) {
+ int numLines = getInt(txt);
+
+ _lines.reserve(numLines);
+ }
+
+ while (!txt.eos()) {
+ Line line;
+
+ line.text = getStr(txt);
+ line.x = (format >= kFormatStringPosition) ? getInt(txt) : 0;
+ line.y = (format >= kFormatStringPosition) ? getInt(txt) : 0;
+ line.color = (format >= kFormatStringPositionColor) ? getInt(txt) : 0;
+ line.font = (format >= kFormatStringPositionColorFont) ? getInt(txt) : 0;
+
+ _lines.push_back(line);
+ }
+
+ while (!_lines.empty() && _lines.back().text.empty())
+ _lines.pop_back();
+}
+
+bool TXTFile::draw(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color) {
+
+ trashBuffer();
+
+ if (!getArea(left, top, right, bottom, fonts, fontCount))
+ return false;
+
+ resizeBuffer(right - left + 1, bottom - top + 1);
+ saveScreen(surface, left, top, right, bottom);
+
+ for (LineArray::const_iterator l = _lines.begin(); l != _lines.end(); ++l) {
+ if (l->font >= fontCount)
+ continue;
+
+ fonts[l->font]->drawString(l->text, l->x, l->y, (color < 0) ? l->color : color, 0, true, surface);
+ }
+
+ return true;
+}
+
+bool TXTFile::draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color) {
+
+ trashBuffer();
+
+ if (!getArea(line, left, top, right, bottom, fonts, fontCount))
+ return false;
+
+ resizeBuffer(right - left + 1, bottom - top + 1);
+ saveScreen(surface, left, top, right, bottom);
+
+ const Line &l = _lines[line];
+
+ fonts[l.font]->drawString(l.text, l.x, l.y, (color < 0) ? l.color : color, 0, true, surface);
+
+ return true;
+}
+
+bool TXTFile::draw(Surface &surface, const Font * const *fonts, uint fontCount, int color) {
+ int16 left, top, right, bottom;
+
+ return draw(surface, left, top, right, bottom, fonts, fontCount, color);
+}
+
+bool TXTFile::draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color) {
+ int16 left, top, right, bottom;
+
+ return draw(line, surface, left, top, right, bottom, fonts, fontCount, color);
+}
+
+bool TXTFile::clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ return restoreScreen(surface, left, top, right, bottom);
+}
+
+bool TXTFile::getArea(int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const {
+
+ bool hasLine = false;
+
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0x0000;
+ bottom = 0x0000;
+
+ for (uint i = 0; i < _lines.size(); i++) {
+ int16 lLeft, lTop, lRight, lBottom;
+
+ if (getArea(i, lLeft, lTop, lRight, lBottom, fonts, fontCount)) {
+ left = MIN(left , lLeft );
+ top = MIN(top , lTop );
+ right = MAX(right , lRight );
+ bottom = MAX(bottom, lBottom);
+
+ hasLine = true;
+ }
+ }
+
+ return hasLine;
+}
+
+bool TXTFile::getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const {
+
+
+ if ((line >= _lines.size()) || (_lines[line].font >= fontCount))
+ return false;
+
+ const Line &l = _lines[line];
+
+ left = l.x;
+ top = l.y;
+ right = l.x + l.text.size() * fonts[l.font]->getCharWidth() - 1;
+ bottom = l.y + fonts[l.font]->getCharHeight() - 1;
+
+ return true;
+}
+
+Common::String TXTFile::getStr(Common::SeekableReadStream &txt) {
+ // Skip all ' ', '\n' and '\r'
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if (txt.eos())
+ break;
+
+ if ((c != ' ') && (c != '\n') && (c != '\r')) {
+ txt.seek(-1, SEEK_CUR);
+ break;
+ }
+ }
+
+ if (txt.eos())
+ return "";
+
+ // Read string until ' ', '\n' or '\r'
+ Common::String string;
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if ((c == ' ') || (c == '\n') || (c == '\r'))
+ break;
+
+ string += c;
+ }
+
+ // Replace all '#' with ' ' and throw out non-printables
+ Common::String cleanString;
+
+ for (uint i = 0; i < string.size(); i++) {
+ if (string[i] == '#')
+ cleanString += ' ';
+ else if ((unsigned char)string[i] >= ' ')
+ cleanString += string[i];
+ }
+
+ return cleanString;
+}
+
+int TXTFile::getInt(Common::SeekableReadStream &txt) {
+ // Skip all [^-0-9]
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if (txt.eos())
+ break;
+
+ if ((c == '-') || ((c >= '0') && (c <= '9'))) {
+ txt.seek(-1, SEEK_CUR);
+ break;
+ }
+ }
+
+ if (txt.eos())
+ return 0;
+
+ // Read until [^-0-9]
+ Common::String string;
+ while (!txt.eos()) {
+ char c = txt.readByte();
+ if ((c != '-') && ((c < '0') || (c > '9')))
+ break;
+
+ string += c;
+ }
+
+ // Convert to integer
+ return atoi(string.c_str());
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/pregob/txtfile.h b/engines/gob/pregob/txtfile.h
new file mode 100644
index 0000000000..c623b58859
--- /dev/null
+++ b/engines/gob/pregob/txtfile.h
@@ -0,0 +1,91 @@
+/* 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 GOB_PREGOB_TXTFILE_H
+#define GOB_PREGOB_TXTFILE_H
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/array.h"
+
+#include "gob/backbuffer.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Gob {
+
+class Surface;
+class Font;
+
+class TXTFile : public BackBuffer {
+public:
+ enum Format {
+ kFormatString,
+ kFormatStringPosition,
+ kFormatStringPositionColor,
+ kFormatStringPositionColorFont
+ };
+
+ struct Line {
+ Common::String text;
+ int x, y;
+ int color;
+ uint font;
+ };
+
+ typedef Common::Array<Line> LineArray;
+
+ TXTFile(Common::SeekableReadStream &txt, Format format);
+ ~TXTFile();
+
+ LineArray &getLines();
+
+ bool draw( Surface &surface, const Font * const *fonts, uint fontCount, int color = -1);
+ bool draw(uint line, Surface &surface, const Font * const *fonts, uint fontCount, int color = -1);
+
+ bool draw( Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color = -1);
+ bool draw(uint line, Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount, int color = -1);
+
+ bool clear(Surface &surface, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+private:
+ LineArray _lines;
+
+ void load(Common::SeekableReadStream &txt, Format format);
+
+ Common::String getStr(Common::SeekableReadStream &txt);
+ int getInt(Common::SeekableReadStream &txt);
+
+
+ bool getArea( int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const;
+ bool getArea(uint line, int16 &left, int16 &top, int16 &right, int16 &bottom,
+ const Font * const *fonts, uint fontCount) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_PREGOB_TXTFILE_H