From 39a8c71f776254b272e68a36fa5355293c0ae5f9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 8 Jun 2009 22:18:52 +0000 Subject: Adding Draci Historie engine skeleton (engine stub, BAR archiver, rudimentary GPL disassembler) svn-id: r41390 --- base/plugins.cpp | 3 + configure | 1 + engines/draci/barchive.cpp | 201 +++++++++++++++++++++++++++ engines/draci/barchive.h | 76 ++++++++++ engines/draci/detection.cpp | 126 +++++++++++++++++ engines/draci/draci.cpp | 189 +++++++++++++++++++++++++ engines/draci/draci.h | 58 ++++++++ engines/draci/gpldisasm.cpp | 329 ++++++++++++++++++++++++++++++++++++++++++++ engines/draci/gpldisasm.h | 35 +++++ engines/draci/module.mk | 18 +++ engines/engines.mk | 5 + 11 files changed, 1041 insertions(+) create mode 100644 engines/draci/barchive.cpp create mode 100644 engines/draci/barchive.h create mode 100644 engines/draci/detection.cpp create mode 100644 engines/draci/draci.cpp create mode 100644 engines/draci/draci.h create mode 100644 engines/draci/gpldisasm.cpp create mode 100644 engines/draci/gpldisasm.h create mode 100644 engines/draci/module.mk diff --git a/base/plugins.cpp b/base/plugins.cpp index 446c26e57c..bcfb865492 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -157,6 +157,9 @@ public: #if PLUGIN_ENABLED_STATIC(TUCKER) LINK_PLUGIN(TUCKER) #endif + #if PLUGIN_ENABLED_STATIC(DRACI) + LINK_PLUGIN(DRACI) + #endif // Music plugins // TODO: Use defines to disable or enable each MIDI driver as a diff --git a/configure b/configure index c2641b31f0..e298b80006 100755 --- a/configure +++ b/configure @@ -96,6 +96,7 @@ add_engine sword2 "Broken Sword 2" yes add_engine tinsel "Tinsel" no add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes add_engine tucker "Bud Tucker in Double Trouble" yes +add_engine draci "Dragon History" no # diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp new file mode 100644 index 0000000000..f813222552 --- /dev/null +++ b/engines/draci/barchive.cpp @@ -0,0 +1,201 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/debug.h" +#include "common/file.h" +#include "common/str.h" +#include "common/stream.h" + +#include "draci/barchive.h" +#include "draci/draci.h" + +namespace Draci { + +const char BArchive::_magicNumber[] = "BAR!"; + +/** + * @brief BArchive open method + * @param path Path to input file + * + * Opens a BAR (Bob's Archiver) archive, which is the game's archiving format. + * BAR archives have a .DFW file extension, due to an unused historical interface. + * + * archive format: header, + * file0, file1, ... + * footer + * header format: [4 bytes] magic number "BAR!" + * [uint16LE] file count (number of archived streams), + * [uint32LE] footer offset from start of file + * file format: [2 bytes] compressed length + * [2 bytes] original length + * [1 byte] compression type + * [1 byte] CRC + * footer format: [array of uint32LE] offsets of individual files from start of archive + * (last entry is footer offset again) + */ + +void BArchive::openArchive(const Common::String &path) { + byte buf[4]; + byte *footer; + uint32 footerOffset, footerSize; + Common::File f; + + // Close previously opened archive (if any) + closeArchive(); + + debugC(5, kDraciGeneralDebugLevel, "Loading BAR archive %s:", + path.c_str()); + + f.open(path); + if (f.isOpen()) { + debugC(5, kDraciGeneralDebugLevel, "Success"); + } else { + debugC(5, kDraciGeneralDebugLevel, "Error"); + return; + } + + // Save path for reading in files later on + _path = path; + + // Read archive header + debugC(5, kDraciGeneralDebugLevel, "Checking magic number:"); + + f.read(buf, 4); + if (memcmp(buf, _magicNumber, 4) == 0) { + debugC(5, kDraciGeneralDebugLevel, "Success"); + } else { + debugC(5, kDraciGeneralDebugLevel, "Error"); + f.close(); + return; + } + + _fileCount = f.readUint16LE(); + footerOffset = f.readUint32LE(); + footerSize = f.size() - footerOffset; + + debugC(5, kDraciGeneralDebugLevel, "Archive info: %d files, %d data bytes", + _fileCount, footerOffset - _archiveHeaderSize); + + // Read in footer + footer = new byte[footerSize]; + f.seek(footerOffset); + f.read(footer, footerSize); + Common::MemoryReadStream reader(footer, footerSize); + + // Read in file headers, but do not read the actual data yet + // The data will be read on demand to save memory + _files = new BAFile[_fileCount]; + + for (unsigned int i = 0; i < _fileCount; i++) { + uint32 fileOffset; + + fileOffset = reader.readUint32LE(); + f.seek(fileOffset); // Seek to next file in archive + f.readUint16LE(); // Compressed size, not used + _files[i]._length = f.readUint16LE(); // Original size + _files[i]._offset = fileOffset; + + assert(f.readByte() == 0 && + "Compression type flag is non-zero (file is compressed)"); + + _files[i]._crc = f.readByte(); // CRC checksum of the file + _files[i]._data = NULL; // File data will be read in on demand + } + + // Last footer item should be equal to footerOffset + assert(reader.readUint32LE() == footerOffset && "Footer offset mismatch"); + + f.close(); +} + +/** + * @brief BArchive close method + * + * Closes the currently opened archive. It can be called explicitly to + * free up memory. + */ +void BArchive::closeArchive(void) { + if (!_files) { + return; + } + + for (unsigned int i = 0; i < _fileCount; ++i) { + if (_files[i]._data) { + delete _files[i]._data; + } + } + + delete[] _files; + + _files = NULL; + _fileCount = 0; +} + +BAFile *BArchive::operator[](unsigned int i) const { + Common::File f; + + // Check whether requested file exists + if (i >= _fileCount) { + return NULL; + } + + debugC(5, kDraciGeneralDebugLevel, "Accessing file %d from archive %s", + i, _path.c_str()); + + // Check if file has already been opened and return that + if (_files[i]._data) { + return _files + i; + } + + // Else open archive and read in requested file + f.open(_path); + if (f.isOpen()) { + debugC(5, kDraciGeneralDebugLevel, "Success"); + } else { + debugC(5, kDraciGeneralDebugLevel, "Error"); + return NULL; + } + + // Read in the file (without the file header) + f.seek(_files[i]._offset + _fileHeaderSize); + _files[i]._data = new byte[_files[i]._length]; + f.read(_files[i]._data, _files[i]._length); + + // Calculate CRC + byte tmp = 0; + for (unsigned int j = 0; j < _files[i]._length; j++) { + tmp ^= _files[i]._data[j]; + } + + debugC(5, kDraciGeneralDebugLevel, "Read in file %d", i); + assert(tmp == _files[i]._crc && "CRC checksum mismatch"); + + return _files + i; +} + +} // End of namespace Draci + + + diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h new file mode 100644 index 0000000000..0a0ecc832b --- /dev/null +++ b/engines/draci/barchive.h @@ -0,0 +1,76 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef BARCHIVE_H +#define BARCHIVE_H + +#include "common/str.h" + +namespace Draci { + +/** + * Represents individual files inside the archive + */ + +struct BAFile { + uint16 _length; + uint32 _offset; //!< Offset of file inside archive + byte *_data; + byte _crc; + + void closeFile(void) { //!< Releases the file data (for memory considerations) + delete _data; + _data = NULL; + } +}; + +class BArchive { +public: + BArchive() : _files(NULL), _fileCount(0) {} + BArchive(Common::String &path) : _files(NULL), _fileCount(0) { openArchive(path); } + ~BArchive() { closeArchive(); } + + void openArchive(const Common::String &path); + void closeArchive(void); + uint16 size() const { return _fileCount; } + + BAFile *operator[](unsigned int i) const; + +private: + // Archive header data + static const char _magicNumber[]; + static const unsigned int _archiveHeaderSize = 10; + + // File stream header data + static const unsigned int _fileHeaderSize = 6; + + Common::String _path; //!< Path to file + BAFile *_files; //!< Internal array of files + uint16 _fileCount; //!< Number of files in archive +}; + +} // End of namespace Draci + +#endif // BARCHIVE_H diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp new file mode 100644 index 0000000000..02ce9f4764 --- /dev/null +++ b/engines/draci/detection.cpp @@ -0,0 +1,126 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "draci/draci.h" + +#include "base/plugins.h" +#include "engines/metaengine.h" + +static const PlainGameDescriptor draciGames[] = { + { "draci", "Draci Historie" }, + { 0, 0 } +}; + +namespace Draci { + +const ADGameDescription gameDescriptions[] = { + + { + "draci", + 0, + AD_ENTRY1s("INIT.DFW", "b890a5aeebaf16af39219cba2416b0a3", 906), + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS + }, + + { + "draci", + 0, + AD_ENTRY1s("INIT.DFW", "9921c8f0045679a8f37eca8d41c5ec02", 906), + Common::CZ_CZE, + Common::kPlatformPC, + ADGF_NO_FLAGS + }, + + { + "draci", + 0, + AD_ENTRY1s("INIT.DFW", "76b9b78a8a8809a240acc395df4d0715", 906), + Common::PL_POL, + Common::kPlatformPC, + ADGF_NO_FLAGS + }, + + AD_TABLE_END_MARKER +}; + +} // End of namespace Draci + +const ADParams detectionParams = { + // Pointer to ADGameDescription or its superset structure + (const byte *)Draci::gameDescriptions, + // Size of that superset structure + sizeof(ADGameDescription), + // Number of bytes to compute MD5 sum for + 5000, + // List of all engine targets + draciGames, + // Structure for autoupgrading obsolete targets + 0, + // Name of single gameid (optional) + "draci", + // List of files for file-based fallback detection (optional) + 0, + // Flags + 0 +}; + +class DraciMetaEngine : public AdvancedMetaEngine { +public: + DraciMetaEngine() : AdvancedMetaEngine(detectionParams) {} + + virtual const char *getName() const { + return "Draci Historie Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Copyright (C) 1995 NoSense"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; +}; + +bool DraciMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool Draci::DraciEngine::hasFeature(EngineFeature f) const { + return false; +} + +bool DraciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new Draci::DraciEngine(syst, Draci::gameDescriptions); + } + return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(DRACI) + REGISTER_PLUGIN_DYNAMIC(DRACI, PLUGIN_TYPE_ENGINE, DraciMetaEngine); +#else + REGISTER_PLUGIN_STATIC(DRACI, PLUGIN_TYPE_ENGINE, DraciMetaEngine); +#endif diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp new file mode 100644 index 0000000000..4de72549f6 --- /dev/null +++ b/engines/draci/draci.cpp @@ -0,0 +1,189 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include +#include "common/scummsys.h" + +#include "common/config-manager.h" +#include "common/events.h" +#include "common/file.h" + +#include "graphics/font.h" + +#include "draci/draci.h" +#include "draci/barchive.h" +#include "draci/gpldisasm.h" + +namespace Draci { + +DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) + : Engine(syst) { + // Put your engine in a sane state, but do nothing big yet; + // in particular, do not load data from files; rather, if you + // need to do such things, do them from init(). + + // Do not initialize graphics here + + // However this is the place to specify all default directories + //Common::File::addDefaultDirectory(_gameDataPath + "sound/"); + + // Here is the right place to set up the engine specific debug levels + Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug level"); + Common::addDebugChannel(kDraciBytecodeDebugLevel, "bytecode", "GPL bytecode instructions"); + + // Don't forget to register your random source + syst->getEventManager()->registerRandomSource(_rnd, "draci"); +} + +void drawString(Graphics::Surface *surf, Common::String str, int x, int y, byte color) { + Graphics::ScummFont temp; + int curx = x; + const int space = 0; + uint len = str.size(); + for (unsigned int i = 0; i < len; ++i) { + temp.drawChar(surf, str.c_str()[i], curx, y, color); + curx += temp.getCharWidth(str.c_str()[i]) + space; + } +} + +int DraciEngine::init() { + // Initialize graphics using following: + initGraphics(320, 200, false); + + // Basic archive test + Common::String path("INIT.DFW"); + BArchive ar(path); + BAFile *f; + debugC(3, kDraciGeneralDebugLevel, "Number of file streams in archive: %d\n", ar.size()); + f = ar[0]; + debugC(3, kDraciGeneralDebugLevel, "First 10 bytes of file %d: ", 0); + for (unsigned int i = 0; i < 10; ++i) { + debugC(3, kDraciGeneralDebugLevel, "0x%02x%c", f->_data[i], (i < 9) ? ' ' : '\n'); + } + + // Read in GPL script for the first game location + debugC(2, kDraciBytecodeDebugLevel, "Disassembling GPL script " + "for the first game location..."); + Common::String path2("MIST.DFW"); + ar.closeArchive(); + ar.openArchive(path2); + f = ar[3]; + + // Disassemble GPL script for the first location + gpldisasm(f->_data, f->_length); + + return 0; +} + +int DraciEngine::go() { + debugC(1, kDraciGeneralDebugLevel, "DraciEngine::go()"); + + // Read in a sample palette + byte *palette = new byte[4 * 256]; + + Common::String path("PALETY.DFW"); + BArchive ar(path); + BAFile *f; + + ar.closeArchive(); + ar.openArchive(path); + f = ar[0]; + Common::MemoryReadStream readerZ(f->_data, f->_length); + + palette[0] = readerZ.readByte(); + palette[1] = readerZ.readByte(); + palette[2] = readerZ.readByte(); + palette[3] = 0; + palette[4] = readerZ.readByte(); + palette[5] = readerZ.readByte(); + palette[6] = readerZ.readByte(); + palette[7] = 0; + for (unsigned int i = 2; i < 256; ++i) { + // FIXME: Sprite is too dark, add a fixed value as a workaround + palette[i*4] = readerZ.readByte() + 20; + palette[i*4+1] = readerZ.readByte() + 20; + palette[i*4+2] = readerZ.readByte() + 20; + palette[i*4+3] = 0; + } + _system->setPalette(palette, 0, 256); + + // Draw a test string + Graphics::Surface *surf = _system->lockScreen(); + drawString(surf, "Testing, testing, read all about it!", 5, 60, 3); + _system->unlockScreen(); + + // Draw and animate the dragon + path = "OBR_AN.DFW"; + ar.closeArchive(); + ar.openArchive(path); + + for (unsigned int t = 0; t < 25; ++t) { + debugC(4, kDraciGeneralDebugLevel, "Drawing frame %d...", t); + + // Load frame to memory + f = ar[t]; + Common::MemoryReadStream reader(f->_data, f->_length); + + // Read in frame width and height + uint16 w = reader.readUint16LE(); + uint16 h = reader.readUint16LE(); + + // Allocate frame memory + byte *scr = new byte[w * h]; + + // Draw frame + for (uint16 i = 0; i < w; ++i) { + for (uint16 j = 0; j < h; ++j) { + scr[j*w+i] = reader.readByte(); + } + } + _system->copyRectToScreen(scr, w, 0, 0, w, h); + _system->updateScreen(); + _system->delayMillis(100); + + debugC(4, kDraciGeneralDebugLevel, "Finished frame %d", t); + + // Free frame memory + delete [] scr; + } + getchar(); + + return 0; +} + +DraciEngine::~DraciEngine() { + // Dispose your resources here + + // Remove all of our debug levels here + Common::clearAllDebugChannels(); +} + +Common::Error DraciEngine::run() { + init(); + go(); + return Common::kNoError; +} + +} // End of namespace Draci diff --git a/engines/draci/draci.h b/engines/draci/draci.h new file mode 100644 index 0000000000..49da23b43e --- /dev/null +++ b/engines/draci/draci.h @@ -0,0 +1,58 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef DRACI_H +#define DRACI_H + +#include "common/system.h" +#include "engines/engine.h" +#include "engines/advancedDetector.h" + +namespace Draci { + +class DraciEngine : public Engine { +public: + DraciEngine(OSystem *syst, const ADGameDescription *gameDesc); + ~DraciEngine(); + + int init(); + int go(); + Common::Error run(); + + bool hasFeature(Engine::EngineFeature f) const; + +private: + Common::RandomSource _rnd; +}; + +enum { + kDraciGeneralDebugLevel = 1 << 0, + kDraciBytecodeDebugLevel = 1 << 1 +}; + +} // End of namespace Draci + +#endif // DRACI_H + diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp new file mode 100644 index 0000000000..1749136702 --- /dev/null +++ b/engines/draci/gpldisasm.cpp @@ -0,0 +1,329 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +/** + * @brief GPL2 bytecode disassembler + * @param gplcode A pointer to the bytecode + * len Length of the bytecode + * + * GPL2 is short for Game Programming Language 2 which is the script language + * used by Draci Historie. This is a simple disassembler for the language. + * + * A compiled GPL2 program consists of a stream of bytes representing commands + * and their parameters. The syntax is as follows: + * + * Syntax of a command: + * + * + * Syntax of a parameter: + * - 1: integer number literally passed to the program + * - 2-1: string stored in the reservouir of game strings (i.e. something to be + * displayed) and stored as an index in this list + * - 2-2: string resolved by the compiler (i.e., a path to another file) and + * replaced by an integer index of this entity in the appropriate namespace + * (e.g., the index of the palette, location, ...) + * - 3-0: relative jump to a label defined in this code. Each label must be + * first declared in the beginning of the program. + * - 3-1 .. 3-9: index of an entity in several namespaces, defined in file ident + * - 4: mathematical expression compiled into a postfix format + * + * In the compiled program, parameters of type 1..3 are represented by a single + * 16-bit integer. The called command knows by its definition what namespace the + * value comes from. + */ + +#include "common/debug.h" +#include "common/stream.h" + +#include "draci/gpldisasm.h" +#include "draci/barchive.h" +#include "draci/draci.h" + +#define skipParams(x) for(unsigned int i = 0; i < (x); ++i) reader.readUint16LELE() +#define CMDPAIR(x, y) (((x) << 8) | y) + +namespace Draci { + +// FIXME: Handle math expressions properly instead of just skipping them +void handleMathExpression(Common::MemoryReadStream &reader) { + uint16 temp; + while (1) { + temp = reader.readUint16LE(); + if (temp == 0) { + break; + } + temp = reader.readUint16LE(); + } + return; +} + +int gpldisasm(byte *gplcode, uint16 len) { + Common::MemoryReadStream reader(gplcode, len); + + while (!reader.eos()) { + // read in command pair + uint16 cmdpair = reader.readUint16BE(); + + uint16 param1, param2, param3; + + switch (cmdpair) { + case CMDPAIR(5,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_Load %hu %hu", param1, param2); + break; + case CMDPAIR(4,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_Start %hu %hu", param1, param2); + break; + case CMDPAIR(5,2): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_StartPlay %hu %hu", + param1, param2); + break; + case CMDPAIR(5,3): + debugC(2, kDraciBytecodeDebugLevel, "C_JustTalk"); + break; + case CMDPAIR(5,4): + debugC(2, kDraciBytecodeDebugLevel, "C_JustStay"); + break; + case CMDPAIR(10,2): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + param3 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_StayOn %hu %hu %hu", + param1, param2, param3); + break; + case CMDPAIR(10,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + param3 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_WalkOn %hu %hu %hu", + param1, param2, param3); + break; + case CMDPAIR(10,3): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + param3 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_WalkOnPlay %hu %hu %hu", + param1, param2, param3); + break; + case CMDPAIR(7,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ObjStat %hu %hu", + param1, param2); + break; + case CMDPAIR(7,2): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ObjStat_On %hu %hu", + param1, param2); + break; + case CMDPAIR(8,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_IcoStat %hu %hu", + param1, param2); + break; + case CMDPAIR(14,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_NewRoom %hu %hu", + param1, param2); + break; + case CMDPAIR(6,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_Talk %hu %hu", + param1, param2); + break; + case CMDPAIR(2,1): + param1 = reader.readUint16LE(); + handleMathExpression(reader); + debugC(2, kDraciBytecodeDebugLevel, "C_Let %hu", param1); + break; + case CMDPAIR(15,1): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ExecInit %hu", param1); + break; + case CMDPAIR(15,2): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ExecLook %hu", param1); + break; + case CMDPAIR(15,3): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ExecUse %hu", param1); + break; + case CMDPAIR(16,1): + debugC(2, kDraciBytecodeDebugLevel, "C_RepaintInventory"); + break; + case CMDPAIR(16,2): + debugC(2, kDraciBytecodeDebugLevel, "C_ExitInventory"); + break; + case CMDPAIR(1,1): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_goto %hu", param1); + break; + case CMDPAIR(3,1): + handleMathExpression(reader); + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_if %hu", param1); + break; + case CMDPAIR(9,1): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_Dialogue %hu", param1); + break; + case CMDPAIR(9,2): + debugC(2, kDraciBytecodeDebugLevel, "C_ExitDialogue"); + break; + case CMDPAIR(9,3): + debugC(2, kDraciBytecodeDebugLevel, "C_ResetDialogue"); + break; + case CMDPAIR(9,4): + debugC(2, kDraciBytecodeDebugLevel, "C_ResetDialogueFrom"); + break; + case CMDPAIR(9,5): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ResetBlock %hu", param1); + break; + case CMDPAIR(11,1): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_LoadPalette %hu", param1); + break; + case CMDPAIR(12,1): + debugC(2, kDraciBytecodeDebugLevel, "C_SetPalette"); + break; + case CMDPAIR(12,2): + debugC(2, kDraciBytecodeDebugLevel, "C_BlackPalette"); + break; + case CMDPAIR(13,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + param3 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_FadePalette %hu %hu %hu", + param1, param2, param3); + break; + case CMDPAIR(13,2): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + param3 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_FadePalettePlay %hu %hu %hu", + param1, param2, param3); + break; + case CMDPAIR(17,1): + debugC(2, kDraciBytecodeDebugLevel, "C_ExitMap"); + break; + case CMDPAIR(18,1): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_LoadMusic %hu", param1); + break; + case CMDPAIR(18,2): + debugC(2, kDraciBytecodeDebugLevel, "C_StartMusic"); + break; + case CMDPAIR(18,3): + debugC(2, kDraciBytecodeDebugLevel, "C_StopMusic"); + break; + case CMDPAIR(18,4): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_FadeOutMusic %hu", param1); + break; + case CMDPAIR(18,5): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_FadeInMusic %hu", param1); + break; + case CMDPAIR(19,1): + debugC(2, kDraciBytecodeDebugLevel, "C_Mark"); + break; + case CMDPAIR(19,2): + debugC(2, kDraciBytecodeDebugLevel, "C_Release"); + break; + case CMDPAIR(20,1): + debugC(2, kDraciBytecodeDebugLevel, "C_Play"); + break; + case CMDPAIR(21,1): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_LoadMap %hu", param1); + break; + case CMDPAIR(21,2): + debugC(2, kDraciBytecodeDebugLevel, "C_RoomMap"); + break; + case CMDPAIR(22,1): + debugC(2, kDraciBytecodeDebugLevel, "C_DisableQuickHero"); + break; + case CMDPAIR(22,2): + debugC(2, kDraciBytecodeDebugLevel, "C_EnableQuickHero"); + break; + case CMDPAIR(23,1): + debugC(2, kDraciBytecodeDebugLevel, "C_DisableSpeedText"); + break; + case CMDPAIR(23,2): + debugC(2, kDraciBytecodeDebugLevel, "C_EnableSpeedText"); + break; + case CMDPAIR(24,1): + debugC(2, kDraciBytecodeDebugLevel, "C_QuitGame"); + break; + case CMDPAIR(25,1): + debugC(2, kDraciBytecodeDebugLevel, "C_PushNewRoom"); + break; + case CMDPAIR(25,2): + debugC(2, kDraciBytecodeDebugLevel, "C_PopNewRoom"); + break; + case CMDPAIR(26,1): + debugC(2, kDraciBytecodeDebugLevel, "C_ShowCheat"); + break; + case CMDPAIR(26,2): + debugC(2, kDraciBytecodeDebugLevel, "C_HideCheat"); + break; + case CMDPAIR(26,3): + param1 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_ClearCheat %hu", param1); + break; + case CMDPAIR(27,1): + param1 = reader.readUint16LE(); + param2 = reader.readUint16LE(); + param3 = reader.readUint16LE(); + debugC(2, kDraciBytecodeDebugLevel, "C_FeedPassword %hu %hu %hu", + param1, param2, param3); + break; + case CMDPAIR(0, 0): + debugC(2, kDraciBytecodeDebugLevel, "gplend"); + break; + case CMDPAIR(0, 1): + debugC(2, kDraciBytecodeDebugLevel, "exit"); + break; + default: + debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", + (cmdpair >> 8) & 0xFF, cmdpair & 0xFF); + } + } + + return 0; +} + +} + diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h new file mode 100644 index 0000000000..b37a670507 --- /dev/null +++ b/engines/draci/gpldisasm.h @@ -0,0 +1,35 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GPLDISASM_H +#define GPLDISASM_H + +namespace Draci { + +int gpldisasm(byte *gplcode, uint16 len); + +} + +#endif // GPLDIASM_H diff --git a/engines/draci/module.mk b/engines/draci/module.mk new file mode 100644 index 0000000000..98a0d90a31 --- /dev/null +++ b/engines/draci/module.mk @@ -0,0 +1,18 @@ +MODULE := engines/draci + +MODULE_OBJS := \ + draci.o \ + detection.o \ + barchive.o \ + gpldisasm.o + +MODULE_DIRS += \ + engines/draci + +# This module can be built as a plugin +ifeq ($(ENABLE_DRACI), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/engines.mk b/engines/engines.mk index 8d7d8de9ff..6c403a61a7 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -36,6 +36,11 @@ DEFINES += -DENABLE_CRUISE=$(ENABLE_CRUISE) MODULES += engines/cruise endif +ifdef ENABLE_DRACI +DEFINES += -DENABLE_DRACI=$(ENABLE_DRACI) +MODULES += engines/draci +endif + ifdef ENABLE_DRASCULA DEFINES += -DENABLE_DRASCULA=$(ENABLE_DRASCULA) MODULES += engines/drascula -- cgit v1.2.3 From 2850023cf3d7d4d342cb44d4de25acec14ed513f Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Tue, 9 Jun 2009 05:25:23 +0000 Subject: Enable Draci engine by default svn-id: r41394 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index e298b80006..fd9f325109 100755 --- a/configure +++ b/configure @@ -96,7 +96,7 @@ add_engine sword2 "Broken Sword 2" yes add_engine tinsel "Tinsel" no add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes add_engine tucker "Bud Tucker in Double Trouble" yes -add_engine draci "Dragon History" no +add_engine draci "Dragon History" yes # -- cgit v1.2.3 From ba49e539d16cc2e48db70434ade95b9da96d0219 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 10 Jun 2009 01:35:47 +0000 Subject: Redesigned the GPL2 disassembler to improve readability. It now does a linear search in a table of commands (instead of having a giant switch) when searching for the correct bytecode command. svn-id: r41414 --- engines/draci/gpldisasm.cpp | 341 ++++++++++++++------------------------------ engines/draci/gpldisasm.h | 13 ++ 2 files changed, 119 insertions(+), 235 deletions(-) diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp index 1749136702..ec27bbf0cc 100644 --- a/engines/draci/gpldisasm.cpp +++ b/engines/draci/gpldisasm.cpp @@ -58,14 +58,71 @@ #include "common/stream.h" #include "draci/gpldisasm.h" -#include "draci/barchive.h" #include "draci/draci.h" -#define skipParams(x) for(unsigned int i = 0; i < (x); ++i) reader.readUint16LELE() -#define CMDPAIR(x, y) (((x) << 8) | y) - namespace Draci { +// FIXME: Change parameter types to names once I figure out what they are exactly +GPL2Command gplCommands[] = { + { 0, 0, "gplend", 0, { 0 } }, + { 0, 1, "exit", 0, { 0 } }, + { 1, 1, "goto", 1, { 3 } }, + { 2, 1, "Let", 2, { 3, 4 } }, + { 3, 1, "if", 2, { 4, 3 } }, + { 4, 1, "Start", 2, { 3, 2 } }, + { 5, 1, "Load", 2, { 3, 2 } }, + { 5, 2, "StartPlay", 2, { 3, 2 } }, + { 5, 3, "JustTalk", 0, { 0 } }, + { 5, 4, "JustStay", 0, { 0 } }, + { 6, 1, "Talk", 2, { 3, 2 } }, + { 7, 1, "ObjStat", 2, { 3, 3 } }, + { 7, 2, "ObjStat_On", 2, { 3, 3 } }, + { 8, 1, "IcoStat", 2, { 3, 3 } }, + { 9, 1, "Dialogue", 1, { 2 } }, + { 9, 2, "ExitDialogue", 0, { 0 } }, + { 9, 3, "ResetDialogue", 0, { 0 } }, + { 9, 4, "ResetDialogueFrom", 0, { 0 } }, + { 9, 5, "ResetBlock", 1, { 3 } }, + { 10, 1, "WalkOn", 3, { 1, 1, 3 } }, + { 10, 2, "StayOn", 3, { 1, 1, 3 } }, + { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 } }, + { 11, 1, "LoadPalette", 1, { 2 } }, + { 12, 1, "SetPalette", 0, { 0 } }, + { 12, 2, "BlackPalette", 0, { 0 } }, + { 13, 1, "FadePalette", 3, { 1, 1, 1 } }, + { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 } }, + { 14, 1, "NewRoom", 2, { 3, 1 } }, + { 15, 1, "ExecInit", 1, { 3 } }, + { 15, 2, "ExecLook", 1, { 3 } }, + { 15, 3, "ExecUse", 1, { 3 } }, + { 16, 1, "RepaintInventory", 0, { 0 } }, + { 16, 2, "ExitInventory", 0, { 0 } }, + { 17, 1, "ExitMap", 0, { 0 } }, + { 18, 1, "LoadMusic", 1, { 2 } }, + { 18, 2, "StartMusic", 0, { 0 } }, + { 18, 3, "StopMusic", 0, { 0 } }, + { 18, 4, "FadeOutMusic", 1, { 1 } }, + { 18, 5, "FadeInMusic", 1, { 1 } }, + { 19, 1, "Mark", 0, { 0 } }, + { 19, 2, "Release", 0, { 0 } }, + { 20, 1, "Play", 0, { 0 } }, + { 21, 1, "LoadMap", 1, { 2 } }, + { 21, 2, "RoomMap", 0, { 0 } }, + { 22, 1, "DisableQuickHero", 0, { 0 } }, + { 22, 2, "EnableQuickHero", 0, { 0 } }, + { 23, 1, "DisableSpeedText", 0, { 0 } }, + { 23, 2, "EnableSpeedText", 0, { 0 } }, + { 24, 1, "QuitGame", 0, { 0 } }, + { 25, 1, "PushNewRoom", 0, { 0 } }, + { 25, 2, "PopNewRoom", 0, { 0 } }, + { 26, 1, "ShowCheat", 0, { 0 } }, + { 26, 2, "HideCheat", 0, { 0 } }, + { 26, 3, "ClearCheat", 1, { 1 } }, + { 27, 1, "FeedPassword", 3, { 1, 1, 1 } } +}; + +const unsigned int kNumCommands = sizeof gplCommands / sizeof gplCommands[0]; + // FIXME: Handle math expressions properly instead of just skipping them void handleMathExpression(Common::MemoryReadStream &reader) { uint16 temp; @@ -79,247 +136,61 @@ void handleMathExpression(Common::MemoryReadStream &reader) { return; } +GPL2Command *findCommand(byte num, byte subnum) { + unsigned int i = 0; + while (1) { + + // Command not found + if (i >= kNumCommands) { + break; + } + + // Return found command + if (gplCommands[i]._number == num && gplCommands[i]._subNumber == subnum) { + return &gplCommands[i]; + } + + ++i; + } + + return NULL; +} + int gpldisasm(byte *gplcode, uint16 len) { Common::MemoryReadStream reader(gplcode, len); while (!reader.eos()) { // read in command pair uint16 cmdpair = reader.readUint16BE(); + + // extract high byte, i.e. the command number + byte num = (cmdpair >> 8) & 0xFF; + + // extract low byte, i.e. the command subnumber + byte subnum = cmdpair & 0xFF; - uint16 param1, param2, param3; + GPL2Command *cmd; + if ((cmd = findCommand(num, subnum))) { + + // Print command name + debugC(2, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); - switch (cmdpair) { - case CMDPAIR(5,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_Load %hu %hu", param1, param2); - break; - case CMDPAIR(4,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_Start %hu %hu", param1, param2); - break; - case CMDPAIR(5,2): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_StartPlay %hu %hu", - param1, param2); - break; - case CMDPAIR(5,3): - debugC(2, kDraciBytecodeDebugLevel, "C_JustTalk"); - break; - case CMDPAIR(5,4): - debugC(2, kDraciBytecodeDebugLevel, "C_JustStay"); - break; - case CMDPAIR(10,2): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - param3 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_StayOn %hu %hu %hu", - param1, param2, param3); - break; - case CMDPAIR(10,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - param3 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_WalkOn %hu %hu %hu", - param1, param2, param3); - break; - case CMDPAIR(10,3): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - param3 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_WalkOnPlay %hu %hu %hu", - param1, param2, param3); - break; - case CMDPAIR(7,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ObjStat %hu %hu", - param1, param2); - break; - case CMDPAIR(7,2): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ObjStat_On %hu %hu", - param1, param2); - break; - case CMDPAIR(8,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_IcoStat %hu %hu", - param1, param2); - break; - case CMDPAIR(14,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_NewRoom %hu %hu", - param1, param2); - break; - case CMDPAIR(6,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_Talk %hu %hu", - param1, param2); - break; - case CMDPAIR(2,1): - param1 = reader.readUint16LE(); - handleMathExpression(reader); - debugC(2, kDraciBytecodeDebugLevel, "C_Let %hu", param1); - break; - case CMDPAIR(15,1): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ExecInit %hu", param1); - break; - case CMDPAIR(15,2): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ExecLook %hu", param1); - break; - case CMDPAIR(15,3): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ExecUse %hu", param1); - break; - case CMDPAIR(16,1): - debugC(2, kDraciBytecodeDebugLevel, "C_RepaintInventory"); - break; - case CMDPAIR(16,2): - debugC(2, kDraciBytecodeDebugLevel, "C_ExitInventory"); - break; - case CMDPAIR(1,1): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_goto %hu", param1); - break; - case CMDPAIR(3,1): - handleMathExpression(reader); - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_if %hu", param1); - break; - case CMDPAIR(9,1): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_Dialogue %hu", param1); - break; - case CMDPAIR(9,2): - debugC(2, kDraciBytecodeDebugLevel, "C_ExitDialogue"); - break; - case CMDPAIR(9,3): - debugC(2, kDraciBytecodeDebugLevel, "C_ResetDialogue"); - break; - case CMDPAIR(9,4): - debugC(2, kDraciBytecodeDebugLevel, "C_ResetDialogueFrom"); - break; - case CMDPAIR(9,5): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ResetBlock %hu", param1); - break; - case CMDPAIR(11,1): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_LoadPalette %hu", param1); - break; - case CMDPAIR(12,1): - debugC(2, kDraciBytecodeDebugLevel, "C_SetPalette"); - break; - case CMDPAIR(12,2): - debugC(2, kDraciBytecodeDebugLevel, "C_BlackPalette"); - break; - case CMDPAIR(13,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - param3 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_FadePalette %hu %hu %hu", - param1, param2, param3); - break; - case CMDPAIR(13,2): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - param3 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_FadePalettePlay %hu %hu %hu", - param1, param2, param3); - break; - case CMDPAIR(17,1): - debugC(2, kDraciBytecodeDebugLevel, "C_ExitMap"); - break; - case CMDPAIR(18,1): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_LoadMusic %hu", param1); - break; - case CMDPAIR(18,2): - debugC(2, kDraciBytecodeDebugLevel, "C_StartMusic"); - break; - case CMDPAIR(18,3): - debugC(2, kDraciBytecodeDebugLevel, "C_StopMusic"); - break; - case CMDPAIR(18,4): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_FadeOutMusic %hu", param1); - break; - case CMDPAIR(18,5): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_FadeInMusic %hu", param1); - break; - case CMDPAIR(19,1): - debugC(2, kDraciBytecodeDebugLevel, "C_Mark"); - break; - case CMDPAIR(19,2): - debugC(2, kDraciBytecodeDebugLevel, "C_Release"); - break; - case CMDPAIR(20,1): - debugC(2, kDraciBytecodeDebugLevel, "C_Play"); - break; - case CMDPAIR(21,1): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_LoadMap %hu", param1); - break; - case CMDPAIR(21,2): - debugC(2, kDraciBytecodeDebugLevel, "C_RoomMap"); - break; - case CMDPAIR(22,1): - debugC(2, kDraciBytecodeDebugLevel, "C_DisableQuickHero"); - break; - case CMDPAIR(22,2): - debugC(2, kDraciBytecodeDebugLevel, "C_EnableQuickHero"); - break; - case CMDPAIR(23,1): - debugC(2, kDraciBytecodeDebugLevel, "C_DisableSpeedText"); - break; - case CMDPAIR(23,2): - debugC(2, kDraciBytecodeDebugLevel, "C_EnableSpeedText"); - break; - case CMDPAIR(24,1): - debugC(2, kDraciBytecodeDebugLevel, "C_QuitGame"); - break; - case CMDPAIR(25,1): - debugC(2, kDraciBytecodeDebugLevel, "C_PushNewRoom"); - break; - case CMDPAIR(25,2): - debugC(2, kDraciBytecodeDebugLevel, "C_PopNewRoom"); - break; - case CMDPAIR(26,1): - debugC(2, kDraciBytecodeDebugLevel, "C_ShowCheat"); - break; - case CMDPAIR(26,2): - debugC(2, kDraciBytecodeDebugLevel, "C_HideCheat"); - break; - case CMDPAIR(26,3): - param1 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_ClearCheat %hu", param1); - break; - case CMDPAIR(27,1): - param1 = reader.readUint16LE(); - param2 = reader.readUint16LE(); - param3 = reader.readUint16LE(); - debugC(2, kDraciBytecodeDebugLevel, "C_FeedPassword %hu %hu %hu", - param1, param2, param3); - break; - case CMDPAIR(0, 0): - debugC(2, kDraciBytecodeDebugLevel, "gplend"); - break; - case CMDPAIR(0, 1): - debugC(2, kDraciBytecodeDebugLevel, "exit"); - break; - default: + for (uint16 i = 0; i < cmd->_numParams; ++i) { + if (cmd->_paramTypes[i] == 4) { + debugC(3, kDraciBytecodeDebugLevel, "\t"); + handleMathExpression(reader); + } + else { + debugC(3, kDraciBytecodeDebugLevel, "\t%hu", reader.readUint16LE()); + } + } + } + else { debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", - (cmdpair >> 8) & 0xFF, cmdpair & 0xFF); + num, subnum); } + + } return 0; diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h index b37a670507..d26fb5c978 100644 --- a/engines/draci/gpldisasm.h +++ b/engines/draci/gpldisasm.h @@ -23,11 +23,24 @@ * */ +#include "common/str.h" + #ifndef GPLDISASM_H #define GPLDISASM_H namespace Draci { +// FIXME: Add parameter types and function handlers +struct GPL2Command { + byte _number; + byte _subNumber; + Common::String _name; + uint16 _numParams; + int _paramTypes[3]; +}; + +const int kMaxParams = 3; + int gpldisasm(byte *gplcode, uint16 len); } -- cgit v1.2.3 From 10b8d82baa0137348473a846b85a20715808215f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 10 Jun 2009 02:59:53 +0000 Subject: Made handleMathExpression() properly handle mathematical expressions inside GPL bytecode (instead of just searching for the ending byte). The actual callbacks still need to be implemented. svn-id: r41415 --- engines/draci/gpldisasm.cpp | 125 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 107 insertions(+), 18 deletions(-) diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp index ec27bbf0cc..d91952b481 100644 --- a/engines/draci/gpldisasm.cpp +++ b/engines/draci/gpldisasm.cpp @@ -56,6 +56,7 @@ #include "common/debug.h" #include "common/stream.h" +#include "common/stack.h" #include "draci/gpldisasm.h" #include "draci/draci.h" @@ -64,8 +65,8 @@ namespace Draci { // FIXME: Change parameter types to names once I figure out what they are exactly GPL2Command gplCommands[] = { - { 0, 0, "gplend", 0, { 0 } }, - { 0, 1, "exit", 0, { 0 } }, + { 0, 0, "gplend", 0, { 0 } }, + { 0, 1, "exit", 0, { 0 } }, { 1, 1, "goto", 1, { 3 } }, { 2, 1, "Let", 2, { 3, 4 } }, { 3, 1, "if", 2, { 4, 3 } }, @@ -121,38 +122,126 @@ GPL2Command gplCommands[] = { { 27, 1, "FeedPassword", 3, { 1, 1, 1 } } }; +Common::String operators[] = { + "oper_and", + "oper_or", + "oper_xor", + "oper_equals", + "oper_not_equal", + "oper_less_than", + "oper_greater_than", + "oper_less_or_equal", + "oper_greater_or_equal", + "oper_multiply", + "oper_divide", + "oper_remainder", + "oper_plus", + "oper_minus" +}; + +Common::String functions[] = { + "F_Not", + "F_Random", + "F_IsIcoOn", + "F_IsIcoAct", + "F_IcoStat", + "F_ActIco", + "F_IsObjOn", + "F_IsObjOff", + "F_IsObjAway", + "F_ObjStat", + "F_LastBlock", + "F_AtBegin", + "F_BlockVar", + "F_HasBeen", + "F_MaxLine", + "F_ActPhase", + "F_Cheat" +}; + const unsigned int kNumCommands = sizeof gplCommands / sizeof gplCommands[0]; -// FIXME: Handle math expressions properly instead of just skipping them +enum mathExpressionObject { + kMathEnd, + kMathNumber, + kMathOperator, + kMathFunctionCall, + kMathVariable +}; + +// FIXME: The evaluator is now complete but I still need to implement callbacks void handleMathExpression(Common::MemoryReadStream &reader) { - uint16 temp; + Common::Stack stk; + mathExpressionObject obj; + + // Read in initial math object + obj = (mathExpressionObject) reader.readUint16LE(); + + uint16 value; while (1) { - temp = reader.readUint16LE(); - if (temp == 0) { + if (obj == kMathEnd) { + break; + } + + switch (obj) { + + // If the object type is not known, assume that it's a number + default: + case kMathNumber: + value = reader.readUint16LE(); + stk.push(value); + debugC(3, kDraciBytecodeDebugLevel, "\t\t-number %hu", value); + break; + + case kMathOperator: + value = reader.readUint16LE(); + stk.pop(); + stk.pop(); + debugC(3, kDraciBytecodeDebugLevel, "\t\t-operator %s", + operators[value-1].c_str()); + break; + + case kMathVariable: + value = reader.readUint16LE(); + stk.push(value); + debugC(3, kDraciBytecodeDebugLevel, "\t\t-variable %hu", value); + break; + + case kMathFunctionCall: + value = reader.readUint16LE(); + + // FIXME: Pushing dummy value for now, but should push return value + stk.push(0); + + debugC(3, kDraciBytecodeDebugLevel, "\t\t-functioncall %s", + functions[value-1].c_str()); break; } - temp = reader.readUint16LE(); + + obj = (mathExpressionObject) reader.readUint16LE(); } + return; } GPL2Command *findCommand(byte num, byte subnum) { unsigned int i = 0; while (1) { - + // Command not found if (i >= kNumCommands) { break; } // Return found command - if (gplCommands[i]._number == num && gplCommands[i]._subNumber == subnum) { + if (gplCommands[i]._number == num && + gplCommands[i]._subNumber == subnum) { return &gplCommands[i]; } - - ++i; + + ++i; } - + return NULL; } @@ -162,24 +251,24 @@ int gpldisasm(byte *gplcode, uint16 len) { while (!reader.eos()) { // read in command pair uint16 cmdpair = reader.readUint16BE(); - + // extract high byte, i.e. the command number byte num = (cmdpair >> 8) & 0xFF; - + // extract low byte, i.e. the command subnumber byte subnum = cmdpair & 0xFF; GPL2Command *cmd; if ((cmd = findCommand(num, subnum))) { - - // Print command name + + // Print command name debugC(2, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); for (uint16 i = 0; i < cmd->_numParams; ++i) { if (cmd->_paramTypes[i] == 4) { debugC(3, kDraciBytecodeDebugLevel, "\t"); handleMathExpression(reader); - } + } else { debugC(3, kDraciBytecodeDebugLevel, "\t%hu", reader.readUint16LE()); } @@ -190,7 +279,7 @@ int gpldisasm(byte *gplcode, uint16 len) { num, subnum); } - + } return 0; -- cgit v1.2.3 From 13dca9a17640168be1a176609334a3e22392bca2 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 10 Jun 2009 10:28:43 +0000 Subject: Backport debugCN() as it is needed for Draci engine svn-id: r41422 --- common/debug.cpp | 26 ++++++++++++++++++++++++++ common/debug.h | 21 +++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/common/debug.cpp b/common/debug.cpp index cc358596f7..ff17959cbf 100644 --- a/common/debug.cpp +++ b/common/debug.cpp @@ -227,6 +227,19 @@ void debugC(int level, uint32 debugChannels, const char *s, ...) { va_end(va); } +void debugCN(int level, uint32 debugChannels, const char *s, ...) { + va_list va; + + // Debug level 11 turns on all special debug level messages + if (gDebugLevel != 11) + if (level > gDebugLevel || !(Common::gDebugLevelsEnabled & debugChannels)) + return; + + va_start(va, s); + debugHelper(s, va, false); + va_end(va); +} + void debugC(uint32 debugChannels, const char *s, ...) { va_list va; @@ -240,4 +253,17 @@ void debugC(uint32 debugChannels, const char *s, ...) { va_end(va); } +void debugCN(uint32 debugChannels, const char *s, ...) { + va_list va; + + // Debug level 11 turns on all special debug level messages + if (gDebugLevel != 11) + if (!(Common::gDebugLevelsEnabled & debugChannels)) + return; + + va_start(va, s); + debugHelper(s, va, false); + va_end(va); +} + #endif diff --git a/common/debug.h b/common/debug.h index 43fe297859..888c71adbb 100644 --- a/common/debug.h +++ b/common/debug.h @@ -106,6 +106,8 @@ inline void debug(int level, const char *s, ...) {} inline void debugN(int level, const char *s, ...) {} inline void debugC(int level, uint32 engine_level, const char *s, ...) {} inline void debugC(uint32 engine_level, const char *s, ...) {} +inline void debugCN(int level, uint32 engine_level, const char *s, ...) {} +inline void debugCN(uint32 engine_level, const char *s, ...) {} #else @@ -144,6 +146,17 @@ void debugN(int level, const char *s, ...) GCC_PRINTF(2, 3); */ void debugC(int level, uint32 debugChannels, const char *s, ...) GCC_PRINTF(3, 4); +/** + * Print a debug message to the text console (stdout), but only if + * the specified level does not exceed the value of gDebugLevel OR + * if the specified special debug level is active. + * As a rule of thumb, the more important the message, the lower the level. + * Does not append a newline automatically. + * + * @see enableDebugChannel + */ +void debugCN(int level, uint32 debugChannels, const char *s, ...) GCC_PRINTF(3, 4); + /** * Print a debug message to the text console (stdout), but only if * the specified special debug level is active. @@ -153,6 +166,14 @@ void debugC(int level, uint32 debugChannels, const char *s, ...) GCC_PRINTF(3, 4 */ void debugC(uint32 debugChannels, const char *s, ...) GCC_PRINTF(2, 3); +/** + * Print a debug message to the text console (stdout), but only if + * the specified special debug level is active. + * Does not append a newline automatically. + * + * @see enableDebugChannel + */ +void debugCN(uint32 debugChannels, const char *s, ...) GCC_PRINTF(2, 3); #endif -- cgit v1.2.3 From 2c00d65501eb838efb72c27e021fdd5af406ff9a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 10 Jun 2009 18:18:09 +0000 Subject: Added an additional debuglevel "archiver" to facilitate displaying debug info from the BAR archiver. Also adjusted numeric debug levels. svn-id: r41436 --- engines/draci/barchive.cpp | 24 +++++++++++++----------- engines/draci/draci.cpp | 11 +++++++---- engines/draci/draci.h | 3 ++- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index f813222552..d11087a809 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -65,14 +65,14 @@ void BArchive::openArchive(const Common::String &path) { // Close previously opened archive (if any) closeArchive(); - debugC(5, kDraciGeneralDebugLevel, "Loading BAR archive %s:", + debugCN(2, kDraciArchiverDebugLevel, "Loading BAR archive %s: ", path.c_str()); f.open(path); if (f.isOpen()) { - debugC(5, kDraciGeneralDebugLevel, "Success"); + debugC(2, kDraciArchiverDebugLevel, "Success"); } else { - debugC(5, kDraciGeneralDebugLevel, "Error"); + debugC(2, kDraciArchiverDebugLevel, "Error"); return; } @@ -80,13 +80,13 @@ void BArchive::openArchive(const Common::String &path) { _path = path; // Read archive header - debugC(5, kDraciGeneralDebugLevel, "Checking magic number:"); + debugCN(2, kDraciArchiverDebugLevel, "Checking magic number: "); f.read(buf, 4); if (memcmp(buf, _magicNumber, 4) == 0) { - debugC(5, kDraciGeneralDebugLevel, "Success"); + debugC(2, kDraciArchiverDebugLevel, "Success"); } else { - debugC(5, kDraciGeneralDebugLevel, "Error"); + debugC(2, kDraciArchiverDebugLevel, "Error"); f.close(); return; } @@ -95,7 +95,7 @@ void BArchive::openArchive(const Common::String &path) { footerOffset = f.readUint32LE(); footerSize = f.size() - footerOffset; - debugC(5, kDraciGeneralDebugLevel, "Archive info: %d files, %d data bytes", + debugC(2, kDraciArchiverDebugLevel, "Archive info: %d files, %d data bytes", _fileCount, footerOffset - _archiveHeaderSize); // Read in footer @@ -161,20 +161,21 @@ BAFile *BArchive::operator[](unsigned int i) const { return NULL; } - debugC(5, kDraciGeneralDebugLevel, "Accessing file %d from archive %s", + debugCN(2, kDraciArchiverDebugLevel, "Accessing file %d from archive %s... ", i, _path.c_str()); // Check if file has already been opened and return that if (_files[i]._data) { + debugC(2, kDraciArchiverDebugLevel, "Success"); return _files + i; } // Else open archive and read in requested file f.open(_path); if (f.isOpen()) { - debugC(5, kDraciGeneralDebugLevel, "Success"); + debugC(2, kDraciArchiverDebugLevel, "Success"); } else { - debugC(5, kDraciGeneralDebugLevel, "Error"); + debugC(2, kDraciArchiverDebugLevel, "Error"); return NULL; } @@ -189,7 +190,8 @@ BAFile *BArchive::operator[](unsigned int i) const { tmp ^= _files[i]._data[j]; } - debugC(5, kDraciGeneralDebugLevel, "Read in file %d", i); + debugC(3, kDraciArchiverDebugLevel, "Cached file %d from archive %s", + i, _path.c_str()); assert(tmp == _files[i]._crc && "CRC checksum mismatch"); return _files + i; diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 4de72549f6..2d401804f1 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -23,7 +23,6 @@ * */ -#include #include "common/scummsys.h" #include "common/config-manager.h" @@ -52,6 +51,7 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) // Here is the right place to set up the engine specific debug levels Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug level"); Common::addDebugChannel(kDraciBytecodeDebugLevel, "bytecode", "GPL bytecode instructions"); + Common::addDebugChannel(kDraciArchiverDebugLevel, "archiver", "BAR archiver debug info"); // Don't forget to register your random source syst->getEventManager()->registerRandomSource(_rnd, "draci"); @@ -73,10 +73,11 @@ int DraciEngine::init() { initGraphics(320, 200, false); // Basic archive test + debugC(2, kDraciGeneralDebugLevel, "Running archive tests..."); Common::String path("INIT.DFW"); BArchive ar(path); BAFile *f; - debugC(3, kDraciGeneralDebugLevel, "Number of file streams in archive: %d\n", ar.size()); + debugC(3, kDraciGeneralDebugLevel, "Number of file streams in archive: %d", ar.size()); f = ar[0]; debugC(3, kDraciGeneralDebugLevel, "First 10 bytes of file %d: ", 0); for (unsigned int i = 0; i < 10; ++i) { @@ -103,6 +104,8 @@ int DraciEngine::go() { // Read in a sample palette byte *palette = new byte[4 * 256]; + debugC(2, kDraciGeneralDebugLevel, "Running graphics/animation test..."); + Common::String path("PALETY.DFW"); BArchive ar(path); BAFile *f; @@ -140,7 +143,7 @@ int DraciEngine::go() { ar.openArchive(path); for (unsigned int t = 0; t < 25; ++t) { - debugC(4, kDraciGeneralDebugLevel, "Drawing frame %d...", t); + debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); // Load frame to memory f = ar[t]; @@ -163,7 +166,7 @@ int DraciEngine::go() { _system->updateScreen(); _system->delayMillis(100); - debugC(4, kDraciGeneralDebugLevel, "Finished frame %d", t); + debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); // Free frame memory delete [] scr; diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 49da23b43e..aabbe4482b 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -49,7 +49,8 @@ private: enum { kDraciGeneralDebugLevel = 1 << 0, - kDraciBytecodeDebugLevel = 1 << 1 + kDraciBytecodeDebugLevel = 1 << 1, + kDraciArchiverDebugLevel = 1 << 2 }; } // End of namespace Draci -- cgit v1.2.3 From b91f93716a7da1721a552e3ccc979fe2170f9bd0 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 10 Jun 2009 21:12:38 +0000 Subject: Code formatting svn-id: r41438 --- engines/draci/draci.cpp | 12 ++++++------ engines/draci/gpldisasm.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 2d401804f1..e57018087b 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -125,10 +125,10 @@ int DraciEngine::go() { palette[7] = 0; for (unsigned int i = 2; i < 256; ++i) { // FIXME: Sprite is too dark, add a fixed value as a workaround - palette[i*4] = readerZ.readByte() + 20; - palette[i*4+1] = readerZ.readByte() + 20; - palette[i*4+2] = readerZ.readByte() + 20; - palette[i*4+3] = 0; + palette[i * 4] = readerZ.readByte() + 20; + palette[i * 4 + 1] = readerZ.readByte() + 20; + palette[i * 4 + 2] = readerZ.readByte() + 20; + palette[i * 4 + 3] = 0; } _system->setPalette(palette, 0, 256); @@ -159,7 +159,7 @@ int DraciEngine::go() { // Draw frame for (uint16 i = 0; i < w; ++i) { for (uint16 j = 0; j < h; ++j) { - scr[j*w+i] = reader.readByte(); + scr[j * w + i] = reader.readByte(); } } _system->copyRectToScreen(scr, w, 0, 0, w, h); @@ -169,7 +169,7 @@ int DraciEngine::go() { debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); // Free frame memory - delete [] scr; + delete[] scr; } getchar(); diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp index d91952b481..9024a2dd72 100644 --- a/engines/draci/gpldisasm.cpp +++ b/engines/draci/gpldisasm.cpp @@ -175,7 +175,7 @@ void handleMathExpression(Common::MemoryReadStream &reader) { mathExpressionObject obj; // Read in initial math object - obj = (mathExpressionObject) reader.readUint16LE(); + obj = (mathExpressionObject)reader.readUint16LE(); uint16 value; while (1) { -- cgit v1.2.3 From 78c07b83f8452b89b199a5100910754307551459 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 10 Jun 2009 21:18:14 +0000 Subject: Shifted the palette one bit to the left aft toemake the dragon animation brighter. svn-id: r41439 --- engines/draci/draci.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index e57018087b..980e02b846 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -124,12 +124,17 @@ int DraciEngine::go() { palette[6] = readerZ.readByte(); palette[7] = 0; for (unsigned int i = 2; i < 256; ++i) { - // FIXME: Sprite is too dark, add a fixed value as a workaround - palette[i * 4] = readerZ.readByte() + 20; - palette[i * 4 + 1] = readerZ.readByte() + 20; - palette[i * 4 + 2] = readerZ.readByte() + 20; + palette[i * 4] = readerZ.readByte(); + palette[i * 4 + 1] = readerZ.readByte(); + palette[i * 4 + 2] = readerZ.readByte(); palette[i * 4 + 3] = 0; } + + // Shift the palette one bit to the left to make it brighter + for (unsigned int i = 0; i < 4 * 256; ++i) { + palette[i] <<= 1; + } + _system->setPalette(palette, 0, 256); // Draw a test string -- cgit v1.2.3 From 4a9ec62e04d0019161ef2b8e8be9223bb5bf6b21 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 10 Jun 2009 21:28:16 +0000 Subject: Removed special-casing for the colour black as it's no longer needed. svn-id: r41440 --- engines/draci/draci.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 980e02b846..54cb6da154 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -113,26 +113,18 @@ int DraciEngine::go() { ar.closeArchive(); ar.openArchive(path); f = ar[0]; - Common::MemoryReadStream readerZ(f->_data, f->_length); + Common::MemoryReadStream paletteReader(f->_data, f->_length); - palette[0] = readerZ.readByte(); - palette[1] = readerZ.readByte(); - palette[2] = readerZ.readByte(); - palette[3] = 0; - palette[4] = readerZ.readByte(); - palette[5] = readerZ.readByte(); - palette[6] = readerZ.readByte(); - palette[7] = 0; - for (unsigned int i = 2; i < 256; ++i) { - palette[i * 4] = readerZ.readByte(); - palette[i * 4 + 1] = readerZ.readByte(); - palette[i * 4 + 2] = readerZ.readByte(); + for (unsigned int i = 0; i < 256; ++i) { + palette[i * 4] = paletteReader.readByte(); + palette[i * 4 + 1] = paletteReader.readByte(); + palette[i * 4 + 2] = paletteReader.readByte(); palette[i * 4 + 3] = 0; } // Shift the palette one bit to the left to make it brighter for (unsigned int i = 0; i < 4 * 256; ++i) { - palette[i] <<= 1; + palette[i] <<= 2; } _system->setPalette(palette, 0, 256); -- cgit v1.2.3 From 293d0ca65dda94b67955f46b9c8815680769d751 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 11 Jun 2009 01:50:10 +0000 Subject: Added support for the new GUI options. svn-id: r41442 --- engines/draci/detection.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp index 02ce9f4764..d01fb30d1c 100644 --- a/engines/draci/detection.cpp +++ b/engines/draci/detection.cpp @@ -35,6 +35,8 @@ static const PlainGameDescriptor draciGames[] = { namespace Draci { +using Common::GUIO_NONE; + const ADGameDescription gameDescriptions[] = { { @@ -43,7 +45,8 @@ const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("INIT.DFW", "b890a5aeebaf16af39219cba2416b0a3", 906), Common::EN_ANY, Common::kPlatformPC, - ADGF_NO_FLAGS + ADGF_NO_FLAGS, + GUIO_NONE }, { @@ -52,7 +55,8 @@ const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("INIT.DFW", "9921c8f0045679a8f37eca8d41c5ec02", 906), Common::CZ_CZE, Common::kPlatformPC, - ADGF_NO_FLAGS + ADGF_NO_FLAGS, + GUIO_NONE }, { @@ -61,7 +65,8 @@ const ADGameDescription gameDescriptions[] = { AD_ENTRY1s("INIT.DFW", "76b9b78a8a8809a240acc395df4d0715", 906), Common::PL_POL, Common::kPlatformPC, - ADGF_NO_FLAGS + ADGF_NO_FLAGS, + GUIO_NONE }, AD_TABLE_END_MARKER @@ -85,7 +90,9 @@ const ADParams detectionParams = { // List of files for file-based fallback detection (optional) 0, // Flags - 0 + 0, + // Global GUI options + Common::GUIO_NONE }; class DraciMetaEngine : public AdvancedMetaEngine { -- cgit v1.2.3 From a36a9a0398c440d5fd9583598ec7a39ea5ca0592 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 11 Jun 2009 20:31:36 +0000 Subject: Implemented font handling via the DraciFont class. Reprogrammed the test animation to use the original game fonts. Removed the old drawString() hack. svn-id: r41454 --- engines/draci/draci.cpp | 39 +++++++------ engines/draci/font.cpp | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ engines/draci/font.h | 59 +++++++++++++++++++ engines/draci/module.mk | 3 +- 4 files changed, 232 insertions(+), 17 deletions(-) create mode 100644 engines/draci/font.cpp create mode 100644 engines/draci/font.h diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 54cb6da154..69460029d3 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -34,6 +34,7 @@ #include "draci/draci.h" #include "draci/barchive.h" #include "draci/gpldisasm.h" +#include "draci/font.h" namespace Draci { @@ -57,17 +58,6 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) syst->getEventManager()->registerRandomSource(_rnd, "draci"); } -void drawString(Graphics::Surface *surf, Common::String str, int x, int y, byte color) { - Graphics::ScummFont temp; - int curx = x; - const int space = 0; - uint len = str.size(); - for (unsigned int i = 0; i < len; ++i) { - temp.drawChar(surf, str.c_str()[i], curx, y, color); - curx += temp.getCharWidth(str.c_str()[i]) + space; - } -} - int DraciEngine::init() { // Initialize graphics using following: initGraphics(320, 200, false); @@ -129,18 +119,34 @@ int DraciEngine::go() { _system->setPalette(palette, 0, 256); - // Draw a test string + // Fill screen with white + _system->fillScreen(255); + + // Draw big string + path = "Big.fon"; + DraciFont font(path); + Common::String testString = "Testing, testing, read all about it!"; Graphics::Surface *surf = _system->lockScreen(); - drawString(surf, "Testing, testing, read all about it!", 5, 60, 3); + font.drawString(surf, testString, + (320 - font.getStringWidth(testString, 1)) / 2, 130, 1); + + // Draw small string + path = "Small.fon"; + font.setFont(path); + testString = "I'm smaller than the font above me"; + font.drawString(surf, testString, + (320 - font.getStringWidth(testString, 1)) / 2, 150, 1); _system->unlockScreen(); + _system->updateScreen(); + // Draw and animate the dragon path = "OBR_AN.DFW"; ar.closeArchive(); ar.openArchive(path); - for (unsigned int t = 0; t < 25; ++t) { - debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); + for (unsigned int t = 0; t < 25; ++t) { + debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); // Load frame to memory f = ar[t]; @@ -159,7 +165,7 @@ int DraciEngine::go() { scr[j * w + i] = reader.readByte(); } } - _system->copyRectToScreen(scr, w, 0, 0, w, h); + _system->copyRectToScreen(scr, w, (320 - w) / 2, 60, w, h); _system->updateScreen(); _system->delayMillis(100); @@ -168,6 +174,7 @@ int DraciEngine::go() { // Free frame memory delete[] scr; } + getchar(); return 0; diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp new file mode 100644 index 0000000000..d1c5eaa3be --- /dev/null +++ b/engines/draci/font.cpp @@ -0,0 +1,148 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/file.h" + +#include "draci/draci.h" +#include "draci/font.h" + +namespace Draci { + +DraciFont::DraciFont(Common::String &filename) : + _fontHeight(0), _maxCharWidth(0), + _charWidths(NULL), _charData(0) { + setFont(filename); +} + +DraciFont::~DraciFont() { + freeFont(); +} + +bool DraciFont::setFont(Common::String &filename) { + + // If there is a font already loaded, free it + if (_charData) { + freeFont(); + } + + Common::File f; + + f.open(filename); + if (f.isOpen()) { + debugC(6, kDraciGeneralDebugLevel, "Opened font file %s", + filename.c_str()); + } else { + debugC(6, kDraciGeneralDebugLevel, "Error opening font file %s", + filename.c_str()); + return false; + } + + _maxCharWidth = f.readByte(); + _fontHeight = f.readByte(); + + // Read in the widths of the glyphs + _charWidths = new uint8[kCharNum]; + for (unsigned int i = 0; i < kCharNum; ++i) { + _charWidths[i] = f.readByte(); + } + + // Calculate size of font data + unsigned int fontDataSize = kCharNum * _maxCharWidth * _fontHeight; + + // Read in all glyphs + _charData = new byte[fontDataSize]; + f.read(_charData, fontDataSize); + + debugC(5, kDraciGeneralDebugLevel, "Font %s loaded", filename.c_str()); + + return true; +} + +void DraciFont::freeFont() { + delete[] _charWidths; + delete[] _charData; +} + +uint8 DraciFont::getCharWidth(uint8 chr) const { + return _charWidths[chr - kCharIndexOffset]; +} + +void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { + assert(dst != NULL); + byte *ptr = (byte *)dst->getBasePtr(tx, ty); + uint8 charIndex = chr - kCharIndexOffset; + int charOffset = charIndex * _fontHeight * _maxCharWidth; + uint8 currentWidth = _charWidths[charIndex]; + + for (uint8 y = 0; y < _fontHeight; ++y) { + + // Check for vertical overflow + if (ty + y < 0 || ty + y >= dst->h) { + continue; + } + + for (uint8 x = 0; x <= currentWidth; ++x) { + + // Check for horizontal overflow + if (tx + x < 0 || tx + x >= dst->w) { + continue; + } + + // Paint pixel + int curr = ((int)y) * _maxCharWidth + x; + ptr[x] = _charData[charOffset + curr]; + } + + // Advance to next row + ptr += dst->pitch; + } +} + +void DraciFont::drawString(Graphics::Surface *dst, Common::String str, + int x, int y, int spacing) const { + assert(dst != NULL); + int curx = x; + uint len = str.size(); + for (unsigned int i = 0; i < len; ++i) { + drawChar(dst, str[i], curx, y); + curx += getCharWidth(str[i]) + spacing; + } +} + +int DraciFont::getStringWidth(Common::String &str, int spacing) const { + int width = 0; + uint len = str.size(); + for (unsigned int i = 0; i < len; ++i) { + uint8 charIndex = str[i] - kCharIndexOffset; + width += _charWidths[charIndex]; + } + + // Add width of spaces, if any + width += (len - 1) * spacing; + + return width; +} + +} // End of namespace Draci diff --git a/engines/draci/font.h b/engines/draci/font.h new file mode 100644 index 0000000000..246bb4cc9f --- /dev/null +++ b/engines/draci/font.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "graphics/font.h" + +namespace Draci { + +class DraciFont { + +public: + DraciFont(Common::String &filename); + ~DraciFont(); + bool setFont(Common::String &filename); + uint8 getFontHeight() const { return _fontHeight; }; + uint8 getMaxCharWidth() const { return _maxCharWidth; }; + uint8 getCharWidth(byte chr) const; + void drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const; + void drawString(Graphics::Surface *dst, Common::String str, + int x, int y, int spacing = 0) const; + int getStringWidth(Common::String &str, int spacing = 0) const; + +private: + uint8 _fontHeight; + uint8 _maxCharWidth; + uint8 *_charWidths; + byte *_charData; + + // Number of glyphs in the font + static const unsigned int kCharNum = 138; + + // Chars are indexed from the ASCII space (decimal value 32) + static const unsigned int kCharIndexOffset = 32; + + void freeFont(); +}; + +} // End of namespace Draci diff --git a/engines/draci/module.mk b/engines/draci/module.mk index 98a0d90a31..1d2d6bc45e 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -4,7 +4,8 @@ MODULE_OBJS := \ draci.o \ detection.o \ barchive.o \ - gpldisasm.o + gpldisasm.o \ + font.o MODULE_DIRS += \ engines/draci -- cgit v1.2.3 From 51672df70002602eb09a6460259ac92960aeaf53 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 09:45:12 +0000 Subject: Properly documented everything (including the new DraciFont class). Reshuffled some old comments. svn-id: r41467 --- engines/draci/barchive.h | 5 +-- engines/draci/font.cpp | 46 ++++++++++++++++++++++++- engines/draci/font.h | 13 +++++-- engines/draci/gpldisasm.cpp | 82 ++++++++++++++++++++++++++++----------------- engines/draci/gpldisasm.h | 11 ++++-- 5 files changed, 119 insertions(+), 38 deletions(-) diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 0a0ecc832b..683ec50a67 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -31,7 +31,7 @@ namespace Draci { /** - * Represents individual files inside the archive + * Represents individual files inside the archive. */ struct BAFile { @@ -40,7 +40,8 @@ struct BAFile { byte *_data; byte _crc; - void closeFile(void) { //!< Releases the file data (for memory considerations) + /** Releases the file data (for memory considerations) */ + void closeFile(void) { delete _data; _data = NULL; } diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index d1c5eaa3be..5ea46ddb17 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -33,13 +33,30 @@ namespace Draci { DraciFont::DraciFont(Common::String &filename) : _fontHeight(0), _maxCharWidth(0), _charWidths(NULL), _charData(0) { - setFont(filename); + setFont(filename); } DraciFont::~DraciFont() { freeFont(); } +/** + * @brief Loads fonts from a file + * @param path Path to font file + * @return true if the font was loaded successfully, false otherwise + * + * Loads fonts from a file into a DraciFont instance. The original game uses two + * fonts (located inside files "Small.fon" and "Big.fon"). The characters in the + * font are indexed from the ASCII space (decimal value 32) so an appropriate + * offset must be added to convert them to equivalent char values, + * i.e. kDraciIndexOffset. + * + * font format: [1 byte] maximum character width + * [1 byte] font height + * [138 bytes] character widths of all 138 characters in the font + * [138 * fontHeight * maxWidth bytes] character data, stored row-wise + */ + bool DraciFont::setFont(Common::String &filename) { // If there is a font already loaded, free it @@ -89,6 +106,14 @@ uint8 DraciFont::getCharWidth(uint8 chr) const { return _charWidths[chr - kCharIndexOffset]; } +/** + * @brief Draw a char to a Graphics::Surface + * @param dst Pointer to the destination surface + * @param chr Character to draw (ASCII value) + * @param tx Horizontal offset on the surface + * @param ty Vertical offset on the surface + */ + void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { assert(dst != NULL); byte *ptr = (byte *)dst->getBasePtr(tx, ty); @@ -120,6 +145,16 @@ void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) cons } } +/** + * @brief Draw a string to a Graphics::Surface + * + * @param dst Pointer to the destination surface + * @param str String to draw + * @param x Horizontal offset on the surface + * @param y Vertical offset on the surface + * @param spacing Space to leave between individual characters. Defaults to 0. + */ + void DraciFont::drawString(Graphics::Surface *dst, Common::String str, int x, int y, int spacing) const { assert(dst != NULL); @@ -131,6 +166,15 @@ void DraciFont::drawString(Graphics::Surface *dst, Common::String str, } } +/** + * @brief Calculate the width of a string when drawn in the current font + * + * @param str String to draw + * @param spacing Space to leave between individual characters. Defaults to 0. + * + * @return The calculated width of the string + */ + int DraciFont::getStringWidth(Common::String &str, int spacing) const { int width = 0; uint len = str.size(); diff --git a/engines/draci/font.h b/engines/draci/font.h index 246bb4cc9f..d74951c783 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -27,6 +27,10 @@ namespace Draci { +/** + * Represents the game's fonts. See docs for setFont() for font format details. + */ + class DraciFont { public: @@ -44,15 +48,20 @@ public: private: uint8 _fontHeight; uint8 _maxCharWidth; + + /** Pointer to an array of individual char widths */ uint8 *_charWidths; + + /** Pointer to a raw byte array representing font pixels stored row-wise */ byte *_charData; - // Number of glyphs in the font + /** Number of glyphs in the font */ static const unsigned int kCharNum = 138; - // Chars are indexed from the ASCII space (decimal value 32) + /** Chars are indexed from the ASCII space (decimal value 32) */ static const unsigned int kCharIndexOffset = 32; + /** Internal function for freeing fonts when destructing/loading another */ void freeFont(); }; diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp index 9024a2dd72..17ed5c7494 100644 --- a/engines/draci/gpldisasm.cpp +++ b/engines/draci/gpldisasm.cpp @@ -23,37 +23,6 @@ * */ -/** - * @brief GPL2 bytecode disassembler - * @param gplcode A pointer to the bytecode - * len Length of the bytecode - * - * GPL2 is short for Game Programming Language 2 which is the script language - * used by Draci Historie. This is a simple disassembler for the language. - * - * A compiled GPL2 program consists of a stream of bytes representing commands - * and their parameters. The syntax is as follows: - * - * Syntax of a command: - * - * - * Syntax of a parameter: - * - 1: integer number literally passed to the program - * - 2-1: string stored in the reservouir of game strings (i.e. something to be - * displayed) and stored as an index in this list - * - 2-2: string resolved by the compiler (i.e., a path to another file) and - * replaced by an integer index of this entity in the appropriate namespace - * (e.g., the index of the palette, location, ...) - * - 3-0: relative jump to a label defined in this code. Each label must be - * first declared in the beginning of the program. - * - 3-1 .. 3-9: index of an entity in several namespaces, defined in file ident - * - 4: mathematical expression compiled into a postfix format - * - * In the compiled program, parameters of type 1..3 are represented by a single - * 16-bit integer. The called command knows by its definition what namespace the - * value comes from. - */ - #include "common/debug.h" #include "common/stream.h" #include "common/stack.h" @@ -64,6 +33,8 @@ namespace Draci { // FIXME: Change parameter types to names once I figure out what they are exactly + +/** A table of all the commands the game player uses */ GPL2Command gplCommands[] = { { 0, 0, "gplend", 0, { 0 } }, { 0, 1, "exit", 0, { 0 } }, @@ -122,6 +93,7 @@ GPL2Command gplCommands[] = { { 27, 1, "FeedPassword", 3, { 1, 1, 1 } } }; +/** Operators used by the mathematical evaluator */ Common::String operators[] = { "oper_and", "oper_or", @@ -139,6 +111,7 @@ Common::String operators[] = { "oper_minus" }; +/** Functions used by the mathematical evaluator */ Common::String functions[] = { "F_Not", "F_Random", @@ -161,6 +134,7 @@ Common::String functions[] = { const unsigned int kNumCommands = sizeof gplCommands / sizeof gplCommands[0]; +/** Type of mathematical object */ enum mathExpressionObject { kMathEnd, kMathNumber, @@ -170,6 +144,12 @@ enum mathExpressionObject { }; // FIXME: The evaluator is now complete but I still need to implement callbacks + +/** + * @brief Evaluates mathematical expressions + * @param reader Stream reader set to the beginning of the expression + */ + void handleMathExpression(Common::MemoryReadStream &reader) { Common::Stack stk; mathExpressionObject obj; @@ -224,6 +204,15 @@ void handleMathExpression(Common::MemoryReadStream &reader) { return; } +/** + * @brief Find the current command in the internal table + * + * @param num Command number + * @param subnum Command subnumer + * + * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command + * struct representing the command. + */ GPL2Command *findCommand(byte num, byte subnum) { unsigned int i = 0; while (1) { @@ -245,6 +234,37 @@ GPL2Command *findCommand(byte num, byte subnum) { return NULL; } +/** + * @brief GPL2 bytecode disassembler + * @param gplcode A pointer to the bytecode + * @param len Length of the bytecode + * + * GPL2 is short for Game Programming Language 2 which is the script language + * used by Draci Historie. This is a simple disassembler for the language. + * + * A compiled GPL2 program consists of a stream of bytes representing commands + * and their parameters. The syntax is as follows: + * + * Syntax of a command: + * + * + * Syntax of a parameter: + * - 1: integer number literally passed to the program + * - 2-1: string stored in the reservouir of game strings (i.e. something to be + * displayed) and stored as an index in this list + * - 2-2: string resolved by the compiler (i.e., a path to another file) and + * replaced by an integer index of this entity in the appropriate namespace + * (e.g., the index of the palette, location, ...) + * - 3-0: relative jump to a label defined in this code. Each label must be + * first declared in the beginning of the program. + * - 3-1 .. 3-9: index of an entity in several namespaces, defined in file ident + * - 4: mathematical expression compiled into a postfix format + * + * In the compiled program, parameters of type 1..3 are represented by a single + * 16-bit integer. The called command knows by its definition what namespace the + * value comes from. + */ + int gpldisasm(byte *gplcode, uint16 len) { Common::MemoryReadStream reader(gplcode, len); diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h index d26fb5c978..17bd75767d 100644 --- a/engines/draci/gpldisasm.h +++ b/engines/draci/gpldisasm.h @@ -30,7 +30,14 @@ namespace Draci { -// FIXME: Add parameter types and function handlers +// FIXME: Add function handlers + +/** + * Represents a single command in the GPL scripting language bytecode. + * Each command is represented in the bytecode by a command number and a + * subnumber. + */ + struct GPL2Command { byte _number; byte _subNumber; @@ -39,7 +46,7 @@ struct GPL2Command { int _paramTypes[3]; }; -const int kMaxParams = 3; +const int kMaxParams = 3; //!< The maximum number of parameters for a GPL command int gpldisasm(byte *gplcode, uint16 len); -- cgit v1.2.3 From 2308748f01e5ef80c22bd489a218aeee85250aa3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 09:52:35 +0000 Subject: Made the DraciFont::freeFont() method safe to call in any circumstance by making it check for NULL pointers itself to prevent double free / corruption. This also fixes a potential bug in the destructor. svn-id: r41469 --- engines/draci/font.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 5ea46ddb17..a99dd06a58 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -59,10 +59,8 @@ DraciFont::~DraciFont() { bool DraciFont::setFont(Common::String &filename) { - // If there is a font already loaded, free it - if (_charData) { - freeFont(); - } + // Free previously loaded font (if any) + freeFont(); Common::File f; @@ -98,8 +96,11 @@ bool DraciFont::setFont(Common::String &filename) { } void DraciFont::freeFont() { - delete[] _charWidths; - delete[] _charData; + // If there is a font already loaded, free it + if (_charData) { + delete[] _charWidths; + delete[] _charData; + } } uint8 DraciFont::getCharWidth(uint8 chr) const { -- cgit v1.2.3 From 32d12e90e3624e57d5f0eb1176f542ec44bd9ef8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 10:22:43 +0000 Subject: Removed overflow/underflow checks from DraciFont::drawChar(). Instead, we now calculate the number of pixels that can be drawn without overflowing beforehand. Also added asserts to catch any negative value passed for the coordinates. svn-id: r41471 --- engines/draci/draci.cpp | 2 +- engines/draci/font.cpp | 32 ++++++++++++++++++-------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 69460029d3..58f5261193 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -133,7 +133,7 @@ int DraciEngine::go() { // Draw small string path = "Small.fon"; font.setFont(path); - testString = "I'm smaller than the font above me"; + testString = "I'm smaller than the font above me."; font.drawString(surf, testString, (320 - font.getStringWidth(testString, 1)) / 2, 150, 1); _system->unlockScreen(); diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index a99dd06a58..808feb7d3c 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -117,27 +117,27 @@ uint8 DraciFont::getCharWidth(uint8 chr) const { void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { assert(dst != NULL); + assert(tx >= 0); + assert(ty >= 0); + byte *ptr = (byte *)dst->getBasePtr(tx, ty); uint8 charIndex = chr - kCharIndexOffset; int charOffset = charIndex * _fontHeight * _maxCharWidth; uint8 currentWidth = _charWidths[charIndex]; - for (uint8 y = 0; y < _fontHeight; ++y) { + // Determine how many pixels to draw horizontally (to prevent overflow) + int xSpaceLeft = dst->w - tx - 1; + int xPixelsToDraw = (currentWidth < xSpaceLeft) ? currentWidth : xSpaceLeft; - // Check for vertical overflow - if (ty + y < 0 || ty + y >= dst->h) { - continue; - } + // Determine how many pixels to draw vertically + int ySpaceLeft = dst->h - ty - 1; + int yPixelsToDraw = (_fontHeight < ySpaceLeft) ? _fontHeight : ySpaceLeft; + + for (int y = 0; y < yPixelsToDraw; ++y) { + for (int x = 0; x <= xPixelsToDraw; ++x) { - for (uint8 x = 0; x <= currentWidth; ++x) { - - // Check for horizontal overflow - if (tx + x < 0 || tx + x >= dst->w) { - continue; - } - // Paint pixel - int curr = ((int)y) * _maxCharWidth + x; + int curr = y * _maxCharWidth + x; ptr[x] = _charData[charOffset + curr]; } @@ -158,9 +158,13 @@ void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) cons void DraciFont::drawString(Graphics::Surface *dst, Common::String str, int x, int y, int spacing) const { - assert(dst != NULL); + assert(dst != NULL); + assert(x >= 0); + assert(y >= 0); + int curx = x; uint len = str.size(); + for (unsigned int i = 0; i < len; ++i) { drawChar(dst, str[i], curx, y); curx += getCharWidth(str[i]) + spacing; -- cgit v1.2.3 From 837f76f61f9e6c7d5c2788c673e8a93fa9700482 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 10:25:05 +0000 Subject: Made DraciFont::drawString() take a String reference instead of a copy. svn-id: r41472 --- engines/draci/font.cpp | 2 +- engines/draci/font.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 808feb7d3c..9f91e466ea 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -156,7 +156,7 @@ void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) cons * @param spacing Space to leave between individual characters. Defaults to 0. */ -void DraciFont::drawString(Graphics::Surface *dst, Common::String str, +void DraciFont::drawString(Graphics::Surface *dst, Common::String &str, int x, int y, int spacing) const { assert(dst != NULL); assert(x >= 0); diff --git a/engines/draci/font.h b/engines/draci/font.h index d74951c783..b8c00af391 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -41,7 +41,7 @@ public: uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; void drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const; - void drawString(Graphics::Surface *dst, Common::String str, + void drawString(Graphics::Surface *dst, Common::String &str, int x, int y, int spacing = 0) const; int getStringWidth(Common::String &str, int spacing = 0) const; -- cgit v1.2.3 From 5808e4f940b6515a2cf61ba39f8b15b40a315f49 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 10:37:46 +0000 Subject: Made DraciFont::drawString() return early if the string is too long to fit on the screen. svn-id: r41475 --- engines/draci/draci.cpp | 6 +++++- engines/draci/font.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 58f5261193..13e5ffae6a 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -136,8 +136,12 @@ int DraciEngine::go() { testString = "I'm smaller than the font above me."; font.drawString(surf, testString, (320 - font.getStringWidth(testString, 1)) / 2, 150, 1); - _system->unlockScreen(); + // Overflow handling test + testString = "Checking overflooooooooooooooooooooooooow..."; + font.drawString(surf, testString, 50, 170, 1); + + _system->unlockScreen(); _system->updateScreen(); // Draw and animate the dragon diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 9f91e466ea..4ef1b578db 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -166,6 +166,12 @@ void DraciFont::drawString(Graphics::Surface *dst, Common::String &str, uint len = str.size(); for (unsigned int i = 0; i < len; ++i) { + + // Return early if there's no more space on the screen + if (curx >= dst->w) { + return; + } + drawChar(dst, str[i], curx, y); curx += getCharWidth(str[i]) + spacing; } -- cgit v1.2.3 From fc22ab5748420f49f1c761fbc7a248ef3adce65f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 10:39:33 +0000 Subject: Replaced a magic number with a proper constant. svn-id: r41476 --- engines/draci/gpldisasm.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h index 17bd75767d..9f33bafc94 100644 --- a/engines/draci/gpldisasm.h +++ b/engines/draci/gpldisasm.h @@ -30,6 +30,9 @@ namespace Draci { +/** The maximum number of parameters for a GPL command */ +const int kMaxParams = 3; + // FIXME: Add function handlers /** @@ -43,11 +46,9 @@ struct GPL2Command { byte _subNumber; Common::String _name; uint16 _numParams; - int _paramTypes[3]; + int _paramTypes[kMaxParams]; }; -const int kMaxParams = 3; //!< The maximum number of parameters for a GPL command - int gpldisasm(byte *gplcode, uint16 len); } -- cgit v1.2.3 From 02cd93421dcedfdb2d3fd0005707e3d351368f1d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 12 Jun 2009 11:32:44 +0000 Subject: Fixed evaluation of GPL mathematical expressions. The evaluator now checks that, at the end of the evaluation, the stack only contains one value (i.e. the result of the expression). svn-id: r41477 --- engines/draci/gpldisasm.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp index 17ed5c7494..ee7b128529 100644 --- a/engines/draci/gpldisasm.cpp +++ b/engines/draci/gpldisasm.cpp @@ -160,6 +160,10 @@ void handleMathExpression(Common::MemoryReadStream &reader) { uint16 value; while (1) { if (obj == kMathEnd) { + // Check whether the expression was evaluated correctly + // The stack should contain only one value after the evaluation + // i.e. the result of the expression + assert(stk.size() == 1 && "Mathematical expression error"); break; } @@ -177,6 +181,10 @@ void handleMathExpression(Common::MemoryReadStream &reader) { value = reader.readUint16LE(); stk.pop(); stk.pop(); + + // FIXME: Pushing dummy value for now, but should push return value + stk.push(0); + debugC(3, kDraciBytecodeDebugLevel, "\t\t-operator %s", operators[value-1].c_str()); break; @@ -189,6 +197,8 @@ void handleMathExpression(Common::MemoryReadStream &reader) { case kMathFunctionCall: value = reader.readUint16LE(); + + stk.pop(); // FIXME: Pushing dummy value for now, but should push return value stk.push(0); -- cgit v1.2.3 From b8ec907ea0e6546da266067c5cd4b5b8143b5ed7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 12:44:12 +0000 Subject: Added a Sprite class for handling sprites in the Draci format transparently. Modified the test animation to use it. svn-id: r41509 --- engines/draci/draci.cpp | 28 +++++----------- engines/draci/module.mk | 3 +- engines/draci/sprite.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ engines/draci/sprite.h | 60 ++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 20 deletions(-) create mode 100644 engines/draci/sprite.cpp create mode 100644 engines/draci/sprite.h diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 13e5ffae6a..42c5f35428 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -35,6 +35,7 @@ #include "draci/barchive.h" #include "draci/gpldisasm.h" #include "draci/font.h" +#include "draci/sprite.h" namespace Draci { @@ -88,6 +89,13 @@ int DraciEngine::init() { return 0; } +// Temporary hack + +void drawFrame(OSystem *syst, BAFile *frame) { + Sprite sp(frame->_data, frame->_length, ((320 - 50) / 2), 60, true); + syst->copyRectToScreen(sp._data, sp._width, sp._x, sp._y, sp._width, sp._height); +} + int DraciEngine::go() { debugC(1, kDraciGeneralDebugLevel, "DraciEngine::go()"); @@ -154,29 +162,11 @@ int DraciEngine::go() { // Load frame to memory f = ar[t]; - Common::MemoryReadStream reader(f->_data, f->_length); - - // Read in frame width and height - uint16 w = reader.readUint16LE(); - uint16 h = reader.readUint16LE(); - - // Allocate frame memory - byte *scr = new byte[w * h]; - - // Draw frame - for (uint16 i = 0; i < w; ++i) { - for (uint16 j = 0; j < h; ++j) { - scr[j * w + i] = reader.readByte(); - } - } - _system->copyRectToScreen(scr, w, (320 - w) / 2, 60, w, h); + drawFrame(_system, f); _system->updateScreen(); _system->delayMillis(100); debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); - - // Free frame memory - delete[] scr; } getchar(); diff --git a/engines/draci/module.mk b/engines/draci/module.mk index 1d2d6bc45e..b41154b576 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -5,7 +5,8 @@ MODULE_OBJS := \ detection.o \ barchive.o \ gpldisasm.o \ - font.o + font.o \ + sprite.o MODULE_DIRS += \ engines/draci diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp new file mode 100644 index 0000000000..790bc4cc2e --- /dev/null +++ b/engines/draci/sprite.cpp @@ -0,0 +1,85 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ +#include "common/stream.h" + +#include "draci/sprite.h" + +namespace Draci { + +/** + * Constructor for loading sprites from a raw data buffer, one byte per pixel. + */ +Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, + bool columnwise) : _width(width), _height(height), _x(x), _y(y), _data(NULL) { + + _data = new byte[width * height]; + + if (!columnwise) { + memcpy(_data, raw_data, width * height); + return; + } + else { + for (uint16 i = 0; i < width; ++i) { + for (uint16 j = 0; j < height; ++j) { + _data[j * width + i] = *raw_data++; + } + } + } + } + +/** + * Constructor for loading sprites from a sprite-formatted buffer, one byte per + * pixel. + */ +Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, + bool columnwise) : _x(x), _y(y), _data(NULL) { + + Common::MemoryReadStream reader(sprite_data, length); + + _width = reader.readUint16LE(); + _height = reader.readUint16LE(); + + _data = new byte[_width * _height]; + + if (!columnwise) { + reader.read(_data, _width * _height); + } + else { + for (uint16 i = 0; i < _width; ++i) { + for (uint16 j = 0; j < _height; ++j) { + _data[j * _width + i] = reader.readByte(); + } + } + } + } + +Sprite::~Sprite() { + delete[] _data; +} + + +} // End of namespace Draci + + diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h new file mode 100644 index 0000000000..28d51ccbf4 --- /dev/null +++ b/engines/draci/sprite.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. + * + * $URL$ + * $Id$ + * + */ + +namespace Draci { + +/** + * Represents a Draci Historie sprite. Supplies two constructors; one for + * loading a sprite from a raw data buffer and one for loading a sprite in + * the Draci sprite format. Supports loading the sprite from a column-wise + * format (transforming them to row-wise) since that is the way the sprites + * are stored in the original game files. + * + * Sprite format: + * [uint16LE] sprite width + * [uint16LE] sprite height + * [height * width bytes] image pixels stored column-wise, one byte per pixel + */ + +class Sprite { + +public: + Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x = 0, uint16 y = 0, + bool columnwise = false); + + Sprite(byte *sprite_data, uint16 length, uint16 x = 0, uint16 y = 0, + bool columnwise = false); + + ~Sprite(); + + byte *_data; + uint16 _width; + uint16 _height; + uint16 _x, _y; +}; + + +} // End of namespace Draci + -- cgit v1.2.3 From d6ddbf7062ecd1cf06ea28d194ff3becf60a2c18 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 13:10:12 +0000 Subject: Removed superfluous checks for NULL in DraciFont::freeFont(). svn-id: r41510 --- engines/draci/font.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 4ef1b578db..19bcbbafbf 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -96,11 +96,8 @@ bool DraciFont::setFont(Common::String &filename) { } void DraciFont::freeFont() { - // If there is a font already loaded, free it - if (_charData) { - delete[] _charWidths; - delete[] _charData; - } + delete[] _charWidths; + delete[] _charData; } uint8 DraciFont::getCharWidth(uint8 chr) const { @@ -109,6 +106,7 @@ uint8 DraciFont::getCharWidth(uint8 chr) const { /** * @brief Draw a char to a Graphics::Surface + * * @param dst Pointer to the destination surface * @param chr Character to draw (ASCII value) * @param tx Horizontal offset on the surface -- cgit v1.2.3 From 92dd6d5474e4474e51434c3e024bf897cc7d4673 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 13:32:21 +0000 Subject: Reworded DraciFont docs (with regards to mentioning ASCII). svn-id: r41511 --- engines/draci/font.cpp | 9 +++++---- engines/draci/font.h | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 19bcbbafbf..72434d9aa0 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -47,9 +47,10 @@ DraciFont::~DraciFont() { * * Loads fonts from a file into a DraciFont instance. The original game uses two * fonts (located inside files "Small.fon" and "Big.fon"). The characters in the - * font are indexed from the ASCII space (decimal value 32) so an appropriate - * offset must be added to convert them to equivalent char values, - * i.e. kDraciIndexOffset. + * font are indexed from the space character so an appropriate offset must be + * added to convert them to equivalent char values, i.e. kDraciIndexOffset. + * Characters in the higher range are non-ASCII and vary between different + * language versions of the game. * * font format: [1 byte] maximum character width * [1 byte] font height @@ -108,7 +109,7 @@ uint8 DraciFont::getCharWidth(uint8 chr) const { * @brief Draw a char to a Graphics::Surface * * @param dst Pointer to the destination surface - * @param chr Character to draw (ASCII value) + * @param chr Character to draw * @param tx Horizontal offset on the surface * @param ty Vertical offset on the surface */ diff --git a/engines/draci/font.h b/engines/draci/font.h index b8c00af391..e222cd5e11 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -58,7 +58,9 @@ private: /** Number of glyphs in the font */ static const unsigned int kCharNum = 138; - /** Chars are indexed from the ASCII space (decimal value 32) */ + /** Chars are indexed from the space character so this should be subtracted + * to get the index of a glyph + */ static const unsigned int kCharIndexOffset = 32; /** Internal function for freeing fonts when destructing/loading another */ -- cgit v1.2.3 From 34d41f61aad64a67807846d832a6533efeef1d80 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 14 Jun 2009 13:41:12 +0000 Subject: Designate hack according to our conventions svn-id: r41512 --- engines/draci/draci.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 42c5f35428..6f4268632a 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -89,6 +89,7 @@ int DraciEngine::init() { return 0; } +// HACK // Temporary hack void drawFrame(OSystem *syst, BAFile *frame) { -- cgit v1.2.3 From 682c272e53196bbb4c59bcdc3fe8aa1380bfdea1 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 14 Jun 2009 13:49:28 +0000 Subject: Replace hackish getch() with proper event loop at end of the demo. svn-id: r41513 --- engines/draci/draci.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 6f4268632a..7095ce2e82 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -170,7 +170,20 @@ int DraciEngine::go() { debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); } - getchar(); + Common::Event event; + bool quit = false; + while (!quit) { + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + quit = true; + default: + break; + } + } + _system->updateScreen(); + _system->delayMillis(20); + } return 0; } -- cgit v1.2.3 From f6f7a1e31a9beb8ca37097098e08c0b263ca57ec Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 14 Jun 2009 13:51:07 +0000 Subject: Whitespce fixes svn-id: r41514 --- engines/draci/sprite.cpp | 50 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 790bc4cc2e..4e17c59c7d 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -32,48 +32,46 @@ namespace Draci { * Constructor for loading sprites from a raw data buffer, one byte per pixel. */ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, - bool columnwise) : _width(width), _height(height), _x(x), _y(y), _data(NULL) { + bool columnwise) : _width(width), _height(height), _x(x), _y(y), _data(NULL) { - _data = new byte[width * height]; + _data = new byte[width * height]; - if (!columnwise) { - memcpy(_data, raw_data, width * height); - return; - } - else { - for (uint16 i = 0; i < width; ++i) { - for (uint16 j = 0; j < height; ++j) { - _data[j * width + i] = *raw_data++; - } + if (!columnwise) { + memcpy(_data, raw_data, width * height); + return; + } else { + for (uint16 i = 0; i < width; ++i) { + for (uint16 j = 0; j < height; ++j) { + _data[j * width + i] = *raw_data++; } } } +} /** * Constructor for loading sprites from a sprite-formatted buffer, one byte per * pixel. */ Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, - bool columnwise) : _x(x), _y(y), _data(NULL) { + bool columnwise) : _x(x), _y(y), _data(NULL) { - Common::MemoryReadStream reader(sprite_data, length); + Common::MemoryReadStream reader(sprite_data, length); - _width = reader.readUint16LE(); - _height = reader.readUint16LE(); + _width = reader.readUint16LE(); + _height = reader.readUint16LE(); - _data = new byte[_width * _height]; + _data = new byte[_width * _height]; - if (!columnwise) { - reader.read(_data, _width * _height); - } - else { - for (uint16 i = 0; i < _width; ++i) { - for (uint16 j = 0; j < _height; ++j) { - _data[j * _width + i] = reader.readByte(); - } + if (!columnwise) { + reader.read(_data, _width * _height); + } else { + for (uint16 i = 0; i < _width; ++i) { + for (uint16 j = 0; j < _height; ++j) { + _data[j * _width + i] = reader.readByte(); } - } - } + } + } +} Sprite::~Sprite() { delete[] _data; -- cgit v1.2.3 From 7e7e96e77d849439ceed742f56cf757d116de3f6 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 14:12:28 +0000 Subject: Replaced a call to getEventManager() with Engine::_eventMan. svn-id: r41518 --- engines/draci/draci.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 7095ce2e82..1a2660acc0 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -56,7 +56,7 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) Common::addDebugChannel(kDraciArchiverDebugLevel, "archiver", "BAR archiver debug info"); // Don't forget to register your random source - syst->getEventManager()->registerRandomSource(_rnd, "draci"); + _eventMan->registerRandomSource(_rnd, "draci"); } int DraciEngine::init() { -- cgit v1.2.3 From 15a35e359d6a5a973a434b03626bc0e1e5001a0f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 16:21:44 +0000 Subject: Changed DraciFont API to accept const Strings when loading fonts and added constants for font types. svn-id: r41522 --- engines/draci/draci.cpp | 6 ++---- engines/draci/font.cpp | 4 ++-- engines/draci/font.h | 7 +++++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 1a2660acc0..151fb046ed 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -132,16 +132,14 @@ int DraciEngine::go() { _system->fillScreen(255); // Draw big string - path = "Big.fon"; - DraciFont font(path); + DraciFont font(kFontBig); Common::String testString = "Testing, testing, read all about it!"; Graphics::Surface *surf = _system->lockScreen(); font.drawString(surf, testString, (320 - font.getStringWidth(testString, 1)) / 2, 130, 1); // Draw small string - path = "Small.fon"; - font.setFont(path); + font.setFont(kFontSmall); testString = "I'm smaller than the font above me."; font.drawString(surf, testString, (320 - font.getStringWidth(testString, 1)) / 2, 150, 1); diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 72434d9aa0..284c6b8f48 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -30,7 +30,7 @@ namespace Draci { -DraciFont::DraciFont(Common::String &filename) : +DraciFont::DraciFont(const Common::String &filename) : _fontHeight(0), _maxCharWidth(0), _charWidths(NULL), _charData(0) { setFont(filename); @@ -58,7 +58,7 @@ DraciFont::~DraciFont() { * [138 * fontHeight * maxWidth bytes] character data, stored row-wise */ -bool DraciFont::setFont(Common::String &filename) { +bool DraciFont::setFont(const Common::String &filename) { // Free previously loaded font (if any) freeFont(); diff --git a/engines/draci/font.h b/engines/draci/font.h index e222cd5e11..b28b1ec338 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -27,6 +27,9 @@ namespace Draci { +const Common::String kFontSmall("Small.fon"); +const Common::String kFontBig("Big.fon"); + /** * Represents the game's fonts. See docs for setFont() for font format details. */ @@ -34,9 +37,9 @@ namespace Draci { class DraciFont { public: - DraciFont(Common::String &filename); + DraciFont(const Common::String &filename); ~DraciFont(); - bool setFont(Common::String &filename); + bool setFont(const Common::String &filename); uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; -- cgit v1.2.3 From 149b45f7a59c5319c912d13d8259b63b5fbb2a21 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 16:33:20 +0000 Subject: Renamed DraciFont class to Font to be more consistent with the rest of the classes and other engines. svn-id: r41523 --- engines/draci/draci.cpp | 2 +- engines/draci/font.cpp | 18 +++++++++--------- engines/draci/font.h | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 151fb046ed..a75080d31d 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -132,7 +132,7 @@ int DraciEngine::go() { _system->fillScreen(255); // Draw big string - DraciFont font(kFontBig); + Font font(kFontBig); Common::String testString = "Testing, testing, read all about it!"; Graphics::Surface *surf = _system->lockScreen(); font.drawString(surf, testString, diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 284c6b8f48..104b341fd1 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -30,13 +30,13 @@ namespace Draci { -DraciFont::DraciFont(const Common::String &filename) : +Font::Font(const Common::String &filename) : _fontHeight(0), _maxCharWidth(0), _charWidths(NULL), _charData(0) { setFont(filename); } -DraciFont::~DraciFont() { +Font::~Font() { freeFont(); } @@ -45,7 +45,7 @@ DraciFont::~DraciFont() { * @param path Path to font file * @return true if the font was loaded successfully, false otherwise * - * Loads fonts from a file into a DraciFont instance. The original game uses two + * Loads fonts from a file into a Font instance. The original game uses two * fonts (located inside files "Small.fon" and "Big.fon"). The characters in the * font are indexed from the space character so an appropriate offset must be * added to convert them to equivalent char values, i.e. kDraciIndexOffset. @@ -58,7 +58,7 @@ DraciFont::~DraciFont() { * [138 * fontHeight * maxWidth bytes] character data, stored row-wise */ -bool DraciFont::setFont(const Common::String &filename) { +bool Font::setFont(const Common::String &filename) { // Free previously loaded font (if any) freeFont(); @@ -96,12 +96,12 @@ bool DraciFont::setFont(const Common::String &filename) { return true; } -void DraciFont::freeFont() { +void Font::freeFont() { delete[] _charWidths; delete[] _charData; } -uint8 DraciFont::getCharWidth(uint8 chr) const { +uint8 Font::getCharWidth(uint8 chr) const { return _charWidths[chr - kCharIndexOffset]; } @@ -114,7 +114,7 @@ uint8 DraciFont::getCharWidth(uint8 chr) const { * @param ty Vertical offset on the surface */ -void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { +void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { assert(dst != NULL); assert(tx >= 0); assert(ty >= 0); @@ -155,7 +155,7 @@ void DraciFont::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) cons * @param spacing Space to leave between individual characters. Defaults to 0. */ -void DraciFont::drawString(Graphics::Surface *dst, Common::String &str, +void Font::drawString(Graphics::Surface *dst, Common::String &str, int x, int y, int spacing) const { assert(dst != NULL); assert(x >= 0); @@ -185,7 +185,7 @@ void DraciFont::drawString(Graphics::Surface *dst, Common::String &str, * @return The calculated width of the string */ -int DraciFont::getStringWidth(Common::String &str, int spacing) const { +int Font::getStringWidth(Common::String &str, int spacing) const { int width = 0; uint len = str.size(); for (unsigned int i = 0; i < len; ++i) { diff --git a/engines/draci/font.h b/engines/draci/font.h index b28b1ec338..ddc6eaec7e 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -34,11 +34,11 @@ const Common::String kFontBig("Big.fon"); * Represents the game's fonts. See docs for setFont() for font format details. */ -class DraciFont { +class Font { public: - DraciFont(const Common::String &filename); - ~DraciFont(); + Font(const Common::String &filename); + ~Font(); bool setFont(const Common::String &filename); uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; -- cgit v1.2.3 From 718f84fb9703f894f11d5d6e76b34bc0e345da42 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 18:59:31 +0000 Subject: Added a Font _font variable to the engine instance. Fixed font colour handling by replacing the appropriate colours before drawing. Added Font::setColour() method for changing the current font colour. Added include guards to draci/font.h. Moved kFontBig and kFontSmall constants to draci/font.cpp to prevent redefinition errors. svn-id: r41524 --- engines/draci/draci.cpp | 18 ++++++++++-------- engines/draci/draci.h | 4 ++++ engines/draci/font.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++++-- engines/draci/font.h | 28 +++++++++++++++++++++++++-- 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index a75080d31d..103f595a12 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -49,7 +49,7 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) // However this is the place to specify all default directories //Common::File::addDefaultDirectory(_gameDataPath + "sound/"); - + // Here is the right place to set up the engine specific debug levels Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug level"); Common::addDebugChannel(kDraciBytecodeDebugLevel, "bytecode", "GPL bytecode instructions"); @@ -63,6 +63,9 @@ int DraciEngine::init() { // Initialize graphics using following: initGraphics(320, 200, false); + // Load default font + _font.setFont(kFontBig); + // Basic archive test debugC(2, kDraciGeneralDebugLevel, "Running archive tests..."); Common::String path("INIT.DFW"); @@ -132,21 +135,20 @@ int DraciEngine::go() { _system->fillScreen(255); // Draw big string - Font font(kFontBig); Common::String testString = "Testing, testing, read all about it!"; Graphics::Surface *surf = _system->lockScreen(); - font.drawString(surf, testString, - (320 - font.getStringWidth(testString, 1)) / 2, 130, 1); + _font.drawString(surf, testString, + (320 - _font.getStringWidth(testString, 1)) / 2, 130, 1); // Draw small string - font.setFont(kFontSmall); + _font.setFont(kFontSmall); testString = "I'm smaller than the font above me."; - font.drawString(surf, testString, - (320 - font.getStringWidth(testString, 1)) / 2, 150, 1); + _font.drawString(surf, testString, + (320 - _font.getStringWidth(testString, 1)) / 2, 150, 1); // Overflow handling test testString = "Checking overflooooooooooooooooooooooooow..."; - font.drawString(surf, testString, 50, 170, 1); + _font.drawString(surf, testString, 50, 170, 1); _system->unlockScreen(); _system->updateScreen(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index aabbe4482b..8a0e073101 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -30,6 +30,8 @@ #include "engines/engine.h" #include "engines/advancedDetector.h" +#include "draci/font.h" + namespace Draci { class DraciEngine : public Engine { @@ -43,6 +45,8 @@ public: bool hasFeature(Engine::EngineFeature f) const; + Font _font; + private: Common::RandomSource _rnd; }; diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 104b341fd1..99f1d37a23 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -30,16 +30,40 @@ namespace Draci { +const Common::String kFontSmall("Small.fon"); +const Common::String kFontBig("Big.fon"); + +Font::Font() : + _fontHeight(0), _maxCharWidth(0), + _charWidths(NULL), _charData(0) { + + setFont(kFontBig); + + _currentFontColour = _fontColour1; +} + Font::Font(const Common::String &filename) : _fontHeight(0), _maxCharWidth(0), _charWidths(NULL), _charData(0) { + setFont(filename); + + _currentFontColour = _fontColour1; } Font::~Font() { freeFont(); } +/** + * @brief Sets the varying font colour + * @param colour The new font colour + */ + +void Font::setColour(uint8 colour) { + _currentFontColour = colour; +} + /** * @brief Loads fonts from a file * @param path Path to font file @@ -135,9 +159,31 @@ void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { for (int y = 0; y < yPixelsToDraw; ++y) { for (int x = 0; x <= xPixelsToDraw; ++x) { - // Paint pixel int curr = y * _maxCharWidth + x; - ptr[x] = _charData[charOffset + curr]; + int colour = _charData[charOffset + curr]; + + // Replace colour with font colours + switch (colour) { + + case 254: + colour = _currentFontColour; + break; + + case 253: + colour = _fontColour2; + break; + + case 252: + colour = _fontColour3; + break; + + case 251: + colour = _fontColour4; + break; + } + + // Paint pixel + ptr[x] = colour; } // Advance to next row diff --git a/engines/draci/font.h b/engines/draci/font.h index ddc6eaec7e..7a50f4099d 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -23,12 +23,15 @@ * */ +#ifndef FONT_H +#define FONT_H + #include "graphics/font.h" namespace Draci { -const Common::String kFontSmall("Small.fon"); -const Common::String kFontBig("Big.fon"); +extern const Common::String kFontSmall; +extern const Common::String kFontBig; /** * Represents the game's fonts. See docs for setFont() for font format details. @@ -37,8 +40,11 @@ const Common::String kFontBig("Big.fon"); class Font { public: + + Font(); Font(const Common::String &filename); ~Font(); + bool setFont(const Common::String &filename); uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; @@ -47,6 +53,7 @@ public: void drawString(Graphics::Surface *dst, Common::String &str, int x, int y, int spacing = 0) const; int getStringWidth(Common::String &str, int spacing = 0) const; + void setColour(uint8 colour); private: uint8 _fontHeight; @@ -66,8 +73,25 @@ private: */ static const unsigned int kCharIndexOffset = 32; + /** Default font colours. They all seem to remain constant except for the + * first one which varies depending on the character speaking. + * _overFontColour is set to transparent. + * TODO: Find out what _fontColour1 should actually be when the game starts + */ + + static const uint8 _fontColour1 = 2; + static const uint8 _fontColour2 = 0; + static const uint8 _fontColour3 = 3; + static const uint8 _fontColour4 = 4; + static const uint8 _overFontColour = 255; + + /** The varying font colour; initially set to _fontColour1 */ + uint8 _currentFontColour; + /** Internal function for freeing fonts when destructing/loading another */ void freeFont(); }; } // End of namespace Draci + +#endif // FONT_H -- cgit v1.2.3 From b942082da4344a2974e77a1a6d63f6bb6c1e9e16 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 14 Jun 2009 19:06:46 +0000 Subject: Removed superfluous return from the Sprite constructor. svn-id: r41525 --- engines/draci/sprite.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 4e17c59c7d..526213362f 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -38,7 +38,6 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, if (!columnwise) { memcpy(_data, raw_data, width * height); - return; } else { for (uint16 i = 0; i < width; ++i) { for (uint16 j = 0; j < height; ++j) { -- cgit v1.2.3 From 910991ddde8bb9c253236807d6d840f4e2141775 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 00:29:05 +0000 Subject: Converted default font colours from static members of Font to constants. Moved the initializer list of the Font constructor to the constructor body (for readability). svn-id: r41529 --- engines/draci/font.cpp | 38 +++++++++++++++++++++++++++----------- engines/draci/font.h | 17 +++-------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 99f1d37a23..2f51695484 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -33,22 +33,38 @@ namespace Draci { const Common::String kFontSmall("Small.fon"); const Common::String kFontBig("Big.fon"); -Font::Font() : - _fontHeight(0), _maxCharWidth(0), - _charWidths(NULL), _charData(0) { +/** + * Default font colours. They all seem to remain constant except for the + * first one which varies depending on the character speaking. + * kOverFontColour is set to transparent. + * TODO: Find out what kFontColour1 should actually be when the game starts + */ +const uint8 kFontColour1 = 2, kFontColour2 = 0, + kFontColour3 = 3, kFontColour4 = 4, + kOverFontColour = 255; + +Font::Font() { + + _fontHeight = 0; + _maxCharWidth = 0; + _charWidths = NULL; + _charData = NULL; setFont(kFontBig); - _currentFontColour = _fontColour1; + _currentFontColour = kFontColour1; } -Font::Font(const Common::String &filename) : - _fontHeight(0), _maxCharWidth(0), - _charWidths(NULL), _charData(0) { +Font::Font(const Common::String &filename) { + + _fontHeight = 0; + _maxCharWidth = 0; + _charWidths = NULL; + _charData = NULL; setFont(filename); - _currentFontColour = _fontColour1; + _currentFontColour = kFontColour1; } Font::~Font() { @@ -170,15 +186,15 @@ void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { break; case 253: - colour = _fontColour2; + colour = kFontColour2; break; case 252: - colour = _fontColour3; + colour = kFontColour3; break; case 251: - colour = _fontColour4; + colour = kFontColour4; break; } diff --git a/engines/draci/font.h b/engines/draci/font.h index 7a50f4099d..55dd495f1e 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -68,24 +68,13 @@ private: /** Number of glyphs in the font */ static const unsigned int kCharNum = 138; - /** Chars are indexed from the space character so this should be subtracted + /** + * Chars are indexed from the space character so this should be subtracted * to get the index of a glyph */ static const unsigned int kCharIndexOffset = 32; - /** Default font colours. They all seem to remain constant except for the - * first one which varies depending on the character speaking. - * _overFontColour is set to transparent. - * TODO: Find out what _fontColour1 should actually be when the game starts - */ - - static const uint8 _fontColour1 = 2; - static const uint8 _fontColour2 = 0; - static const uint8 _fontColour3 = 3; - static const uint8 _fontColour4 = 4; - static const uint8 _overFontColour = 255; - - /** The varying font colour; initially set to _fontColour1 */ + /** The varying font colour; initially set to kFontColour1 */ uint8 _currentFontColour; /** Internal function for freeing fonts when destructing/loading another */ -- cgit v1.2.3 From a3a9f5c790a8b669597b087b761f887fc5a77228 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 00:31:25 +0000 Subject: Added const to reference parameters of Font::drawString() and Font::getStringWidth(). svn-id: r41530 --- engines/draci/font.cpp | 4 ++-- engines/draci/font.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 2f51695484..aff674a92f 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -217,7 +217,7 @@ void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { * @param spacing Space to leave between individual characters. Defaults to 0. */ -void Font::drawString(Graphics::Surface *dst, Common::String &str, +void Font::drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int spacing) const { assert(dst != NULL); assert(x >= 0); @@ -247,7 +247,7 @@ void Font::drawString(Graphics::Surface *dst, Common::String &str, * @return The calculated width of the string */ -int Font::getStringWidth(Common::String &str, int spacing) const { +int Font::getStringWidth(const Common::String &str, int spacing) const { int width = 0; uint len = str.size(); for (unsigned int i = 0; i < len; ++i) { diff --git a/engines/draci/font.h b/engines/draci/font.h index 55dd495f1e..3e8b120397 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -50,9 +50,9 @@ public: uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; void drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const; - void drawString(Graphics::Surface *dst, Common::String &str, + void drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int spacing = 0) const; - int getStringWidth(Common::String &str, int spacing = 0) const; + int getStringWidth(const Common::String &str, int spacing = 0) const; void setColour(uint8 colour); private: -- cgit v1.2.3 From 326cf7e735062d399f6fe5f2ae79ac8f34e8b61b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 03:48:16 +0000 Subject: Added support for DFW format archives. Rewrote some BArchive methods to be able to seamlessly handle both BAR and DFW archives. Modified the BAFile struct to support both types of files. Tested it by enabling the mouse in the event loop (the cursor was stored in a DFW file). Added and rewrote docs to reflect the changes. svn-id: r41533 --- engines/draci/barchive.cpp | 232 +++++++++++++++++++++++++++++++++++++++++---- engines/draci/barchive.h | 12 ++- engines/draci/draci.cpp | 12 +++ 3 files changed, 233 insertions(+), 23 deletions(-) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index d11087a809..7865b1b574 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -34,24 +34,111 @@ namespace Draci { const char BArchive::_magicNumber[] = "BAR!"; +const char BArchive::_dfwMagicNumber[] = "BS"; + +/** + * @brief Loads a DFW archive + * @param path Path to input file + * + * Tries to load the file as a DFW archive if opening as BAR fails. Should only be called + * from openArchive(). Only one of the game files appears to use this format (HRA.DFW) + * and this file is compressed using a simple run-length scheme. + * + * archive format: header + * index table + * file0, file1, ... + * + * header format: [uint16LE] file count + * [uint16LE] index table size + * [2 bytes] magic number "BS" + * + * index table format: entry0, entry1, ... + * + * entry format: [uint16LE] compressed size (not including the 2 bytes for the + * "uncompressed size" field) + * [uint32LE] fileN offset from start of file + * + * file format: [uint16LE] uncompressed size + * [uint16LE] compressed size (the same as in the index table entry) + * [byte] stopper mark (for run-length compression) + * [multiple bytes] compressed data + */ + +void BArchive::openDFW(const Common::String &path) { + byte *table; + uint16 tableSize; + byte buf[2]; + + Common::File f; + + f.open(path); + if (!f.isOpen()) { + debugC(2, kDraciArchiverDebugLevel, "Error opening file"); + return; + } + + _fileCount = f.readUint16LE(); + tableSize = f.readUint16LE(); + + f.read(buf, 2); + if (memcmp(buf, _dfwMagicNumber, 2) == 0) { + debugC(2, kDraciArchiverDebugLevel, "Success"); + _isDFW = true; + } else { + debugC(2, kDraciArchiverDebugLevel, "Not a DFW archive"); + f.close(); + return; + } + + debugC(2, kDraciArchiverDebugLevel, "Archive info (DFW): %d files", _fileCount); + + // Read in index table + table = new byte[tableSize]; + f.read(table, tableSize); + + // Read in file headers, but do not read the actual data yet + // The data will be read on demand to save memory + _files = new BAFile[_fileCount]; + Common::MemoryReadStream tableReader(table, tableSize); + for (unsigned int i = 0; i < _fileCount; ++i) { + _files[i]._compLength = tableReader.readUint16LE(); + _files[i]._offset = tableReader.readUint32LE(); + + // Seek to the current file + f.seek(_files[i]._offset); + + _files[i]._length = f.readUint16LE(); // Read in uncompressed length + f.readUint16LE(); // Compressed length again (already read from the index table) + _files[i]._stopper = f.readByte(); + + _files[i]._data = NULL; // File data will be read in on demand + _files[i]._crc = 0; // Dummy value; not used in DFW archives + } + + delete[] table; +} /** * @brief BArchive open method * @param path Path to input file * * Opens a BAR (Bob's Archiver) archive, which is the game's archiving format. - * BAR archives have a .DFW file extension, due to an unused historical interface. + * BAR archives have a .DFW file extension, due to a historical interface. * * archive format: header, * file0, file1, ... * footer + * * header format: [4 bytes] magic number "BAR!" * [uint16LE] file count (number of archived streams), * [uint32LE] footer offset from start of file + * * file format: [2 bytes] compressed length * [2 bytes] original length * [1 byte] compression type * [1 byte] CRC + * [multiple bytes] actual data + * * footer format: [array of uint32LE] offsets of individual files from start of archive * (last entry is footer offset again) */ @@ -65,8 +152,7 @@ void BArchive::openArchive(const Common::String &path) { // Close previously opened archive (if any) closeArchive(); - debugCN(2, kDraciArchiverDebugLevel, "Loading BAR archive %s: ", - path.c_str()); + debugCN(2, kDraciArchiverDebugLevel, "Loading archive %s: ", path.c_str()); f.open(path); if (f.isOpen()) { @@ -80,14 +166,17 @@ void BArchive::openArchive(const Common::String &path) { _path = path; // Read archive header - debugCN(2, kDraciArchiverDebugLevel, "Checking magic number: "); + debugCN(2, kDraciArchiverDebugLevel, "Checking for BAR magic number: "); f.read(buf, 4); if (memcmp(buf, _magicNumber, 4) == 0) { debugC(2, kDraciArchiverDebugLevel, "Success"); + _isDFW = false; } else { - debugC(2, kDraciArchiverDebugLevel, "Error"); + debugC(2, kDraciArchiverDebugLevel, "Not a BAR archive"); + debugCN(2, kDraciArchiverDebugLevel, "Retrying as DFW: "); f.close(); + openDFW(_path); return; } @@ -113,7 +202,8 @@ void BArchive::openArchive(const Common::String &path) { fileOffset = reader.readUint32LE(); f.seek(fileOffset); // Seek to next file in archive - f.readUint16LE(); // Compressed size, not used + _files[i]._compLength = f.readUint16LE(); // Compressed size + // should be the same as uncompressed _files[i]._length = f.readUint16LE(); // Original size _files[i]._offset = fileOffset; @@ -122,6 +212,7 @@ void BArchive::openArchive(const Common::String &path) { _files[i]._crc = f.readByte(); // CRC checksum of the file _files[i]._data = NULL; // File data will be read in on demand + _files[i]._stopper = 0; // Dummy value; not used in BAR files, needed in DFW } // Last footer item should be equal to footerOffset @@ -153,23 +244,18 @@ void BArchive::closeArchive(void) { _fileCount = 0; } -BAFile *BArchive::operator[](unsigned int i) const { +/** + * @brief On-demand BAR file loader + * @param i Index of file inside an archive + * @return Pointer to a BAFile coresponding to the opened file or NULL (on failure) + * + * Loads individual BAR files from an archive to memory on demand. + * Should not be called directly. Instead, one should access files + * through the operator[] interface. + */ +BAFile *BArchive::loadFileBAR(unsigned int i) const { Common::File f; - // Check whether requested file exists - if (i >= _fileCount) { - return NULL; - } - - debugCN(2, kDraciArchiverDebugLevel, "Accessing file %d from archive %s... ", - i, _path.c_str()); - - // Check if file has already been opened and return that - if (_files[i]._data) { - debugC(2, kDraciArchiverDebugLevel, "Success"); - return _files + i; - } - // Else open archive and read in requested file f.open(_path); if (f.isOpen()) { @@ -197,6 +283,110 @@ BAFile *BArchive::operator[](unsigned int i) const { return _files + i; } +/** + * @brief On-demand DFW file loader + * @param i Index of file inside an archive + * @return Pointer to a BAFile coresponding to the opened file or NULL (on failure) + * + * Loads individual DFW files from an archive to memory on demand. + * Should not be called directly. Instead, one should access files + * through the operator[] interface. + */ +BAFile *BArchive::loadFileDFW(unsigned int i) const { + Common::File f; + byte *buf; + + // Else open archive and read in requested file + f.open(_path); + if (f.isOpen()) { + debugC(2, kDraciArchiverDebugLevel, "Success"); + } else { + debugC(2, kDraciArchiverDebugLevel, "Error"); + return NULL; + } + + // Seek to raw data of the file + // Five bytes are for the header (uncompressed and compressed length, stopper mark) + f.seek(_files[i]._offset + 5); + + // Since we are seeking directly to raw data, we subtract 3 bytes from the length + // (to take account the compressed length and stopper mark) + uint16 compressedLength = _files[i]._compLength - 3; + uint16 uncompressedLength = _files[i]._length; + + debugC(2, kDraciArchiverDebugLevel, + "File info (DFW): uncompressed %d bytes, compressed %d bytes", + uncompressedLength, compressedLength); + + // Allocate a buffer for the file data + buf = new byte[compressedLength]; + + // Read in file data into the buffer + f.read(buf, compressedLength); + + // Allocate the space for the uncompressed file + byte *dst; + dst = _files[i]._data = new byte[uncompressedLength]; + + Common::MemoryReadStream data(buf, compressedLength); + + // Uncompress file + byte current, what; + byte stopper = _files[i]._stopper; + unsigned int repeat; + unsigned int len = 0; // Sanity check (counts uncompressed bytes) + + current = data.readByte(); // Read initial byte + while (!data.eos()) { + + if (current != stopper) { + *dst++ = current; + ++len; + } else { + // Inflate block + repeat = data.readByte(); + what = data.readByte(); + len += repeat; + for (unsigned int j = 0; j < repeat; ++j) { + *dst++ = what; + } + } + + current = data.readByte(); + } + + assert(len == _files[i]._length && "Uncompressed file not of the expected length"); + + return _files + i; +} + + +BAFile *BArchive::operator[](unsigned int i) const { + + // Check whether requested file exists + if (i >= _fileCount) { + return NULL; + } + + debugCN(2, kDraciArchiverDebugLevel, "Accessing file %d from archive %s... ", + i, _path.c_str()); + + // Check if file has already been opened and return that + if (_files[i]._data) { + debugC(2, kDraciArchiverDebugLevel, "Success"); + return _files + i; + } + + BAFile *file; + if (_isDFW) { + file = loadFileDFW(i); + } else { + file = loadFileBAR(i); + } + + return file; +} + } // End of namespace Draci diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 683ec50a67..0971375c7b 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -35,10 +35,12 @@ namespace Draci { */ struct BAFile { - uint16 _length; - uint32 _offset; //!< Offset of file inside archive + uint16 _compLength; //!< Compressed length (the same as _length if the file is uncompressed) + uint16 _length; //!< Uncompressed length + uint32 _offset; //!< Offset of file inside archive byte *_data; byte _crc; + byte _stopper; //!< Not used in BAR files, needed for DFW /** Releases the file data (for memory considerations) */ void closeFile(void) { @@ -62,6 +64,7 @@ public: private: // Archive header data static const char _magicNumber[]; + static const char _dfwMagicNumber[]; static const unsigned int _archiveHeaderSize = 10; // File stream header data @@ -70,6 +73,11 @@ private: Common::String _path; //!< Path to file BAFile *_files; //!< Internal array of files uint16 _fileCount; //!< Number of files in archive + bool _isDFW; //!< True if the archive is in DFW format, false otherwise + + void openDFW(const Common::String &path); + BAFile *loadFileDFW(unsigned int i) const; + BAFile *loadFileBAR(unsigned int i) const; }; } // End of namespace Draci diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 103f595a12..2f55906a2b 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -29,6 +29,7 @@ #include "common/events.h" #include "common/file.h" +#include "graphics/cursorman.h" #include "graphics/font.h" #include "draci/draci.h" @@ -170,6 +171,15 @@ int DraciEngine::go() { debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); } + path = "HRA.DFW"; + ar.closeArchive(); + ar.openArchive(path); + f = ar[0]; + Sprite sp(f->_data, f->_length, 0, 0, true); + CursorMan.pushCursorPalette(palette, 0, 256); + CursorMan.pushCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); + CursorMan.showMouse(true); + Common::Event event; bool quit = false; while (!quit) { @@ -177,6 +187,8 @@ int DraciEngine::go() { switch (event.type) { case Common::EVENT_QUIT: quit = true; + case Common::EVENT_MOUSEMOVE: + _system->warpMouse(event.mouse.x, event.mouse.y); default: break; } -- cgit v1.2.3 From ea3cf319388b01659e04a563314b0de81619fb9c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 03:50:45 +0000 Subject: Close a file after we're done using it. svn-id: r41534 --- engines/draci/barchive.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index 7865b1b574..c3117cd0f2 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -116,6 +116,8 @@ void BArchive::openDFW(const Common::String &path) { } delete[] table; + + f.close(); } /** -- cgit v1.2.3 From a8c784245c1b5a277fdea098ff19c4bd53aac70c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 03:53:03 +0000 Subject: Fixed a memory leak in BArchive::openArchive(). A buffer wasn't being freed. svn-id: r41535 --- engines/draci/barchive.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index c3117cd0f2..df527221cd 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -220,6 +220,8 @@ void BArchive::openArchive(const Common::String &path) { // Last footer item should be equal to footerOffset assert(reader.readUint32LE() == footerOffset && "Footer offset mismatch"); + delete[] footer; + f.close(); } -- cgit v1.2.3 From 30ef3a122369ab3002b2e718934afea676a48fe7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 17:08:39 +0000 Subject: Added BArchive::isOpen() method. Modified DraciEngine::go() to use it. Updated BArchive docs. svn-id: r41550 --- engines/draci/barchive.cpp | 34 +++++++++++++++++++++++++--------- engines/draci/barchive.h | 16 ++++++++++++++-- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index df527221cd..4b9a1d9807 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -115,8 +115,11 @@ void BArchive::openDFW(const Common::String &path) { _files[i]._crc = 0; // Dummy value; not used in DFW archives } + // Indicate that the archive was successfully opened + _opened = true; + + // Cleanup delete[] table; - f.close(); } @@ -173,12 +176,17 @@ void BArchive::openArchive(const Common::String &path) { f.read(buf, 4); if (memcmp(buf, _magicNumber, 4) == 0) { debugC(2, kDraciArchiverDebugLevel, "Success"); + + // Indicate this archive is a BAR _isDFW = false; } else { debugC(2, kDraciArchiverDebugLevel, "Not a BAR archive"); debugCN(2, kDraciArchiverDebugLevel, "Retrying as DFW: "); f.close(); + + // Try to open as DFW openDFW(_path); + return; } @@ -203,25 +211,30 @@ void BArchive::openArchive(const Common::String &path) { uint32 fileOffset; fileOffset = reader.readUint32LE(); - f.seek(fileOffset); // Seek to next file in archive + f.seek(fileOffset); // Seek to next file in archive + _files[i]._compLength = f.readUint16LE(); // Compressed size // should be the same as uncompressed - _files[i]._length = f.readUint16LE(); // Original size - _files[i]._offset = fileOffset; + + _files[i]._length = f.readUint16LE(); // Original size + + _files[i]._offset = fileOffset; // Offset of file from start assert(f.readByte() == 0 && "Compression type flag is non-zero (file is compressed)"); - _files[i]._crc = f.readByte(); // CRC checksum of the file - _files[i]._data = NULL; // File data will be read in on demand - _files[i]._stopper = 0; // Dummy value; not used in BAR files, needed in DFW + _files[i]._crc = f.readByte(); // CRC checksum of the file + _files[i]._data = NULL; // File data will be read in on demand + _files[i]._stopper = 0; // Dummy value; not used in BAR files, needed in DFW } // Last footer item should be equal to footerOffset assert(reader.readUint32LE() == footerOffset && "Footer offset mismatch"); + + // Indicate that the archive has been successfully opened + _opened = true; delete[] footer; - f.close(); } @@ -232,7 +245,7 @@ void BArchive::openArchive(const Common::String &path) { * free up memory. */ void BArchive::closeArchive(void) { - if (!_files) { + if (!_opened) { return; } @@ -244,6 +257,7 @@ void BArchive::closeArchive(void) { delete[] _files; + _opened = false; _files = NULL; _fileCount = 0; } @@ -382,6 +396,8 @@ BAFile *BArchive::operator[](unsigned int i) const { } BAFile *file; + + // file will be NULL if something goes wrong if (_isDFW) { file = loadFileDFW(i); } else { diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 0971375c7b..a53fb79ee1 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -51,14 +51,25 @@ struct BAFile { class BArchive { public: - BArchive() : _files(NULL), _fileCount(0) {} - BArchive(Common::String &path) : _files(NULL), _fileCount(0) { openArchive(path); } + BArchive() : _files(NULL), _fileCount(0), _opened(false) {} + + BArchive(Common::String &path) : + _files(NULL), _fileCount(0), _opened(false) { + openArchive(path); + } + ~BArchive() { closeArchive(); } void openArchive(const Common::String &path); void closeArchive(void); uint16 size() const { return _fileCount; } + /** + * Checks whether there is an archive opened. Should be called before reading + * from the archive to check whether openArchive() succeeded. + */ + bool isOpen() const { return _opened; } + BAFile *operator[](unsigned int i) const; private: @@ -74,6 +85,7 @@ private: BAFile *_files; //!< Internal array of files uint16 _fileCount; //!< Number of files in archive bool _isDFW; //!< True if the archive is in DFW format, false otherwise + bool _opened; //!< True if the archive is opened, false otherwise void openDFW(const Common::String &path); BAFile *loadFileDFW(unsigned int i) const; -- cgit v1.2.3 From ca7d400dc35ed69d5e6368672102822b7eab081c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 17:12:21 +0000 Subject: Submitting changes to DraciEngine::go() mentioned in the last commit but omitted by accident. Removed superfluous BArchive::closeArchive() calls. svn-id: r41552 --- engines/draci/draci.cpp | 51 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 2f55906a2b..99b9cd1ab2 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -73,7 +73,14 @@ int DraciEngine::init() { BArchive ar(path); BAFile *f; debugC(3, kDraciGeneralDebugLevel, "Number of file streams in archive: %d", ar.size()); - f = ar[0]; + + if(ar.isOpen()) { + f = ar[0]; + } else { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); + return 0; + } + debugC(3, kDraciGeneralDebugLevel, "First 10 bytes of file %d: ", 0); for (unsigned int i = 0; i < 10; ++i) { debugC(3, kDraciGeneralDebugLevel, "0x%02x%c", f->_data[i], (i < 9) ? ' ' : '\n'); @@ -82,10 +89,16 @@ int DraciEngine::init() { // Read in GPL script for the first game location debugC(2, kDraciBytecodeDebugLevel, "Disassembling GPL script " "for the first game location..."); - Common::String path2("MIST.DFW"); - ar.closeArchive(); - ar.openArchive(path2); - f = ar[3]; + + path = "MIST.DFW"; + ar.openArchive(path); + + if(ar.isOpen()) { + f = ar[3]; + } else { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); + return 0; + } // Disassemble GPL script for the first location gpldisasm(f->_data, f->_length); @@ -113,9 +126,15 @@ int DraciEngine::go() { BArchive ar(path); BAFile *f; - ar.closeArchive(); ar.openArchive(path); - f = ar[0]; + + if(ar.isOpen()) { + f = ar[0]; + } else { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); + return 0; + } + Common::MemoryReadStream paletteReader(f->_data, f->_length); for (unsigned int i = 0; i < 256; ++i) { @@ -156,8 +175,12 @@ int DraciEngine::go() { // Draw and animate the dragon path = "OBR_AN.DFW"; - ar.closeArchive(); ar.openArchive(path); + + if(!ar.isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); + return 0; + } for (unsigned int t = 0; t < 25; ++t) { debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); @@ -170,11 +193,17 @@ int DraciEngine::go() { debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); } - + path = "HRA.DFW"; - ar.closeArchive(); ar.openArchive(path); - f = ar[0]; + + if(ar.isOpen()) { + f = ar[0]; + } else { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); + return 0; + } + Sprite sp(f->_data, f->_length, 0, 0, true); CursorMan.pushCursorPalette(palette, 0, 256); CursorMan.pushCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); -- cgit v1.2.3 From 8249d24a637adefe25ef03f976acd6e7df782c00 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 15 Jun 2009 17:14:38 +0000 Subject: Changing font colour constants to an enum. svn-id: r41553 --- engines/draci/font.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index aff674a92f..87c1cdaaa3 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -39,9 +39,11 @@ const Common::String kFontBig("Big.fon"); * kOverFontColour is set to transparent. * TODO: Find out what kFontColour1 should actually be when the game starts */ -const uint8 kFontColour1 = 2, kFontColour2 = 0, - kFontColour3 = 3, kFontColour4 = 4, - kOverFontColour = 255; +enum { + kFontColour1 = 2, kFontColour2 = 0, + kFontColour3 = 3, kFontColour4 = 4, + kOverFontColour = 255 +}; Font::Font() { -- cgit v1.2.3 From 7420c1bfb620b62ae59c1ca91df6267281a9455a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 17 Jun 2009 03:14:22 +0000 Subject: Added include guards. svn-id: r41600 --- engines/draci/sprite.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 28d51ccbf4..1b4f718896 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -23,6 +23,9 @@ * */ +#ifndef SPRITE_H +#define SPRITE_H + namespace Draci { /** @@ -58,3 +61,4 @@ public: } // End of namespace Draci +#endif // SPRITE_H -- cgit v1.2.3 From 997b37eff15485c095181b2b1c3ade24722bdb8f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 17 Jun 2009 04:48:48 +0000 Subject: Began work on the Screen class. Modified the demo animation to use the it. svn-id: r41604 --- engines/draci/draci.cpp | 53 +++++++------------- engines/draci/draci.h | 5 ++ engines/draci/module.mk | 3 +- engines/draci/screen.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++++ engines/draci/screen.h | 60 +++++++++++++++++++++++ 5 files changed, 209 insertions(+), 36 deletions(-) create mode 100644 engines/draci/screen.cpp create mode 100644 engines/draci/screen.h diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 99b9cd1ab2..2ffec72927 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -37,6 +37,7 @@ #include "draci/gpldisasm.h" #include "draci/font.h" #include "draci/sprite.h" +#include "draci/screen.h" namespace Draci { @@ -50,6 +51,9 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) // However this is the place to specify all default directories //Common::File::addDefaultDirectory(_gameDataPath + "sound/"); + + _screenHeight = 200; + _screenWidth = 320; // Here is the right place to set up the engine specific debug levels Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug level"); @@ -62,7 +66,9 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) int DraciEngine::init() { // Initialize graphics using following: - initGraphics(320, 200, false); + initGraphics(_screenWidth, _screenHeight, false); + + _screen = new Screen(this); // Load default font _font.setFont(kFontBig); @@ -106,20 +112,9 @@ int DraciEngine::init() { return 0; } -// HACK -// Temporary hack - -void drawFrame(OSystem *syst, BAFile *frame) { - Sprite sp(frame->_data, frame->_length, ((320 - 50) / 2), 60, true); - syst->copyRectToScreen(sp._data, sp._width, sp._x, sp._y, sp._width, sp._height); -} - int DraciEngine::go() { debugC(1, kDraciGeneralDebugLevel, "DraciEngine::go()"); - // Read in a sample palette - byte *palette = new byte[4 * 256]; - debugC(2, kDraciGeneralDebugLevel, "Running graphics/animation test..."); Common::String path("PALETY.DFW"); @@ -135,28 +130,14 @@ int DraciEngine::go() { return 0; } - Common::MemoryReadStream paletteReader(f->_data, f->_length); - - for (unsigned int i = 0; i < 256; ++i) { - palette[i * 4] = paletteReader.readByte(); - palette[i * 4 + 1] = paletteReader.readByte(); - palette[i * 4 + 2] = paletteReader.readByte(); - palette[i * 4 + 3] = 0; - } - - // Shift the palette one bit to the left to make it brighter - for (unsigned int i = 0; i < 4 * 256; ++i) { - palette[i] <<= 2; - } - - _system->setPalette(palette, 0, 256); + _screen->setPalette(f->_data, 0, 256); // Fill screen with white - _system->fillScreen(255); + _screen->fillScreen(255); // Draw big string Common::String testString = "Testing, testing, read all about it!"; - Graphics::Surface *surf = _system->lockScreen(); + Graphics::Surface *surf = _screen->getSurface(); _font.drawString(surf, testString, (320 - _font.getStringWidth(testString, 1)) / 2, 130, 1); @@ -170,8 +151,7 @@ int DraciEngine::go() { testString = "Checking overflooooooooooooooooooooooooow..."; _font.drawString(surf, testString, 50, 170, 1); - _system->unlockScreen(); - _system->updateScreen(); + _screen->copyToScreen(); // Draw and animate the dragon path = "OBR_AN.DFW"; @@ -187,8 +167,9 @@ int DraciEngine::go() { // Load frame to memory f = ar[t]; - drawFrame(_system, f); - _system->updateScreen(); + Sprite sp(f->_data, f->_length, ((320 - 50) / 2), 60, true); + _screen->drawSprite(sp); + _screen->copyToScreen(); _system->delayMillis(100); debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); @@ -205,7 +186,7 @@ int DraciEngine::go() { } Sprite sp(f->_data, f->_length, 0, 0, true); - CursorMan.pushCursorPalette(palette, 0, 256); + CursorMan.pushCursorPalette(_screen->getPalette(), 0, 256); CursorMan.pushCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); CursorMan.showMouse(true); @@ -222,7 +203,7 @@ int DraciEngine::go() { break; } } - _system->updateScreen(); + _screen->copyToScreen(); _system->delayMillis(20); } @@ -232,6 +213,8 @@ int DraciEngine::go() { DraciEngine::~DraciEngine() { // Dispose your resources here + delete _screen; + // Remove all of our debug levels here Common::clearAllDebugChannels(); } diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 8a0e073101..481de8e4b3 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -30,6 +30,7 @@ #include "engines/engine.h" #include "engines/advancedDetector.h" +#include "draci/screen.h" #include "draci/font.h" namespace Draci { @@ -46,6 +47,10 @@ public: bool hasFeature(Engine::EngineFeature f) const; Font _font; + Screen *_screen; + + int _screenWidth; + int _screenHeight; private: Common::RandomSource _rnd; diff --git a/engines/draci/module.mk b/engines/draci/module.mk index b41154b576..ac214d0ccd 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -6,7 +6,8 @@ MODULE_OBJS := \ barchive.o \ gpldisasm.o \ font.o \ - sprite.o + sprite.o \ + screen.o MODULE_DIRS += \ engines/draci diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp new file mode 100644 index 0000000000..b1c12ccbae --- /dev/null +++ b/engines/draci/screen.cpp @@ -0,0 +1,124 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stream.h" + +#include "draci/draci.h" +#include "draci/screen.h" + +namespace Draci { + +Screen::Screen(DraciEngine *vm) : _vm(vm) { + _surface = new Graphics::Surface(); + _surface->create(_vm->_screenWidth, _vm->_screenHeight, 1); + this->clearScreen(); + _palette = new byte[4 * 256]; + setPaletteEmpty(256); +} + +Screen::~Screen() { + _surface->free(); + delete[] _surface; + delete[] _palette; +} + +void Screen::setPaletteEmpty(unsigned int numEntries) { + for (unsigned int i = 0; i < numEntries * 4; ++i) { + _palette[i] = 0; + } + + _vm->_system->setPalette(_palette, 0, numEntries); + _vm->_system->updateScreen(); +} + +void Screen::setPalette(byte *data, uint16 start, uint16 num) { + + Common::MemoryReadStream pal(data, 256 * 3); + pal.seek(start * 4); + + // Copy the palette + for (unsigned int i = start; i < start + num; ++i) { + _palette[i * 4] = pal.readByte(); + _palette[i * 4 + 1] = pal.readByte(); + _palette[i * 4 + 2] = pal.readByte(); + _palette[i * 4 + 3] = 0; + } + + // TODO: Investigate why this is needed + // Shift the palette one bit to the left to make it brighter + for (unsigned int i = 0; i < 4 * 256; ++i) { + _palette[i] <<= 2; + } + + _vm->_system->setPalette(_palette, start, num); + _vm->_system->updateScreen(); +} + +void Screen::copyToScreen() const { + byte *ptr = (byte *)_surface->getBasePtr(0, 0); + + _vm->_system->copyRectToScreen(ptr, _vm->_screenWidth, 0, 0, + _vm->_screenWidth, _vm->_screenHeight); + + _vm->_system->updateScreen(); +} + + +void Screen::clearScreen() const { + byte *ptr = (byte *)_surface->getBasePtr(0, 0); + + memset(ptr, 0, _vm->_screenWidth * _vm->_screenHeight); +} + +void Screen::drawSprite(const Sprite &s) const { + byte *dst = (byte *)_surface->getBasePtr(s._x, s._y); + byte *src = s._data; + + for (unsigned int i = 0; i < s._height; ++i) { + for(unsigned int j = 0; j < s._width; ++j) { + dst[j] = *src++; + } + + dst += _surface->pitch; + } +} + +void Screen::fillScreen(uint16 colour) const { + byte *ptr = (byte *)_surface->getBasePtr(0, 0); + + memset(ptr, colour, _vm->_screenWidth * _vm->_screenHeight); +} + +byte *Screen::getPalette() const { + return _palette; +} + +Graphics::Surface *Screen::getSurface() { + return _surface; +} + +} // End of namespace Draci + + diff --git a/engines/draci/screen.h b/engines/draci/screen.h new file mode 100644 index 0000000000..0180cc7f6f --- /dev/null +++ b/engines/draci/screen.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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCREEN_H +#define SCREEN_H + +#include "graphics/surface.h" + +#include "draci/sprite.h" + +namespace Draci { + +class DraciEngine; + +class Screen { + +public: + Screen(DraciEngine *vm); + ~Screen(); + + void setPaletteEmpty(unsigned int numEntries); + void setPalette(byte *data, uint16 start, uint16 num); + byte *getPalette() const; + void copyToScreen() const; + void clearScreen() const; + void drawSprite(const Sprite &s) const; + void fillScreen(uint16 colour) const; + Graphics::Surface *getSurface(); + +private: + Graphics::Surface *_surface; + byte *_palette; + DraciEngine *_vm; +}; + +} // End of namespace Draci + +#endif // SCREEN_H -- cgit v1.2.3 From 569fe8804157c203e95cc90fed48d65e263b5bd8 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 17 Jun 2009 05:18:48 +0000 Subject: Added prefices to safeguard defines in order to minimize risk of name clash. svn-id: r41605 --- engines/draci/barchive.h | 6 +++--- engines/draci/font.h | 6 +++--- engines/draci/gpldisasm.h | 6 +++--- engines/draci/screen.h | 6 +++--- engines/draci/sprite.h | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index a53fb79ee1..e52e41e737 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -23,8 +23,8 @@ * */ -#ifndef BARCHIVE_H -#define BARCHIVE_H +#ifndef DRACI_BARCHIVE_H +#define DRACI_BARCHIVE_H #include "common/str.h" @@ -94,4 +94,4 @@ private: } // End of namespace Draci -#endif // BARCHIVE_H +#endif // DRACI_BARCHIVE_H diff --git a/engines/draci/font.h b/engines/draci/font.h index 3e8b120397..12cc8bf9a9 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -23,8 +23,8 @@ * */ -#ifndef FONT_H -#define FONT_H +#ifndef DRACI_FONT_H +#define DRACI_FONT_H #include "graphics/font.h" @@ -83,4 +83,4 @@ private: } // End of namespace Draci -#endif // FONT_H +#endif // DRACI_FONT_H diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h index 9f33bafc94..f93fd1f4a5 100644 --- a/engines/draci/gpldisasm.h +++ b/engines/draci/gpldisasm.h @@ -25,8 +25,8 @@ #include "common/str.h" -#ifndef GPLDISASM_H -#define GPLDISASM_H +#ifndef DRACI_GPLDISASM_H +#define DRACI_GPLDISASM_H namespace Draci { @@ -53,4 +53,4 @@ int gpldisasm(byte *gplcode, uint16 len); } -#endif // GPLDIASM_H +#endif // DRACI_GPLDIASM_H diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 0180cc7f6f..5983e73c81 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -23,8 +23,8 @@ * */ -#ifndef SCREEN_H -#define SCREEN_H +#ifndef DRACI_SCREEN_H +#define DRACI_SCREEN_H #include "graphics/surface.h" @@ -57,4 +57,4 @@ private: } // End of namespace Draci -#endif // SCREEN_H +#endif // DRACI_SCREEN_H diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 1b4f718896..fab59958f2 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -23,8 +23,8 @@ * */ -#ifndef SPRITE_H -#define SPRITE_H +#ifndef DRACI_SPRITE_H +#define DRACI_SPRITE_H namespace Draci { @@ -61,4 +61,4 @@ public: } // End of namespace Draci -#endif // SPRITE_H +#endif // DRACI_SPRITE_H -- cgit v1.2.3 From 17133fdfa06febf73a3bd5a3b1df92c0e358c710 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 17 Jun 2009 14:31:21 +0000 Subject: Fixed typo. svn-id: r41608 --- engines/draci/gpldisasm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h index f93fd1f4a5..c23de4ba33 100644 --- a/engines/draci/gpldisasm.h +++ b/engines/draci/gpldisasm.h @@ -53,4 +53,4 @@ int gpldisasm(byte *gplcode, uint16 len); } -#endif // DRACI_GPLDIASM_H +#endif // DRACI_GPLDISASM_H -- cgit v1.2.3 From 491800c19a73dc281823635a5406ecc488ce6408 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 17 Jun 2009 21:07:59 +0000 Subject: Changed the _font DraciEngine member from a Font instance to a pointer to an instance. This way the default constructor is invoked in DraciEngine::init() and can properly initialize the fonts because the game data paths are set. svn-id: r41612 --- engines/draci/draci.cpp | 17 +++++++++-------- engines/draci/draci.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 2ffec72927..1ee757ccb3 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -68,10 +68,11 @@ int DraciEngine::init() { // Initialize graphics using following: initGraphics(_screenWidth, _screenHeight, false); - _screen = new Screen(this); + _screen = new Screen(this); + _font = new Font(); // Load default font - _font.setFont(kFontBig); + _font->setFont(kFontBig); // Basic archive test debugC(2, kDraciGeneralDebugLevel, "Running archive tests..."); @@ -138,18 +139,18 @@ int DraciEngine::go() { // Draw big string Common::String testString = "Testing, testing, read all about it!"; Graphics::Surface *surf = _screen->getSurface(); - _font.drawString(surf, testString, - (320 - _font.getStringWidth(testString, 1)) / 2, 130, 1); + _font->drawString(surf, testString, + (320 - _font->getStringWidth(testString, 1)) / 2, 130, 1); // Draw small string - _font.setFont(kFontSmall); + _font->setFont(kFontSmall); testString = "I'm smaller than the font above me."; - _font.drawString(surf, testString, - (320 - _font.getStringWidth(testString, 1)) / 2, 150, 1); + _font->drawString(surf, testString, + (320 - _font->getStringWidth(testString, 1)) / 2, 150, 1); // Overflow handling test testString = "Checking overflooooooooooooooooooooooooow..."; - _font.drawString(surf, testString, 50, 170, 1); + _font->drawString(surf, testString, 50, 170, 1); _screen->copyToScreen(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 481de8e4b3..cfc1e5c307 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -46,7 +46,7 @@ public: bool hasFeature(Engine::EngineFeature f) const; - Font _font; + Font *_font; Screen *_screen; int _screenWidth; -- cgit v1.2.3 From 1712db9112dbfb2948a23b2aa2a22023041b52e3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 17 Jun 2009 21:29:05 +0000 Subject: Added default parameter to Screen::setPaletteEmpty() so it clears all colours by default. svn-id: r41614 --- engines/draci/screen.cpp | 2 +- engines/draci/screen.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index b1c12ccbae..ff6fc5856f 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -35,7 +35,7 @@ Screen::Screen(DraciEngine *vm) : _vm(vm) { _surface->create(_vm->_screenWidth, _vm->_screenHeight, 1); this->clearScreen(); _palette = new byte[4 * 256]; - setPaletteEmpty(256); + setPaletteEmpty(); } Screen::~Screen() { diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 5983e73c81..8033fa7f53 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -35,12 +35,12 @@ namespace Draci { class DraciEngine; class Screen { - + public: Screen(DraciEngine *vm); ~Screen(); - void setPaletteEmpty(unsigned int numEntries); + void setPaletteEmpty(unsigned int numEntries = 256); void setPalette(byte *data, uint16 start, uint16 num); byte *getPalette() const; void copyToScreen() const; -- cgit v1.2.3 From efef9e4eff421a150331b1af23b669ddb4cce0dd Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 17 Jun 2009 23:11:24 +0000 Subject: Added kNumColours constant and replaced magic numbers with it. svn-id: r41617 --- engines/draci/draci.cpp | 4 ++-- engines/draci/screen.cpp | 10 ++++++---- engines/draci/screen.h | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 1ee757ccb3..3cc89abe1d 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -131,7 +131,7 @@ int DraciEngine::go() { return 0; } - _screen->setPalette(f->_data, 0, 256); + _screen->setPalette(f->_data, 0, kNumColours); // Fill screen with white _screen->fillScreen(255); @@ -187,7 +187,7 @@ int DraciEngine::go() { } Sprite sp(f->_data, f->_length, 0, 0, true); - CursorMan.pushCursorPalette(_screen->getPalette(), 0, 256); + CursorMan.pushCursorPalette(_screen->getPalette(), 0, kNumColours); CursorMan.pushCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); CursorMan.showMouse(true); diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index ff6fc5856f..0a84a24c1b 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -30,11 +30,13 @@ namespace Draci { +const uint16 kNumColours = 256; + Screen::Screen(DraciEngine *vm) : _vm(vm) { _surface = new Graphics::Surface(); _surface->create(_vm->_screenWidth, _vm->_screenHeight, 1); this->clearScreen(); - _palette = new byte[4 * 256]; + _palette = new byte[4 * kNumColours]; setPaletteEmpty(); } @@ -45,7 +47,7 @@ Screen::~Screen() { } void Screen::setPaletteEmpty(unsigned int numEntries) { - for (unsigned int i = 0; i < numEntries * 4; ++i) { + for (unsigned int i = 0; i < 4 * numEntries; ++i) { _palette[i] = 0; } @@ -55,7 +57,7 @@ void Screen::setPaletteEmpty(unsigned int numEntries) { void Screen::setPalette(byte *data, uint16 start, uint16 num) { - Common::MemoryReadStream pal(data, 256 * 3); + Common::MemoryReadStream pal(data, 3 * kNumColours); pal.seek(start * 4); // Copy the palette @@ -68,7 +70,7 @@ void Screen::setPalette(byte *data, uint16 start, uint16 num) { // TODO: Investigate why this is needed // Shift the palette one bit to the left to make it brighter - for (unsigned int i = 0; i < 4 * 256; ++i) { + for (unsigned int i = 0; i < 4 * kNumColours; ++i) { _palette[i] <<= 2; } diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 8033fa7f53..08c9f4b4b7 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -32,6 +32,8 @@ namespace Draci { +extern const uint16 kNumColours; + class DraciEngine; class Screen { @@ -40,7 +42,7 @@ public: Screen(DraciEngine *vm); ~Screen(); - void setPaletteEmpty(unsigned int numEntries = 256); + void setPaletteEmpty(unsigned int numEntries = kNumColours); void setPalette(byte *data, uint16 start, uint16 num); byte *getPalette() const; void copyToScreen() const; -- cgit v1.2.3 From 0ff3c1945ff83938cd453f92002fbc2c688c641d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 18 Jun 2009 00:33:16 +0000 Subject: Changed _screenWidth and _screenHeight from member variables to constants because the screen size doesn't change. svn-id: r41620 --- engines/draci/draci.cpp | 11 ++++------- engines/draci/draci.h | 3 --- engines/draci/screen.cpp | 12 +++++++----- engines/draci/screen.h | 2 ++ 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 3cc89abe1d..8d018ee023 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -52,9 +52,6 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) // However this is the place to specify all default directories //Common::File::addDefaultDirectory(_gameDataPath + "sound/"); - _screenHeight = 200; - _screenWidth = 320; - // Here is the right place to set up the engine specific debug levels Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug level"); Common::addDebugChannel(kDraciBytecodeDebugLevel, "bytecode", "GPL bytecode instructions"); @@ -66,7 +63,7 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) int DraciEngine::init() { // Initialize graphics using following: - initGraphics(_screenWidth, _screenHeight, false); + initGraphics(kScreenWidth, kScreenHeight, false); _screen = new Screen(this); _font = new Font(); @@ -140,13 +137,13 @@ int DraciEngine::go() { Common::String testString = "Testing, testing, read all about it!"; Graphics::Surface *surf = _screen->getSurface(); _font->drawString(surf, testString, - (320 - _font->getStringWidth(testString, 1)) / 2, 130, 1); + (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 130, 1); // Draw small string _font->setFont(kFontSmall); testString = "I'm smaller than the font above me."; _font->drawString(surf, testString, - (320 - _font->getStringWidth(testString, 1)) / 2, 150, 1); + (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 150, 1); // Overflow handling test testString = "Checking overflooooooooooooooooooooooooow..."; @@ -168,7 +165,7 @@ int DraciEngine::go() { // Load frame to memory f = ar[t]; - Sprite sp(f->_data, f->_length, ((320 - 50) / 2), 60, true); + Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, true); _screen->drawSprite(sp); _screen->copyToScreen(); _system->delayMillis(100); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index cfc1e5c307..851fc12ed2 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -49,9 +49,6 @@ public: Font *_font; Screen *_screen; - int _screenWidth; - int _screenHeight; - private: Common::RandomSource _rnd; }; diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index 0a84a24c1b..2d12267f2f 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -30,11 +30,13 @@ namespace Draci { +const int kScreenWidth = 320; +const int kScreenHeight = 200; const uint16 kNumColours = 256; Screen::Screen(DraciEngine *vm) : _vm(vm) { _surface = new Graphics::Surface(); - _surface->create(_vm->_screenWidth, _vm->_screenHeight, 1); + _surface->create(kScreenWidth, kScreenHeight, 1); this->clearScreen(); _palette = new byte[4 * kNumColours]; setPaletteEmpty(); @@ -81,8 +83,8 @@ void Screen::setPalette(byte *data, uint16 start, uint16 num) { void Screen::copyToScreen() const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); - _vm->_system->copyRectToScreen(ptr, _vm->_screenWidth, 0, 0, - _vm->_screenWidth, _vm->_screenHeight); + _vm->_system->copyRectToScreen(ptr, kScreenWidth, 0, 0, + kScreenWidth, kScreenHeight); _vm->_system->updateScreen(); } @@ -91,7 +93,7 @@ void Screen::copyToScreen() const { void Screen::clearScreen() const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); - memset(ptr, 0, _vm->_screenWidth * _vm->_screenHeight); + memset(ptr, 0, kScreenWidth * kScreenHeight); } void Screen::drawSprite(const Sprite &s) const { @@ -110,7 +112,7 @@ void Screen::drawSprite(const Sprite &s) const { void Screen::fillScreen(uint16 colour) const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); - memset(ptr, colour, _vm->_screenWidth * _vm->_screenHeight); + memset(ptr, colour, kScreenWidth * kScreenHeight); } byte *Screen::getPalette() const { diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 08c9f4b4b7..d8459489c1 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -32,6 +32,8 @@ namespace Draci { +extern const int kScreenHeight; +extern const int kScreenWidth; extern const uint16 kNumColours; class DraciEngine; -- cgit v1.2.3 From fbec4434e5aaacee5d4a3ecf5644f3d6d5ec0b2d Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Thu, 18 Jun 2009 05:30:21 +0000 Subject: Turned constants into enum in order to remove need of prototypes. svn-id: r41623 --- engines/draci/screen.cpp | 4 ---- engines/draci/screen.h | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index 2d12267f2f..a1ac27211e 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -30,10 +30,6 @@ namespace Draci { -const int kScreenWidth = 320; -const int kScreenHeight = 200; -const uint16 kNumColours = 256; - Screen::Screen(DraciEngine *vm) : _vm(vm) { _surface = new Graphics::Surface(); _surface->create(kScreenWidth, kScreenHeight, 1); diff --git a/engines/draci/screen.h b/engines/draci/screen.h index d8459489c1..95b73b92ac 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -32,9 +32,12 @@ namespace Draci { -extern const int kScreenHeight; -extern const int kScreenWidth; -extern const uint16 kNumColours; +enum ScreenParameters { + kScreenWidth = 320, + kScreenHeight = 200, + + kNumColours = 256 +}; class DraciEngine; -- cgit v1.2.3 From a6355466d0a4d860288b5bdc049e3fcb277dc06e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 18 Jun 2009 23:55:35 +0000 Subject: Added Surface class. svn-id: r41653 --- engines/draci/surface.cpp | 93 +++++++++++++++++++++++++++++++++++++++++++++++ engines/draci/surface.h | 56 ++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 engines/draci/surface.cpp create mode 100644 engines/draci/surface.h diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp new file mode 100644 index 0000000000..1c7fce08b5 --- /dev/null +++ b/engines/draci/surface.cpp @@ -0,0 +1,93 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "draci/screen.h" +#include "draci/surface.h" + +namespace Draci { + +Surface::Surface(int width, int height) { + this->create(width, height, 1); + this->markClean(); + _transparentColour = kDefaultTransparent; +} + +Surface::~Surface() { + this->free(); +} + +void Surface::markDirtyRect(Common::Rect r) { + Common::List::iterator it; + + r.clip(w, h); + + if (r.isEmpty()) + return; + + it = _dirtyRects.begin(); + while (it != _dirtyRects.end()) { + + if (it->contains(r)) + return; + + if (r.contains(*it)) + it = _dirtyRects.erase(it); + else + ++it; + } + + _dirtyRects.push_back(r); +} + +void Surface::clearDirtyRects() { + _dirtyRects.clear(); +} + +void Surface::markDirty() { + _fullUpdate = true; +} + +void Surface::markClean() { + _fullUpdate = false; + _dirtyRects.clear(); +} + +bool Surface::needsFullUpdate() { + return _fullUpdate; +} + +Common::List *Surface::getDirtyRects() { + return &_dirtyRects; +} + +uint8 Surface::getTransparentColour() { + return _transparentColour; +} + +void Surface::setTransparentColour(uint8 colour) { + _transparentColour = colour; +} + +} // End of namespace Draci diff --git a/engines/draci/surface.h b/engines/draci/surface.h new file mode 100644 index 0000000000..cc1dff806b --- /dev/null +++ b/engines/draci/surface.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef DRACI_SURFACE_H +#define DRACI_SURFACE_H + +#include "graphics/surface.h" + +namespace Draci { + +class Surface : public Graphics::Surface { + +public: + Surface(int width, int height); + ~Surface(); + + void markDirtyRect(Common::Rect r); + Common::List *getDirtyRects(); + void clearDirtyRects(); + void markDirty(); + void markClean(); + bool needsFullUpdate(); + uint8 getTransparentColour(); + void setTransparentColour(uint8 colour); + +private: + bool _fullUpdate; + uint8 _transparentColour; + Common::List _dirtyRects; +}; + +} // End of namespace Draci + +#endif // DRACI_SURFACE_H -- cgit v1.2.3 From 1fe88abf6b0518b1bb4cb6baf2344c84da4b6312 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 19 Jun 2009 00:00:31 +0000 Subject: Added Sprite::draw() method for drawing sprites to a Surface. svn-id: r41654 --- engines/draci/sprite.cpp | 19 +++++++++++++++++++ engines/draci/sprite.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 526213362f..6a55894907 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -22,8 +22,10 @@ * $Id$ * */ + #include "common/stream.h" +#include "draci/draci.h" #include "draci/sprite.h" namespace Draci { @@ -75,6 +77,23 @@ Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, Sprite::~Sprite() { delete[] _data; } + +void Sprite::draw(Surface *surface) const { + byte *dst = (byte *)surface->getBasePtr(_x, _y); + byte *src = _data; + + for (unsigned int i = 0; i < _height; ++i) { + for(unsigned int j = 0; j < _width; ++j, ++src) { + if (*src != surface->getTransparentColour()) + dst[j] = *src; + } + + dst += surface->pitch; + } + + Common::Rect r(_x, _y, _x + _width, _y + _height); + surface->markDirtyRect(r); +} } // End of namespace Draci diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index fab59958f2..0bd825cf14 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -26,6 +26,8 @@ #ifndef DRACI_SPRITE_H #define DRACI_SPRITE_H +#include "draci/surface.h" + namespace Draci { /** @@ -52,6 +54,8 @@ public: ~Sprite(); + void draw(Surface *surface) const; + byte *_data; uint16 _width; uint16 _height; -- cgit v1.2.3 From fc461246cf58329f1de1fcbd848234a26123a668 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 19 Jun 2009 00:06:11 +0000 Subject: Made the Surface class compile. svn-id: r41655 --- engines/draci/module.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/draci/module.mk b/engines/draci/module.mk index ac214d0ccd..128e4ba8e9 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -7,7 +7,8 @@ MODULE_OBJS := \ gpldisasm.o \ font.o \ sprite.o \ - screen.o + screen.o \ + surface.o MODULE_DIRS += \ engines/draci -- cgit v1.2.3 From 9d0b940af312efe50008ea2ac3f9e28bb3ea7daf Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 19 Jun 2009 00:09:36 +0000 Subject: Added support for the new Surface class to Font (transparency, marking dirty rectangles). svn-id: r41656 --- engines/draci/font.cpp | 24 ++++++++---------------- engines/draci/font.h | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 87c1cdaaa3..6dc6d7e7f6 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -33,18 +33,6 @@ namespace Draci { const Common::String kFontSmall("Small.fon"); const Common::String kFontBig("Big.fon"); -/** - * Default font colours. They all seem to remain constant except for the - * first one which varies depending on the character speaking. - * kOverFontColour is set to transparent. - * TODO: Find out what kFontColour1 should actually be when the game starts - */ -enum { - kFontColour1 = 2, kFontColour2 = 0, - kFontColour3 = 3, kFontColour4 = 4, - kOverFontColour = 255 -}; - Font::Font() { _fontHeight = 0; @@ -156,7 +144,7 @@ uint8 Font::getCharWidth(uint8 chr) const { * @param ty Vertical offset on the surface */ -void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { +void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { assert(dst != NULL); assert(tx >= 0); assert(ty >= 0); @@ -200,13 +188,17 @@ void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { break; } - // Paint pixel - ptr[x] = colour; + // Paint pixel (if not transparent) + if (colour != dst->getTransparentColour()) + ptr[x] = colour; } // Advance to next row ptr += dst->pitch; } + + Common::Rect r(tx, ty, tx + xPixelsToDraw, ty + yPixelsToDraw); + dst->markDirtyRect(r); } /** @@ -219,7 +211,7 @@ void Font::drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const { * @param spacing Space to leave between individual characters. Defaults to 0. */ -void Font::drawString(Graphics::Surface *dst, const Common::String &str, +void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int spacing) const { assert(dst != NULL); assert(x >= 0); diff --git a/engines/draci/font.h b/engines/draci/font.h index 12cc8bf9a9..3853e92eaa 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -33,6 +33,18 @@ namespace Draci { extern const Common::String kFontSmall; extern const Common::String kFontBig; +/** + * Default font colours. They all seem to remain constant except for the + * first one which varies depending on the character speaking. + * kOverFontColour is set to transparent. + * TODO: Find out what kFontColour1 should actually be when the game starts + */ +enum { + kFontColour1 = 2, kFontColour2 = 0, + kFontColour3 = 3, kFontColour4 = 4, + kOverFontColour = 255 +}; + /** * Represents the game's fonts. See docs for setFont() for font format details. */ @@ -49,8 +61,8 @@ public: uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; - void drawChar(Graphics::Surface *dst, uint8 chr, int tx, int ty) const; - void drawString(Graphics::Surface *dst, const Common::String &str, + void drawChar(Surface *dst, uint8 chr, int tx, int ty) const; + void drawString(Surface *dst, const Common::String &str, int x, int y, int spacing = 0) const; int getStringWidth(const Common::String &str, int spacing = 0) const; void setColour(uint8 colour); -- cgit v1.2.3 From adef44e4519c1f553062b1f213028e8e1afe0512 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 19 Jun 2009 00:13:05 +0000 Subject: * Made the Screen class use the new Surface class. * Added Screen::drawRect() method. * Added support for updating dirty rectangles. svn-id: r41657 --- engines/draci/screen.cpp | 68 +++++++++++++++++++++++++++++++----------------- engines/draci/screen.h | 14 +++++----- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index a1ac27211e..9011fa235c 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -31,16 +31,14 @@ namespace Draci { Screen::Screen(DraciEngine *vm) : _vm(vm) { - _surface = new Graphics::Surface(); - _surface->create(kScreenWidth, kScreenHeight, 1); - this->clearScreen(); + _surface = new Surface(kScreenWidth, kScreenHeight); _palette = new byte[4 * kNumColours]; setPaletteEmpty(); + this->clearScreen(); } Screen::~Screen() { - _surface->free(); - delete[] _surface; + delete _surface; delete[] _palette; } @@ -50,7 +48,7 @@ void Screen::setPaletteEmpty(unsigned int numEntries) { } _vm->_system->setPalette(_palette, 0, numEntries); - _vm->_system->updateScreen(); + copyToScreen(); } void Screen::setPalette(byte *data, uint16 start, uint16 num) { @@ -73,49 +71,71 @@ void Screen::setPalette(byte *data, uint16 start, uint16 num) { } _vm->_system->setPalette(_palette, start, num); - _vm->_system->updateScreen(); + copyToScreen(); } void Screen::copyToScreen() const { - byte *ptr = (byte *)_surface->getBasePtr(0, 0); + Common::List *dirtyRects = _surface->getDirtyRects(); + Common::List::iterator it; + + if (_surface->needsFullUpdate()) { + byte *ptr = (byte *)_surface->getBasePtr(0, 0); - _vm->_system->copyRectToScreen(ptr, kScreenWidth, 0, 0, - kScreenWidth, kScreenHeight); + _vm->_system->copyRectToScreen(ptr, kScreenWidth, + 0, 0, kScreenWidth, kScreenHeight); + } else { + for (it = dirtyRects->begin(); it != dirtyRects->end(); ++it) { + byte *ptr = (byte *)_surface->getBasePtr(it->left, it->top); + _vm->_system->copyRectToScreen(ptr, kScreenWidth, + it->left, it->top, it->width(), it->height()); + } + } + _vm->_system->updateScreen(); + _surface->markClean(); } void Screen::clearScreen() const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); + _surface->markDirty(); + memset(ptr, 0, kScreenWidth * kScreenHeight); } -void Screen::drawSprite(const Sprite &s) const { - byte *dst = (byte *)_surface->getBasePtr(s._x, s._y); - byte *src = s._data; +void Screen::fillScreen(uint16 colour) const { + byte *ptr = (byte *)_surface->getBasePtr(0, 0); + + _surface->markDirty(); + + memset(ptr, colour, kScreenWidth * kScreenHeight); +} + +void Screen::drawRect(Common::Rect &r, uint8 colour) { + + r.clip(_surface->w, _surface->h); + + if (r.isEmpty()) + return; - for (unsigned int i = 0; i < s._height; ++i) { - for(unsigned int j = 0; j < s._width; ++j) { - dst[j] = *src++; + byte *ptr = (byte *)_surface->getBasePtr(r.left, r.top); + + for (uint16 i = 0; i < r.width(); ++i) { + for (uint16 j = 0; j < r.height(); ++j) { + ptr[j * kScreenWidth + i] = colour; } - - dst += _surface->pitch; } -} -void Screen::fillScreen(uint16 colour) const { - byte *ptr = (byte *)_surface->getBasePtr(0, 0); - - memset(ptr, colour, kScreenWidth * kScreenHeight); + _surface->markDirtyRect(r); } byte *Screen::getPalette() const { return _palette; } -Graphics::Surface *Screen::getSurface() { +Draci::Surface *Screen::getSurface() { return _surface; } diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 95b73b92ac..20fa3553f1 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -26,8 +26,7 @@ #ifndef DRACI_SCREEN_H #define DRACI_SCREEN_H -#include "graphics/surface.h" - +#include "draci/surface.h" #include "draci/sprite.h" namespace Draci { @@ -35,8 +34,8 @@ namespace Draci { enum ScreenParameters { kScreenWidth = 320, kScreenHeight = 200, - - kNumColours = 256 + kNumColours = 256, + kDefaultTransparent = 255 }; class DraciEngine; @@ -54,10 +53,11 @@ public: void clearScreen() const; void drawSprite(const Sprite &s) const; void fillScreen(uint16 colour) const; - Graphics::Surface *getSurface(); - + Surface *getSurface(); + void drawRect(Common::Rect &r, uint8 colour); + private: - Graphics::Surface *_surface; + Surface *_surface; byte *_palette; DraciEngine *_vm; }; -- cgit v1.2.3 From f15adff4d8d31d2cf2de149a39e228d6c2fa72bf Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 19 Jun 2009 00:15:28 +0000 Subject: Updated the demo animation to use the new Surface features (transparency, dirty rects). Changed background to light grey. A transparent string is now drawn over the dragon sprite. svn-id: r41658 --- engines/draci/draci.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 8d018ee023..6769d70300 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -130,12 +130,12 @@ int DraciEngine::go() { _screen->setPalette(f->_data, 0, kNumColours); - // Fill screen with white - _screen->fillScreen(255); + // Fill screen with light grey + _screen->fillScreen(225); // Draw big string Common::String testString = "Testing, testing, read all about it!"; - Graphics::Surface *surf = _screen->getSurface(); + Surface *surf = _screen->getSurface(); _font->drawString(surf, testString, (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 130, 1); @@ -160,13 +160,26 @@ int DraciEngine::go() { return 0; } + testString = "I'm transparent"; for (unsigned int t = 0; t < 25; ++t) { debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); // Load frame to memory f = ar[t]; Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, true); - _screen->drawSprite(sp); + + // Delete previous frame + Common::Rect r(sp._x, sp._y, sp._x + sp._width, sp._y + sp._height); + _screen->drawRect(r, 225); + + // Draw dragon + sp.draw(surf); + + // Draw transparent text over dragon + _font->setColour(kDefaultTransparent); + _font->drawString(surf, testString, + (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 80, 1); + _screen->copyToScreen(); _system->delayMillis(100); -- cgit v1.2.3 From a4693b863904360348c0c3e677fbf0fbcb2280f5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 22 Jun 2009 19:31:18 +0000 Subject: Replaced return values with Common::k*Error constants. svn-id: r41775 --- engines/draci/draci.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 6769d70300..c53700b4f6 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -82,7 +82,7 @@ int DraciEngine::init() { f = ar[0]; } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return 0; + return Common::kUnknownError; } debugC(3, kDraciGeneralDebugLevel, "First 10 bytes of file %d: ", 0); @@ -101,13 +101,13 @@ int DraciEngine::init() { f = ar[3]; } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return 0; + return Common::kUnknownError; } // Disassemble GPL script for the first location gpldisasm(f->_data, f->_length); - return 0; + return Common::kNoError; } int DraciEngine::go() { @@ -125,7 +125,7 @@ int DraciEngine::go() { f = ar[0]; } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return 0; + return Common::kUnknownError; } _screen->setPalette(f->_data, 0, kNumColours); @@ -157,7 +157,7 @@ int DraciEngine::go() { if(!ar.isOpen()) { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return 0; + return Common::kUnknownError; } testString = "I'm transparent"; @@ -193,7 +193,7 @@ int DraciEngine::go() { f = ar[0]; } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return 0; + return Common::kUnknownError; } Sprite sp(f->_data, f->_length, 0, 0, true); @@ -218,7 +218,7 @@ int DraciEngine::go() { _system->delayMillis(20); } - return 0; + return Common::kNoError; } DraciEngine::~DraciEngine() { -- cgit v1.2.3 From 8c3e1b0e8dd66e5c8eaa87f405a2d940c9e858ec Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 22 Jun 2009 19:32:47 +0000 Subject: Documentation fix for the Font class. svn-id: r41776 --- engines/draci/font.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 6dc6d7e7f6..d9e84899b7 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -136,7 +136,7 @@ uint8 Font::getCharWidth(uint8 chr) const { } /** - * @brief Draw a char to a Graphics::Surface + * @brief Draw a char to a Draci::Surface * * @param dst Pointer to the destination surface * @param chr Character to draw @@ -202,7 +202,7 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { } /** - * @brief Draw a string to a Graphics::Surface + * @brief Draw a string to a Draci::Surface * * @param dst Pointer to the destination surface * @param str String to draw -- cgit v1.2.3 From f5e39fa61d9a2ca46010c37701bd11547e3aa27f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 22 Jun 2009 20:13:25 +0000 Subject: * Expanded docs for the Sprite class * Added Surface and Screen docs * Small documentation fixes svn-id: r41779 --- engines/draci/font.h | 2 +- engines/draci/screen.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++-- engines/draci/sprite.cpp | 20 +++++++++++++++++-- engines/draci/sprite.h | 8 ++++---- engines/draci/surface.cpp | 27 ++++++++++++++++++++++++++ engines/draci/surface.h | 13 +++++++++++-- 6 files changed, 108 insertions(+), 11 deletions(-) diff --git a/engines/draci/font.h b/engines/draci/font.h index 3853e92eaa..a805a99016 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -37,7 +37,7 @@ extern const Common::String kFontBig; * Default font colours. They all seem to remain constant except for the * first one which varies depending on the character speaking. * kOverFontColour is set to transparent. - * TODO: Find out what kFontColour1 should actually be when the game starts + * TODO: Find out what kFontColour1 should actually be when the game starts */ enum { kFontColour1 = 2, kFontColour2 = 0, diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index 9011fa235c..3a5e0e8b58 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -42,6 +42,10 @@ Screen::~Screen() { delete[] _palette; } +/** + * @brief Sets the first numEntries of palette to zero + * @param numEntries The number of entries to set to zero (from start) + */ void Screen::setPaletteEmpty(unsigned int numEntries) { for (unsigned int i = 0; i < 4 * numEntries; ++i) { _palette[i] = 0; @@ -51,6 +55,12 @@ void Screen::setPaletteEmpty(unsigned int numEntries) { copyToScreen(); } +/** + * @brief Sets a part of the palette + * @param data Pointer to a buffer containing new palette data + * start Index of the colour where replacement should start + * num Number of colours to replace + */ void Screen::setPalette(byte *data, uint16 start, uint16 num) { Common::MemoryReadStream pal(data, 3 * kNumColours); @@ -65,7 +75,7 @@ void Screen::setPalette(byte *data, uint16 start, uint16 num) { } // TODO: Investigate why this is needed - // Shift the palette one bit to the left to make it brighter + // Shift the palette two bits to the left to make it brighter for (unsigned int i = 0; i < 4 * kNumColours; ++i) { _palette[i] <<= 2; } @@ -74,17 +84,26 @@ void Screen::setPalette(byte *data, uint16 start, uint16 num) { copyToScreen(); } +/** + * @brief Copies the current memory screen buffer to the real screen + */ void Screen::copyToScreen() const { Common::List *dirtyRects = _surface->getDirtyRects(); Common::List::iterator it; + // If a full update is needed, update the whole screen if (_surface->needsFullUpdate()) { byte *ptr = (byte *)_surface->getBasePtr(0, 0); _vm->_system->copyRectToScreen(ptr, kScreenWidth, 0, 0, kScreenWidth, kScreenHeight); } else { + + // Otherwise, update only the dirty rectangles + for (it = dirtyRects->begin(); it != dirtyRects->end(); ++it) { + + // Pointer to the upper left corner of the rectangle byte *ptr = (byte *)_surface->getBasePtr(it->left, it->top); _vm->_system->copyRectToScreen(ptr, kScreenWidth, @@ -92,11 +111,16 @@ void Screen::copyToScreen() const { } } + // Call the "real" updateScreen and mark the surface clean _vm->_system->updateScreen(); _surface->markClean(); } - +/** + * @brief Clears the screen + * + * Clears the screen and marks the whole screen dirty. + */ void Screen::clearScreen() const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); @@ -105,6 +129,12 @@ void Screen::clearScreen() const { memset(ptr, 0, kScreenWidth * kScreenHeight); } +/** + * @brief Fills the screen with the specified colour + * @param colour The colour the screen should be filled with + * + * Fills the screen with the specified colour and marks the whole screen dirty. + */ void Screen::fillScreen(uint16 colour) const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); @@ -113,10 +143,17 @@ void Screen::fillScreen(uint16 colour) const { memset(ptr, colour, kScreenWidth * kScreenHeight); } +/** + * @brief Draws a rectangle on the screen + * @param r Which rectangle to draw + * colour The colour of the rectangle + */ void Screen::drawRect(Common::Rect &r, uint8 colour) { + // Clip the rectangle to screen size r.clip(_surface->w, _surface->h); + // If the whole rectangle is outside the screen, return if (r.isEmpty()) return; @@ -131,10 +168,18 @@ void Screen::drawRect(Common::Rect &r, uint8 colour) { _surface->markDirtyRect(r); } +/** + * @brief Fetches the current palette + * @return A byte pointer to the current palette + */ byte *Screen::getPalette() const { return _palette; } +/** + * @brief Fetches the current surface + * @return A pointer to the current surface + */ Draci::Surface *Screen::getSurface() { return _surface; } diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 6a55894907..e54364bd44 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -37,7 +37,10 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, bool columnwise) : _width(width), _height(height), _x(x), _y(y), _data(NULL) { _data = new byte[width * height]; - + + // If the sprite is stored row-wise, just copy it to the internal buffer. + // Otherwise, transform it and then copy. + if (!columnwise) { memcpy(_data, raw_data, width * height); } else { @@ -62,7 +65,10 @@ Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, _height = reader.readUint16LE(); _data = new byte[_width * _height]; - + + // If the sprite is stored row-wise, just copy it to the internal buffer. + // Otherwise, transform it and then copy. + if (!columnwise) { reader.read(_data, _width * _height); } else { @@ -78,12 +84,21 @@ Sprite::~Sprite() { delete[] _data; } +/** + * @brief Draws the sprite to a Draci::Surface + * @param surface Pointer to a Draci::Surface + * + * Draws the sprite to a Draci::Surface and marks its rectangle on the surface as dirty. + */ void Sprite::draw(Surface *surface) const { byte *dst = (byte *)surface->getBasePtr(_x, _y); byte *src = _data; + // Blit the sprite to the surface for (unsigned int i = 0; i < _height; ++i) { for(unsigned int j = 0; j < _width; ++j, ++src) { + + // Don't blit if the pixel is transparent on the target surface if (*src != surface->getTransparentColour()) dst[j] = *src; } @@ -91,6 +106,7 @@ void Sprite::draw(Surface *surface) const { dst += surface->pitch; } + // Mark the sprite's rectangle dirty Common::Rect r(_x, _y, _x + _width, _y + _height); surface->markDirtyRect(r); } diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 0bd825cf14..18ea899641 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -56,10 +56,10 @@ public: void draw(Surface *surface) const; - byte *_data; - uint16 _width; - uint16 _height; - uint16 _x, _y; + byte *_data; //!< Pointer to a buffer containing raw sprite data (row-wise) + uint16 _width; //!< Width of the sprite + uint16 _height; //!< Height of the sprite + uint16 _x, _y; //!< Sprite coordinates }; diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp index 1c7fce08b5..148c24633b 100644 --- a/engines/draci/surface.cpp +++ b/engines/draci/surface.cpp @@ -38,6 +38,10 @@ Surface::~Surface() { this->free(); } +/** + * @brief Marks a dirty rectangle on the surface + * @param r The rectangle to be marked dirty + */ void Surface::markDirtyRect(Common::Rect r) { Common::List::iterator it; @@ -61,31 +65,54 @@ void Surface::markDirtyRect(Common::Rect r) { _dirtyRects.push_back(r); } +/** + * @brief Clears all dirty rectangles + * + */ void Surface::clearDirtyRects() { _dirtyRects.clear(); } +/** + * @brief Marks the whole surface dirty + */ void Surface::markDirty() { _fullUpdate = true; } +/** + * @brief Marks the whole surface clean + */ void Surface::markClean() { _fullUpdate = false; _dirtyRects.clear(); } +/** + * @brief Checks whether the surface needs a full update + */ bool Surface::needsFullUpdate() { return _fullUpdate; } +/** + * @brief Fetches the surface's dirty rectangles + * @return A pointer a list of dirty rectangles + */ Common::List *Surface::getDirtyRects() { return &_dirtyRects; } +/** + * @brief Returns the current transparent colour of the surface + */ uint8 Surface::getTransparentColour() { return _transparentColour; } +/** + * @brief Sets the surface's transparent colour + */ void Surface::setTransparentColour(uint8 colour) { _transparentColour = colour; } diff --git a/engines/draci/surface.h b/engines/draci/surface.h index cc1dff806b..20df29d7f9 100644 --- a/engines/draci/surface.h +++ b/engines/draci/surface.h @@ -46,9 +46,18 @@ public: void setTransparentColour(uint8 colour); private: - bool _fullUpdate; + /** The current transparent colour of the surface. See getTransparentColour() and + * setTransparentColour(). + */ uint8 _transparentColour; - Common::List _dirtyRects; + + /** Set when the surface is scheduled for a full update. + * See markDirty(), markClean(). Accessed via needsFullUpdate(). + */ + bool _fullUpdate; + + Common::List _dirtyRects; //!< List of currently dirty rectangles + }; } // End of namespace Draci -- cgit v1.2.3 From 36fd17d499f6357a1b28d6271e87b07557685471 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 22 Jun 2009 20:18:53 +0000 Subject: Changed Font::fillScreen() to accept a uint8 instead of a uint16. svn-id: r41780 --- engines/draci/screen.cpp | 2 +- engines/draci/screen.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index 3a5e0e8b58..bc10249332 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -135,7 +135,7 @@ void Screen::clearScreen() const { * * Fills the screen with the specified colour and marks the whole screen dirty. */ -void Screen::fillScreen(uint16 colour) const { +void Screen::fillScreen(uint8 colour) const { byte *ptr = (byte *)_surface->getBasePtr(0, 0); _surface->markDirty(); diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 20fa3553f1..4c09e77926 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -52,7 +52,7 @@ public: void copyToScreen() const; void clearScreen() const; void drawSprite(const Sprite &s) const; - void fillScreen(uint16 colour) const; + void fillScreen(uint8 colour) const; Surface *getSurface(); void drawRect(Common::Rect &r, uint8 colour); -- cgit v1.2.3 From c87f05b14cae5253ff5635e4d23638aff3a1b3b5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 24 Jun 2009 23:58:30 +0000 Subject: Started work on the Mouse class. svn-id: r41840 --- engines/draci/draci.cpp | 6 ++-- engines/draci/draci.h | 2 ++ engines/draci/module.mk | 3 +- engines/draci/mouse.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ engines/draci/mouse.h | 68 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 engines/draci/mouse.cpp create mode 100644 engines/draci/mouse.h diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index c53700b4f6..8c92f97340 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -38,6 +38,7 @@ #include "draci/font.h" #include "draci/sprite.h" #include "draci/screen.h" +#include "draci/mouse.h" namespace Draci { @@ -65,6 +66,7 @@ int DraciEngine::init() { // Initialize graphics using following: initGraphics(kScreenWidth, kScreenHeight, false); + _mouse = new Mouse(this); _screen = new Screen(this); _font = new Font(); @@ -208,10 +210,8 @@ int DraciEngine::go() { switch (event.type) { case Common::EVENT_QUIT: quit = true; - case Common::EVENT_MOUSEMOVE: - _system->warpMouse(event.mouse.x, event.mouse.y); default: - break; + _mouse->handleEvent(event); } } _screen->copyToScreen(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 851fc12ed2..1b91e89623 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -30,6 +30,7 @@ #include "engines/engine.h" #include "engines/advancedDetector.h" +#include "draci/mouse.h" #include "draci/screen.h" #include "draci/font.h" @@ -48,6 +49,7 @@ public: Font *_font; Screen *_screen; + Mouse *_mouse; private: Common::RandomSource _rnd; diff --git a/engines/draci/module.mk b/engines/draci/module.mk index 128e4ba8e9..57a860857e 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -8,7 +8,8 @@ MODULE_OBJS := \ font.o \ sprite.o \ screen.o \ - surface.o + surface.o \ + mouse.o MODULE_DIRS += \ engines/draci diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp new file mode 100644 index 0000000000..b954915b8d --- /dev/null +++ b/engines/draci/mouse.cpp @@ -0,0 +1,85 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "draci/draci.h" +#include "draci/mouse.h" + +namespace Draci { + +Mouse::Mouse(DraciEngine *vm) { + _x = 0; + _y = 0; + _lButton = false; + _rButton = false; + _cursorNum = kNormalCursor; + _vm = vm; +} + +void Mouse::handleEvent(Common::Event event) { + _x = (uint16) event.mouse.x; + _y = (uint16) event.mouse.y; + + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: + debugC(6, kDraciGeneralDebugLevel, "Left button down (x: %u y: %u)", _x, _y); + _lButton = true; + break; + case Common::EVENT_LBUTTONUP: + debugC(6, kDraciGeneralDebugLevel, "Left up down (x: %u y: %u)", _x, _y); + _lButton = false; + break; + case Common::EVENT_RBUTTONDOWN: + debugC(6, kDraciGeneralDebugLevel, "Right button down (x: %u y: %u)", _x, _y); + _rButton = true; + break; + case Common::EVENT_RBUTTONUP: + debugC(6, kDraciGeneralDebugLevel, "Right button up (x: %u y: %u)", _x, _y); + _rButton = false; + break; + case Common::EVENT_MOUSEMOVE: + setPosition(_x, _y); + break; + default: + break; + } +} + +void Mouse::cursorOn() { + CursorMan.showMouse(true); +} + +void Mouse::cursorOff() { + CursorMan.showMouse(false); +} + +void Mouse::setPosition(uint16 x, uint16 y) { + _vm->_system->warpMouse(x, y); +} + +// FIXME: stub +void Mouse::setCursorNum(CursorType cursorNum) { +} + +} diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h new file mode 100644 index 0000000000..cb14c14383 --- /dev/null +++ b/engines/draci/mouse.h @@ -0,0 +1,68 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef DRACI_MOUSE_H +#define DRACI_MOUSE_H + +#include "common/events.h" +#include "graphics/cursorman.h" + +namespace Draci { + +enum CursorType { + kNormalCursor, kArrowCursor1, + kArrowCursor2, kArrowCursor3, + kArrowCursor4, kDialogCursor, + kHighlightedCursor, kMainMenuCursor +}; + +class DraciEngine; + +class Mouse { +public: + Mouse(DraciEngine *vm); + ~Mouse() {}; + + void handleEvent(Common::Event event); + void cursorOn(); + void cursorOff(); + void setPosition(uint16 x, uint16 y); + void setCursorNum(CursorType cursorNum); + CursorType getCursorNum() { return _cursorNum; } + bool lButtonPressed() { return _lButton; } + bool rButtonPressed() { return _rButton; } + uint16 getPosX() { return _x; } + uint16 getPosY() { return _y; } + +private: + uint16 _x, _y; + bool _lButton, _rButton; + CursorType _cursorNum; + DraciEngine *_vm; +}; + +} + +#endif // DRACI_MOUSE_H -- cgit v1.2.3 From 02dadc70fce56be7bfb3704de13367c3142c6ff3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 25 Jun 2009 11:02:10 +0000 Subject: Implemented some more methods in Mouse so all mouse-related events are handled through it. svn-id: r41861 --- engines/draci/draci.cpp | 25 +++++++------------------ engines/draci/mouse.cpp | 21 ++++++++++++++++++++- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 8c92f97340..36c65fdbb3 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -66,9 +66,9 @@ int DraciEngine::init() { // Initialize graphics using following: initGraphics(kScreenWidth, kScreenHeight, false); - _mouse = new Mouse(this); _screen = new Screen(this); _font = new Font(); + _mouse = new Mouse(this); // Load default font _font->setFont(kFontBig); @@ -131,7 +131,7 @@ int DraciEngine::go() { } _screen->setPalette(f->_data, 0, kNumColours); - + // Fill screen with light grey _screen->fillScreen(225); @@ -186,22 +186,10 @@ int DraciEngine::go() { _system->delayMillis(100); debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); - } - - path = "HRA.DFW"; - ar.openArchive(path); - - if(ar.isOpen()) { - f = ar[0]; - } else { - debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return Common::kUnknownError; - } + } - Sprite sp(f->_data, f->_length, 0, 0, true); - CursorMan.pushCursorPalette(_screen->getPalette(), 0, kNumColours); - CursorMan.pushCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); - CursorMan.showMouse(true); + _mouse->setCursorNum(kNormalCursor); + _mouse->cursorOn(); Common::Event event; bool quit = false; @@ -210,9 +198,10 @@ int DraciEngine::go() { switch (event.type) { case Common::EVENT_QUIT: quit = true; + break; default: _mouse->handleEvent(event); - } + } } _screen->copyToScreen(); _system->delayMillis(20); diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index b954915b8d..83ae0bab1a 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -25,6 +25,7 @@ #include "draci/draci.h" #include "draci/mouse.h" +#include "draci/barchive.h" namespace Draci { @@ -78,8 +79,26 @@ void Mouse::setPosition(uint16 x, uint16 y) { _vm->_system->warpMouse(x, y); } -// FIXME: stub +// FIXME: Handle hotspots properly +// TODO: Implement a resource manager void Mouse::setCursorNum(CursorType cursorNum) { + _cursorNum = cursorNum; + + Common::String path("HRA.DFW"); + BAFile *f; + BArchive ar; + ar.openArchive(path); + + if(ar.isOpen()) { + f = ar[cursorNum]; + } else { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened - %s", path.c_str()); + return; + } + + Sprite sp(f->_data, f->_length, 0, 0, true); + CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); + CursorMan.replaceCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); } } -- cgit v1.2.3 From d6729f380409096c1e4a54d0a605169506a85ff4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 25 Jun 2009 14:03:57 +0000 Subject: Added transformToRows() static method to Sprite. Modified Sprite constructors to use it. svn-id: r41865 --- engines/draci/sprite.cpp | 54 +++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index e54364bd44..6e4cb8b6b6 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -30,6 +30,26 @@ namespace Draci { +/** + * @brief Transforms an image from column-wise to row-wise + * @param img pointer to the buffer containing the image data + * width width of the image in the buffer + * height height of the image in the buffer + */ +static void transformToRows(byte *img, uint16 width, uint16 height) { + byte *buf = new byte[width * height]; + byte *tmp = buf; + memcpy(buf, img, width * height); + + for (uint16 i = 0; i < width; ++i) { + for (uint16 j = 0; j < height; ++j) { + img[j * width + i] = *tmp++; + } + } + + delete[] buf; +} + /** * Constructor for loading sprites from a raw data buffer, one byte per pixel. */ @@ -38,18 +58,12 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, _data = new byte[width * height]; - // If the sprite is stored row-wise, just copy it to the internal buffer. - // Otherwise, transform it and then copy. - - if (!columnwise) { - memcpy(_data, raw_data, width * height); - } else { - for (uint16 i = 0; i < width; ++i) { - for (uint16 j = 0; j < height; ++j) { - _data[j * width + i] = *raw_data++; - } - } - } + memcpy(_data, raw_data, width * height); + + // If the sprite is stored column-wise, transform it to row-wise + if (columnwise) { + transformToRows(_data, width, height); + } } /** @@ -66,17 +80,11 @@ Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, _data = new byte[_width * _height]; - // If the sprite is stored row-wise, just copy it to the internal buffer. - // Otherwise, transform it and then copy. - - if (!columnwise) { - reader.read(_data, _width * _height); - } else { - for (uint16 i = 0; i < _width; ++i) { - for (uint16 j = 0; j < _height; ++j) { - _data[j * _width + i] = reader.readByte(); - } - } + reader.read(_data, _width * _height); + + // If the sprite is stored column-wise, transform it to row-wise + if (columnwise) { + transformToRows(_data, _width, _height); } } -- cgit v1.2.3 From 566dd20e4f9ecad6d6b96bd720673f80282350ff Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 25 Jun 2009 15:08:49 +0000 Subject: Renamed *cursorNum identifiers in Mouse to *cursorType for consistency. svn-id: r41866 --- engines/draci/draci.cpp | 2 +- engines/draci/mouse.cpp | 8 ++++---- engines/draci/mouse.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 36c65fdbb3..457119cbbd 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -188,7 +188,7 @@ int DraciEngine::go() { debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); } - _mouse->setCursorNum(kNormalCursor); + _mouse->setCursorType(kNormalCursor); _mouse->cursorOn(); Common::Event event; diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 83ae0bab1a..c1a4e7bc21 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -34,7 +34,7 @@ Mouse::Mouse(DraciEngine *vm) { _y = 0; _lButton = false; _rButton = false; - _cursorNum = kNormalCursor; + _cursorType = kNormalCursor; _vm = vm; } @@ -81,8 +81,8 @@ void Mouse::setPosition(uint16 x, uint16 y) { // FIXME: Handle hotspots properly // TODO: Implement a resource manager -void Mouse::setCursorNum(CursorType cursorNum) { - _cursorNum = cursorNum; +void Mouse::setCursorType(CursorType cur) { + _cursorType = cur; Common::String path("HRA.DFW"); BAFile *f; @@ -90,7 +90,7 @@ void Mouse::setCursorNum(CursorType cursorNum) { ar.openArchive(path); if(ar.isOpen()) { - f = ar[cursorNum]; + f = ar[_cursorType]; } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened - %s", path.c_str()); return; diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h index cb14c14383..918b10d75f 100644 --- a/engines/draci/mouse.h +++ b/engines/draci/mouse.h @@ -49,8 +49,8 @@ public: void cursorOn(); void cursorOff(); void setPosition(uint16 x, uint16 y); - void setCursorNum(CursorType cursorNum); - CursorType getCursorNum() { return _cursorNum; } + void setCursorType(CursorType cur); + CursorType getCursorType() { return _cursorType; } bool lButtonPressed() { return _lButton; } bool rButtonPressed() { return _rButton; } uint16 getPosX() { return _x; } @@ -59,7 +59,7 @@ public: private: uint16 _x, _y; bool _lButton, _rButton; - CursorType _cursorNum; + CursorType _cursorType; DraciEngine *_vm; }; -- cgit v1.2.3 From a1b02870d898bc24dcd3776ecb0bee00791b4cd9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 25 Jun 2009 16:02:00 +0000 Subject: Made the DraciEngine destructor free _font and _mouse. svn-id: r41872 --- engines/draci/draci.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 457119cbbd..e0cbcafe19 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -214,7 +214,9 @@ DraciEngine::~DraciEngine() { // Dispose your resources here delete _screen; - + delete _font; + delete _mouse; + // Remove all of our debug levels here Common::clearAllDebugChannels(); } -- cgit v1.2.3 From 09313ccebb93ae38141cbe39d19a4556417bd9d4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 25 Jun 2009 17:56:14 +0000 Subject: Fixed typo. svn-id: r41873 --- engines/draci/mouse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index c1a4e7bc21..24a53141f5 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -48,7 +48,7 @@ void Mouse::handleEvent(Common::Event event) { _lButton = true; break; case Common::EVENT_LBUTTONUP: - debugC(6, kDraciGeneralDebugLevel, "Left up down (x: %u y: %u)", _x, _y); + debugC(6, kDraciGeneralDebugLevel, "Left button down (x: %u y: %u)", _x, _y); _lButton = false; break; case Common::EVENT_RBUTTONDOWN: -- cgit v1.2.3 From 991102681694cf5fec6b88205ca7fd5446102b51 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 25 Jun 2009 18:06:35 +0000 Subject: Oops, really fixed typo. svn-id: r41874 --- engines/draci/mouse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 24a53141f5..d8b9935f2e 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -48,7 +48,7 @@ void Mouse::handleEvent(Common::Event event) { _lButton = true; break; case Common::EVENT_LBUTTONUP: - debugC(6, kDraciGeneralDebugLevel, "Left button down (x: %u y: %u)", _x, _y); + debugC(6, kDraciGeneralDebugLevel, "Left button up (x: %u y: %u)", _x, _y); _lButton = false; break; case Common::EVENT_RBUTTONDOWN: -- cgit v1.2.3 From c1644493b87204728f2ec9a32df28e40e9542103 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 26 Jun 2009 23:34:06 +0000 Subject: Added empty Game class. svn-id: r41906 --- engines/draci/game.cpp | 26 ++++++++++++++++++++++++++ engines/draci/game.h | 36 ++++++++++++++++++++++++++++++++++++ engines/draci/module.mk | 3 ++- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 engines/draci/game.cpp create mode 100644 engines/draci/game.h diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp new file mode 100644 index 0000000000..cc008abd8f --- /dev/null +++ b/engines/draci/game.cpp @@ -0,0 +1,26 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "draci/game.h" diff --git a/engines/draci/game.h b/engines/draci/game.h new file mode 100644 index 0000000000..d2c42fe83e --- /dev/null +++ b/engines/draci/game.h @@ -0,0 +1,36 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef DRACI_GAME_H +#define DRACI_GAME_H + +namespace Draci { + +class Game { +}; + +} // End of namespace Draci + +#endif // DRACI_GAME_H diff --git a/engines/draci/module.mk b/engines/draci/module.mk index 57a860857e..2d7c33a1bf 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -9,7 +9,8 @@ MODULE_OBJS := \ sprite.o \ screen.o \ surface.o \ - mouse.o + mouse.o \ + game.o MODULE_DIRS += \ engines/draci -- cgit v1.2.3 From 04309390069f8466ddeadd599c403aca9c1e3ccd Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 27 Jun 2009 01:04:24 +0000 Subject: Added Game's constructor. Added the Person struct and made Game constructor read in the list of persons from INIT.DFW. Added Game instance to DraciEngine. svn-id: r41907 --- engines/draci/draci.cpp | 1 + engines/draci/draci.h | 2 ++ engines/draci/game.cpp | 27 +++++++++++++++++++++++++++ engines/draci/game.h | 18 ++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index e0cbcafe19..3fc9553a8c 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -69,6 +69,7 @@ int DraciEngine::init() { _screen = new Screen(this); _font = new Font(); _mouse = new Mouse(this); + _game = new Game(); // Load default font _font->setFont(kFontBig); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 1b91e89623..5062eba563 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -30,6 +30,7 @@ #include "engines/engine.h" #include "engines/advancedDetector.h" +#include "draci/game.h" #include "draci/mouse.h" #include "draci/screen.h" #include "draci/font.h" @@ -50,6 +51,7 @@ public: Font *_font; Screen *_screen; Mouse *_mouse; + Game *_game; private: Common::RandomSource _rnd; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index cc008abd8f..358956c50b 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -23,4 +23,31 @@ * */ +#include "common/stream.h" + +#include "draci/draci.h" #include "draci/game.h" +#include "draci/barchive.h" + +namespace Draci { + +Game::Game() { + Common::String path("INIT.DFW"); + + BArchive initArchive(path); + BAFile *file; + + file = initArchive[5]; + Common::MemoryReadStream reader(file->_data, file->_length); + + unsigned int numPersons = file->_length / personSize; + _persons = new Person[numPersons]; + + for (unsigned int i = 0; i < numPersons; ++i) { + _persons[i]._x = reader.readByte(); + _persons[i]._y = reader.readByte(); + _persons[i]._fontColour = reader.readUint16LE(); + } +} + +} diff --git a/engines/draci/game.h b/engines/draci/game.h index d2c42fe83e..5c0524fab5 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -26,9 +26,27 @@ #ifndef DRACI_GAME_H #define DRACI_GAME_H +#include "common/str.h" + namespace Draci { +enum StructSizes { + personSize = 3 +}; + +struct Person { + uint16 _x, _y; + byte _fontColour; +}; + class Game { + +public: + Game(); + ~Game(); + +private: + Person *_persons; }; } // End of namespace Draci -- cgit v1.2.3 From 746e2214ee6f2e3eeab0afa7552aaa675ccdf40d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 27 Jun 2009 05:10:24 +0000 Subject: Extended Game to load all info from INIT.DFW (general game info, dialog offsets, variables, item status, object status). svn-id: r41908 --- engines/draci/game.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++++--- engines/draci/game.h | 21 +++++++++++- 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 358956c50b..1b6a25679d 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -32,22 +32,104 @@ namespace Draci { Game::Game() { + unsigned int i; Common::String path("INIT.DFW"); BArchive initArchive(path); BAFile *file; + // Read in persons + file = initArchive[5]; - Common::MemoryReadStream reader(file->_data, file->_length); + Common::MemoryReadStream personData(file->_data, file->_length); unsigned int numPersons = file->_length / personSize; _persons = new Person[numPersons]; - for (unsigned int i = 0; i < numPersons; ++i) { - _persons[i]._x = reader.readByte(); - _persons[i]._y = reader.readByte(); - _persons[i]._fontColour = reader.readUint16LE(); + for (i = 0; i < numPersons; ++i) { + _persons[i]._x = personData.readByte(); + _persons[i]._y = personData.readByte(); + _persons[i]._fontColour = personData.readUint16LE(); + } + + // Read in dialog offsets + + file = initArchive[4]; + Common::MemoryReadStream dialogData(file->_data, file->_length); + + unsigned int numDialogs = file->_length / sizeof(uint16); + _dialogOffsets = new uint16[numDialogs]; + + unsigned int curOffset; + for (i = 0, curOffset = 0; i < numDialogs; ++i) { + _dialogOffsets[i] = curOffset; + curOffset += dialogData.readUint16LE(); } + + // Read in game info + + file = initArchive[3]; + Common::MemoryReadStream gameData(file->_data, file->_length); + _info = new GameInfo(); + + _info->_currentRoom = gameData.readByte(); + _info->_mapRoom = gameData.readByte(); + _info->_numObjects = gameData.readUint16LE(); + _info->_numIcons = gameData.readUint16LE(); + _info->_numVariables = gameData.readByte(); + _info->_numPersons = gameData.readByte(); + _info->_numDialogs = gameData.readByte(); + _info->_maxIconWidth = gameData.readUint16LE(); + _info->_maxIconHeight = gameData.readUint16LE(); + _info->_musicLength = gameData.readUint32LE(); + +// FIXME: Something is wrong here. The total file length is only 23 bytes +// but the whole struct should be 35 bytes. + _info->_crc[0] = gameData.readUint32LE(); + _info->_crc[1] = gameData.readUint32LE(); + _info->_crc[2] = gameData.readUint32LE(); + _info->_crc[3] = gameData.readUint32LE(); + _info->_numDialogBlocks = gameData.readUint16LE(); + + // Read in variables + + file = initArchive[2]; + unsigned int numVariables = file->_length / sizeof (int16); + + _variables = new int16[numVariables]; + memcpy(_variables, file->_data, file->_length); + + // Read in item status + + file = initArchive[1]; + _itemStatus = new byte[file->_length]; + memcpy(_itemStatus, file->_data, file->_length); + + // Read in object status + + file = initArchive[0]; + unsigned int numObjects = file->_length; + + _objectStatus = new byte[numObjects]; + memcpy(_objectStatus, file->_data, file->_length); + + assert(numDialogs == _info->_numDialogs); + assert(numPersons == _info->_numPersons); + assert(numVariables == _info->_numVariables); + assert(numObjects == _info->_numObjects); + +// TODO: Why is this failing? +// assert(curOffset == _info->_numDialogBlocks); + } +Game::~Game() { + delete[] _persons; + delete[] _variables; + delete[] _dialogOffsets; + delete[] _itemStatus; + delete[] _objectStatus; + delete _info; +} + } diff --git a/engines/draci/game.h b/engines/draci/game.h index 5c0524fab5..418cccb11c 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -31,7 +31,21 @@ namespace Draci { enum StructSizes { - personSize = 3 + personSize = sizeof(uint16) * 2 + sizeof(byte) +}; + +struct GameInfo { + byte _currentRoom; + byte _mapRoom; + uint16 _numObjects; + uint16 _numIcons; + byte _numVariables; + byte _numPersons; + byte _numDialogs; + uint16 _maxIconWidth, _maxIconHeight; + uint32 _musicLength; + uint32 _crc[4]; + uint16 _numDialogBlocks; }; struct Person { @@ -46,7 +60,12 @@ public: ~Game(); private: + GameInfo *_info; Person *_persons; + uint16 *_dialogOffsets; + int16 *_variables; + byte *_itemStatus; + byte *_objectStatus; }; } // End of namespace Draci -- cgit v1.2.3 From 2e30fae261307b47885ade487a43d418bfe15fa5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 27 Jun 2009 15:00:14 +0000 Subject: Renamed gpldisasm.* to script.* in anticipation of using it as a script intepreter. svn-id: r41918 --- engines/draci/gpldisasm.cpp | 319 -------------------------------------------- engines/draci/gpldisasm.h | 56 -------- engines/draci/module.mk | 2 +- engines/draci/script.cpp | 319 ++++++++++++++++++++++++++++++++++++++++++++ engines/draci/script.h | 56 ++++++++ 5 files changed, 376 insertions(+), 376 deletions(-) delete mode 100644 engines/draci/gpldisasm.cpp delete mode 100644 engines/draci/gpldisasm.h create mode 100644 engines/draci/script.cpp create mode 100644 engines/draci/script.h diff --git a/engines/draci/gpldisasm.cpp b/engines/draci/gpldisasm.cpp deleted file mode 100644 index ee7b128529..0000000000 --- a/engines/draci/gpldisasm.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/debug.h" -#include "common/stream.h" -#include "common/stack.h" - -#include "draci/gpldisasm.h" -#include "draci/draci.h" - -namespace Draci { - -// FIXME: Change parameter types to names once I figure out what they are exactly - -/** A table of all the commands the game player uses */ -GPL2Command gplCommands[] = { - { 0, 0, "gplend", 0, { 0 } }, - { 0, 1, "exit", 0, { 0 } }, - { 1, 1, "goto", 1, { 3 } }, - { 2, 1, "Let", 2, { 3, 4 } }, - { 3, 1, "if", 2, { 4, 3 } }, - { 4, 1, "Start", 2, { 3, 2 } }, - { 5, 1, "Load", 2, { 3, 2 } }, - { 5, 2, "StartPlay", 2, { 3, 2 } }, - { 5, 3, "JustTalk", 0, { 0 } }, - { 5, 4, "JustStay", 0, { 0 } }, - { 6, 1, "Talk", 2, { 3, 2 } }, - { 7, 1, "ObjStat", 2, { 3, 3 } }, - { 7, 2, "ObjStat_On", 2, { 3, 3 } }, - { 8, 1, "IcoStat", 2, { 3, 3 } }, - { 9, 1, "Dialogue", 1, { 2 } }, - { 9, 2, "ExitDialogue", 0, { 0 } }, - { 9, 3, "ResetDialogue", 0, { 0 } }, - { 9, 4, "ResetDialogueFrom", 0, { 0 } }, - { 9, 5, "ResetBlock", 1, { 3 } }, - { 10, 1, "WalkOn", 3, { 1, 1, 3 } }, - { 10, 2, "StayOn", 3, { 1, 1, 3 } }, - { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 } }, - { 11, 1, "LoadPalette", 1, { 2 } }, - { 12, 1, "SetPalette", 0, { 0 } }, - { 12, 2, "BlackPalette", 0, { 0 } }, - { 13, 1, "FadePalette", 3, { 1, 1, 1 } }, - { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 } }, - { 14, 1, "NewRoom", 2, { 3, 1 } }, - { 15, 1, "ExecInit", 1, { 3 } }, - { 15, 2, "ExecLook", 1, { 3 } }, - { 15, 3, "ExecUse", 1, { 3 } }, - { 16, 1, "RepaintInventory", 0, { 0 } }, - { 16, 2, "ExitInventory", 0, { 0 } }, - { 17, 1, "ExitMap", 0, { 0 } }, - { 18, 1, "LoadMusic", 1, { 2 } }, - { 18, 2, "StartMusic", 0, { 0 } }, - { 18, 3, "StopMusic", 0, { 0 } }, - { 18, 4, "FadeOutMusic", 1, { 1 } }, - { 18, 5, "FadeInMusic", 1, { 1 } }, - { 19, 1, "Mark", 0, { 0 } }, - { 19, 2, "Release", 0, { 0 } }, - { 20, 1, "Play", 0, { 0 } }, - { 21, 1, "LoadMap", 1, { 2 } }, - { 21, 2, "RoomMap", 0, { 0 } }, - { 22, 1, "DisableQuickHero", 0, { 0 } }, - { 22, 2, "EnableQuickHero", 0, { 0 } }, - { 23, 1, "DisableSpeedText", 0, { 0 } }, - { 23, 2, "EnableSpeedText", 0, { 0 } }, - { 24, 1, "QuitGame", 0, { 0 } }, - { 25, 1, "PushNewRoom", 0, { 0 } }, - { 25, 2, "PopNewRoom", 0, { 0 } }, - { 26, 1, "ShowCheat", 0, { 0 } }, - { 26, 2, "HideCheat", 0, { 0 } }, - { 26, 3, "ClearCheat", 1, { 1 } }, - { 27, 1, "FeedPassword", 3, { 1, 1, 1 } } -}; - -/** Operators used by the mathematical evaluator */ -Common::String operators[] = { - "oper_and", - "oper_or", - "oper_xor", - "oper_equals", - "oper_not_equal", - "oper_less_than", - "oper_greater_than", - "oper_less_or_equal", - "oper_greater_or_equal", - "oper_multiply", - "oper_divide", - "oper_remainder", - "oper_plus", - "oper_minus" -}; - -/** Functions used by the mathematical evaluator */ -Common::String functions[] = { - "F_Not", - "F_Random", - "F_IsIcoOn", - "F_IsIcoAct", - "F_IcoStat", - "F_ActIco", - "F_IsObjOn", - "F_IsObjOff", - "F_IsObjAway", - "F_ObjStat", - "F_LastBlock", - "F_AtBegin", - "F_BlockVar", - "F_HasBeen", - "F_MaxLine", - "F_ActPhase", - "F_Cheat" -}; - -const unsigned int kNumCommands = sizeof gplCommands / sizeof gplCommands[0]; - -/** Type of mathematical object */ -enum mathExpressionObject { - kMathEnd, - kMathNumber, - kMathOperator, - kMathFunctionCall, - kMathVariable -}; - -// FIXME: The evaluator is now complete but I still need to implement callbacks - -/** - * @brief Evaluates mathematical expressions - * @param reader Stream reader set to the beginning of the expression - */ - -void handleMathExpression(Common::MemoryReadStream &reader) { - Common::Stack stk; - mathExpressionObject obj; - - // Read in initial math object - obj = (mathExpressionObject)reader.readUint16LE(); - - uint16 value; - while (1) { - if (obj == kMathEnd) { - // Check whether the expression was evaluated correctly - // The stack should contain only one value after the evaluation - // i.e. the result of the expression - assert(stk.size() == 1 && "Mathematical expression error"); - break; - } - - switch (obj) { - - // If the object type is not known, assume that it's a number - default: - case kMathNumber: - value = reader.readUint16LE(); - stk.push(value); - debugC(3, kDraciBytecodeDebugLevel, "\t\t-number %hu", value); - break; - - case kMathOperator: - value = reader.readUint16LE(); - stk.pop(); - stk.pop(); - - // FIXME: Pushing dummy value for now, but should push return value - stk.push(0); - - debugC(3, kDraciBytecodeDebugLevel, "\t\t-operator %s", - operators[value-1].c_str()); - break; - - case kMathVariable: - value = reader.readUint16LE(); - stk.push(value); - debugC(3, kDraciBytecodeDebugLevel, "\t\t-variable %hu", value); - break; - - case kMathFunctionCall: - value = reader.readUint16LE(); - - stk.pop(); - - // FIXME: Pushing dummy value for now, but should push return value - stk.push(0); - - debugC(3, kDraciBytecodeDebugLevel, "\t\t-functioncall %s", - functions[value-1].c_str()); - break; - } - - obj = (mathExpressionObject) reader.readUint16LE(); - } - - return; -} - -/** - * @brief Find the current command in the internal table - * - * @param num Command number - * @param subnum Command subnumer - * - * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command - * struct representing the command. - */ -GPL2Command *findCommand(byte num, byte subnum) { - unsigned int i = 0; - while (1) { - - // Command not found - if (i >= kNumCommands) { - break; - } - - // Return found command - if (gplCommands[i]._number == num && - gplCommands[i]._subNumber == subnum) { - return &gplCommands[i]; - } - - ++i; - } - - return NULL; -} - -/** - * @brief GPL2 bytecode disassembler - * @param gplcode A pointer to the bytecode - * @param len Length of the bytecode - * - * GPL2 is short for Game Programming Language 2 which is the script language - * used by Draci Historie. This is a simple disassembler for the language. - * - * A compiled GPL2 program consists of a stream of bytes representing commands - * and their parameters. The syntax is as follows: - * - * Syntax of a command: - * - * - * Syntax of a parameter: - * - 1: integer number literally passed to the program - * - 2-1: string stored in the reservouir of game strings (i.e. something to be - * displayed) and stored as an index in this list - * - 2-2: string resolved by the compiler (i.e., a path to another file) and - * replaced by an integer index of this entity in the appropriate namespace - * (e.g., the index of the palette, location, ...) - * - 3-0: relative jump to a label defined in this code. Each label must be - * first declared in the beginning of the program. - * - 3-1 .. 3-9: index of an entity in several namespaces, defined in file ident - * - 4: mathematical expression compiled into a postfix format - * - * In the compiled program, parameters of type 1..3 are represented by a single - * 16-bit integer. The called command knows by its definition what namespace the - * value comes from. - */ - -int gpldisasm(byte *gplcode, uint16 len) { - Common::MemoryReadStream reader(gplcode, len); - - while (!reader.eos()) { - // read in command pair - uint16 cmdpair = reader.readUint16BE(); - - // extract high byte, i.e. the command number - byte num = (cmdpair >> 8) & 0xFF; - - // extract low byte, i.e. the command subnumber - byte subnum = cmdpair & 0xFF; - - GPL2Command *cmd; - if ((cmd = findCommand(num, subnum))) { - - // Print command name - debugC(2, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); - - for (uint16 i = 0; i < cmd->_numParams; ++i) { - if (cmd->_paramTypes[i] == 4) { - debugC(3, kDraciBytecodeDebugLevel, "\t"); - handleMathExpression(reader); - } - else { - debugC(3, kDraciBytecodeDebugLevel, "\t%hu", reader.readUint16LE()); - } - } - } - else { - debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", - num, subnum); - } - - - } - - return 0; -} - -} - diff --git a/engines/draci/gpldisasm.h b/engines/draci/gpldisasm.h deleted file mode 100644 index c23de4ba33..0000000000 --- a/engines/draci/gpldisasm.h +++ /dev/null @@ -1,56 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/str.h" - -#ifndef DRACI_GPLDISASM_H -#define DRACI_GPLDISASM_H - -namespace Draci { - -/** The maximum number of parameters for a GPL command */ -const int kMaxParams = 3; - -// FIXME: Add function handlers - -/** - * Represents a single command in the GPL scripting language bytecode. - * Each command is represented in the bytecode by a command number and a - * subnumber. - */ - -struct GPL2Command { - byte _number; - byte _subNumber; - Common::String _name; - uint16 _numParams; - int _paramTypes[kMaxParams]; -}; - -int gpldisasm(byte *gplcode, uint16 len); - -} - -#endif // DRACI_GPLDISASM_H diff --git a/engines/draci/module.mk b/engines/draci/module.mk index 2d7c33a1bf..d79407cff7 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -4,7 +4,7 @@ MODULE_OBJS := \ draci.o \ detection.o \ barchive.o \ - gpldisasm.o \ + script.o \ font.o \ sprite.o \ screen.o \ diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp new file mode 100644 index 0000000000..ee7b128529 --- /dev/null +++ b/engines/draci/script.cpp @@ -0,0 +1,319 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/debug.h" +#include "common/stream.h" +#include "common/stack.h" + +#include "draci/gpldisasm.h" +#include "draci/draci.h" + +namespace Draci { + +// FIXME: Change parameter types to names once I figure out what they are exactly + +/** A table of all the commands the game player uses */ +GPL2Command gplCommands[] = { + { 0, 0, "gplend", 0, { 0 } }, + { 0, 1, "exit", 0, { 0 } }, + { 1, 1, "goto", 1, { 3 } }, + { 2, 1, "Let", 2, { 3, 4 } }, + { 3, 1, "if", 2, { 4, 3 } }, + { 4, 1, "Start", 2, { 3, 2 } }, + { 5, 1, "Load", 2, { 3, 2 } }, + { 5, 2, "StartPlay", 2, { 3, 2 } }, + { 5, 3, "JustTalk", 0, { 0 } }, + { 5, 4, "JustStay", 0, { 0 } }, + { 6, 1, "Talk", 2, { 3, 2 } }, + { 7, 1, "ObjStat", 2, { 3, 3 } }, + { 7, 2, "ObjStat_On", 2, { 3, 3 } }, + { 8, 1, "IcoStat", 2, { 3, 3 } }, + { 9, 1, "Dialogue", 1, { 2 } }, + { 9, 2, "ExitDialogue", 0, { 0 } }, + { 9, 3, "ResetDialogue", 0, { 0 } }, + { 9, 4, "ResetDialogueFrom", 0, { 0 } }, + { 9, 5, "ResetBlock", 1, { 3 } }, + { 10, 1, "WalkOn", 3, { 1, 1, 3 } }, + { 10, 2, "StayOn", 3, { 1, 1, 3 } }, + { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 } }, + { 11, 1, "LoadPalette", 1, { 2 } }, + { 12, 1, "SetPalette", 0, { 0 } }, + { 12, 2, "BlackPalette", 0, { 0 } }, + { 13, 1, "FadePalette", 3, { 1, 1, 1 } }, + { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 } }, + { 14, 1, "NewRoom", 2, { 3, 1 } }, + { 15, 1, "ExecInit", 1, { 3 } }, + { 15, 2, "ExecLook", 1, { 3 } }, + { 15, 3, "ExecUse", 1, { 3 } }, + { 16, 1, "RepaintInventory", 0, { 0 } }, + { 16, 2, "ExitInventory", 0, { 0 } }, + { 17, 1, "ExitMap", 0, { 0 } }, + { 18, 1, "LoadMusic", 1, { 2 } }, + { 18, 2, "StartMusic", 0, { 0 } }, + { 18, 3, "StopMusic", 0, { 0 } }, + { 18, 4, "FadeOutMusic", 1, { 1 } }, + { 18, 5, "FadeInMusic", 1, { 1 } }, + { 19, 1, "Mark", 0, { 0 } }, + { 19, 2, "Release", 0, { 0 } }, + { 20, 1, "Play", 0, { 0 } }, + { 21, 1, "LoadMap", 1, { 2 } }, + { 21, 2, "RoomMap", 0, { 0 } }, + { 22, 1, "DisableQuickHero", 0, { 0 } }, + { 22, 2, "EnableQuickHero", 0, { 0 } }, + { 23, 1, "DisableSpeedText", 0, { 0 } }, + { 23, 2, "EnableSpeedText", 0, { 0 } }, + { 24, 1, "QuitGame", 0, { 0 } }, + { 25, 1, "PushNewRoom", 0, { 0 } }, + { 25, 2, "PopNewRoom", 0, { 0 } }, + { 26, 1, "ShowCheat", 0, { 0 } }, + { 26, 2, "HideCheat", 0, { 0 } }, + { 26, 3, "ClearCheat", 1, { 1 } }, + { 27, 1, "FeedPassword", 3, { 1, 1, 1 } } +}; + +/** Operators used by the mathematical evaluator */ +Common::String operators[] = { + "oper_and", + "oper_or", + "oper_xor", + "oper_equals", + "oper_not_equal", + "oper_less_than", + "oper_greater_than", + "oper_less_or_equal", + "oper_greater_or_equal", + "oper_multiply", + "oper_divide", + "oper_remainder", + "oper_plus", + "oper_minus" +}; + +/** Functions used by the mathematical evaluator */ +Common::String functions[] = { + "F_Not", + "F_Random", + "F_IsIcoOn", + "F_IsIcoAct", + "F_IcoStat", + "F_ActIco", + "F_IsObjOn", + "F_IsObjOff", + "F_IsObjAway", + "F_ObjStat", + "F_LastBlock", + "F_AtBegin", + "F_BlockVar", + "F_HasBeen", + "F_MaxLine", + "F_ActPhase", + "F_Cheat" +}; + +const unsigned int kNumCommands = sizeof gplCommands / sizeof gplCommands[0]; + +/** Type of mathematical object */ +enum mathExpressionObject { + kMathEnd, + kMathNumber, + kMathOperator, + kMathFunctionCall, + kMathVariable +}; + +// FIXME: The evaluator is now complete but I still need to implement callbacks + +/** + * @brief Evaluates mathematical expressions + * @param reader Stream reader set to the beginning of the expression + */ + +void handleMathExpression(Common::MemoryReadStream &reader) { + Common::Stack stk; + mathExpressionObject obj; + + // Read in initial math object + obj = (mathExpressionObject)reader.readUint16LE(); + + uint16 value; + while (1) { + if (obj == kMathEnd) { + // Check whether the expression was evaluated correctly + // The stack should contain only one value after the evaluation + // i.e. the result of the expression + assert(stk.size() == 1 && "Mathematical expression error"); + break; + } + + switch (obj) { + + // If the object type is not known, assume that it's a number + default: + case kMathNumber: + value = reader.readUint16LE(); + stk.push(value); + debugC(3, kDraciBytecodeDebugLevel, "\t\t-number %hu", value); + break; + + case kMathOperator: + value = reader.readUint16LE(); + stk.pop(); + stk.pop(); + + // FIXME: Pushing dummy value for now, but should push return value + stk.push(0); + + debugC(3, kDraciBytecodeDebugLevel, "\t\t-operator %s", + operators[value-1].c_str()); + break; + + case kMathVariable: + value = reader.readUint16LE(); + stk.push(value); + debugC(3, kDraciBytecodeDebugLevel, "\t\t-variable %hu", value); + break; + + case kMathFunctionCall: + value = reader.readUint16LE(); + + stk.pop(); + + // FIXME: Pushing dummy value for now, but should push return value + stk.push(0); + + debugC(3, kDraciBytecodeDebugLevel, "\t\t-functioncall %s", + functions[value-1].c_str()); + break; + } + + obj = (mathExpressionObject) reader.readUint16LE(); + } + + return; +} + +/** + * @brief Find the current command in the internal table + * + * @param num Command number + * @param subnum Command subnumer + * + * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command + * struct representing the command. + */ +GPL2Command *findCommand(byte num, byte subnum) { + unsigned int i = 0; + while (1) { + + // Command not found + if (i >= kNumCommands) { + break; + } + + // Return found command + if (gplCommands[i]._number == num && + gplCommands[i]._subNumber == subnum) { + return &gplCommands[i]; + } + + ++i; + } + + return NULL; +} + +/** + * @brief GPL2 bytecode disassembler + * @param gplcode A pointer to the bytecode + * @param len Length of the bytecode + * + * GPL2 is short for Game Programming Language 2 which is the script language + * used by Draci Historie. This is a simple disassembler for the language. + * + * A compiled GPL2 program consists of a stream of bytes representing commands + * and their parameters. The syntax is as follows: + * + * Syntax of a command: + * + * + * Syntax of a parameter: + * - 1: integer number literally passed to the program + * - 2-1: string stored in the reservouir of game strings (i.e. something to be + * displayed) and stored as an index in this list + * - 2-2: string resolved by the compiler (i.e., a path to another file) and + * replaced by an integer index of this entity in the appropriate namespace + * (e.g., the index of the palette, location, ...) + * - 3-0: relative jump to a label defined in this code. Each label must be + * first declared in the beginning of the program. + * - 3-1 .. 3-9: index of an entity in several namespaces, defined in file ident + * - 4: mathematical expression compiled into a postfix format + * + * In the compiled program, parameters of type 1..3 are represented by a single + * 16-bit integer. The called command knows by its definition what namespace the + * value comes from. + */ + +int gpldisasm(byte *gplcode, uint16 len) { + Common::MemoryReadStream reader(gplcode, len); + + while (!reader.eos()) { + // read in command pair + uint16 cmdpair = reader.readUint16BE(); + + // extract high byte, i.e. the command number + byte num = (cmdpair >> 8) & 0xFF; + + // extract low byte, i.e. the command subnumber + byte subnum = cmdpair & 0xFF; + + GPL2Command *cmd; + if ((cmd = findCommand(num, subnum))) { + + // Print command name + debugC(2, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); + + for (uint16 i = 0; i < cmd->_numParams; ++i) { + if (cmd->_paramTypes[i] == 4) { + debugC(3, kDraciBytecodeDebugLevel, "\t"); + handleMathExpression(reader); + } + else { + debugC(3, kDraciBytecodeDebugLevel, "\t%hu", reader.readUint16LE()); + } + } + } + else { + debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", + num, subnum); + } + + + } + + return 0; +} + +} + diff --git a/engines/draci/script.h b/engines/draci/script.h new file mode 100644 index 0000000000..c23de4ba33 --- /dev/null +++ b/engines/draci/script.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/str.h" + +#ifndef DRACI_GPLDISASM_H +#define DRACI_GPLDISASM_H + +namespace Draci { + +/** The maximum number of parameters for a GPL command */ +const int kMaxParams = 3; + +// FIXME: Add function handlers + +/** + * Represents a single command in the GPL scripting language bytecode. + * Each command is represented in the bytecode by a command number and a + * subnumber. + */ + +struct GPL2Command { + byte _number; + byte _subNumber; + Common::String _name; + uint16 _numParams; + int _paramTypes[kMaxParams]; +}; + +int gpldisasm(byte *gplcode, uint16 len); + +} + +#endif // DRACI_GPLDISASM_H -- cgit v1.2.3 From 97dde5e1eddcff4e038843a880343429b26a1fe9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 27 Jun 2009 15:17:26 +0000 Subject: Put all GPL interpreter related routines inside a Script class. svn-id: r41919 --- engines/draci/draci.cpp | 4 ++-- engines/draci/script.cpp | 8 ++++---- engines/draci/script.h | 20 +++++++++++++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 3fc9553a8c..42023588ec 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -34,7 +34,7 @@ #include "draci/draci.h" #include "draci/barchive.h" -#include "draci/gpldisasm.h" +#include "draci/script.h" #include "draci/font.h" #include "draci/sprite.h" #include "draci/screen.h" @@ -108,7 +108,7 @@ int DraciEngine::init() { } // Disassemble GPL script for the first location - gpldisasm(f->_data, f->_length); + //gpldisasm(f->_data, f->_length); return Common::kNoError; } diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index ee7b128529..05018b590d 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -27,7 +27,7 @@ #include "common/stream.h" #include "common/stack.h" -#include "draci/gpldisasm.h" +#include "draci/script.h" #include "draci/draci.h" namespace Draci { @@ -150,7 +150,7 @@ enum mathExpressionObject { * @param reader Stream reader set to the beginning of the expression */ -void handleMathExpression(Common::MemoryReadStream &reader) { +void Script::handleMathExpression(Common::MemoryReadStream &reader) { Common::Stack stk; mathExpressionObject obj; @@ -223,7 +223,7 @@ void handleMathExpression(Common::MemoryReadStream &reader) { * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command * struct representing the command. */ -GPL2Command *findCommand(byte num, byte subnum) { +GPL2Command *Script::findCommand(byte num, byte subnum) { unsigned int i = 0; while (1) { @@ -275,7 +275,7 @@ GPL2Command *findCommand(byte num, byte subnum) { * value comes from. */ -int gpldisasm(byte *gplcode, uint16 len) { +int Script::gpldisasm(byte *gplcode, uint16 len) { Common::MemoryReadStream reader(gplcode, len); while (!reader.eos()) { diff --git a/engines/draci/script.h b/engines/draci/script.h index c23de4ba33..11aded6330 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -23,10 +23,11 @@ * */ -#include "common/str.h" +#ifndef DRACI_SCRIPT_H +#define DRACI_SCRIPT_H -#ifndef DRACI_GPLDISASM_H -#define DRACI_GPLDISASM_H +#include "common/str.h" +#include "common/stream.h" namespace Draci { @@ -49,8 +50,17 @@ struct GPL2Command { int _paramTypes[kMaxParams]; }; -int gpldisasm(byte *gplcode, uint16 len); +class Script { + +public: + int gpldisasm(byte *gplcode, uint16 len); + +private: + GPL2Command *findCommand(byte num, byte subnum); + void handleMathExpression(Common::MemoryReadStream &reader); + +}; } -#endif // DRACI_GPLDISASM_H +#endif // DRACI_SCRIPT_H -- cgit v1.2.3 From 4c524f5e0a62fe34c3c3bb9978ee8cd3c0c3ccbc Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 27 Jun 2009 15:19:03 +0000 Subject: Renamed Script::gpldisasm() to Script::run(). svn-id: r41920 --- engines/draci/script.cpp | 2 +- engines/draci/script.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 05018b590d..c04100af78 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -275,7 +275,7 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { * value comes from. */ -int Script::gpldisasm(byte *gplcode, uint16 len) { +int Script::run(byte *gplcode, uint16 len) { Common::MemoryReadStream reader(gplcode, len); while (!reader.eos()) { diff --git a/engines/draci/script.h b/engines/draci/script.h index 11aded6330..4ad305c209 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -53,7 +53,7 @@ struct GPL2Command { class Script { public: - int gpldisasm(byte *gplcode, uint16 len); + int run(byte *gplcode, uint16 len); private: GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From 1e70f25fcfed439149a5fc1a87a4ce0461656127 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 27 Jun 2009 15:26:33 +0000 Subject: Added Script instance to DraciEngine. Restored disassembling of a demo script on engine startup (previously via gpldisasm(), now via _script->run()). svn-id: r41921 --- engines/draci/draci.cpp | 6 +++++- engines/draci/draci.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 42023588ec..1d86b730da 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -70,6 +70,7 @@ int DraciEngine::init() { _font = new Font(); _mouse = new Mouse(this); _game = new Game(); + _script = new Script(); // Load default font _font->setFont(kFontBig); @@ -108,7 +109,7 @@ int DraciEngine::init() { } // Disassemble GPL script for the first location - //gpldisasm(f->_data, f->_length); + _script->run(f->_data, f->_length); return Common::kNoError; } @@ -214,9 +215,12 @@ int DraciEngine::go() { DraciEngine::~DraciEngine() { // Dispose your resources here + // TODO: Investigate possibility of using sharedPtr or similar delete _screen; delete _font; delete _mouse; + delete _game; + delete _script; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 5062eba563..ae9826464a 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -34,6 +34,7 @@ #include "draci/mouse.h" #include "draci/screen.h" #include "draci/font.h" +#include "draci/script.h" namespace Draci { @@ -52,6 +53,7 @@ public: Screen *_screen; Mouse *_mouse; Game *_game; + Script *_script; private: Common::RandomSource _rnd; -- cgit v1.2.3 From d28bbe51bffe67866b3e1d53188be847c7f533e4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 28 Jun 2009 13:10:53 +0000 Subject: Added struct GameObject (such structs are stored in OBJEKTY.DFW and used for in-game objects' info). Added Game::loadObject() for loading such objects into memory. Made Game's constructor load the object for the main hero. svn-id: r41925 --- engines/draci/game.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- engines/draci/game.h | 23 +++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 1b6a25679d..7cceb0e854 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -121,8 +121,51 @@ Game::Game() { // TODO: Why is this failing? // assert(curOffset == _info->_numDialogBlocks); + loadObject(0, &_heroObj); } +void Game::loadObject(uint16 objNum, GameObject *obj) { + Common::String path("OBJEKTY.DFW"); + + BArchive objArchive(path); + BAFile *file; + + file = objArchive[objNum * 3]; + Common::MemoryReadStream objReader(file->_data, file->_length); + + obj->_init = objReader.readUint16LE(); + obj->_look = objReader.readUint16LE(); + obj->_use = objReader.readUint16LE(); + obj->_canUse = objReader.readUint16LE(); + obj->_imInit = objReader.readByte(); + obj->_imLook = objReader.readByte(); + obj->_imUse = objReader.readByte(); + obj->_walkDir = objReader.readByte(); + obj->_priority = objReader.readByte(); + obj->_idxSeq = objReader.readUint16LE(); + obj->_numSeq = objReader.readUint16LE(); + obj->_lookX = objReader.readUint16LE(); + obj->_lookY = objReader.readUint16LE(); + obj->_useX = objReader.readUint16LE(); + obj->_useY = objReader.readUint16LE(); + obj->_lookDir = objReader.readByte(); + obj->_useDir = objReader.readByte(); + + obj->_absNum = objNum; + obj->_animObj = 0; + + obj->_seqTab = new uint16[obj->_numSeq]; + + file = objArchive[objNum * 3 + 1]; + obj->_title = new byte[file->_length]; + memcpy(obj->_title, file->_data, file->_length); + + file = objArchive[objNum * 3 + 2]; + obj->_program = new byte[file->_length]; + memcpy(obj->_program, file->_data, file->_length); + obj->_progLen = file->_length; +} + Game::~Game() { delete[] _persons; delete[] _variables; @@ -130,6 +173,15 @@ Game::~Game() { delete[] _itemStatus; delete[] _objectStatus; delete _info; -} +} + +GameObject::~GameObject() { + if (_seqTab) + delete[] _seqTab; + if (_title) + delete[] _title; + if (_program) + delete[] _program; +} } diff --git a/engines/draci/game.h b/engines/draci/game.h index 418cccb11c..5bd2074489 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -34,6 +34,26 @@ enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; +struct GameObject { + + GameObject() : _seqTab(NULL), _title(NULL), _program(NULL) {} + ~GameObject(); + + uint16 _init, _look, _use, _canUse; + bool _imInit, _imLook, _imUse; + byte _walkDir; + byte _priority; + uint16 _idxSeq, _numSeq; + uint16 _lookX, _lookY, _useX, _useY; + byte _lookDir, _useDir; + uint16 _absNum; + byte _animObj; + uint16 *_seqTab; + byte *_program; + byte *_title; + uint32 _progLen; +}; + struct GameInfo { byte _currentRoom; byte _mapRoom; @@ -66,6 +86,9 @@ private: int16 *_variables; byte *_itemStatus; byte *_objectStatus; + GameObject _heroObj; + + void loadObject(uint16 numObj, GameObject *obj); }; } // End of namespace Draci -- cgit v1.2.3 From 948bf2cfcc23dc95fa7b29ff2f6ae7a27af132bd Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 28 Jun 2009 15:28:20 +0000 Subject: Removed disassembling of the GPL script for the first game location from Draci::init(). svn-id: r41926 --- engines/draci/draci.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 1d86b730da..7e73e3d4b2 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -94,23 +94,6 @@ int DraciEngine::init() { debugC(3, kDraciGeneralDebugLevel, "0x%02x%c", f->_data[i], (i < 9) ? ' ' : '\n'); } - // Read in GPL script for the first game location - debugC(2, kDraciBytecodeDebugLevel, "Disassembling GPL script " - "for the first game location..."); - - path = "MIST.DFW"; - ar.openArchive(path); - - if(ar.isOpen()) { - f = ar[3]; - } else { - debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return Common::kUnknownError; - } - - // Disassemble GPL script for the first location - _script->run(f->_data, f->_length); - return Common::kNoError; } -- cgit v1.2.3 From f61b2d289d0e6ec960e20ac5b59a0fe7dfe8740e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 28 Jun 2009 16:19:10 +0000 Subject: Changed Script::run() to accept a GPL2Program struct instead of a byte pointer and a length. Also, Script::run() now executes the GPL program until a gplend instruction rather than to the end of the whole program. Modified GameObject according to the new changes. svn-id: r41927 --- engines/draci/draci.cpp | 2 +- engines/draci/game.cpp | 18 ++++++++---------- engines/draci/game.h | 12 ++++++++---- engines/draci/script.cpp | 15 ++++++--------- engines/draci/script.h | 14 +++++++++++++- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 7e73e3d4b2..5ace58c8bc 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -69,7 +69,7 @@ int DraciEngine::init() { _screen = new Screen(this); _font = new Font(); _mouse = new Mouse(this); - _game = new Game(); + _game = new Game(this); _script = new Script(); // Load default font diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 7cceb0e854..9b8a2855ef 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -28,10 +28,11 @@ #include "draci/draci.h" #include "draci/game.h" #include "draci/barchive.h" +#include "draci/script.h" namespace Draci { -Game::Game() { +Game::Game(DraciEngine *vm) : _vm(vm) { unsigned int i; Common::String path("INIT.DFW"); @@ -161,9 +162,9 @@ void Game::loadObject(uint16 objNum, GameObject *obj) { memcpy(obj->_title, file->_data, file->_length); file = objArchive[objNum * 3 + 2]; - obj->_program = new byte[file->_length]; - memcpy(obj->_program, file->_data, file->_length); - obj->_progLen = file->_length; + obj->_program._bytecode = new byte[file->_length]; + obj->_program._length = file->_length; + memcpy(obj->_program._bytecode, file->_data, file->_length); } Game::~Game() { @@ -176,12 +177,9 @@ Game::~Game() { } GameObject::~GameObject() { - if (_seqTab) - delete[] _seqTab; - if (_title) - delete[] _title; - if (_program) - delete[] _program; + delete[] _seqTab; + delete[] _title; + delete[] _program._bytecode; } } diff --git a/engines/draci/game.h b/engines/draci/game.h index 5bd2074489..bdbb402795 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -27,16 +27,19 @@ #define DRACI_GAME_H #include "common/str.h" +#include "draci/script.h" namespace Draci { +class DraciEngine; + enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; struct GameObject { - GameObject() : _seqTab(NULL), _title(NULL), _program(NULL) {} + GameObject() : _seqTab(NULL), _title(NULL) {} ~GameObject(); uint16 _init, _look, _use, _canUse; @@ -49,9 +52,8 @@ struct GameObject { uint16 _absNum; byte _animObj; uint16 *_seqTab; - byte *_program; + GPL2Program _program; byte *_title; - uint32 _progLen; }; struct GameInfo { @@ -76,10 +78,12 @@ struct Person { class Game { public: - Game(); + Game(DraciEngine *vm); ~Game(); private: + DraciEngine *_vm; + GameInfo *_info; Person *_persons; uint16 *_dialogOffsets; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index c04100af78..751aadc3f3 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -246,8 +246,7 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { /** * @brief GPL2 bytecode disassembler - * @param gplcode A pointer to the bytecode - * @param len Length of the bytecode + * @param program GPL program in the form of a GPL2Program struct * * GPL2 is short for Game Programming Language 2 which is the script language * used by Draci Historie. This is a simple disassembler for the language. @@ -275,10 +274,11 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { * value comes from. */ -int Script::run(byte *gplcode, uint16 len) { - Common::MemoryReadStream reader(gplcode, len); +int Script::run(GPL2Program program) { + Common::MemoryReadStream reader(program._bytecode, program._length); - while (!reader.eos()) { + GPL2Command *cmd; + do { // read in command pair uint16 cmdpair = reader.readUint16BE(); @@ -288,7 +288,6 @@ int Script::run(byte *gplcode, uint16 len) { // extract low byte, i.e. the command subnumber byte subnum = cmdpair & 0xFF; - GPL2Command *cmd; if ((cmd = findCommand(num, subnum))) { // Print command name @@ -308,9 +307,7 @@ int Script::run(byte *gplcode, uint16 len) { debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", num, subnum); } - - - } + } while (cmd->_name != "gplend"); return 0; } diff --git a/engines/draci/script.h b/engines/draci/script.h index 4ad305c209..55712e99f2 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -50,10 +50,22 @@ struct GPL2Command { int _paramTypes[kMaxParams]; }; +/** + * A convenience data type that holds both the actual bytecode and the + * length of the bytecode. Passed to Script::run(). + */ + +struct GPL2Program { + GPL2Program() : _bytecode(NULL), _length(0) {} + + byte *_bytecode; + uint16 _length; +}; + class Script { public: - int run(byte *gplcode, uint16 len); + int run(GPL2Program program); private: GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From 6a78781889a9803ae06f2818c2809f2625baefb8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 28 Jun 2009 16:28:16 +0000 Subject: Added an offset parameter to Script::run() so we can specify where to start the GPL program execution. Also, the init script for the dragon object is now run inside Game::Game(). svn-id: r41928 --- engines/draci/game.cpp | 1 + engines/draci/script.cpp | 11 ++++++++++- engines/draci/script.h | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 9b8a2855ef..76dee965f1 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -123,6 +123,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // assert(curOffset == _info->_numDialogBlocks); loadObject(0, &_heroObj); + _vm->_script->run(_heroObj._program, _heroObj._init); } void Game::loadObject(uint16 objNum, GameObject *obj) { diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 751aadc3f3..ce38960265 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -247,6 +247,7 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { /** * @brief GPL2 bytecode disassembler * @param program GPL program in the form of a GPL2Program struct + * offset Offset into the program where execution should begin * * GPL2 is short for Game Programming Language 2 which is the script language * used by Draci Historie. This is a simple disassembler for the language. @@ -274,9 +275,17 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { * value comes from. */ -int Script::run(GPL2Program program) { +int Script::run(GPL2Program program, uint16 offset) { Common::MemoryReadStream reader(program._bytecode, program._length); + // Offset is given as number of 16-bit integers so we need to convert + // it to a number of bytes + offset -= 1; + offset *= 2; + + // Seek to the requested part of the program + reader.seek(offset); + GPL2Command *cmd; do { // read in command pair diff --git a/engines/draci/script.h b/engines/draci/script.h index 55712e99f2..ac994f1d27 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -65,7 +65,7 @@ struct GPL2Program { class Script { public: - int run(GPL2Program program); + int run(GPL2Program program, uint16 offset); private: GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From 63aa2b7aafefbd1611ac8f6cbf1f55339b5d9a74 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 29 Jun 2009 22:20:30 +0000 Subject: Account for endianess properly when reading in game variables. svn-id: r41965 --- engines/draci/game.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 76dee965f1..94c7c1fc31 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -96,10 +96,14 @@ Game::Game(DraciEngine *vm) : _vm(vm) { file = initArchive[2]; unsigned int numVariables = file->_length / sizeof (int16); - + _variables = new int16[numVariables]; - memcpy(_variables, file->_data, file->_length); + Common::MemoryReadStream variableData(file->_data, file->_length); + for (i = 0; i < numVariables; ++i) { + _variables[i] = variableData.readUint16LE(); + } + // Read in item status file = initArchive[1]; -- cgit v1.2.3 From 138d17bbabd5e5639b6aab24f1c2a0b75a9384f7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 29 Jun 2009 22:27:38 +0000 Subject: Changed some data members in Draci::GameInfo from uint32 to uint16 (previously I thought that the 'word' type in the original engine was 32 bits). Removed a FIXME concerning struct size mismatch (matches when the previous sentence is taken into account). GameInfo::_numDialogBlocks is now calculated, not read in (it wasn't stored in the data files at all). svn-id: r41966 --- engines/draci/game.cpp | 17 ++++++----------- engines/draci/game.h | 4 ++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 94c7c1fc31..72e431bf44 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -82,15 +82,13 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info->_numDialogs = gameData.readByte(); _info->_maxIconWidth = gameData.readUint16LE(); _info->_maxIconHeight = gameData.readUint16LE(); - _info->_musicLength = gameData.readUint32LE(); + _info->_musicLength = gameData.readUint16LE(); + _info->_crc[0] = gameData.readUint16LE(); + _info->_crc[1] = gameData.readUint16LE(); + _info->_crc[2] = gameData.readUint16LE(); + _info->_crc[3] = gameData.readUint16LE(); -// FIXME: Something is wrong here. The total file length is only 23 bytes -// but the whole struct should be 35 bytes. - _info->_crc[0] = gameData.readUint32LE(); - _info->_crc[1] = gameData.readUint32LE(); - _info->_crc[2] = gameData.readUint32LE(); - _info->_crc[3] = gameData.readUint32LE(); - _info->_numDialogBlocks = gameData.readUint16LE(); + _info->_numDialogBlocks = curOffset; // Read in variables @@ -123,9 +121,6 @@ Game::Game(DraciEngine *vm) : _vm(vm) { assert(numVariables == _info->_numVariables); assert(numObjects == _info->_numObjects); -// TODO: Why is this failing? -// assert(curOffset == _info->_numDialogBlocks); - loadObject(0, &_heroObj); _vm->_script->run(_heroObj._program, _heroObj._init); } diff --git a/engines/draci/game.h b/engines/draci/game.h index bdbb402795..abefb0f963 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -65,8 +65,8 @@ struct GameInfo { byte _numPersons; byte _numDialogs; uint16 _maxIconWidth, _maxIconHeight; - uint32 _musicLength; - uint32 _crc[4]; + uint16 _musicLength; + uint16 _crc[4]; uint16 _numDialogBlocks; }; -- cgit v1.2.3 From 85a5871873499a2965dd5badffd224a7560f9b60 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 30 Jun 2009 22:31:29 +0000 Subject: Added the Drawable abstract base class and made Sprite inherit from it. svn-id: r41979 --- engines/draci/sprite.cpp | 12 +++++++++--- engines/draci/sprite.h | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 6e4cb8b6b6..cce3f51cfa 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -54,7 +54,11 @@ static void transformToRows(byte *img, uint16 width, uint16 height) { * Constructor for loading sprites from a raw data buffer, one byte per pixel. */ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, - bool columnwise) : _width(width), _height(height), _x(x), _y(y), _data(NULL) { + bool columnwise) : _data(NULL) { + _width = width; + _height = height; + _x = x; + _y = y; _data = new byte[width * height]; @@ -71,8 +75,10 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, * pixel. */ Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, - bool columnwise) : _x(x), _y(y), _data(NULL) { - + bool columnwise) : _data(NULL) { + _x = x; + _y = y; + Common::MemoryReadStream reader(sprite_data, length); _width = reader.readUint16LE(); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 18ea899641..c9591514e3 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -30,6 +30,17 @@ namespace Draci { +class Drawable { + +public: + virtual void draw(Surface *surface) const = 0; + virtual ~Drawable() {}; + + uint16 _width; //!< Width of the sprite + uint16 _height; //!< Height of the sprite + uint16 _x, _y; //!< Sprite coordinates +}; + /** * Represents a Draci Historie sprite. Supplies two constructors; one for * loading a sprite from a raw data buffer and one for loading a sprite in @@ -43,7 +54,7 @@ namespace Draci { * [height * width bytes] image pixels stored column-wise, one byte per pixel */ -class Sprite { +class Sprite : public Drawable { public: Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x = 0, uint16 y = 0, @@ -57,9 +68,6 @@ public: void draw(Surface *surface) const; byte *_data; //!< Pointer to a buffer containing raw sprite data (row-wise) - uint16 _width; //!< Width of the sprite - uint16 _height; //!< Height of the sprite - uint16 _x, _y; //!< Sprite coordinates }; -- cgit v1.2.3 From 49e1a07f277d48b5e597730af76e9247bfff58b8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 01:02:48 +0000 Subject: Added Font::drawString overload that takes in a pointer to a byte buffer and a length instead of a Common::String. Changed the former drawString to be a wrapper for the new one. svn-id: r41980 --- engines/draci/font.cpp | 22 +++++++++++++++++++--- engines/draci/font.h | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index d9e84899b7..cfc09cb5ef 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -205,20 +205,20 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { * @brief Draw a string to a Draci::Surface * * @param dst Pointer to the destination surface - * @param str String to draw + * @param str Buffer containing string data + * @param len Length of the data * @param x Horizontal offset on the surface * @param y Vertical offset on the surface * @param spacing Space to leave between individual characters. Defaults to 0. */ -void Font::drawString(Surface *dst, const Common::String &str, +void Font::drawString(Surface *dst, const byte *str, uint len int x, int y, int spacing) const { assert(dst != NULL); assert(x >= 0); assert(y >= 0); int curx = x; - uint len = str.size(); for (unsigned int i = 0; i < len; ++i) { @@ -232,6 +232,22 @@ void Font::drawString(Surface *dst, const Common::String &str, } } +/** + * @brief Draw a string to a Draci::Surface + * + * @param dst Pointer to the destination surface + * @param str String to draw + * @param x Horizontal offset on the surface + * @param y Vertical offset on the surface + * @param spacing Space to leave between individual characters. Defaults to 0. + */ + +void Font::drawString(Surface *dst, const Common::String &str, + int x, int y, int spacing) const { + + drawString(dst, str, str.size(), x, y, spacing); +} + /** * @brief Calculate the width of a string when drawn in the current font * diff --git a/engines/draci/font.h b/engines/draci/font.h index a805a99016..c108a4493e 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -62,8 +62,12 @@ public: uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; void drawChar(Surface *dst, uint8 chr, int tx, int ty) const; + + void drawString(Surface *dst, const byte *str, uint len, int x, int y, + int spacing = 0) const; void drawString(Surface *dst, const Common::String &str, int x, int y, int spacing = 0) const; + int getStringWidth(const Common::String &str, int spacing = 0) const; void setColour(uint8 colour); -- cgit v1.2.3 From 78d5b96f51fa59a7d024d3da7667c3cdcba3410c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 01:11:48 +0000 Subject: Added Text as a subclass of Drawable. Fixed syntax error in font.cpp svn-id: r41981 --- engines/draci/font.cpp | 4 ++-- engines/draci/sprite.cpp | 24 +++++++++++++++++++++++- engines/draci/sprite.h | 15 +++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index cfc09cb5ef..b3c5768b51 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -212,7 +212,7 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { * @param spacing Space to leave between individual characters. Defaults to 0. */ -void Font::drawString(Surface *dst, const byte *str, uint len +void Font::drawString(Surface *dst, const byte *str, uint len, int x, int y, int spacing) const { assert(dst != NULL); assert(x >= 0); @@ -245,7 +245,7 @@ void Font::drawString(Surface *dst, const byte *str, uint len void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int spacing) const { - drawString(dst, str, str.size(), x, y, spacing); + drawString(dst, (byte *) str.c_str(), str.size(), x, y, spacing); } /** diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index cce3f51cfa..14d2e905c9 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -27,6 +27,7 @@ #include "draci/draci.h" #include "draci/sprite.h" +#include "draci/font.h" namespace Draci { @@ -124,7 +125,28 @@ void Sprite::draw(Surface *surface) const { Common::Rect r(_x, _y, _x + _width, _y + _height); surface->markDirtyRect(r); } - + +Text::Text(const Common::String &str, Font *font, byte fontColour, uint spacing) { + uint len = str.size(); + + _text = new byte[len]; + memcpy(_text, str.c_str(), len); + _length = len; + + _spacing = spacing; + _colour = fontColour; + + _font = font; +} + +Text::~Text() { + delete _text; +} + +void Text::draw(Surface *surface) const { + _font->setColour(_colour); + _font->drawString(surface, _text, _length, _x, _y, _spacing); +} } // End of namespace Draci diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index c9591514e3..68f823512a 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -27,6 +27,7 @@ #define DRACI_SPRITE_H #include "draci/surface.h" +#include "draci/font.h" namespace Draci { @@ -70,7 +71,21 @@ public: byte *_data; //!< Pointer to a buffer containing raw sprite data (row-wise) }; +class Text : public Drawable { +public: + Text(const Common::String &str, Font *font, byte fontColour, uint spacing = 0); + ~Text(); + + void draw(Surface *surface) const; + + byte *_text; + uint _length; + uint8 _colour; + uint _spacing; + Font *_font; +}; + } // End of namespace Draci #endif // DRACI_SPRITE_H -- cgit v1.2.3 From d7f8cbf17068b4e0a8fa97cf11e72a0fc51e6908 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 01:18:22 +0000 Subject: Added text position specification to Text constructor. svn-id: r41982 --- engines/draci/sprite.cpp | 6 +++++- engines/draci/sprite.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 14d2e905c9..062499471d 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -126,9 +126,13 @@ void Sprite::draw(Surface *surface) const { surface->markDirtyRect(r); } -Text::Text(const Common::String &str, Font *font, byte fontColour, uint spacing) { +Text::Text(const Common::String &str, Font *font, byte fontColour, + uint16 x, uint16 y, uint spacing) { uint len = str.size(); + _x = x; + _y = y; + _text = new byte[len]; memcpy(_text, str.c_str(), len); _length = len; diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 68f823512a..50b091e3d5 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -74,7 +74,8 @@ public: class Text : public Drawable { public: - Text(const Common::String &str, Font *font, byte fontColour, uint spacing = 0); + Text(const Common::String &str, Font *font, byte fontColour, + uint16 x = 0, uint16 y = 0, uint spacing = 0); ~Text(); void draw(Surface *surface) const; -- cgit v1.2.3 From 4c86646db67d8f7d66f96e633af0bd1ca8e14f25 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 01:25:48 +0000 Subject: Changed intro animation to render text via the new Text class. svn-id: r41983 --- engines/draci/draci.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 5ace58c8bc..da81074655 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -121,20 +121,34 @@ int DraciEngine::go() { _screen->fillScreen(225); // Draw big string - Common::String testString = "Testing, testing, read all about it!"; + Surface *surf = _screen->getSurface(); - _font->drawString(surf, testString, - (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 130, 1); + uint16 xpos; + uint16 ypos; + + Common::String testString = "Testing, testing, read all about it!"; + xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; + ypos = 130; + Text txt1(testString, _font, kFontColour1, xpos, ypos, 1); + + txt1.draw(surf); // Draw small string _font->setFont(kFontSmall); testString = "I'm smaller than the font above me."; - _font->drawString(surf, testString, - (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 150, 1); + xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; + ypos += 20; + Text txt2(testString, _font, kFontColour1, xpos, ypos, 1); + + txt2.draw(surf); - // Overflow handling test + // Overflow handling test testString = "Checking overflooooooooooooooooooooooooow..."; - _font->drawString(surf, testString, 50, 170, 1); + xpos = 50; + ypos += 20; + Text txt3(testString, _font, kFontColour1, xpos, ypos, 1); + + txt3.draw(surf); _screen->copyToScreen(); -- cgit v1.2.3 From 48959935880a991d14768dac66f41c183eb0dd44 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 01:43:20 +0000 Subject: Added Text::setText() and Text::setColour() methods. Changed demo animation to use them. svn-id: r41984 --- engines/draci/draci.cpp | 26 +++++++++++++++++--------- engines/draci/sprite.cpp | 18 ++++++++++++++++-- engines/draci/sprite.h | 3 +++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index da81074655..3d8a6cc4f9 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -129,26 +129,30 @@ int DraciEngine::go() { Common::String testString = "Testing, testing, read all about it!"; xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; ypos = 130; - Text txt1(testString, _font, kFontColour1, xpos, ypos, 1); + Text txt(testString, _font, kFontColour1, xpos, ypos, 1); - txt1.draw(surf); + txt.draw(surf); // Draw small string _font->setFont(kFontSmall); testString = "I'm smaller than the font above me."; xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; ypos += 20; - Text txt2(testString, _font, kFontColour1, xpos, ypos, 1); + txt.setText(testString); + txt._x = xpos; + txt._y = ypos; - txt2.draw(surf); + txt.draw(surf); // Overflow handling test testString = "Checking overflooooooooooooooooooooooooow..."; xpos = 50; ypos += 20; - Text txt3(testString, _font, kFontColour1, xpos, ypos, 1); + txt.setText(testString); + txt._x = xpos; + txt._y = ypos; - txt3.draw(surf); + txt.draw(surf); _screen->copyToScreen(); @@ -162,6 +166,12 @@ int DraciEngine::go() { } testString = "I'm transparent"; + xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; + ypos = 80; + txt.setText(testString); + txt.setColour(kDefaultTransparent); + txt._x = xpos; + txt._y = ypos; for (unsigned int t = 0; t < 25; ++t) { debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); @@ -177,9 +187,7 @@ int DraciEngine::go() { sp.draw(surf); // Draw transparent text over dragon - _font->setColour(kDefaultTransparent); - _font->drawString(surf, testString, - (kScreenWidth - _font->getStringWidth(testString, 1)) / 2, 80, 1); + txt.draw(surf); _screen->copyToScreen(); _system->delayMillis(100); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 062499471d..b56727e15c 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -129,13 +129,13 @@ void Sprite::draw(Surface *surface) const { Text::Text(const Common::String &str, Font *font, byte fontColour, uint16 x, uint16 y, uint spacing) { uint len = str.size(); + _length = len; _x = x; _y = y; _text = new byte[len]; memcpy(_text, str.c_str(), len); - _length = len; _spacing = spacing; _colour = fontColour; @@ -144,7 +144,21 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, } Text::~Text() { - delete _text; + delete[] _text; +} + +void Text::setText(const Common::String &str) { + delete[] _text; + + uint len = str.size(); + _length = len; + + _text = new byte[len]; + memcpy(_text, str.c_str(), len); +} + +void Text::setColour(byte fontColour) { + _colour = fontColour; } void Text::draw(Surface *surface) const { diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 50b091e3d5..84c38527d4 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -78,6 +78,9 @@ public: uint16 x = 0, uint16 y = 0, uint spacing = 0); ~Text(); + void setText(const Common::String &str); + void setColour(byte fontColour); + void draw(Surface *surface) const; byte *_text; -- cgit v1.2.3 From f0fcd7fd8ee28d525f53df364233f4e064123a28 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 15:22:36 +0000 Subject: Modified Sprite, Text and Drawable to handle data hiding properly since they're no longer just C-like struct containers. Implemented getters/setters accordingly and changed existing code that used those classes. svn-id: r41995 --- engines/draci/draci.cpp | 15 ++++++++------- engines/draci/mouse.cpp | 3 ++- engines/draci/sprite.h | 26 +++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 3d8a6cc4f9..bbc8b531d6 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -139,8 +139,8 @@ int DraciEngine::go() { xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; ypos += 20; txt.setText(testString); - txt._x = xpos; - txt._y = ypos; + txt.setX(xpos); + txt.setY(ypos); txt.draw(surf); @@ -149,8 +149,8 @@ int DraciEngine::go() { xpos = 50; ypos += 20; txt.setText(testString); - txt._x = xpos; - txt._y = ypos; + txt.setX(xpos); + txt.setY(ypos); txt.draw(surf); @@ -170,8 +170,9 @@ int DraciEngine::go() { ypos = 80; txt.setText(testString); txt.setColour(kDefaultTransparent); - txt._x = xpos; - txt._y = ypos; + txt.setX(xpos); + txt.setY(ypos); + for (unsigned int t = 0; t < 25; ++t) { debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); @@ -180,7 +181,7 @@ int DraciEngine::go() { Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, true); // Delete previous frame - Common::Rect r(sp._x, sp._y, sp._x + sp._width, sp._y + sp._height); + Common::Rect r(sp.getX(), sp.getY(), sp.getX() + sp.getWidth(), sp.getY() + sp.getHeight()); _screen->drawRect(r, 225); // Draw dragon diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index d8b9935f2e..008659c415 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -98,7 +98,8 @@ void Mouse::setCursorType(CursorType cur) { Sprite sp(f->_data, f->_length, 0, 0, true); CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); - CursorMan.replaceCursor(sp._data, sp._width, sp._height, sp._width / 2, sp._height / 2); + CursorMan.replaceCursor(sp.getBuffer(), sp.getWidth(), sp.getHeight(), + sp.getWidth() / 2, sp.getHeight() / 2); } } diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 84c38527d4..a013965e2d 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -33,13 +33,29 @@ namespace Draci { class Drawable { +friend class Sprite; +friend class Text; + public: virtual void draw(Surface *surface) const = 0; virtual ~Drawable() {}; + + virtual uint16 getWidth() { return _width; } + virtual uint16 getHeight() { return _height; } + + virtual uint16 getX() { return _x; } + virtual uint16 getY() { return _y; } + virtual uint16 getZ() { return _z; } + virtual void setX(uint16 x) { _x = x; } + virtual void setY(uint16 y) { _y = y; } + virtual void setZ(uint16 z) { _z = z; } + +private: uint16 _width; //!< Width of the sprite uint16 _height; //!< Height of the sprite uint16 _x, _y; //!< Sprite coordinates + uint16 _z; //!< Sprite depth position }; /** @@ -66,13 +82,16 @@ public: ~Sprite(); - void draw(Surface *surface) const; + void draw(Surface *surface) const; + + const byte *getBuffer() const { return _data; } +private: byte *_data; //!< Pointer to a buffer containing raw sprite data (row-wise) }; class Text : public Drawable { - + public: Text(const Common::String &str, Font *font, byte fontColour, uint16 x = 0, uint16 y = 0, uint spacing = 0); @@ -82,7 +101,8 @@ public: void setColour(byte fontColour); void draw(Surface *surface) const; - + +private: byte *_text; uint _length; uint8 _colour; -- cgit v1.2.3 From cfadb6cc3daeb70a4776d3455964c8b463dad411 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 16:00:27 +0000 Subject: Made coordinate specification mandatory when constructing objects of type Sprite and Class. Made transforming from columnwise a default (since it was done most of the time anyway). Changed coordinates to use uint instead of uint16. svn-id: r41996 --- engines/draci/draci.cpp | 2 +- engines/draci/mouse.cpp | 2 +- engines/draci/sprite.cpp | 14 +++++++++----- engines/draci/sprite.h | 27 ++++++++++++++------------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index bbc8b531d6..6558e777cf 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -178,7 +178,7 @@ int DraciEngine::go() { // Load frame to memory f = ar[t]; - Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, true); + Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, 0); // Delete previous frame Common::Rect r(sp.getX(), sp.getY(), sp.getX() + sp.getWidth(), sp.getY() + sp.getHeight()); diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 008659c415..cbd3cd7a59 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -96,7 +96,7 @@ void Mouse::setCursorType(CursorType cur) { return; } - Sprite sp(f->_data, f->_length, 0, 0, true); + Sprite sp(f->_data, f->_length, 0, 0, 0); CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); CursorMan.replaceCursor(sp.getBuffer(), sp.getWidth(), sp.getHeight(), sp.getWidth() / 2, sp.getHeight() / 2); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index b56727e15c..43cab8838b 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -53,13 +53,14 @@ static void transformToRows(byte *img, uint16 width, uint16 height) { /** * Constructor for loading sprites from a raw data buffer, one byte per pixel. - */ -Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, - bool columnwise) : _data(NULL) { + */ +Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint x, uint y, + uint z, bool columnwise) : _data(NULL) { _width = width; _height = height; _x = x; _y = y; + _z = z; _data = new byte[width * height]; @@ -71,14 +72,16 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x, uint16 y, } } + /** * Constructor for loading sprites from a sprite-formatted buffer, one byte per * pixel. */ -Sprite::Sprite(byte *sprite_data, uint16 length, uint16 x, uint16 y, +Sprite::Sprite(byte *sprite_data, uint16 length, uint x, uint y, uint z, bool columnwise) : _data(NULL) { _x = x; _y = y; + _z = z; Common::MemoryReadStream reader(sprite_data, length); @@ -127,12 +130,13 @@ void Sprite::draw(Surface *surface) const { } Text::Text(const Common::String &str, Font *font, byte fontColour, - uint16 x, uint16 y, uint spacing) { + uint x, uint y, uint z, uint spacing) { uint len = str.size(); _length = len; _x = x; _y = y; + _z = z; _text = new byte[len]; memcpy(_text, str.c_str(), len); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index a013965e2d..d92cf7848f 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -43,19 +43,19 @@ public: virtual uint16 getWidth() { return _width; } virtual uint16 getHeight() { return _height; } - virtual uint16 getX() { return _x; } - virtual uint16 getY() { return _y; } - virtual uint16 getZ() { return _z; } + virtual uint getX() { return _x; } + virtual uint getY() { return _y; } + virtual uint getZ() { return _z; } - virtual void setX(uint16 x) { _x = x; } - virtual void setY(uint16 y) { _y = y; } - virtual void setZ(uint16 z) { _z = z; } + virtual void setX(uint x) { _x = x; } + virtual void setY(uint y) { _y = y; } + virtual void setZ(uint z) { _z = z; } private: uint16 _width; //!< Width of the sprite uint16 _height; //!< Height of the sprite - uint16 _x, _y; //!< Sprite coordinates - uint16 _z; //!< Sprite depth position + uint _x, _y; //!< Sprite coordinates + uint _z; //!< Sprite depth position }; /** @@ -74,11 +74,12 @@ private: class Sprite : public Drawable { public: - Sprite(byte *raw_data, uint16 width, uint16 height, uint16 x = 0, uint16 y = 0, - bool columnwise = false); + Sprite(byte *raw_data, uint16 width, uint16 height, uint x, uint y, + uint z, bool columnwise = true); + - Sprite(byte *sprite_data, uint16 length, uint16 x = 0, uint16 y = 0, - bool columnwise = false); + Sprite(byte *sprite_data, uint16 length, uint x, uint y, + uint z, bool columnwise = true); ~Sprite(); @@ -94,7 +95,7 @@ class Text : public Drawable { public: Text(const Common::String &str, Font *font, byte fontColour, - uint16 x = 0, uint16 y = 0, uint spacing = 0); + uint x, uint y, uint z, uint spacing = 0); ~Text(); void setText(const Common::String &str); -- cgit v1.2.3 From 1402a3f5fed4b3b97050924ad56bd4bfaf602a42 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 16:01:07 +0000 Subject: Removed declaration of Screen::drawSprite() which is now obsolete. svn-id: r41997 --- engines/draci/screen.h | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/draci/screen.h b/engines/draci/screen.h index 4c09e77926..42dcf40bae 100644 --- a/engines/draci/screen.h +++ b/engines/draci/screen.h @@ -51,7 +51,6 @@ public: byte *getPalette() const; void copyToScreen() const; void clearScreen() const; - void drawSprite(const Sprite &s) const; void fillScreen(uint8 colour) const; Surface *getSurface(); void drawRect(Common::Rect &r, uint8 colour); -- cgit v1.2.3 From 1373eeea126ea576d1b99d6df27238bb8d6c6b90 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 16:14:04 +0000 Subject: Made Text objects calculate their widths and heights properly. svn-id: r41998 --- engines/draci/draci.cpp | 2 +- engines/draci/sprite.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 6558e777cf..4c4ed39ee3 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -129,7 +129,7 @@ int DraciEngine::go() { Common::String testString = "Testing, testing, read all about it!"; xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; ypos = 130; - Text txt(testString, _font, kFontColour1, xpos, ypos, 1); + Text txt(testString, _font, kFontColour1, xpos, ypos, 0, 1); txt.draw(surf); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 43cab8838b..afabdf96ce 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -145,6 +145,9 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, _colour = fontColour; _font = font; + + _width = _font->getStringWidth(str, _spacing); + _height = _font->getFontHeight(); } Text::~Text() { @@ -157,6 +160,9 @@ void Text::setText(const Common::String &str) { uint len = str.size(); _length = len; + _width = _font->getStringWidth(str, _spacing); + _height = _font->getFontHeight(); + _text = new byte[len]; memcpy(_text, str.c_str(), len); } -- cgit v1.2.3 From 58c1591ae0ba68f4d259cff86b9ec3caa1137b74 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 16:15:06 +0000 Subject: Added Text::setSpacing() method. svn-id: r41999 --- engines/draci/sprite.cpp | 4 ++++ engines/draci/sprite.h | 1 + 2 files changed, 5 insertions(+) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index afabdf96ce..7456e28159 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -171,6 +171,10 @@ void Text::setColour(byte fontColour) { _colour = fontColour; } +void Text::setSpacing(uint spacing) { + _spacing = spacing; +} + void Text::draw(Surface *surface) const { _font->setColour(_colour); _font->drawString(surface, _text, _length, _x, _y, _spacing); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index d92cf7848f..490bf39211 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -100,6 +100,7 @@ public: void setText(const Common::String &str); void setColour(byte fontColour); + void setSpacing(uint spacing); void draw(Surface *surface) const; -- cgit v1.2.3 From d47ab6ae987cd01d1d0b87a54e226b3eaae89b24 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 1 Jul 2009 16:20:47 +0000 Subject: Added empty animation.cpp and animation.h files. svn-id: r42000 --- engines/draci/animation.cpp | 29 +++++++++++++++++++++++++++++ engines/draci/animation.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 engines/draci/animation.cpp create mode 100644 engines/draci/animation.h diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp new file mode 100644 index 0000000000..0aa9c14b8a --- /dev/null +++ b/engines/draci/animation.cpp @@ -0,0 +1,29 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +namespace Draci { + +} + diff --git a/engines/draci/animation.h b/engines/draci/animation.h new file mode 100644 index 0000000000..85973aea19 --- /dev/null +++ b/engines/draci/animation.h @@ -0,0 +1,33 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef DRACI_ANIMATION_H +#define DRACI_ANIMATION_H + +namespace Draci { + +} + +#endif // DRACI_ANIMATION_H -- cgit v1.2.3 From fed2281125f862f6f0356d8d40642a90ce772394 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 10:31:56 +0000 Subject: Make the meta engine pass the pointer to the detected version and not the whole ADGameDescription table. svn-id: r42018 --- engines/draci/detection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp index d01fb30d1c..b8aeb11200 100644 --- a/engines/draci/detection.cpp +++ b/engines/draci/detection.cpp @@ -121,7 +121,7 @@ bool Draci::DraciEngine::hasFeature(EngineFeature f) const { bool DraciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { if (desc) { - *engine = new Draci::DraciEngine(syst, Draci::gameDescriptions); + *engine = new Draci::DraciEngine(syst, desc); } return desc != 0; } -- cgit v1.2.3 From 35a677fb08402b5a9fd07366d60651bcc2f598ce Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 10:39:51 +0000 Subject: Added BArchive::clearCache() method for clearing the data cache of opened files. svn-id: r42019 --- engines/draci/barchive.cpp | 12 ++++++++++++ engines/draci/barchive.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index 4b9a1d9807..c6d6354716 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -377,6 +377,18 @@ BAFile *BArchive::loadFileDFW(unsigned int i) const { return _files + i; } + +/** + * Clears the cache of the open files inside the archive without closing it. + * If the files are subsequently accessed, they are read from the disk. + */ +void BArchive::clearCache() { + + // Delete all cached data + for (unsigned int i = 0; i < _fileCount; ++i) { + _files[i].closeFile(); + } +} BAFile *BArchive::operator[](unsigned int i) const { diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index e52e41e737..28c34fbcbb 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -70,6 +70,8 @@ public: */ bool isOpen() const { return _opened; } + void clearCache(); + BAFile *operator[](unsigned int i) const; private: -- cgit v1.2.3 From 936e5f4c5e5c70f9869ed8a986173c92b7f39d4a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 15:08:42 +0000 Subject: Merged the info available from _objectStatus with the GameObject struct. Made Game keep a list of all the game's objects. Added Game::getObject() method for fetching a pointer to a particular object. Changed Game::loadObject() to not accept a pointer to a GameObject struct anymore. svn-id: r42026 --- engines/draci/game.cpp | 34 +++++++++++++++++++++++++++------- engines/draci/game.h | 8 +++++--- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 72e431bf44..d13883087c 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -113,19 +113,29 @@ Game::Game(DraciEngine *vm) : _vm(vm) { file = initArchive[0]; unsigned int numObjects = file->_length; - _objectStatus = new byte[numObjects]; - memcpy(_objectStatus, file->_data, file->_length); + _objects = new GameObject[numObjects]; + Common::MemoryReadStream objStatus(file->_data, file->_length); + for (i = 0; i < numObjects; ++i) { + byte tmp = objStatus.readByte(); + + // Set object visibility + _objects[i]._visible = tmp & 1; + + // Set object location + _objects[i]._location = tmp & ~1; + } + assert(numDialogs == _info->_numDialogs); assert(numPersons == _info->_numPersons); assert(numVariables == _info->_numVariables); assert(numObjects == _info->_numObjects); - loadObject(0, &_heroObj); - _vm->_script->run(_heroObj._program, _heroObj._init); + loadObject(1); + _vm->_script->run(getObject(1)->_program, getObject(1)->_init); } -void Game::loadObject(uint16 objNum, GameObject *obj) { +void Game::loadObject(uint16 objNum) { Common::String path("OBJEKTY.DFW"); BArchive objArchive(path); @@ -134,6 +144,8 @@ void Game::loadObject(uint16 objNum, GameObject *obj) { file = objArchive[objNum * 3]; Common::MemoryReadStream objReader(file->_data, file->_length); + GameObject *obj = getObject(objNum); + obj->_init = objReader.readUint16LE(); obj->_look = objReader.readUint16LE(); obj->_use = objReader.readUint16LE(); @@ -166,13 +178,21 @@ void Game::loadObject(uint16 objNum, GameObject *obj) { obj->_program._length = file->_length; memcpy(obj->_program._bytecode, file->_data, file->_length); } - + +GameObject *Game::getObject(uint16 objNum) { + + // Convert to real index (indexes begin with 1 in the data files) + objNum -= 1; + + return &_objects[objNum]; +} + Game::~Game() { delete[] _persons; delete[] _variables; delete[] _dialogOffsets; delete[] _itemStatus; - delete[] _objectStatus; + delete[] _objects; delete _info; } diff --git a/engines/draci/game.h b/engines/draci/game.h index abefb0f963..4b6ba17878 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -54,6 +54,8 @@ struct GameObject { uint16 *_seqTab; GPL2Program _program; byte *_title; + byte _location; + bool _visible; }; struct GameInfo { @@ -89,10 +91,10 @@ private: uint16 *_dialogOffsets; int16 *_variables; byte *_itemStatus; - byte *_objectStatus; - GameObject _heroObj; + GameObject *_objects; - void loadObject(uint16 numObj, GameObject *obj); + void loadObject(uint16 numObj); + GameObject *getObject(uint16 objNum); }; } // End of namespace Draci -- cgit v1.2.3 From be3c0461d6af8f3631da88a92e9b66524a3c0a9c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 16:15:32 +0000 Subject: DraciEngine now opens and stores pointers to essential archives. Changed code that used those archives to use that instead of opening them manually. Replaced BArchive::operator[] functionality with BArchive::getFile() to prevent ugliness when accessing archives via pointers. svn-id: r42031 --- engines/draci/barchive.cpp | 2 +- engines/draci/barchive.h | 4 ++-- engines/draci/draci.cpp | 52 +++++++++++++++++++++++++++++----------------- engines/draci/draci.h | 5 +++++ engines/draci/game.cpp | 28 ++++++++++++------------- engines/draci/mouse.cpp | 2 +- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index c6d6354716..cd0d4b2172 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -391,7 +391,7 @@ void BArchive::clearCache() { } -BAFile *BArchive::operator[](unsigned int i) const { +BAFile *BArchive::getFile(unsigned int i) const { // Check whether requested file exists if (i >= _fileCount) { diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 28c34fbcbb..185cfcb38d 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -53,7 +53,7 @@ class BArchive { public: BArchive() : _files(NULL), _fileCount(0), _opened(false) {} - BArchive(Common::String &path) : + BArchive(const Common::String &path) : _files(NULL), _fileCount(0), _opened(false) { openArchive(path); } @@ -72,7 +72,7 @@ public: void clearCache(); - BAFile *operator[](unsigned int i) const; + BAFile *getFile(unsigned int i) const; private: // Archive header data diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 4c4ed39ee3..f83a5994fd 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -42,6 +42,12 @@ namespace Draci { +// Data file paths + +const Common::String objectsPath("OBJEKTY.DFW"); +const Common::String palettePath("PALETY.DFW"); +const Common::String spritesPath("OBR_AN.DFW"); + DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { // Put your engine in a sane state, but do nothing big yet; @@ -66,6 +72,11 @@ int DraciEngine::init() { // Initialize graphics using following: initGraphics(kScreenWidth, kScreenHeight, false); + // Open game's archives + _objectsArchive = new BArchive(objectsPath); + _spritesArchive = new BArchive(spritesPath); + _paletteArchive = new BArchive(palettePath); + _screen = new Screen(this); _font = new Font(); _mouse = new Mouse(this); @@ -75,6 +86,21 @@ int DraciEngine::init() { // Load default font _font->setFont(kFontBig); + if(!_objectsArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening objects archive failed"); + return Common::kUnknownError; + } + + if(!_spritesArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening sprites archive failed"); + return Common::kUnknownError; + } + + if(!_paletteArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening palette archive failed"); + return Common::kUnknownError; + } + // Basic archive test debugC(2, kDraciGeneralDebugLevel, "Running archive tests..."); Common::String path("INIT.DFW"); @@ -83,7 +109,7 @@ int DraciEngine::init() { debugC(3, kDraciGeneralDebugLevel, "Number of file streams in archive: %d", ar.size()); if(ar.isOpen()) { - f = ar[0]; + f = ar.getFile(0); } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); return Common::kUnknownError; @@ -102,18 +128,9 @@ int DraciEngine::go() { debugC(2, kDraciGeneralDebugLevel, "Running graphics/animation test..."); - Common::String path("PALETY.DFW"); - BArchive ar(path); BAFile *f; - ar.openArchive(path); - - if(ar.isOpen()) { - f = ar[0]; - } else { - debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return Common::kUnknownError; - } + f = _paletteArchive->getFile(0); _screen->setPalette(f->_data, 0, kNumColours); @@ -157,13 +174,6 @@ int DraciEngine::go() { _screen->copyToScreen(); // Draw and animate the dragon - path = "OBR_AN.DFW"; - ar.openArchive(path); - - if(!ar.isOpen()) { - debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened"); - return Common::kUnknownError; - } testString = "I'm transparent"; xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; @@ -177,7 +187,7 @@ int DraciEngine::go() { debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); // Load frame to memory - f = ar[t]; + f = _spritesArchive->getFile(t); Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, 0); // Delete previous frame @@ -227,6 +237,10 @@ DraciEngine::~DraciEngine() { delete _mouse; delete _game; delete _script; + + delete _paletteArchive; + delete _objectsArchive; + delete _spritesArchive; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index ae9826464a..196dc0762e 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -35,6 +35,7 @@ #include "draci/screen.h" #include "draci/font.h" #include "draci/script.h" +#include "draci/barchive.h" namespace Draci { @@ -55,6 +56,10 @@ public: Game *_game; Script *_script; + BArchive *_objectsArchive; + BArchive *_spritesArchive; + BArchive *_paletteArchive; + private: Common::RandomSource _rnd; }; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d13883087c..c423292b0d 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -41,7 +41,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in persons - file = initArchive[5]; + file = initArchive.getFile(5); Common::MemoryReadStream personData(file->_data, file->_length); unsigned int numPersons = file->_length / personSize; @@ -55,7 +55,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in dialog offsets - file = initArchive[4]; + file = initArchive.getFile(4); Common::MemoryReadStream dialogData(file->_data, file->_length); unsigned int numDialogs = file->_length / sizeof(uint16); @@ -69,7 +69,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in game info - file = initArchive[3]; + file = initArchive.getFile(3); Common::MemoryReadStream gameData(file->_data, file->_length); _info = new GameInfo(); @@ -92,7 +92,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in variables - file = initArchive[2]; + file = initArchive.getFile(2); unsigned int numVariables = file->_length / sizeof (int16); _variables = new int16[numVariables]; @@ -104,13 +104,13 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in item status - file = initArchive[1]; + file = initArchive.getFile(1); _itemStatus = new byte[file->_length]; memcpy(_itemStatus, file->_data, file->_length); // Read in object status - file = initArchive[0]; + file = initArchive.getFile(0); unsigned int numObjects = file->_length; _objects = new GameObject[numObjects]; @@ -136,15 +136,15 @@ Game::Game(DraciEngine *vm) : _vm(vm) { } void Game::loadObject(uint16 objNum) { - Common::String path("OBJEKTY.DFW"); - - BArchive objArchive(path); BAFile *file; - file = objArchive[objNum * 3]; + // Convert to real index (indexes begin with 1 in the data files) + objNum -= 1; + + file = _vm->_objectsArchive->getFile(objNum * 3); Common::MemoryReadStream objReader(file->_data, file->_length); - GameObject *obj = getObject(objNum); + GameObject *obj = _objects + objNum; obj->_init = objReader.readUint16LE(); obj->_look = objReader.readUint16LE(); @@ -169,11 +169,11 @@ void Game::loadObject(uint16 objNum) { obj->_seqTab = new uint16[obj->_numSeq]; - file = objArchive[objNum * 3 + 1]; + file = _vm->_objectsArchive->getFile(objNum * 3 + 1); obj->_title = new byte[file->_length]; memcpy(obj->_title, file->_data, file->_length); - file = objArchive[objNum * 3 + 2]; + file = _vm->_objectsArchive->getFile(objNum * 3 + 2); obj->_program._bytecode = new byte[file->_length]; obj->_program._length = file->_length; memcpy(obj->_program._bytecode, file->_data, file->_length); @@ -184,7 +184,7 @@ GameObject *Game::getObject(uint16 objNum) { // Convert to real index (indexes begin with 1 in the data files) objNum -= 1; - return &_objects[objNum]; + return _objects + objNum; } Game::~Game() { diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index cbd3cd7a59..b4c0aea542 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -90,7 +90,7 @@ void Mouse::setCursorType(CursorType cur) { ar.openArchive(path); if(ar.isOpen()) { - f = ar[_cursorType]; + f = ar.getFile(_cursorType); } else { debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened - %s", path.c_str()); return; -- cgit v1.2.3 From b0334e102fea2cc8d5b425b5a5131d3a65f18953 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 19:47:25 +0000 Subject: Added struct Room. svn-id: r42033 --- engines/draci/game.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/engines/draci/game.h b/engines/draci/game.h index 4b6ba17878..f1982ede94 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -77,6 +77,19 @@ struct Person { byte _fontColour; }; +struct Room { + byte _music; + byte _map; + byte _palette; + uint16 _numMasks; + uint16 _init, _look, _use, _canUse; + boolean _imInit, _imLook, _imUse; + boolean _mouseOn, _heroOn; + double _pers0, _persStep; + byte _escRoom; + byte _numGates; +}; + class Game { public: -- cgit v1.2.3 From 4a4aab83d0ee19040536bb8aa7e8832a715a85a3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 19:54:18 +0000 Subject: Fixed typo. svn-id: r42034 --- engines/draci/game.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.h b/engines/draci/game.h index f1982ede94..e65de7c771 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -83,8 +83,8 @@ struct Room { byte _palette; uint16 _numMasks; uint16 _init, _look, _use, _canUse; - boolean _imInit, _imLook, _imUse; - boolean _mouseOn, _heroOn; + bool _imInit, _imLook, _imUse; + bool _mouseOn, _heroOn; double _pers0, _persStep; byte _escRoom; byte _numGates; -- cgit v1.2.3 From cac39d8295c7be133d9d51c3e5b9dd7d8b5637cc Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 19:57:09 +0000 Subject: Added rooms and overlays archives. svn-id: r42035 --- engines/draci/draci.cpp | 4 ++++ engines/draci/draci.h | 2 ++ engines/draci/game.cpp | 2 ++ 3 files changed, 8 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index f83a5994fd..ba6d10e816 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -47,6 +47,8 @@ namespace Draci { const Common::String objectsPath("OBJEKTY.DFW"); const Common::String palettePath("PALETY.DFW"); const Common::String spritesPath("OBR_AN.DFW"); +const Common::String overlaysPath("OBR_MAS.DFW"); +const Common::String roomsPath("MIST.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { @@ -76,6 +78,8 @@ int DraciEngine::init() { _objectsArchive = new BArchive(objectsPath); _spritesArchive = new BArchive(spritesPath); _paletteArchive = new BArchive(palettePath); + _roomsArchive = new BArchive(roomsPath); + _overlaysArchive = new BArchive(overlaysPath); _screen = new Screen(this); _font = new Font(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 196dc0762e..971fe3f228 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -59,6 +59,8 @@ public: BArchive *_objectsArchive; BArchive *_spritesArchive; BArchive *_paletteArchive; + BArchive *_roomsArchive; + BArchive *_overlaysArchive; private: Common::RandomSource _rnd; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index c423292b0d..5bcaa1434e 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -133,6 +133,8 @@ Game::Game(DraciEngine *vm) : _vm(vm) { loadObject(1); _vm->_script->run(getObject(1)->_program, getObject(1)->_init); + + // changeRoom(_currentRoom); } void Game::loadObject(uint16 objNum) { -- cgit v1.2.3 From 8bba3e6f10ce68dd9615ab7340fb0c54b3f61e1a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 2 Jul 2009 20:29:14 +0000 Subject: Added Game::changeRoom() method and Game::_currentRoom. svn-id: r42036 --- engines/draci/game.cpp | 34 +++++++++++++++++++++++++++++++++- engines/draci/game.h | 4 +++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 5bcaa1434e..75f55e1798 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -134,7 +134,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { loadObject(1); _vm->_script->run(getObject(1)->_program, getObject(1)->_init); - // changeRoom(_currentRoom); + changeRoom(_info->_currentRoom); } void Game::loadObject(uint16 objNum) { @@ -189,6 +189,38 @@ GameObject *Game::getObject(uint16 objNum) { return _objects + objNum; } +void Game::changeRoom(uint16 roomNum) { + + // Convert to real index (indexes begin with 1 in the data files) + roomNum -= 1; + + BAFile *f; + f = _vm->_roomsArchive->getFile(roomNum); + Common::MemoryReadStream roomReader(f->_data, f->_length); + + roomReader.readUint32LE(); // Pointer to room program, not used + roomReader.readUint16LE(); // Program length, not used + roomReader.readUint32LE(); // Pointer to room title, not used + + _currentRoom._music = roomReader.readByte(); + _currentRoom._map = roomReader.readByte(); + _currentRoom._palette = roomReader.readByte(); + _currentRoom._numMasks = roomReader.readUint16LE(); + _currentRoom._init = roomReader.readUint16LE(); + _currentRoom._look = roomReader.readUint16LE(); + _currentRoom._use = roomReader.readUint16LE(); + _currentRoom._canUse = roomReader.readUint16LE(); + _currentRoom._imInit = roomReader.readByte(); + _currentRoom._imLook = roomReader.readByte(); + _currentRoom._imUse = roomReader.readByte(); + _currentRoom._mouseOn = roomReader.readByte(); + _currentRoom._heroOn = roomReader.readByte(); + roomReader.read(&_currentRoom._pers0, 12); + roomReader.read(&_currentRoom._persStep, 12); + _currentRoom._escRoom = roomReader.readByte(); + _currentRoom._numGates = roomReader.readByte(); +} + Game::~Game() { delete[] _persons; delete[] _variables; diff --git a/engines/draci/game.h b/engines/draci/game.h index e65de7c771..d3a47902d8 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -105,9 +105,11 @@ private: int16 *_variables; byte *_itemStatus; GameObject *_objects; - + Room _currentRoom; + void loadObject(uint16 numObj); GameObject *getObject(uint16 objNum); + void changeRoom(uint16 roomNum); }; } // End of namespace Draci -- cgit v1.2.3 From b232202b3383b44407d24101cb175e4190f851b4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 16:29:56 +0000 Subject: Removed demo code so I can start working on the real intro. svn-id: r42063 --- engines/draci/draci.cpp | 79 +------------------------------------------------ 1 file changed, 1 insertion(+), 78 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index ba6d10e816..295314f044 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -87,6 +87,7 @@ int DraciEngine::init() { _game = new Game(this); _script = new Script(); + // Load default font _font->setFont(kFontBig); @@ -132,84 +133,6 @@ int DraciEngine::go() { debugC(2, kDraciGeneralDebugLevel, "Running graphics/animation test..."); - BAFile *f; - - f = _paletteArchive->getFile(0); - - _screen->setPalette(f->_data, 0, kNumColours); - - // Fill screen with light grey - _screen->fillScreen(225); - - // Draw big string - - Surface *surf = _screen->getSurface(); - uint16 xpos; - uint16 ypos; - - Common::String testString = "Testing, testing, read all about it!"; - xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; - ypos = 130; - Text txt(testString, _font, kFontColour1, xpos, ypos, 0, 1); - - txt.draw(surf); - - // Draw small string - _font->setFont(kFontSmall); - testString = "I'm smaller than the font above me."; - xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; - ypos += 20; - txt.setText(testString); - txt.setX(xpos); - txt.setY(ypos); - - txt.draw(surf); - - // Overflow handling test - testString = "Checking overflooooooooooooooooooooooooow..."; - xpos = 50; - ypos += 20; - txt.setText(testString); - txt.setX(xpos); - txt.setY(ypos); - - txt.draw(surf); - - _screen->copyToScreen(); - - // Draw and animate the dragon - - testString = "I'm transparent"; - xpos = (kScreenWidth - _font->getStringWidth(testString, 1)) / 2; - ypos = 80; - txt.setText(testString); - txt.setColour(kDefaultTransparent); - txt.setX(xpos); - txt.setY(ypos); - - for (unsigned int t = 0; t < 25; ++t) { - debugC(5, kDraciGeneralDebugLevel, "Drawing frame %d...", t); - - // Load frame to memory - f = _spritesArchive->getFile(t); - Sprite sp(f->_data, f->_length, ((kScreenWidth - 50) / 2), 60, 0); - - // Delete previous frame - Common::Rect r(sp.getX(), sp.getY(), sp.getX() + sp.getWidth(), sp.getY() + sp.getHeight()); - _screen->drawRect(r, 225); - - // Draw dragon - sp.draw(surf); - - // Draw transparent text over dragon - txt.draw(surf); - - _screen->copyToScreen(); - _system->delayMillis(100); - - debugC(5, kDraciGeneralDebugLevel, "Finished frame %d", t); - } - _mouse->setCursorType(kNormalCursor); _mouse->cursorOn(); -- cgit v1.2.3 From 52642e2dc9db65b87994b56e19c14b1b039dcb08 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 16:35:04 +0000 Subject: Added two more debug levels (logic and animation). svn-id: r42065 --- engines/draci/draci.cpp | 4 +++- engines/draci/draci.h | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 295314f044..cef66893fe 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -62,9 +62,11 @@ DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) //Common::File::addDefaultDirectory(_gameDataPath + "sound/"); // Here is the right place to set up the engine specific debug levels - Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug level"); + Common::addDebugChannel(kDraciGeneralDebugLevel, "general", "Draci general debug info"); Common::addDebugChannel(kDraciBytecodeDebugLevel, "bytecode", "GPL bytecode instructions"); Common::addDebugChannel(kDraciArchiverDebugLevel, "archiver", "BAR archiver debug info"); + Common::addDebugChannel(kDraciLogicDebugLevel, "logic", "Game logic debug info"); + Common::addDebugChannel(kDraciAnimationDebugLevel, "animation", "Animation debug info"); // Don't forget to register your random source _eventMan->registerRandomSource(_rnd, "draci"); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 971fe3f228..aa8969d9aa 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -67,9 +67,11 @@ private: }; enum { - kDraciGeneralDebugLevel = 1 << 0, - kDraciBytecodeDebugLevel = 1 << 1, - kDraciArchiverDebugLevel = 1 << 2 + kDraciGeneralDebugLevel = 1 << 0, + kDraciBytecodeDebugLevel = 1 << 1, + kDraciArchiverDebugLevel = 1 << 2, + kDraciLogicDebugLevel = 1 << 3, + kDraciAnimationDebugLevel = 1 << 4 }; } // End of namespace Draci -- cgit v1.2.3 From 8e9771d15c3e328fb5183f78f37501f9f2646c09 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 16:41:11 +0000 Subject: Added bool parameter markDirty to Sprite::draw() and Text::draw() to specify whether to mark a dirty rect for a particular draw (also added such support to the Font class since it's needed by Text). Made spacing parameters for Text instances mandatory. svn-id: r42066 --- engines/draci/font.cpp | 16 +++++++++------- engines/draci/font.h | 6 +++--- engines/draci/sprite.cpp | 10 ++++++---- engines/draci/sprite.h | 6 +++--- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index b3c5768b51..17ff8644cb 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -144,7 +144,7 @@ uint8 Font::getCharWidth(uint8 chr) const { * @param ty Vertical offset on the surface */ -void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { +void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) const { assert(dst != NULL); assert(tx >= 0); assert(ty >= 0); @@ -197,8 +197,10 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { ptr += dst->pitch; } - Common::Rect r(tx, ty, tx + xPixelsToDraw, ty + yPixelsToDraw); - dst->markDirtyRect(r); + if (markDirty) { + Common::Rect r(tx, ty, tx + xPixelsToDraw, ty + yPixelsToDraw); + dst->markDirtyRect(r); + } } /** @@ -213,7 +215,7 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { */ void Font::drawString(Surface *dst, const byte *str, uint len, - int x, int y, int spacing) const { + int x, int y, int spacing, bool markDirty) const { assert(dst != NULL); assert(x >= 0); assert(y >= 0); @@ -227,7 +229,7 @@ void Font::drawString(Surface *dst, const byte *str, uint len, return; } - drawChar(dst, str[i], curx, y); + drawChar(dst, str[i], curx, y, markDirty); curx += getCharWidth(str[i]) + spacing; } } @@ -243,9 +245,9 @@ void Font::drawString(Surface *dst, const byte *str, uint len, */ void Font::drawString(Surface *dst, const Common::String &str, - int x, int y, int spacing) const { + int x, int y, int spacing, bool markDirty) const { - drawString(dst, (byte *) str.c_str(), str.size(), x, y, spacing); + drawString(dst, (byte *) str.c_str(), str.size(), x, y, spacing, markDirty); } /** diff --git a/engines/draci/font.h b/engines/draci/font.h index c108a4493e..cdce071e5a 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -61,12 +61,12 @@ public: uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; - void drawChar(Surface *dst, uint8 chr, int tx, int ty) const; + void drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty = true) const; void drawString(Surface *dst, const byte *str, uint len, int x, int y, - int spacing = 0) const; + int spacing, bool markDirty = true) const; void drawString(Surface *dst, const Common::String &str, - int x, int y, int spacing = 0) const; + int x, int y, int spacing, bool markDirty = true) const; int getStringWidth(const Common::String &str, int spacing = 0) const; void setColour(uint8 colour); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 7456e28159..45f4c40e05 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -108,7 +108,7 @@ Sprite::~Sprite() { * * Draws the sprite to a Draci::Surface and marks its rectangle on the surface as dirty. */ -void Sprite::draw(Surface *surface) const { +void Sprite::draw(Surface *surface, bool markDirty) const { byte *dst = (byte *)surface->getBasePtr(_x, _y); byte *src = _data; @@ -125,8 +125,10 @@ void Sprite::draw(Surface *surface) const { } // Mark the sprite's rectangle dirty - Common::Rect r(_x, _y, _x + _width, _y + _height); - surface->markDirtyRect(r); + if (markDirty) { + Common::Rect r(_x, _y, _x + _width, _y + _height); + surface->markDirtyRect(r); + } } Text::Text(const Common::String &str, Font *font, byte fontColour, @@ -175,7 +177,7 @@ void Text::setSpacing(uint spacing) { _spacing = spacing; } -void Text::draw(Surface *surface) const { +void Text::draw(Surface *surface, bool markDirty) const { _font->setColour(_colour); _font->drawString(surface, _text, _length, _x, _y, _spacing); } diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 490bf39211..c0572f085c 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -37,7 +37,7 @@ friend class Sprite; friend class Text; public: - virtual void draw(Surface *surface) const = 0; + virtual void draw(Surface *surface, bool markDirty = true) const = 0; virtual ~Drawable() {}; virtual uint16 getWidth() { return _width; } @@ -83,7 +83,7 @@ public: ~Sprite(); - void draw(Surface *surface) const; + void draw(Surface *surface, bool markDirty = true) const; const byte *getBuffer() const { return _data; } @@ -102,7 +102,7 @@ public: void setColour(byte fontColour); void setSpacing(uint spacing); - void draw(Surface *surface) const; + void draw(Surface *surface, bool markDirty = true) const; private: byte *_text; -- cgit v1.2.3 From 90e6ff9d8a2dab45ddaba2713831d47264493fa0 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 17:39:13 +0000 Subject: Added support for mirrored sprites. svn-id: r42067 --- engines/draci/sprite.cpp | 39 ++++++++++++++++++++++++++++++--------- engines/draci/sprite.h | 4 ++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 45f4c40e05..b417afc0ed 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -61,7 +61,8 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint x, uint y, _x = x; _y = y; _z = z; - + _mirror = false; + _data = new byte[width * height]; memcpy(_data, raw_data, width * height); @@ -82,7 +83,8 @@ Sprite::Sprite(byte *sprite_data, uint16 length, uint x, uint y, uint z, _x = x; _y = y; _z = z; - + _mirror = false; + Common::MemoryReadStream reader(sprite_data, length); _width = reader.readUint16LE(); @@ -102,6 +104,14 @@ Sprite::~Sprite() { delete[] _data; } +void Sprite::setMirrorOn() { + _mirror = true; +} + +void Sprite::setMirrorOff() { + _mirror = false; +} + /** * @brief Draws the sprite to a Draci::Surface * @param surface Pointer to a Draci::Surface @@ -113,14 +123,25 @@ void Sprite::draw(Surface *surface, bool markDirty) const { byte *src = _data; // Blit the sprite to the surface - for (unsigned int i = 0; i < _height; ++i) { - for(unsigned int j = 0; j < _width; ++j, ++src) { - - // Don't blit if the pixel is transparent on the target surface - if (*src != surface->getTransparentColour()) - dst[j] = *src; + for (int i = 0; i < _height; ++i) { + + // Draw the sprite mirrored if the _mirror flag is set + if (_mirror) { + for(int j = _width - 1; j >= 0; --j, ++src) { + + // Don't blit if the pixel is transparent on the target surface + if (*src != surface->getTransparentColour()) + dst[j] = *src; + } + } else { + for(int j = 0; j < _width; ++j, ++src) { + + // Don't blit if the pixel is transparent on the target surface + if (*src != surface->getTransparentColour()) + dst[j] = *src; + } } - + dst += surface->pitch; } diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index c0572f085c..191d20ca9e 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -84,11 +84,15 @@ public: ~Sprite(); void draw(Surface *surface, bool markDirty = true) const; + + void setMirrorOn(); + void setMirrorOff(); const byte *getBuffer() const { return _data; } private: byte *_data; //!< Pointer to a buffer containing raw sprite data (row-wise) + bool _mirror; }; class Text : public Drawable { -- cgit v1.2.3 From c178409b56990297e7521b072fda1d537b067b4c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 17:50:22 +0000 Subject: Implemented beginning of the animation engine. svn-id: r42068 --- engines/draci/animation.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++ engines/draci/animation.h | 34 +++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 0aa9c14b8a..c074deb867 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -23,7 +23,87 @@ * */ +#include "draci/draci.h" +#include "draci/animation.h" + namespace Draci { +void Animation::addAnimation(uint id, uint z) { + + AnimObj *obj = new AnimObj(); + obj->_id = id; + obj->_z = z; + obj->_currentFrame = 0; + + insertAnimation(*obj); +} + +Common::List::iterator Animation::getAnimation(uint id) { + + Common::List::iterator it; + + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + if (it->_id == id) { + return it; + } + } + + return _animObjects.end(); +} + +void Animation::insertAnimation(AnimObj &animObj) { + + Common::List::iterator it; + + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + if (animObj._z < it->_z) + break; + } + + _animObjects.insert(it, animObj); +} + +void Animation::addFrame(uint id, Drawable *frame) { + + Common::List::iterator it = getAnimation(id); + + it->_frames.push_back(frame); +} + +void Animation::addOverlay(Drawable *overlay, uint z) { + AnimObj *obj = new AnimObj(); + obj->_id = kOverlayImage; + obj->_z = z; + obj->_currentFrame = 0; + obj->_frames.push_back(overlay); + + insertAnimation(*obj); +} + +void Animation::drawScene(Surface *surf) { + + Common::List::iterator it; + + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + if(it->_id == kOverlayImage) { + it->_frames[it->_currentFrame]->draw(surf, false); + } + else { + it->_frames[it->_currentFrame]->draw(surf, true); + } + } +} + +void Animation::deleteAnimation(uint id) { + + Common::List::iterator it = getAnimation(id); + + _animObjects.erase(it); +} + +void Animation::deleteAll() { + + _animObjects.clear(); } +} diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 85973aea19..8f4cc8e324 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -26,8 +26,42 @@ #ifndef DRACI_ANIMATION_H #define DRACI_ANIMATION_H +#include "draci/sprite.h" + namespace Draci { +enum { kOverlayImage = -1 }; + +class DraciEngine; + +struct AnimObj { + uint _id; + uint _currentFrame; + uint _z; + Common::Array _frames; +}; + +class Animation { + +public: + Animation(DraciEngine *vm) : _vm(vm) {}; + + void addAnimation(uint id, uint z = 0); + void addFrame(uint id, Drawable *frame); + void addOverlay(Drawable *overlay, uint z = 0); + void deleteAnimation(uint id); + void deleteAll(); + void drawScene(Surface *surf); + Common::List::iterator getAnimation(uint id); + +private: + + void insertAnimation(AnimObj &animObj); + + DraciEngine *_vm; + Common::List _animObjects; +}; + } #endif // DRACI_ANIMATION_H -- cgit v1.2.3 From 22cfdf01ee316745b4951d4ff314d18e6ca1f11b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 17:53:05 +0000 Subject: Made the animation engine compile. svn-id: r42069 --- engines/draci/module.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/draci/module.mk b/engines/draci/module.mk index d79407cff7..3eddfd3079 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -10,7 +10,8 @@ MODULE_OBJS := \ screen.o \ surface.o \ mouse.o \ - game.o + game.o \ + animation.o MODULE_DIRS += \ engines/draci -- cgit v1.2.3 From 4ba1ea8adf75b1e665827314ae3ebc164887e450 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 17:54:13 +0000 Subject: Added support for loading room overlays to Game::changeRoom(). svn-id: r42070 --- engines/draci/game.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 75f55e1798..3f5329eee4 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -29,6 +29,7 @@ #include "draci/game.h" #include "draci/barchive.h" #include "draci/script.h" +#include "draci/animation.h" namespace Draci { @@ -190,12 +191,12 @@ GameObject *Game::getObject(uint16 objNum) { } void Game::changeRoom(uint16 roomNum) { - + // Convert to real index (indexes begin with 1 in the data files) roomNum -= 1; BAFile *f; - f = _vm->_roomsArchive->getFile(roomNum); + f = _vm->_roomsArchive->getFile(roomNum * 4); Common::MemoryReadStream roomReader(f->_data, f->_length); roomReader.readUint32LE(); // Pointer to room program, not used @@ -219,6 +220,30 @@ void Game::changeRoom(uint16 roomNum) { roomReader.read(&_currentRoom._persStep, 12); _currentRoom._escRoom = roomReader.readByte(); _currentRoom._numGates = roomReader.readByte(); + + f = _vm->_paletteArchive->getFile(_currentRoom._palette - 1); + _vm->_screen->setPalette(f->_data, 0, kNumColours); + + uint x, y, z, num; + + f = _vm->_roomsArchive->getFile(roomNum * 4 + 2); + Common::MemoryReadStream overlayReader(f->_data, f->_length); + BAFile *overlayFile; + + for (uint i = 0; i < _currentRoom._numMasks; i++) { + + num = overlayReader.readUint16LE(); + x = overlayReader.readUint16LE(); + y = overlayReader.readUint16LE(); + z = overlayReader.readByte(); + + overlayFile = _vm->_overlaysArchive->getFile(num - 1); + Sprite *sp = new Sprite(overlayFile->_data, overlayFile->_length, x, y, z, true); + + _vm->_anims->addOverlay(sp, z); + } + + _vm->_screen->getSurface()->markDirty(); } Game::~Game() { -- cgit v1.2.3 From 1853d594b837358bde0ec89697d74ae29e7459a0 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 17:55:28 +0000 Subject: Enabled loading room number 1 as a test. svn-id: r42071 --- engines/draci/draci.cpp | 6 +++++- engines/draci/draci.h | 2 ++ engines/draci/game.cpp | 2 +- engines/draci/game.h | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index cef66893fe..79d38134b9 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -85,9 +85,11 @@ int DraciEngine::init() { _screen = new Screen(this); _font = new Font(); + _anims = new Animation(this); _mouse = new Mouse(this); - _game = new Game(this); _script = new Script(); + _game = new Game(this); + // Load default font @@ -150,6 +152,7 @@ int DraciEngine::go() { _mouse->handleEvent(event); } } + _anims->drawScene(_screen->getSurface()); _screen->copyToScreen(); _system->delayMillis(20); } @@ -166,6 +169,7 @@ DraciEngine::~DraciEngine() { delete _mouse; delete _game; delete _script; + delete _anims; delete _paletteArchive; delete _objectsArchive; diff --git a/engines/draci/draci.h b/engines/draci/draci.h index aa8969d9aa..9b4444277a 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -36,6 +36,7 @@ #include "draci/font.h" #include "draci/script.h" #include "draci/barchive.h" +#include "draci/animation.h" namespace Draci { @@ -55,6 +56,7 @@ public: Mouse *_mouse; Game *_game; Script *_script; + Animation *_anims; BArchive *_objectsArchive; BArchive *_spritesArchive; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3f5329eee4..06e460724f 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -135,7 +135,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { loadObject(1); _vm->_script->run(getObject(1)->_program, getObject(1)->_init); - changeRoom(_info->_currentRoom); + changeRoom(1); } void Game::loadObject(uint16 objNum) { diff --git a/engines/draci/game.h b/engines/draci/game.h index d3a47902d8..b04ad785e3 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -28,6 +28,8 @@ #include "common/str.h" #include "draci/script.h" +#include "draci/animation.h" +#include "draci/sprite.h" namespace Draci { -- cgit v1.2.3 From c651d1c2e252995cf3c6b84fe7b0a161437f5e99 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 18:17:05 +0000 Subject: Made Game::changeRoom() clear the overlaysArchive cache when it's done loading overlays. svn-id: r42072 --- engines/draci/game.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 06e460724f..4dc2668f04 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -242,6 +242,8 @@ void Game::changeRoom(uint16 roomNum) { _vm->_anims->addOverlay(sp, z); } + + _vm->_overlaysArchive->clearCache(); _vm->_screen->getSurface()->markDirty(); } -- cgit v1.2.3 From 4465ecf1233726ce70a27b1d03ac49d222961ede Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 18:19:51 +0000 Subject: Added deconstructor for Animation. Made Animation objects delete their frames when deleteAll() or deleteAnimation() are called. svn-id: r42073 --- engines/draci/animation.cpp | 12 ++++++++++++ engines/draci/animation.h | 1 + 2 files changed, 13 insertions(+) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index c074deb867..94c12d1c51 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -98,11 +98,23 @@ void Animation::deleteAnimation(uint id) { Common::List::iterator it = getAnimation(id); + for(uint i = 0; i < it->_frames.size(); ++i) { + delete it->_frames[i]; + } + _animObjects.erase(it); } void Animation::deleteAll() { + Common::List::iterator it; + + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + for(uint i = 0; i < it->_frames.size(); ++i) { + delete it->_frames[i]; + } + } + _animObjects.clear(); } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 8f4cc8e324..c654155a03 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -45,6 +45,7 @@ class Animation { public: Animation(DraciEngine *vm) : _vm(vm) {}; + ~Animation() { deleteAll(); } void addAnimation(uint id, uint z = 0); void addFrame(uint id, Drawable *frame); -- cgit v1.2.3 From 63d0fdea68f8f43a84a22d7e8a72eef5a862a20a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 19:02:08 +0000 Subject: Added Sprite::getRect() and Text::getRect(). svn-id: r42074 --- engines/draci/sprite.cpp | 10 +++++++++- engines/draci/sprite.h | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index b417afc0ed..4461a743f5 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -152,6 +152,10 @@ void Sprite::draw(Surface *surface, bool markDirty) const { } } +Common::Rect Sprite::getRect() const { + return Common::Rect(_x, _y, _x + _width, _y + _height); +} + Text::Text(const Common::String &str, Font *font, byte fontColour, uint x, uint y, uint z, uint spacing) { uint len = str.size(); @@ -201,7 +205,11 @@ void Text::setSpacing(uint spacing) { void Text::draw(Surface *surface, bool markDirty) const { _font->setColour(_colour); _font->drawString(surface, _text, _length, _x, _y, _spacing); -} +} + +Common::Rect Text::getRect() const { + return Common::Rect(_x, _y, _x + _width, _y + _height); +} } // End of namespace Draci diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 191d20ca9e..6af4e8ca1e 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -50,6 +50,8 @@ public: virtual void setX(uint x) { _x = x; } virtual void setY(uint y) { _y = y; } virtual void setZ(uint z) { _z = z; } + + virtual Common::Rect getRect() const = 0; private: uint16 _width; //!< Width of the sprite @@ -88,6 +90,8 @@ public: void setMirrorOn(); void setMirrorOff(); + + virtual Common::Rect getRect() const; const byte *getBuffer() const { return _data; } private: @@ -108,6 +112,8 @@ public: void draw(Surface *surface, bool markDirty = true) const; + virtual Common::Rect getRect() const; + private: byte *_text; uint _length; -- cgit v1.2.3 From a4e6464a63fdf109df39c3c3106e1b3cd84bf5a7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 3 Jul 2009 19:05:58 +0000 Subject: Added support for playing and stopping animations. svn-id: r42075 --- engines/draci/animation.cpp | 28 ++++++++++++++++++++++++---- engines/draci/animation.h | 11 +++++++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 94c12d1c51..5e6578de57 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -28,16 +28,31 @@ namespace Draci { -void Animation::addAnimation(uint id, uint z) { +void Animation::addAnimation(uint id, uint z, bool playing) { AnimObj *obj = new AnimObj(); obj->_id = id; obj->_z = z; obj->_currentFrame = 0; + obj->_playing = playing; insertAnimation(*obj); } +void Animation::play(uint id) { + + AnimObj &obj = *getAnimation(id); + + obj._playing = true; +} + +void Animation::stop(uint id) { + + AnimObj &obj = *getAnimation(id); + + obj._playing = false; +} + Common::List::iterator Animation::getAnimation(uint id) { Common::List::iterator it; @@ -75,6 +90,7 @@ void Animation::addOverlay(Drawable *overlay, uint z) { obj->_id = kOverlayImage; obj->_z = z; obj->_currentFrame = 0; + obj->_playing = true; obj->_frames.push_back(overlay); insertAnimation(*obj); @@ -85,7 +101,11 @@ void Animation::drawScene(Surface *surf) { Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if(it->_id == kOverlayImage) { + if (!it->_playing) { + continue; + } + + if (it->_id == kOverlayImage) { it->_frames[it->_currentFrame]->draw(surf, false); } else { @@ -98,7 +118,7 @@ void Animation::deleteAnimation(uint id) { Common::List::iterator it = getAnimation(id); - for(uint i = 0; i < it->_frames.size(); ++i) { + for (uint i = 0; i < it->_frames.size(); ++i) { delete it->_frames[i]; } @@ -110,7 +130,7 @@ void Animation::deleteAll() { Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - for(uint i = 0; i < it->_frames.size(); ++i) { + for (uint i = 0; i < it->_frames.size(); ++i) { delete it->_frames[i]; } } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index c654155a03..c69947ea28 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -38,6 +38,7 @@ struct AnimObj { uint _id; uint _currentFrame; uint _z; + bool _playing; Common::Array _frames; }; @@ -47,12 +48,18 @@ public: Animation(DraciEngine *vm) : _vm(vm) {}; ~Animation() { deleteAll(); } - void addAnimation(uint id, uint z = 0); + void addAnimation(uint id, uint z, bool playing = false); void addFrame(uint id, Drawable *frame); - void addOverlay(Drawable *overlay, uint z = 0); + void addOverlay(Drawable *overlay, uint z); + + void play(uint id); + void stop(uint id); + void deleteAnimation(uint id); void deleteAll(); + void drawScene(Surface *surf); + Common::List::iterator getAnimation(uint id); private: -- cgit v1.2.3 From 885ce59ce8b02046e165598c40facccceda48927 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 14:48:36 +0000 Subject: Restructured Script so I can start adding callbacks to GPL commands (added DraciEngine * member to Script, added Script::setupCommandList() which initialises the command list array, added Script::dummy() callback for the Load command for testing). svn-id: r42090 --- engines/draci/draci.cpp | 2 +- engines/draci/script.cpp | 169 +++++++++++++++++++++++++++-------------------- engines/draci/script.h | 28 ++++++-- 3 files changed, 122 insertions(+), 77 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 79d38134b9..abec21d29b 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -87,7 +87,7 @@ int DraciEngine::init() { _font = new Font(); _anims = new Animation(this); _mouse = new Mouse(this); - _script = new Script(); + _script = new Script(this); _game = new Game(this); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index ce38960265..f4041157d8 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -26,73 +26,78 @@ #include "common/debug.h" #include "common/stream.h" #include "common/stack.h" +#include "common/queue.h" -#include "draci/script.h" #include "draci/draci.h" +#include "draci/script.h" +#include "draci/game.h" namespace Draci { // FIXME: Change parameter types to names once I figure out what they are exactly -/** A table of all the commands the game player uses */ -GPL2Command gplCommands[] = { - { 0, 0, "gplend", 0, { 0 } }, - { 0, 1, "exit", 0, { 0 } }, - { 1, 1, "goto", 1, { 3 } }, - { 2, 1, "Let", 2, { 3, 4 } }, - { 3, 1, "if", 2, { 4, 3 } }, - { 4, 1, "Start", 2, { 3, 2 } }, - { 5, 1, "Load", 2, { 3, 2 } }, - { 5, 2, "StartPlay", 2, { 3, 2 } }, - { 5, 3, "JustTalk", 0, { 0 } }, - { 5, 4, "JustStay", 0, { 0 } }, - { 6, 1, "Talk", 2, { 3, 2 } }, - { 7, 1, "ObjStat", 2, { 3, 3 } }, - { 7, 2, "ObjStat_On", 2, { 3, 3 } }, - { 8, 1, "IcoStat", 2, { 3, 3 } }, - { 9, 1, "Dialogue", 1, { 2 } }, - { 9, 2, "ExitDialogue", 0, { 0 } }, - { 9, 3, "ResetDialogue", 0, { 0 } }, - { 9, 4, "ResetDialogueFrom", 0, { 0 } }, - { 9, 5, "ResetBlock", 1, { 3 } }, - { 10, 1, "WalkOn", 3, { 1, 1, 3 } }, - { 10, 2, "StayOn", 3, { 1, 1, 3 } }, - { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 } }, - { 11, 1, "LoadPalette", 1, { 2 } }, - { 12, 1, "SetPalette", 0, { 0 } }, - { 12, 2, "BlackPalette", 0, { 0 } }, - { 13, 1, "FadePalette", 3, { 1, 1, 1 } }, - { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 } }, - { 14, 1, "NewRoom", 2, { 3, 1 } }, - { 15, 1, "ExecInit", 1, { 3 } }, - { 15, 2, "ExecLook", 1, { 3 } }, - { 15, 3, "ExecUse", 1, { 3 } }, - { 16, 1, "RepaintInventory", 0, { 0 } }, - { 16, 2, "ExitInventory", 0, { 0 } }, - { 17, 1, "ExitMap", 0, { 0 } }, - { 18, 1, "LoadMusic", 1, { 2 } }, - { 18, 2, "StartMusic", 0, { 0 } }, - { 18, 3, "StopMusic", 0, { 0 } }, - { 18, 4, "FadeOutMusic", 1, { 1 } }, - { 18, 5, "FadeInMusic", 1, { 1 } }, - { 19, 1, "Mark", 0, { 0 } }, - { 19, 2, "Release", 0, { 0 } }, - { 20, 1, "Play", 0, { 0 } }, - { 21, 1, "LoadMap", 1, { 2 } }, - { 21, 2, "RoomMap", 0, { 0 } }, - { 22, 1, "DisableQuickHero", 0, { 0 } }, - { 22, 2, "EnableQuickHero", 0, { 0 } }, - { 23, 1, "DisableSpeedText", 0, { 0 } }, - { 23, 2, "EnableSpeedText", 0, { 0 } }, - { 24, 1, "QuitGame", 0, { 0 } }, - { 25, 1, "PushNewRoom", 0, { 0 } }, - { 25, 2, "PopNewRoom", 0, { 0 } }, - { 26, 1, "ShowCheat", 0, { 0 } }, - { 26, 2, "HideCheat", 0, { 0 } }, - { 26, 3, "ClearCheat", 1, { 1 } }, - { 27, 1, "FeedPassword", 3, { 1, 1, 1 } } -}; - +void Script::setupCommandList() { + /** A table of all the commands the game player uses */ + static const GPL2Command gplCommands[] = { + { 0, 0, "gplend", 0, { 0 }, NULL }, + { 0, 1, "exit", 0, { 0 }, NULL }, + { 1, 1, "goto", 1, { 3 }, NULL }, + { 2, 1, "Let", 2, { 3, 4 }, NULL }, + { 3, 1, "if", 2, { 4, 3 }, NULL }, + { 4, 1, "Start", 2, { 3, 2 }, NULL }, + { 5, 1, "Load", 2, { 3, 2 }, &Script::dummy }, + { 5, 2, "StartPlay", 2, { 3, 2 }, NULL }, + { 5, 3, "JustTalk", 0, { 0 }, NULL }, + { 5, 4, "JustStay", 0, { 0 }, NULL }, + { 6, 1, "Talk", 2, { 3, 2 }, NULL }, + { 7, 1, "ObjStat", 2, { 3, 3 }, NULL }, + { 7, 2, "ObjStat_On", 2, { 3, 3 }, NULL }, + { 8, 1, "IcoStat", 2, { 3, 3 }, NULL }, + { 9, 1, "Dialogue", 1, { 2 }, NULL }, + { 9, 2, "ExitDialogue", 0, { 0 }, NULL }, + { 9, 3, "ResetDialogue", 0, { 0 }, NULL }, + { 9, 4, "ResetDialogueFrom", 0, { 0 }, NULL }, + { 9, 5, "ResetBlock", 1, { 3 }, NULL }, + { 10, 1, "WalkOn", 3, { 1, 1, 3 }, NULL }, + { 10, 2, "StayOn", 3, { 1, 1, 3 }, NULL }, + { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, NULL }, + { 11, 1, "LoadPalette", 1, { 2 }, NULL }, + { 12, 1, "SetPalette", 0, { 0 }, NULL }, + { 12, 2, "BlackPalette", 0, { 0 }, NULL }, + { 13, 1, "FadePalette", 3, { 1, 1, 1 }, NULL }, + { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 }, NULL }, + { 14, 1, "NewRoom", 2, { 3, 1 }, NULL }, + { 15, 1, "ExecInit", 1, { 3 }, NULL }, + { 15, 2, "ExecLook", 1, { 3 }, NULL }, + { 15, 3, "ExecUse", 1, { 3 }, NULL }, + { 16, 1, "RepaintInventory", 0, { 0 }, NULL }, + { 16, 2, "ExitInventory", 0, { 0 }, NULL }, + { 17, 1, "ExitMap", 0, { 0 }, NULL }, + { 18, 1, "LoadMusic", 1, { 2 }, NULL }, + { 18, 2, "StartMusic", 0, { 0 }, NULL }, + { 18, 3, "StopMusic", 0, { 0 }, NULL }, + { 18, 4, "FadeOutMusic", 1, { 1 }, NULL }, + { 18, 5, "FadeInMusic", 1, { 1 }, NULL }, + { 19, 1, "Mark", 0, { 0 }, NULL }, + { 19, 2, "Release", 0, { 0 }, NULL }, + { 20, 1, "Play", 0, { 0 }, NULL }, + { 21, 1, "LoadMap", 1, { 2 }, NULL }, + { 21, 2, "RoomMap", 0, { 0 }, NULL }, + { 22, 1, "DisableQuickHero", 0, { 0 }, NULL }, + { 22, 2, "EnableQuickHero", 0, { 0 }, NULL }, + { 23, 1, "DisableSpeedText", 0, { 0 }, NULL }, + { 23, 2, "EnableSpeedText", 0, { 0 }, NULL }, + { 24, 1, "QuitGame", 0, { 0 }, NULL }, + { 25, 1, "PushNewRoom", 0, { 0 }, NULL }, + { 25, 2, "PopNewRoom", 0, { 0 }, NULL }, + { 26, 1, "ShowCheat", 0, { 0 }, NULL }, + { 26, 2, "HideCheat", 0, { 0 }, NULL }, + { 26, 3, "ClearCheat", 1, { 1 }, NULL }, + { 27, 1, "FeedPassword", 3, { 1, 1, 1 }, NULL } + }; + + _commandList = gplCommands; +} /** Operators used by the mathematical evaluator */ Common::String operators[] = { "oper_and", @@ -132,8 +137,6 @@ Common::String functions[] = { "F_Cheat" }; -const unsigned int kNumCommands = sizeof gplCommands / sizeof gplCommands[0]; - /** Type of mathematical object */ enum mathExpressionObject { kMathEnd, @@ -143,6 +146,12 @@ enum mathExpressionObject { kMathVariable }; +void Script::dummy(Common::Queue ¶ms) { + + debug(1, "- %d", params.pop()); + debug(1, "- %d", params.pop()); +} + // FIXME: The evaluator is now complete but I still need to implement callbacks /** @@ -150,7 +159,7 @@ enum mathExpressionObject { * @param reader Stream reader set to the beginning of the expression */ -void Script::handleMathExpression(Common::MemoryReadStream &reader) { +int Script::handleMathExpression(Common::MemoryReadStream &reader) { Common::Stack stk; mathExpressionObject obj; @@ -211,7 +220,7 @@ void Script::handleMathExpression(Common::MemoryReadStream &reader) { obj = (mathExpressionObject) reader.readUint16LE(); } - return; + return stk.pop(); } /** @@ -223,7 +232,7 @@ void Script::handleMathExpression(Common::MemoryReadStream &reader) { * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command * struct representing the command. */ -GPL2Command *Script::findCommand(byte num, byte subnum) { +const GPL2Command *Script::findCommand(byte num, byte subnum) { unsigned int i = 0; while (1) { @@ -233,9 +242,9 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { } // Return found command - if (gplCommands[i]._number == num && - gplCommands[i]._subNumber == subnum) { - return &gplCommands[i]; + if (_commandList[i]._number == num && + _commandList[i]._subNumber == subnum) { + return &_commandList[i]; } ++i; @@ -276,7 +285,12 @@ GPL2Command *Script::findCommand(byte num, byte subnum) { */ int Script::run(GPL2Program program, uint16 offset) { + + // Stream reader for the whole program Common::MemoryReadStream reader(program._bytecode, program._length); + + // Parameter queue that is passed to each command + Common::Queue params; // Offset is given as number of 16-bit integers so we need to convert // it to a number of bytes @@ -286,7 +300,7 @@ int Script::run(GPL2Program program, uint16 offset) { // Seek to the requested part of the program reader.seek(offset); - GPL2Command *cmd; + const GPL2Command *cmd; do { // read in command pair uint16 cmdpair = reader.readUint16BE(); @@ -298,17 +312,20 @@ int Script::run(GPL2Program program, uint16 offset) { byte subnum = cmdpair & 0xFF; if ((cmd = findCommand(num, subnum))) { + int tmp; // Print command name debugC(2, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); - for (uint16 i = 0; i < cmd->_numParams; ++i) { + for (int i = 0; i < cmd->_numParams; ++i) { if (cmd->_paramTypes[i] == 4) { debugC(3, kDraciBytecodeDebugLevel, "\t"); - handleMathExpression(reader); + params.push(handleMathExpression(reader)); } else { - debugC(3, kDraciBytecodeDebugLevel, "\t%hu", reader.readUint16LE()); + tmp = reader.readUint16LE(); + params.push(tmp); + debugC(3, kDraciBytecodeDebugLevel, "\t%hu", tmp); } } } @@ -316,6 +333,14 @@ int Script::run(GPL2Program program, uint16 offset) { debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", num, subnum); } + + GPLHandler handler = cmd->_handler; + + if (handler != NULL) { + // Call the handler for the current command + (this->*(cmd->_handler))(params); + } + } while (cmd->_name != "gplend"); return 0; diff --git a/engines/draci/script.h b/engines/draci/script.h index ac994f1d27..c4d9e75100 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -28,13 +28,21 @@ #include "common/str.h" #include "common/stream.h" +#include "common/queue.h" namespace Draci { /** The maximum number of parameters for a GPL command */ const int kMaxParams = 3; -// FIXME: Add function handlers +class DraciEngine; +class Script; + +enum { + kNumCommands = 55 +}; + +typedef void (Script::* GPLHandler)(Common::Queue &); /** * Represents a single command in the GPL scripting language bytecode. @@ -48,6 +56,7 @@ struct GPL2Command { Common::String _name; uint16 _numParams; int _paramTypes[kMaxParams]; + GPLHandler _handler; }; /** @@ -65,11 +74,22 @@ struct GPL2Program { class Script { public: + Script(DraciEngine *vm) : _vm(vm) { setupCommandList(); }; + int run(GPL2Program program, uint16 offset); - + private: - GPL2Command *findCommand(byte num, byte subnum); - void handleMathExpression(Common::MemoryReadStream &reader); + + /** List of all GPL commands. Initialised in the constructor. */ + const GPL2Command *_commandList; + + void dummy(Common::Queue ¶ms); + + void setupCommandList(); + const GPL2Command *findCommand(byte num, byte subnum); + int handleMathExpression(Common::MemoryReadStream &reader); + + DraciEngine *_vm; }; -- cgit v1.2.3 From b1d6377aa1c3216588600a3e51d181eb249d0a69 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 14:54:22 +0000 Subject: Added _animationsArchive member to DraciEngine. svn-id: r42091 --- engines/draci/draci.cpp | 2 ++ engines/draci/draci.h | 1 + 2 files changed, 3 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index abec21d29b..429db7e62d 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -49,6 +49,7 @@ const Common::String palettePath("PALETY.DFW"); const Common::String spritesPath("OBR_AN.DFW"); const Common::String overlaysPath("OBR_MAS.DFW"); const Common::String roomsPath("MIST.DFW"); +const Common::String animationsPath("ANIM.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { @@ -82,6 +83,7 @@ int DraciEngine::init() { _paletteArchive = new BArchive(palettePath); _roomsArchive = new BArchive(roomsPath); _overlaysArchive = new BArchive(overlaysPath); + _animationsArchive = new BArchive(animationsPath); _screen = new Screen(this); _font = new Font(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 9b4444277a..4a8c3d455a 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -63,6 +63,7 @@ public: BArchive *_paletteArchive; BArchive *_roomsArchive; BArchive *_overlaysArchive; + BArchive *_animationsArchive; private: Common::RandomSource _rnd; -- cgit v1.2.3 From 0888e8a6da350c88c8e69f02963203772c7ea33b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 15:21:12 +0000 Subject: * Split code from Game::changeRoom() into Game::loadRoom() and game::loadOverlays(). Game::changeRoom() now calls them instead. * Added Game::loadAnimation() * The engine now stores "real" indexes (zero-based) instead of Pascal's because the previous approach was messy. svn-id: r42092 --- engines/draci/game.cpp | 177 ++++++++++++++++++++++++++++++------------------- engines/draci/game.h | 12 +++- 2 files changed, 119 insertions(+), 70 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 4dc2668f04..05cc0e6636 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -74,8 +74,8 @@ Game::Game(DraciEngine *vm) : _vm(vm) { Common::MemoryReadStream gameData(file->_data, file->_length); _info = new GameInfo(); - _info->_currentRoom = gameData.readByte(); - _info->_mapRoom = gameData.readByte(); + _info->_currentRoom = gameData.readByte() - 1; + _info->_mapRoom = gameData.readByte() - 1; _info->_numObjects = gameData.readUint16LE(); _info->_numIcons = gameData.readUint16LE(); _info->_numVariables = gameData.readByte(); @@ -132,18 +132,90 @@ Game::Game(DraciEngine *vm) : _vm(vm) { assert(numVariables == _info->_numVariables); assert(numObjects == _info->_numObjects); - loadObject(1); - _vm->_script->run(getObject(1)->_program, getObject(1)->_init); + loadObject(0); + + _vm->_script->run(getObject(0)->_program, getObject(0)->_init); - changeRoom(1); + changeRoom(0); } -void Game::loadObject(uint16 objNum) { - BAFile *file; +void Game::loadRoom(uint roomNum) { + + BAFile *f; + f = _vm->_roomsArchive->getFile(roomNum * 4); + Common::MemoryReadStream roomReader(f->_data, f->_length); + + roomReader.readUint32LE(); // Pointer to room program, not used + roomReader.readUint16LE(); // Program length, not used + roomReader.readUint32LE(); // Pointer to room title, not used + + _currentRoom._music = roomReader.readByte(); + _currentRoom._map = roomReader.readByte(); + _currentRoom._palette = roomReader.readByte() - 1; + _currentRoom._numMasks = roomReader.readUint16LE(); + _currentRoom._init = roomReader.readUint16LE(); + _currentRoom._look = roomReader.readUint16LE(); + _currentRoom._use = roomReader.readUint16LE(); + _currentRoom._canUse = roomReader.readUint16LE(); + _currentRoom._imInit = roomReader.readByte(); + _currentRoom._imLook = roomReader.readByte(); + _currentRoom._imUse = roomReader.readByte(); + _currentRoom._mouseOn = roomReader.readByte(); + _currentRoom._heroOn = roomReader.readByte(); + roomReader.read(&_currentRoom._pers0, 12); + roomReader.read(&_currentRoom._persStep, 12); + _currentRoom._escRoom = roomReader.readByte() - 1; + _currentRoom._numGates = roomReader.readByte(); + + f = _vm->_paletteArchive->getFile(_currentRoom._palette); + _vm->_screen->setPalette(f->_data, 0, kNumColours); +} + +int Game::loadAnimation(uint animNum) { + + BAFile *animFile = _vm->_animationsArchive->getFile(animNum); + Common::MemoryReadStream animationReader(animFile->_data, animFile->_length); + + int numFrames = animationReader.readByte(); + + // FIXME: handle these properly + animationReader.readByte(); // Memory logic field, not used + animationReader.readByte(); // Disable erasing field, not used + animationReader.readByte(); // Cyclic field, not used + animationReader.readByte(); // Relative field, not used + + _vm->_anims->addAnimation(animNum, 254, true); - // Convert to real index (indexes begin with 1 in the data files) - objNum -= 1; + for (uint i = 0; i < numFrames; ++i) { + uint spriteNum = animationReader.readUint16LE() - 1; + int x = animationReader.readSint16LE(); + int y = animationReader.readSint16LE(); + uint zoomX = animationReader.readUint16LE(); + uint zoomY = animationReader.readUint16LE(); + byte mirror = animationReader.readByte(); + uint sample = animationReader.readUint16LE(); + uint freq = animationReader.readUint16LE(); + uint delay = animationReader.readUint16LE(); + + // TODO: implement Animation::setDelay() + //_vm->_anims->setDelay(animNum, delay*10); + + BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); + + Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, 1, true); + + if (mirror) + sp->setMirrorOn(); + + _vm->_anims->addFrame(animNum, sp); + } + + return animNum; +} +void Game::loadObject(uint objNum) { + BAFile *file; + file = _vm->_objectsArchive->getFile(objNum * 3); Common::MemoryReadStream objReader(file->_data, file->_length); @@ -182,70 +254,41 @@ void Game::loadObject(uint16 objNum) { memcpy(obj->_program._bytecode, file->_data, file->_length); } -GameObject *Game::getObject(uint16 objNum) { - - // Convert to real index (indexes begin with 1 in the data files) - objNum -= 1; - +GameObject *Game::getObject(uint objNum) { return _objects + objNum; } -void Game::changeRoom(uint16 roomNum) { - - // Convert to real index (indexes begin with 1 in the data files) - roomNum -= 1; - - BAFile *f; - f = _vm->_roomsArchive->getFile(roomNum * 4); - Common::MemoryReadStream roomReader(f->_data, f->_length); - - roomReader.readUint32LE(); // Pointer to room program, not used - roomReader.readUint16LE(); // Program length, not used - roomReader.readUint32LE(); // Pointer to room title, not used - - _currentRoom._music = roomReader.readByte(); - _currentRoom._map = roomReader.readByte(); - _currentRoom._palette = roomReader.readByte(); - _currentRoom._numMasks = roomReader.readUint16LE(); - _currentRoom._init = roomReader.readUint16LE(); - _currentRoom._look = roomReader.readUint16LE(); - _currentRoom._use = roomReader.readUint16LE(); - _currentRoom._canUse = roomReader.readUint16LE(); - _currentRoom._imInit = roomReader.readByte(); - _currentRoom._imLook = roomReader.readByte(); - _currentRoom._imUse = roomReader.readByte(); - _currentRoom._mouseOn = roomReader.readByte(); - _currentRoom._heroOn = roomReader.readByte(); - roomReader.read(&_currentRoom._pers0, 12); - roomReader.read(&_currentRoom._persStep, 12); - _currentRoom._escRoom = roomReader.readByte(); - _currentRoom._numGates = roomReader.readByte(); - - f = _vm->_paletteArchive->getFile(_currentRoom._palette - 1); - _vm->_screen->setPalette(f->_data, 0, kNumColours); - - uint x, y, z, num; - - f = _vm->_roomsArchive->getFile(roomNum * 4 + 2); - Common::MemoryReadStream overlayReader(f->_data, f->_length); - BAFile *overlayFile; - - for (uint i = 0; i < _currentRoom._numMasks; i++) { - - num = overlayReader.readUint16LE(); - x = overlayReader.readUint16LE(); - y = overlayReader.readUint16LE(); - z = overlayReader.readByte(); - - overlayFile = _vm->_overlaysArchive->getFile(num - 1); - Sprite *sp = new Sprite(overlayFile->_data, overlayFile->_length, x, y, z, true); - - _vm->_anims->addOverlay(sp, z); +void Game::loadOverlays() { + uint x, y, z, num; + + BAFile *overlayHeader; + + overlayHeader = _vm->_roomsArchive->getFile(_currentRoom._roomNum * 4 + 2); + Common::MemoryReadStream overlayReader(overlayHeader->_data, overlayHeader->_length); + BAFile *overlayFile; + + for (uint i = 0; i < _currentRoom._numMasks; i++) { + + num = overlayReader.readUint16LE() - 1; + x = overlayReader.readUint16LE(); + y = overlayReader.readUint16LE(); + z = overlayReader.readByte(); + + overlayFile = _vm->_overlaysArchive->getFile(num); + Sprite *sp = new Sprite(overlayFile->_data, overlayFile->_length, x, y, z, true); + + _vm->_anims->addOverlay(sp, z); } - + _vm->_overlaysArchive->clearCache(); - _vm->_screen->getSurface()->markDirty(); + _vm->_screen->getSurface()->markDirty(); +} + +void Game::changeRoom(uint roomNum) { + _currentRoom._roomNum = roomNum; + loadRoom(roomNum); + loadOverlays(); } Game::~Game() { diff --git a/engines/draci/game.h b/engines/draci/game.h index b04ad785e3..1de27d40d0 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -80,6 +80,7 @@ struct Person { }; struct Room { + byte _roomNum; byte _music; byte _map; byte _palette; @@ -109,9 +110,14 @@ private: GameObject *_objects; Room _currentRoom; - void loadObject(uint16 numObj); - GameObject *getObject(uint16 objNum); - void changeRoom(uint16 roomNum); + void loadRoom(uint roomNum); + int loadAnimation(uint animNum); + void loadOverlays(); + void loadObject(uint numObj); + + GameObject *getObject(uint objNum); + + void changeRoom(uint roomNum); }; } // End of namespace Draci -- cgit v1.2.3 From a06509f3c255b89c322975fcfcc620735789122b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 18:29:01 +0000 Subject: * Removed tracking of Z coordinates in Drawable since it's not used * Made columnwise parameter mandatory * Made Sprite coordinates signed (the engine sometimes uses negative coordinates) * Prevented overflow when drawing sprites in some cases svn-id: r42100 --- engines/draci/sprite.cpp | 39 ++++++++++++++++++++++++--------------- engines/draci/sprite.h | 22 ++++++++-------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 4461a743f5..39a33438ae 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -53,14 +53,15 @@ static void transformToRows(byte *img, uint16 width, uint16 height) { /** * Constructor for loading sprites from a raw data buffer, one byte per pixel. - */ -Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint x, uint y, - uint z, bool columnwise) : _data(NULL) { + */ +Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, int x, int y, + bool columnwise) : _data(NULL) { + _width = width; _height = height; _x = x; _y = y; - _z = z; + _mirror = false; _data = new byte[width * height]; @@ -73,22 +74,22 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, uint x, uint y, } } - /** * Constructor for loading sprites from a sprite-formatted buffer, one byte per * pixel. */ -Sprite::Sprite(byte *sprite_data, uint16 length, uint x, uint y, uint z, - bool columnwise) : _data(NULL) { +Sprite::Sprite(byte *sprite_data, uint16 length, int x, int y, bool columnwise) + : _data(NULL) { + _x = x; _y = y; - _z = z; + _mirror = false; Common::MemoryReadStream reader(sprite_data, length); - _width = reader.readUint16LE(); - _height = reader.readUint16LE(); + _width = reader.readSint16LE(); + _height = reader.readSint16LE(); _data = new byte[_width * _height]; @@ -122,19 +123,27 @@ void Sprite::draw(Surface *surface, bool markDirty) const { byte *dst = (byte *)surface->getBasePtr(_x, _y); byte *src = _data; + // Determine how many pixels to draw horizontally (to prevent overflow) + int xSpaceLeft = surface->w - _x - 1; + int xPixelsToDraw = (_width < xSpaceLeft) ? _width : xSpaceLeft; + + // Determine how many pixels to draw vertically + int ySpaceLeft = surface->h - _y - 1; + int yPixelsToDraw = (_height < ySpaceLeft) ? _height : ySpaceLeft; + // Blit the sprite to the surface - for (int i = 0; i < _height; ++i) { + for (int i = 0; i < yPixelsToDraw; ++i) { // Draw the sprite mirrored if the _mirror flag is set if (_mirror) { - for(int j = _width - 1; j >= 0; --j, ++src) { + for (int j = xPixelsToDraw - 1; j >= 0; --j, ++src) { // Don't blit if the pixel is transparent on the target surface if (*src != surface->getTransparentColour()) dst[j] = *src; } } else { - for(int j = 0; j < _width; ++j, ++src) { + for (int j = 0; j < xPixelsToDraw; ++j, ++src) { // Don't blit if the pixel is transparent on the target surface if (*src != surface->getTransparentColour()) @@ -142,6 +151,7 @@ void Sprite::draw(Surface *surface, bool markDirty) const { } } + src += _width - xPixelsToDraw; dst += surface->pitch; } @@ -157,13 +167,12 @@ Common::Rect Sprite::getRect() const { } Text::Text(const Common::String &str, Font *font, byte fontColour, - uint x, uint y, uint z, uint spacing) { + int x, int y, uint spacing) { uint len = str.size(); _length = len; _x = x; _y = y; - _z = z; _text = new byte[len]; memcpy(_text, str.c_str(), len); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 6af4e8ca1e..3e881914ca 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -43,21 +43,18 @@ public: virtual uint16 getWidth() { return _width; } virtual uint16 getHeight() { return _height; } - virtual uint getX() { return _x; } - virtual uint getY() { return _y; } - virtual uint getZ() { return _z; } + virtual int getX() { return _x; } + virtual int getY() { return _y; } - virtual void setX(uint x) { _x = x; } - virtual void setY(uint y) { _y = y; } - virtual void setZ(uint z) { _z = z; } + virtual void setX(int x) { _x = x; } + virtual void setY(int y) { _y = y; } virtual Common::Rect getRect() const = 0; private: uint16 _width; //!< Width of the sprite uint16 _height; //!< Height of the sprite - uint _x, _y; //!< Sprite coordinates - uint _z; //!< Sprite depth position + int _x, _y; //!< Sprite coordinates }; /** @@ -76,12 +73,10 @@ private: class Sprite : public Drawable { public: - Sprite(byte *raw_data, uint16 width, uint16 height, uint x, uint y, - uint z, bool columnwise = true); + Sprite(byte *raw_data, uint16 width, uint16 height, int x, int y, bool columnwise); - Sprite(byte *sprite_data, uint16 length, uint x, uint y, - uint z, bool columnwise = true); + Sprite(byte *sprite_data, uint16 length, int x, int y, bool columnwise); ~Sprite(); @@ -90,7 +85,6 @@ public: void setMirrorOn(); void setMirrorOff(); - virtual Common::Rect getRect() const; const byte *getBuffer() const { return _data; } @@ -103,7 +97,7 @@ class Text : public Drawable { public: Text(const Common::String &str, Font *font, byte fontColour, - uint x, uint y, uint z, uint spacing = 0); + int x, int y, uint spacing = 0); ~Text(); void setText(const Common::String &str); -- cgit v1.2.3 From b96b4344468f1ba4214574bc1854e47f62501e76 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 18:35:08 +0000 Subject: * Added Game::init() and moved some functionality from Game::Game to it (loading objects, changing rooms) * Made Game::load*(), Game::getObject() and Game::changeRoom() methods public * Stopped specifying Z coordinate when creating some Sprites (which I forgot in my previous commit) svn-id: r42101 --- engines/draci/draci.cpp | 4 ++-- engines/draci/game.cpp | 6 ++++-- engines/draci/game.h | 20 +++++++++++--------- engines/draci/mouse.cpp | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 429db7e62d..cd9c3eeaed 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -92,8 +92,6 @@ int DraciEngine::init() { _script = new Script(this); _game = new Game(this); - - // Load default font _font->setFont(kFontBig); @@ -139,6 +137,8 @@ int DraciEngine::go() { debugC(2, kDraciGeneralDebugLevel, "Running graphics/animation test..."); + _game->init(); + _mouse->setCursorType(kNormalCursor); _mouse->cursorOn(); diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 05cc0e6636..be29cf9fda 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -131,7 +131,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { assert(numPersons == _info->_numPersons); assert(numVariables == _info->_numVariables); assert(numObjects == _info->_numObjects); +} +void Game::init() { loadObject(0); _vm->_script->run(getObject(0)->_program, getObject(0)->_init); @@ -202,7 +204,7 @@ int Game::loadAnimation(uint animNum) { BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); - Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, 1, true); + Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, true); if (mirror) sp->setMirrorOn(); @@ -275,7 +277,7 @@ void Game::loadOverlays() { z = overlayReader.readByte(); overlayFile = _vm->_overlaysArchive->getFile(num); - Sprite *sp = new Sprite(overlayFile->_data, overlayFile->_length, x, y, z, true); + Sprite *sp = new Sprite(overlayFile->_data, overlayFile->_length, x, y, true); _vm->_anims->addOverlay(sp, z); } diff --git a/engines/draci/game.h b/engines/draci/game.h index 1de27d40d0..8f02dd579a 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -99,6 +99,17 @@ public: Game(DraciEngine *vm); ~Game(); + void init(); + + void changeRoom(uint roomNum); + + void loadRoom(uint roomNum); + int loadAnimation(uint animNum); + void loadOverlays(); + void loadObject(uint numObj); + + GameObject *getObject(uint objNum); + private: DraciEngine *_vm; @@ -109,15 +120,6 @@ private: byte *_itemStatus; GameObject *_objects; Room _currentRoom; - - void loadRoom(uint roomNum); - int loadAnimation(uint animNum); - void loadOverlays(); - void loadObject(uint numObj); - - GameObject *getObject(uint objNum); - - void changeRoom(uint roomNum); }; } // End of namespace Draci diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index b4c0aea542..b342487209 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -96,7 +96,7 @@ void Mouse::setCursorType(CursorType cur) { return; } - Sprite sp(f->_data, f->_length, 0, 0, 0); + Sprite sp(f->_data, f->_length, 0, 0, true); CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); CursorMan.replaceCursor(sp.getBuffer(), sp.getWidth(), sp.getHeight(), sp.getWidth() / 2, sp.getHeight() / 2); -- cgit v1.2.3 From fdf9eb84d6f9c59527a06a2571ee80b467dffdd3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 18:36:45 +0000 Subject: Implemented handler for the Load instruction. Removed Script::dummy(). svn-id: r42102 --- engines/draci/script.cpp | 13 +++++++------ engines/draci/script.h | 3 +-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index f4041157d8..00d68676e4 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -45,7 +45,7 @@ void Script::setupCommandList() { { 2, 1, "Let", 2, { 3, 4 }, NULL }, { 3, 1, "if", 2, { 4, 3 }, NULL }, { 4, 1, "Start", 2, { 3, 2 }, NULL }, - { 5, 1, "Load", 2, { 3, 2 }, &Script::dummy }, + { 5, 1, "Load", 2, { 3, 2 }, &Script::load }, { 5, 2, "StartPlay", 2, { 3, 2 }, NULL }, { 5, 3, "JustTalk", 0, { 0 }, NULL }, { 5, 4, "JustStay", 0, { 0 }, NULL }, @@ -146,13 +146,14 @@ enum mathExpressionObject { kMathVariable }; -void Script::dummy(Common::Queue ¶ms) { +void Script::load(Common::Queue ¶ms) { + int objID = params.pop() - 1; + int animID = params.pop() - 1; - debug(1, "- %d", params.pop()); - debug(1, "- %d", params.pop()); -} + GameObject *obj = _vm->_game->getObject(objID); -// FIXME: The evaluator is now complete but I still need to implement callbacks + obj->_seqTab[animID - obj->_idxSeq] = _vm->_game->loadAnimation(animID); +} /** * @brief Evaluates mathematical expressions diff --git a/engines/draci/script.h b/engines/draci/script.h index c4d9e75100..5d8340858c 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -83,14 +83,13 @@ private: /** List of all GPL commands. Initialised in the constructor. */ const GPL2Command *_commandList; - void dummy(Common::Queue ¶ms); + void load(Common::Queue ¶ms); void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); int handleMathExpression(Common::MemoryReadStream &reader); DraciEngine *_vm; - }; } -- cgit v1.2.3 From 960740fe83ee1d1e4cea33f732df4b698d22c479 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 4 Jul 2009 23:05:13 +0000 Subject: Rewrote Sprite::draw() to draw overflowing sprites correctly. Stopped playing animations as soon as they're loaded from Game::loadAnimation(). svn-id: r42111 --- engines/draci/game.cpp | 5 +++- engines/draci/sprite.cpp | 61 ++++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index be29cf9fda..b24d62d36d 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -138,6 +138,9 @@ void Game::init() { _vm->_script->run(getObject(0)->_program, getObject(0)->_init); + // HACK: this is only for testing + _vm->_anims->play(getObject(0)->_seqTab[9]); + changeRoom(0); } @@ -186,7 +189,7 @@ int Game::loadAnimation(uint animNum) { animationReader.readByte(); // Cyclic field, not used animationReader.readByte(); // Relative field, not used - _vm->_anims->addAnimation(animNum, 254, true); + _vm->_anims->addAnimation(animNum, 254, false); for (uint i = 0; i < numFrames; ++i) { uint spriteNum = animationReader.readUint16LE() - 1; diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 39a33438ae..bd442e5ee8 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -115,50 +115,55 @@ void Sprite::setMirrorOff() { /** * @brief Draws the sprite to a Draci::Surface - * @param surface Pointer to a Draci::Surface + * @param surface Pointer to a Draci::Surface * * Draws the sprite to a Draci::Surface and marks its rectangle on the surface as dirty. + * It is safe to call it for sprites that would overflow the surface. */ void Sprite::draw(Surface *surface, bool markDirty) const { - byte *dst = (byte *)surface->getBasePtr(_x, _y); - byte *src = _data; - - // Determine how many pixels to draw horizontally (to prevent overflow) - int xSpaceLeft = surface->w - _x - 1; - int xPixelsToDraw = (_width < xSpaceLeft) ? _width : xSpaceLeft; - // Determine how many pixels to draw vertically - int ySpaceLeft = surface->h - _y - 1; - int yPixelsToDraw = (_height < ySpaceLeft) ? _height : ySpaceLeft; + Common::Rect sourceRect(0, 0, _width, _height); + Common::Rect destRect(_x, _y, _x + _width, _y + _height); + Common::Rect surfaceRect(0, 0, surface->w, surface->h); + Common::Rect clippedDestRect(destRect); - // Blit the sprite to the surface - for (int i = 0; i < yPixelsToDraw; ++i) { + clippedDestRect.clip(surfaceRect); - // Draw the sprite mirrored if the _mirror flag is set - if (_mirror) { - for (int j = xPixelsToDraw - 1; j >= 0; --j, ++src) { + int adjustLeft = clippedDestRect.left - destRect.left; + int adjustRight = clippedDestRect.right - destRect.right; + int adjustTop = clippedDestRect.top - destRect.top; + int adjustBottom = clippedDestRect.bottom - destRect.bottom; - // Don't blit if the pixel is transparent on the target surface - if (*src != surface->getTransparentColour()) - dst[j] = *src; - } - } else { - for (int j = 0; j < xPixelsToDraw; ++j, ++src) { + sourceRect.left += adjustLeft; + sourceRect.right += adjustRight; + sourceRect.top += adjustTop; + sourceRect.bottom += adjustBottom; + + byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); + byte *src = _data; - // Don't blit if the pixel is transparent on the target surface - if (*src != surface->getTransparentColour()) - dst[j] = *src; - } + // Blit the sprite to the surface + for (int i = sourceRect.top; i < sourceRect.bottom; ++i) { + for (int j = sourceRect.left; j < sourceRect.right; ++j) { + + // Don't blit if the pixel is transparent on the target surface + if (src[i * _width + j] != surface->getTransparentColour()) { + + // Draw the sprite mirrored if the _mirror flag is set + if (_mirror) { + dst[sourceRect.right - j - 1] = src[i * _width + j]; + } else { + dst[j] = src[i * _width + j]; + } + } } - src += _width - xPixelsToDraw; dst += surface->pitch; } // Mark the sprite's rectangle dirty if (markDirty) { - Common::Rect r(_x, _y, _x + _width, _y + _height); - surface->markDirtyRect(r); + surface->markDirtyRect(destRect); } } -- cgit v1.2.3 From 6c3e9f5151fac4906c2fabc2e26ee39bc7043664 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 5 Jul 2009 03:24:46 +0000 Subject: * API change for Animation and AnimObj; AnimObj is now a proper class and each instance handles its own animation. Animation handles adding, fetching and deleting of AnimObjs (probably needs a namechange). * Implemented actual animation (previously only the first frame was display) * Implemented animation starting, stoping, looping * Loaded looping dragon animation as a test svn-id: r42114 --- engines/draci/animation.cpp | 215 +++++++++++++++++++++++++++++++++----------- engines/draci/animation.h | 61 ++++++++++--- engines/draci/game.cpp | 10 ++- 3 files changed, 219 insertions(+), 67 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 5e6578de57..a29281d510 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -28,111 +28,224 @@ namespace Draci { -void Animation::addAnimation(uint id, uint z, bool playing) { +AnimObj::AnimObj(DraciEngine *vm) : _vm(vm) { + _id = kUnused; + _z = 0; + _playing = false; + _looping = false; + _delay = 0; + _tick = _vm->_system->getMillis(); + _currentFrame = 0; +} + +AnimObj::~AnimObj() { + deleteFrames(); +} + +bool AnimObj::isLooping() { + return _looping; +} + +void AnimObj::setLooping(bool looping) { + _looping = looping; +} + +void AnimObj::setDelay(uint delay) { + _delay = delay; +} + +void AnimObj::nextFrame(bool force) { + + // If there's only one or no frames, return + if (getFramesNum() < 2) + return; + + Common::Rect frameRect = _frames[_currentFrame]->getRect(); + + // If we are at the last frame and not looping, stop the animation + // The animation is also restarted to frame zero + if ((_currentFrame == nextFrameNum() - 1) && !_looping) { + _currentFrame = 0; + _playing = false; + return; + } + + if (force || (_tick + _delay <= _vm->_system->getMillis())) { + _vm->_screen->getSurface()->markDirtyRect(frameRect); + _currentFrame = nextFrameNum(); + _tick = _vm->_system->getMillis(); + } + + debugC(6, kDraciAnimationDebugLevel, + "tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d", + _tick, _delay, _tick + _delay, _vm->_system->getMillis(), _currentFrame, _frames.size()); +} + +uint AnimObj::nextFrameNum() { + + if ((_currentFrame == getFramesNum() - 1) && _looping) + return 0; + else + return _currentFrame + 1; +} + +void AnimObj::drawFrame(Surface *surface) { - AnimObj *obj = new AnimObj(); - obj->_id = id; - obj->_z = z; - obj->_currentFrame = 0; - obj->_playing = playing; + if (_frames.size() == 0) + return; + + if (_id == kOverlayImage) { + _frames[_currentFrame]->draw(surface, false); + } + else { + _frames[_currentFrame]->draw(surface, true); + } +} - insertAnimation(*obj); +void AnimObj::setID(int id) { + + _id = id; } -void Animation::play(uint id) { +int AnimObj::getID() { + + return _id; +} - AnimObj &obj = *getAnimation(id); +void AnimObj::setZ(uint z) { - obj._playing = true; + _z = z; } -void Animation::stop(uint id) { +uint AnimObj::getZ() { + + return _z; +} - AnimObj &obj = *getAnimation(id); +bool AnimObj::isPlaying() { - obj._playing = false; + return _playing; } -Common::List::iterator Animation::getAnimation(uint id) { +void AnimObj::setPlaying(bool playing) { - Common::List::iterator it; + _playing = playing; +} - for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if (it->_id == id) { - return it; - } +void AnimObj::addFrame(Drawable *frame) { + + _frames.push_back(frame); +} + +uint AnimObj::getFramesNum() { + + return _frames.size(); +} + +void AnimObj::deleteFrames() { + + for (uint i = 0; i < getFramesNum(); ++i) { + delete _frames[i]; + _frames.pop_back(); } +} + +AnimObj *Animation::addAnimation(int id, uint z, bool playing) { + + AnimObj *obj = new AnimObj(_vm); + obj->setID(id); + obj->setZ(z); + obj->setPlaying(playing); + obj->setLooping(false); + + insertAnimation(obj); + + return obj; +} + +void Animation::play(int id) { + + AnimObj *obj = getAnimation(id); + + obj->setPlaying(true); +} - return _animObjects.end(); +void Animation::stop(int id) { + + AnimObj *obj = getAnimation(id); + + obj->setPlaying(false); } -void Animation::insertAnimation(AnimObj &animObj) { +AnimObj *Animation::getAnimation(int id) { - Common::List::iterator it; + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if (animObj._z < it->_z) - break; + if ((*it)->getID() == id) { + return *it; + } } - _animObjects.insert(it, animObj); + return *_animObjects.end(); } -void Animation::addFrame(uint id, Drawable *frame) { +void Animation::insertAnimation(AnimObj *animObj) { - Common::List::iterator it = getAnimation(id); + Common::List::iterator it; + + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + if (animObj->getZ() < (*it)->getZ()) + break; + } - it->_frames.push_back(frame); + _animObjects.insert(it, animObj); } void Animation::addOverlay(Drawable *overlay, uint z) { - AnimObj *obj = new AnimObj(); - obj->_id = kOverlayImage; - obj->_z = z; - obj->_currentFrame = 0; - obj->_playing = true; - obj->_frames.push_back(overlay); + AnimObj *obj = new AnimObj(_vm); + obj->setID(kOverlayImage); + obj->setZ(z); + obj->setPlaying(true); + obj->addFrame(overlay); - insertAnimation(*obj); + insertAnimation(obj); } void Animation::drawScene(Surface *surf) { - Common::List::iterator it; + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if (!it->_playing) { + if (! ((*it)->isPlaying()) ) { continue; } - if (it->_id == kOverlayImage) { - it->_frames[it->_currentFrame]->draw(surf, false); - } - else { - it->_frames[it->_currentFrame]->draw(surf, true); - } + (*it)->nextFrame(); + (*it)->drawFrame(surf); } } -void Animation::deleteAnimation(uint id) { +void Animation::deleteAnimation(int id) { - Common::List::iterator it = getAnimation(id); + Common::List::iterator it; - for (uint i = 0; i < it->_frames.size(); ++i) { - delete it->_frames[i]; + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + if ((*it)->getID() == id) + break; } + + (*it)->deleteFrames(); _animObjects.erase(it); } void Animation::deleteAll() { - Common::List::iterator it; + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - for (uint i = 0; i < it->_frames.size(); ++i) { - delete it->_frames[i]; - } + (*it)->deleteFrames(); } _animObjects.clear(); diff --git a/engines/draci/animation.h b/engines/draci/animation.h index c69947ea28..d4be8b5ba3 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -30,44 +30,81 @@ namespace Draci { -enum { kOverlayImage = -1 }; +enum { kOverlayImage = -1, kUnused = -2 }; class DraciEngine; -struct AnimObj { - uint _id; +class AnimObj { +public: + AnimObj(DraciEngine *vm); + ~AnimObj(); + + uint getZ(); + void setZ(uint z); + + void setID(int id); + int getID(); + + void setDelay(uint delay); + + void nextFrame(bool force = false); + void drawFrame(Surface *surface); + + void addFrame(Drawable *frame); + uint getFramesNum(); + void deleteFrames(); + + bool isPlaying(); + void setPlaying(bool playing); + + bool isLooping(); + void setLooping(bool looping); + + +private: + + uint nextFrameNum(); + + int _id; uint _currentFrame; uint _z; - bool _playing; + uint _delay; + uint _tick; + bool _playing; + bool _looping; Common::Array _frames; + + DraciEngine *_vm; }; +// TODO: Probably needs a namechange to AnimationManager or similar since AnimObj now +// acts as an animation object + class Animation { public: Animation(DraciEngine *vm) : _vm(vm) {}; ~Animation() { deleteAll(); } - void addAnimation(uint id, uint z, bool playing = false); - void addFrame(uint id, Drawable *frame); + AnimObj *addAnimation(int id, uint z, bool playing = false); void addOverlay(Drawable *overlay, uint z); - void play(uint id); - void stop(uint id); + void play(int id); + void stop(int id); - void deleteAnimation(uint id); + void deleteAnimation(int id); void deleteAll(); void drawScene(Surface *surf); - Common::List::iterator getAnimation(uint id); + AnimObj *getAnimation(int id); private: - void insertAnimation(AnimObj &animObj); + void insertAnimation(AnimObj *animObj); DraciEngine *_vm; - Common::List _animObjects; + Common::List _animObjects; }; } diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index b24d62d36d..a843a8267e 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -189,7 +189,7 @@ int Game::loadAnimation(uint animNum) { animationReader.readByte(); // Cyclic field, not used animationReader.readByte(); // Relative field, not used - _vm->_anims->addAnimation(animNum, 254, false); + AnimObj *obj = _vm->_anims->addAnimation(animNum, 254, false); for (uint i = 0; i < numFrames; ++i) { uint spriteNum = animationReader.readUint16LE() - 1; @@ -202,8 +202,7 @@ int Game::loadAnimation(uint animNum) { uint freq = animationReader.readUint16LE(); uint delay = animationReader.readUint16LE(); - // TODO: implement Animation::setDelay() - //_vm->_anims->setDelay(animNum, delay*10); + obj->setDelay(delay * 10); BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); @@ -212,7 +211,10 @@ int Game::loadAnimation(uint animNum) { if (mirror) sp->setMirrorOn(); - _vm->_anims->addFrame(animNum, sp); + // HACK: This is only for testing + obj->setLooping(true); + + obj->addFrame(sp); } return animNum; -- cgit v1.2.3 From 8e341ee968017be7d5bf7690473c80500c6b75d9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 5 Jul 2009 11:52:17 +0000 Subject: Renaming Animation -> AnimationManager and AnimObj -> Animation in light of the new API change. svn-id: r42133 --- engines/draci/animation.cpp | 115 ++++++++++++++++++++++---------------------- engines/draci/animation.h | 24 +++++---- engines/draci/draci.cpp | 2 +- engines/draci/draci.h | 2 +- engines/draci/game.cpp | 8 +-- 5 files changed, 75 insertions(+), 76 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index a29281d510..e553942c63 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -28,7 +28,7 @@ namespace Draci { -AnimObj::AnimObj(DraciEngine *vm) : _vm(vm) { +Animation::Animation(DraciEngine *vm) : _vm(vm) { _id = kUnused; _z = 0; _playing = false; @@ -38,23 +38,23 @@ AnimObj::AnimObj(DraciEngine *vm) : _vm(vm) { _currentFrame = 0; } -AnimObj::~AnimObj() { +Animation::~Animation() { deleteFrames(); } -bool AnimObj::isLooping() { +bool Animation::isLooping() { return _looping; } -void AnimObj::setLooping(bool looping) { +void Animation::setLooping(bool looping) { _looping = looping; } -void AnimObj::setDelay(uint delay) { +void Animation::setDelay(uint delay) { _delay = delay; } -void AnimObj::nextFrame(bool force) { +void Animation::nextFrame(bool force) { // If there's only one or no frames, return if (getFramesNum() < 2) @@ -81,7 +81,7 @@ void AnimObj::nextFrame(bool force) { _tick, _delay, _tick + _delay, _vm->_system->getMillis(), _currentFrame, _frames.size()); } -uint AnimObj::nextFrameNum() { +uint Animation::nextFrameNum() { if ((_currentFrame == getFramesNum() - 1) && _looping) return 0; @@ -89,7 +89,7 @@ uint AnimObj::nextFrameNum() { return _currentFrame + 1; } -void AnimObj::drawFrame(Surface *surface) { +void Animation::drawFrame(Surface *surface) { if (_frames.size() == 0) return; @@ -102,47 +102,47 @@ void AnimObj::drawFrame(Surface *surface) { } } -void AnimObj::setID(int id) { +void Animation::setID(int id) { _id = id; } -int AnimObj::getID() { +int Animation::getID() { return _id; } -void AnimObj::setZ(uint z) { +void Animation::setZ(uint z) { _z = z; } -uint AnimObj::getZ() { +uint Animation::getZ() { return _z; } -bool AnimObj::isPlaying() { +bool Animation::isPlaying() { return _playing; } -void AnimObj::setPlaying(bool playing) { +void Animation::setPlaying(bool playing) { _playing = playing; } -void AnimObj::addFrame(Drawable *frame) { +void Animation::addFrame(Drawable *frame) { _frames.push_back(frame); } -uint AnimObj::getFramesNum() { +uint Animation::getFramesNum() { return _frames.size(); } -void AnimObj::deleteFrames() { +void Animation::deleteFrames() { for (uint i = 0; i < getFramesNum(); ++i) { delete _frames[i]; @@ -150,73 +150,74 @@ void AnimObj::deleteFrames() { } } -AnimObj *Animation::addAnimation(int id, uint z, bool playing) { +Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { - AnimObj *obj = new AnimObj(_vm); - obj->setID(id); - obj->setZ(z); - obj->setPlaying(playing); - obj->setLooping(false); + Animation *anim = new Animation(_vm); + + anim->setID(id); + anim->setZ(z); + anim->setPlaying(playing); + anim->setLooping(false); - insertAnimation(obj); + insertAnimation(anim); - return obj; + return anim; } -void Animation::play(int id) { +void AnimationManager::play(int id) { - AnimObj *obj = getAnimation(id); + Animation *anim = getAnimation(id); - obj->setPlaying(true); + anim->setPlaying(true); } -void Animation::stop(int id) { +void AnimationManager::stop(int id) { - AnimObj *obj = getAnimation(id); + Animation *anim = getAnimation(id); - obj->setPlaying(false); + anim->setPlaying(false); } -AnimObj *Animation::getAnimation(int id) { +Animation *AnimationManager::getAnimation(int id) { - Common::List::iterator it; + Common::List::iterator it; - for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + for (it = _animations.begin(); it != _animations.end(); ++it) { if ((*it)->getID() == id) { return *it; } } - return *_animObjects.end(); + return *_animations.end(); } -void Animation::insertAnimation(AnimObj *animObj) { +void AnimationManager::insertAnimation(Animation *animObj) { - Common::List::iterator it; + Common::List::iterator it; - for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + for (it = _animations.begin(); it != _animations.end(); ++it) { if (animObj->getZ() < (*it)->getZ()) break; } - _animObjects.insert(it, animObj); + _animations.insert(it, animObj); } -void Animation::addOverlay(Drawable *overlay, uint z) { - AnimObj *obj = new AnimObj(_vm); - obj->setID(kOverlayImage); - obj->setZ(z); - obj->setPlaying(true); - obj->addFrame(overlay); +void AnimationManager::addOverlay(Drawable *overlay, uint z) { + Animation *anim = new Animation(_vm); + anim->setID(kOverlayImage); + anim->setZ(z); + anim->setPlaying(true); + anim->addFrame(overlay); - insertAnimation(obj); + insertAnimation(anim); } -void Animation::drawScene(Surface *surf) { +void AnimationManager::drawScene(Surface *surf) { - Common::List::iterator it; + Common::List::iterator it; - for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + for (it = _animations.begin(); it != _animations.end(); ++it) { if (! ((*it)->isPlaying()) ) { continue; } @@ -226,29 +227,29 @@ void Animation::drawScene(Surface *surf) { } } -void Animation::deleteAnimation(int id) { +void AnimationManager::deleteAnimation(int id) { - Common::List::iterator it; + Common::List::iterator it; - for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + for (it = _animations.begin(); it != _animations.end(); ++it) { if ((*it)->getID() == id) break; } (*it)->deleteFrames(); - _animObjects.erase(it); + _animations.erase(it); } -void Animation::deleteAll() { +void AnimationManager::deleteAll() { - Common::List::iterator it; + Common::List::iterator it; - for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + for (it = _animations.begin(); it != _animations.end(); ++it) { (*it)->deleteFrames(); } - _animObjects.clear(); + _animations.clear(); } } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index d4be8b5ba3..6fbd185b1f 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -34,10 +34,11 @@ enum { kOverlayImage = -1, kUnused = -2 }; class DraciEngine; -class AnimObj { +class Animation { + public: - AnimObj(DraciEngine *vm); - ~AnimObj(); + Animation(DraciEngine *vm); + ~Animation(); uint getZ(); void setZ(uint z); @@ -60,7 +61,6 @@ public: bool isLooping(); void setLooping(bool looping); - private: uint nextFrameNum(); @@ -77,16 +77,14 @@ private: DraciEngine *_vm; }; -// TODO: Probably needs a namechange to AnimationManager or similar since AnimObj now -// acts as an animation object -class Animation { +class AnimationManager { public: - Animation(DraciEngine *vm) : _vm(vm) {}; - ~Animation() { deleteAll(); } + AnimationManager(DraciEngine *vm) : _vm(vm) {}; + ~AnimationManager() { deleteAll(); } - AnimObj *addAnimation(int id, uint z, bool playing = false); + Animation *addAnimation(int id, uint z, bool playing = false); void addOverlay(Drawable *overlay, uint z); void play(int id); @@ -97,14 +95,14 @@ public: void drawScene(Surface *surf); - AnimObj *getAnimation(int id); + Animation *getAnimation(int id); private: - void insertAnimation(AnimObj *animObj); + void insertAnimation(Animation *anim); DraciEngine *_vm; - Common::List _animObjects; + Common::List _animations; }; } diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index cd9c3eeaed..cef66c6092 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -87,7 +87,7 @@ int DraciEngine::init() { _screen = new Screen(this); _font = new Font(); - _anims = new Animation(this); + _anims = new AnimationManager(this); _mouse = new Mouse(this); _script = new Script(this); _game = new Game(this); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 4a8c3d455a..cba78d3cd6 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -56,7 +56,7 @@ public: Mouse *_mouse; Game *_game; Script *_script; - Animation *_anims; + AnimationManager *_anims; BArchive *_objectsArchive; BArchive *_spritesArchive; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index a843a8267e..b2295d15b8 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -189,7 +189,7 @@ int Game::loadAnimation(uint animNum) { animationReader.readByte(); // Cyclic field, not used animationReader.readByte(); // Relative field, not used - AnimObj *obj = _vm->_anims->addAnimation(animNum, 254, false); + Animation *anim = _vm->_anims->addAnimation(animNum, 254, false); for (uint i = 0; i < numFrames; ++i) { uint spriteNum = animationReader.readUint16LE() - 1; @@ -202,7 +202,7 @@ int Game::loadAnimation(uint animNum) { uint freq = animationReader.readUint16LE(); uint delay = animationReader.readUint16LE(); - obj->setDelay(delay * 10); + anim->setDelay(delay * 10); BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); @@ -212,9 +212,9 @@ int Game::loadAnimation(uint animNum) { sp->setMirrorOn(); // HACK: This is only for testing - obj->setLooping(true); + anim->setLooping(true); - obj->addFrame(sp); + anim->addFrame(sp); } return animNum; -- cgit v1.2.3 From f4ba64d2e4783b300242fd43ab6813d6c8ca8cdb Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 17:25:34 +0000 Subject: Implemented GPL operators. svn-id: r42183 --- engines/draci/script.cpp | 128 ++++++++++++++++++++++++++++++++++++----------- engines/draci/script.h | 23 +++++++++ 2 files changed, 123 insertions(+), 28 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 00d68676e4..1e51402d65 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -96,25 +96,27 @@ void Script::setupCommandList() { { 27, 1, "FeedPassword", 3, { 1, 1, 1 }, NULL } }; + /** Operators used by the mathematical evaluator */ + static const GPL2Operator gplOperators[] = { + {"&", &Script::operAnd }, + {"|", &Script::operOr }, + {"^", &Script::operXor }, + {"==", &Script::operEqual }, + {"!=", &Script::operNotEqual }, + {"<", &Script::operLess }, + {">", &Script::operGreater }, + {"<=", &Script::operLessOrEqual }, + {">=", &Script::operGreaterOrEqual }, + {"*", &Script::operMul }, + {"/", &Script::operDiv }, + {"%", &Script::operMod }, + {"+", &Script::operAdd }, + {"-", &Script::operSub } + }; + _commandList = gplCommands; + _operatorList = gplOperators; } -/** Operators used by the mathematical evaluator */ -Common::String operators[] = { - "oper_and", - "oper_or", - "oper_xor", - "oper_equals", - "oper_not_equal", - "oper_less_than", - "oper_greater_than", - "oper_less_or_equal", - "oper_greater_or_equal", - "oper_multiply", - "oper_divide", - "oper_remainder", - "oper_plus", - "oper_minus" -}; /** Functions used by the mathematical evaluator */ Common::String functions[] = { @@ -146,6 +148,66 @@ enum mathExpressionObject { kMathVariable }; +/* GPL operators */ + +int Script::operAnd(int op1, int op2) { + return op1 & op2; +} + +int Script::operOr(int op1, int op2) { + return op1 | op2; +} + +int Script::operXor(int op1, int op2) { + return op1 ^ op2; +} + +int Script::operEqual(int op1, int op2) { + return op1 == op2; +} + +int Script::operNotEqual(int op1, int op2) { + return op1 != op2; +} + +int Script::operLess(int op1, int op2) { + return op1 < op2; +} + +int Script::operGreater(int op1, int op2) { + return op1 > op2; +} + +int Script::operGreaterOrEqual(int op1, int op2) { + return op1 >= op2; +} + +int Script::operLessOrEqual(int op1, int op2) { + return op1 <= op2; +} + +int Script::operMul(int op1, int op2) { + return op1 * op2; +} + +int Script::operAdd(int op1, int op2) { + return op1 + op2; +} + +int Script::operSub(int op1, int op2) { + return op1 - op2; +} + +int Script::operDiv(int op1, int op2) { + return op1 / op2; +} + +int Script::operMod(int op1, int op2) { + return op1 % op2; +} + +/* GPL commands */ + void Script::load(Common::Queue ¶ms) { int objID = params.pop() - 1; int animID = params.pop() - 1; @@ -161,13 +223,16 @@ void Script::load(Common::Queue ¶ms) { */ int Script::handleMathExpression(Common::MemoryReadStream &reader) { - Common::Stack stk; + Common::Stack stk; mathExpressionObject obj; + GPL2Operator oper; // Read in initial math object obj = (mathExpressionObject)reader.readUint16LE(); - uint16 value; + int value; + int op1, op2, res; + while (1) { if (obj == kMathEnd) { // Check whether the expression was evaluated correctly @@ -184,25 +249,31 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathNumber: value = reader.readUint16LE(); stk.push(value); - debugC(3, kDraciBytecodeDebugLevel, "\t\t-number %hu", value); + debugC(3, kDraciBytecodeDebugLevel, "\t\tnumber: %d", value); break; case kMathOperator: value = reader.readUint16LE(); - stk.pop(); - stk.pop(); + op1 = stk.pop(); + op2 = stk.pop(); - // FIXME: Pushing dummy value for now, but should push return value - stk.push(0); + // Fetch operator + oper = _operatorList[value-1]; - debugC(3, kDraciBytecodeDebugLevel, "\t\t-operator %s", - operators[value-1].c_str()); + // Calculate result + res = (this->*(oper._handler))(op1, op2); + + // Push result + stk.push(res); + + debugC(3, kDraciBytecodeDebugLevel, "\t\t%d %s %d (res: %d)", + op1, oper._name.c_str(), op2, res); break; case kMathVariable: value = reader.readUint16LE(); stk.push(value); - debugC(3, kDraciBytecodeDebugLevel, "\t\t-variable %hu", value); + debugC(3, kDraciBytecodeDebugLevel, "\t\tvariable: %d", value); break; case kMathFunctionCall: @@ -213,7 +284,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { // FIXME: Pushing dummy value for now, but should push return value stk.push(0); - debugC(3, kDraciBytecodeDebugLevel, "\t\t-functioncall %s", + debugC(3, kDraciBytecodeDebugLevel, "\t\tfunction: %s", functions[value-1].c_str()); break; } @@ -303,6 +374,7 @@ int Script::run(GPL2Program program, uint16 offset) { const GPL2Command *cmd; do { + // read in command pair uint16 cmdpair = reader.readUint16BE(); diff --git a/engines/draci/script.h b/engines/draci/script.h index 5d8340858c..3908b1b660 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -43,6 +43,7 @@ enum { }; typedef void (Script::* GPLHandler)(Common::Queue &); +typedef int (Script::* GPLOperatorHandler)(int, int); /** * Represents a single command in the GPL scripting language bytecode. @@ -59,6 +60,11 @@ struct GPL2Command { GPLHandler _handler; }; +struct GPL2Operator { + Common::String _name; + GPLOperatorHandler _handler; +}; + /** * A convenience data type that holds both the actual bytecode and the * length of the bytecode. Passed to Script::run(). @@ -82,8 +88,25 @@ private: /** List of all GPL commands. Initialised in the constructor. */ const GPL2Command *_commandList; + const GPL2Operator *_operatorList; void load(Common::Queue ¶ms); + void start(Common::Queue ¶ms); + + int operAnd(int op1, int op2); + int operOr(int op1, int op2); + int operXor(int op1, int op2); + int operSub(int op1, int op2); + int operAdd(int op1, int op2); + int operDiv(int op1, int op2); + int operMul(int op1, int op2); + int operEqual(int op1, int op2); + int operNotEqual(int op1, int op2); + int operGreater(int op1, int op2); + int operLess(int op1, int op2); + int operGreaterOrEqual(int op1, int op2); + int operLessOrEqual(int op1, int op2); + int operMod(int op1, int op2); void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From 4e15262e7493b726fa4a6ea57089063211180d2d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 17:27:12 +0000 Subject: Implemented Script::play() GPL opcode. svn-id: r42184 --- engines/draci/script.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 1e51402d65..68bfbe6583 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -44,7 +44,7 @@ void Script::setupCommandList() { { 1, 1, "goto", 1, { 3 }, NULL }, { 2, 1, "Let", 2, { 3, 4 }, NULL }, { 3, 1, "if", 2, { 4, 3 }, NULL }, - { 4, 1, "Start", 2, { 3, 2 }, NULL }, + { 4, 1, "Start", 2, { 3, 2 }, &Script::start }, { 5, 1, "Load", 2, { 3, 2 }, &Script::load }, { 5, 2, "StartPlay", 2, { 3, 2 }, NULL }, { 5, 3, "JustTalk", 0, { 0 }, NULL }, @@ -217,6 +217,15 @@ void Script::load(Common::Queue ¶ms) { obj->_seqTab[animID - obj->_idxSeq] = _vm->_game->loadAnimation(animID); } +void Script::start(Common::Queue ¶ms) { + int objID = params.pop() - 1; + int animID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + + _vm->_anims->play(animID); +} + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression -- cgit v1.2.3 From 237707dd6e0d07db130de9cdae5f7c9f5169ff71 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 17:29:44 +0000 Subject: Fixed bug where the GPL interpreter left parameters from previous commands on the stack. svn-id: r42185 --- engines/draci/script.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 68bfbe6583..b23f2cbfed 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -384,6 +384,10 @@ int Script::run(GPL2Program program, uint16 offset) { const GPL2Command *cmd; do { + // Clear any parameters left on the stack from the previous command + // This likely won't be needed once all commands are implemented + params.clear(); + // read in command pair uint16 cmdpair = reader.readUint16BE(); -- cgit v1.2.3 From edaaca97f95a26b235fadaf199d291c98d88d43a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 18:49:51 +0000 Subject: Set up GPL functions properly (the math evaluator now calls the handler if its implemented). svn-id: r42188 --- engines/draci/script.cpp | 87 ++++++++++++++++++++++++++++++------------------ engines/draci/script.h | 7 ++++ 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index b23f2cbfed..3a39f61e2d 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -114,31 +114,32 @@ void Script::setupCommandList() { {"-", &Script::operSub } }; + /** Functions used by the mathematical evaluator */ + static const GPL2Function gplFunctions[] = { + { "Not", NULL }, + { "Random", NULL }, + { "IsIcoOn", NULL }, + { "IsIcoAct", NULL }, + { "IcoStat", NULL }, + { "ActIco", NULL }, + { "IsObjOn", NULL }, + { "IsObjOff", NULL }, + { "IsObjAway", NULL }, + { "ObjStat", NULL }, + { "LastBlock", NULL }, + { "AtBegin", NULL }, + { "BlockVar", NULL }, + { "HasBeen", NULL }, + { "MaxLine", NULL }, + { "ActPhase", NULL }, + { "Cheat", NULL }, + }; + _commandList = gplCommands; _operatorList = gplOperators; + _functionList = gplFunctions; } -/** Functions used by the mathematical evaluator */ -Common::String functions[] = { - "F_Not", - "F_Random", - "F_IsIcoOn", - "F_IsIcoAct", - "F_IcoStat", - "F_ActIco", - "F_IsObjOn", - "F_IsObjOff", - "F_IsObjAway", - "F_ObjStat", - "F_LastBlock", - "F_AtBegin", - "F_BlockVar", - "F_HasBeen", - "F_MaxLine", - "F_ActPhase", - "F_Cheat" -}; - /** Type of mathematical object */ enum mathExpressionObject { kMathEnd, @@ -223,7 +224,11 @@ void Script::start(Common::Queue ¶ms) { GameObject *obj = _vm->_game->getObject(objID); - _vm->_anims->play(animID); + int visiblethingy = obj->_visible ? 1 << 7 : 0x00; + int thingy = (obj->_location + 1) | visiblethingy; + + if ( ((objID == 0) || (obj->_visible)) && (obj->_location == _vm->_game->_currentRoom._roomNum)) + _vm->_anims->play(animID); } /** @@ -235,12 +240,13 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { Common::Stack stk; mathExpressionObject obj; GPL2Operator oper; + GPL2Function func; // Read in initial math object obj = (mathExpressionObject)reader.readUint16LE(); int value; - int op1, op2, res; + int arg1, arg2, res; while (1) { if (obj == kMathEnd) { @@ -263,20 +269,20 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathOperator: value = reader.readUint16LE(); - op1 = stk.pop(); - op2 = stk.pop(); + arg1 = stk.pop(); + arg2 = stk.pop(); // Fetch operator oper = _operatorList[value-1]; // Calculate result - res = (this->*(oper._handler))(op1, op2); + res = (this->*(oper._handler))(arg1, arg2); // Push result stk.push(res); debugC(3, kDraciBytecodeDebugLevel, "\t\t%d %s %d (res: %d)", - op1, oper._name.c_str(), op2, res); + arg1, oper._name.c_str(), arg2, res); break; case kMathVariable: @@ -287,14 +293,29 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathFunctionCall: value = reader.readUint16LE(); - - stk.pop(); - // FIXME: Pushing dummy value for now, but should push return value - stk.push(0); + // Fetch function + func = _functionList[value-1]; + + // If not yet implemented + if (func._handler == NULL) { + stk.pop(); + + // FIXME: Pushing dummy value for now, but should push return value + stk.push(0); + + debugC(3, kDraciBytecodeDebugLevel, "\t\tcall: %s (not implemented)", + func._name.c_str()); + } else { + arg1 = stk.pop(); + + // Calculate result + res = (this->*(func._handler))(arg1); + + debugC(3, kDraciBytecodeDebugLevel, "\t\tcall: %s(%d) (res: %d)", + func._name.c_str(), arg1, res); + } - debugC(3, kDraciBytecodeDebugLevel, "\t\tfunction: %s", - functions[value-1].c_str()); break; } diff --git a/engines/draci/script.h b/engines/draci/script.h index 3908b1b660..6259f675a5 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -44,6 +44,7 @@ enum { typedef void (Script::* GPLHandler)(Common::Queue &); typedef int (Script::* GPLOperatorHandler)(int, int); +typedef int (Script::* GPLFunctionHandler)(int); /** * Represents a single command in the GPL scripting language bytecode. @@ -65,6 +66,11 @@ struct GPL2Operator { GPLOperatorHandler _handler; }; +struct GPL2Function { + Common::String _name; + GPLFunctionHandler _handler; +}; + /** * A convenience data type that holds both the actual bytecode and the * length of the bytecode. Passed to Script::run(). @@ -89,6 +95,7 @@ private: /** List of all GPL commands. Initialised in the constructor. */ const GPL2Command *_commandList; const GPL2Operator *_operatorList; + const GPL2Function *_functionList; void load(Common::Queue ¶ms); void start(Common::Queue ¶ms); -- cgit v1.2.3 From 218a15d890d089e48d135533bb51f0b68043e197 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 19:22:13 +0000 Subject: Made _rnd member of DraciEngine public. svn-id: r42190 --- engines/draci/draci.h | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/draci/draci.h b/engines/draci/draci.h index cba78d3cd6..bdab419e64 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -65,7 +65,6 @@ public: BArchive *_overlaysArchive; BArchive *_animationsArchive; -private: Common::RandomSource _rnd; }; -- cgit v1.2.3 From b2c24dd640eba57c1c2460a027f021118ca44920 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 19:26:53 +0000 Subject: Implemented Script::funcRandom (GPL function). svn-id: r42191 --- engines/draci/script.cpp | 13 ++++++++++++- engines/draci/script.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 3a39f61e2d..330fc85d0a 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -117,7 +117,7 @@ void Script::setupCommandList() { /** Functions used by the mathematical evaluator */ static const GPL2Function gplFunctions[] = { { "Not", NULL }, - { "Random", NULL }, + { "Random", &Script::funcRandom }, { "IsIcoOn", NULL }, { "IsIcoAct", NULL }, { "IcoStat", NULL }, @@ -207,6 +207,17 @@ int Script::operMod(int op1, int op2) { return op1 % op2; } +/* GPL functions */ + +int Script::funcRandom(int n) { + +// The function needs to return numbers in the [0..n-1] range so we need to deduce 1 +// (RandomSource::getRandomNumber returns a number in the range [0..n]) + + n -= 1; + return _vm->_rnd.getRandomNumber(n); +} + /* GPL commands */ void Script::load(Common::Queue ¶ms) { diff --git a/engines/draci/script.h b/engines/draci/script.h index 6259f675a5..16bef9c7ff 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -115,6 +115,8 @@ private: int operLessOrEqual(int op1, int op2); int operMod(int op1, int op2); + int funcRandom(int n); + void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); int handleMathExpression(Common::MemoryReadStream &reader); -- cgit v1.2.3 From 61fa4d27d5cbeb6029b07596d2db2af381567e83 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 19:41:13 +0000 Subject: Cache the transparent colour instead of calling a function for every pixel. svn-id: r42192 --- engines/draci/font.cpp | 4 +++- engines/draci/sprite.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 17ff8644cb..8a6f353876 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -162,6 +162,8 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con int ySpaceLeft = dst->h - ty - 1; int yPixelsToDraw = (_fontHeight < ySpaceLeft) ? _fontHeight : ySpaceLeft; + int _transparent = dst->getTransparentColour(); + for (int y = 0; y < yPixelsToDraw; ++y) { for (int x = 0; x <= xPixelsToDraw; ++x) { @@ -189,7 +191,7 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con } // Paint pixel (if not transparent) - if (colour != dst->getTransparentColour()) + if (colour != _transparent) ptr[x] = colour; } diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index bd442e5ee8..32f9d04171 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -142,12 +142,14 @@ void Sprite::draw(Surface *surface, bool markDirty) const { byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); byte *src = _data; + int _transparent = surface->getTransparentColour(); + // Blit the sprite to the surface for (int i = sourceRect.top; i < sourceRect.bottom; ++i) { for (int j = sourceRect.left; j < sourceRect.right; ++j) { // Don't blit if the pixel is transparent on the target surface - if (src[i * _width + j] != surface->getTransparentColour()) { + if (src[i * _width + j] != _transparent) { // Draw the sprite mirrored if the _mirror flag is set if (_mirror) { -- cgit v1.2.3 From 3b75b8003d74f5587d3434d642b05c61a4227fed Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 19:43:21 +0000 Subject: Removed two variables that were committed by mistake. svn-id: r42193 --- engines/draci/script.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 330fc85d0a..d0fad493fe 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -235,10 +235,7 @@ void Script::start(Common::Queue ¶ms) { GameObject *obj = _vm->_game->getObject(objID); - int visiblethingy = obj->_visible ? 1 << 7 : 0x00; - int thingy = (obj->_location + 1) | visiblethingy; - - if ( ((objID == 0) || (obj->_visible)) && (obj->_location == _vm->_game->_currentRoom._roomNum)) + if ( ((objID == 0) || (obj->_visible)) && (obj->_location == _vm->_game->getRoomNum())) _vm->_anims->play(animID); } -- cgit v1.2.3 From 79c42abf086911537400750fc356127669bf4c23 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 6 Jul 2009 19:50:59 +0000 Subject: * Fixed extracting visibility and location of object from its status byte * Added Game::getRoomNum() which returns the current room number * Made Game::loadRoom() execute the room's startup script, load the room's objects and run their init scripts as well svn-id: r42194 --- engines/draci/game.cpp | 38 +++++++++++++++++++++++++++++++++++--- engines/draci/game.h | 5 ++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index b2295d15b8..ab2302cae4 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -121,10 +121,10 @@ Game::Game(DraciEngine *vm) : _vm(vm) { byte tmp = objStatus.readByte(); // Set object visibility - _objects[i]._visible = tmp & 1; + _objects[i]._visible = tmp & (1 << 7); // Set object location - _objects[i]._location = tmp & ~1; + _objects[i]._location = (~(1 << 7) & tmp) - 1; } assert(numDialogs == _info->_numDialogs); @@ -172,6 +172,32 @@ void Game::loadRoom(uint roomNum) { _currentRoom._escRoom = roomReader.readByte() - 1; _currentRoom._numGates = roomReader.readByte(); + for (uint i = 0; i < _info->_numObjects; ++i) { + debugC(1, kDraciLogicDebugLevel, + "Checking if object %d (%d) is at the current location (%d)", i, + _objects[i]._location, roomNum); + + if (_objects[i]._location == roomNum) { + debugC(1, kDraciLogicDebugLevel, "Loading object %d from room %d", i, roomNum); + loadObject(i); + } + } + + // We can't do this in the above loop because some objects' scripts reference + // other objects that may not yet be loaded + for (uint i = 0; i < _info->_numObjects; ++i) { + if (_objects[i]._location == roomNum) { + _vm->_script->run(getObject(i)->_program, getObject(i)->_init); + } + } + + f = _vm->_roomsArchive->getFile(roomNum * 4 + 3); + _currentRoom._program._bytecode = new byte[f->_length]; + _currentRoom._program._length = f->_length; + memcpy(_currentRoom._program._bytecode, f->_data, f->_length); + + _vm->_script->run(_currentRoom._program, _currentRoom._init); + f = _vm->_paletteArchive->getFile(_currentRoom._palette); _vm->_screen->setPalette(f->_data, 0, kNumColours); } @@ -295,7 +321,13 @@ void Game::loadOverlays() { void Game::changeRoom(uint roomNum) { _currentRoom._roomNum = roomNum; loadRoom(roomNum); - loadOverlays(); + loadOverlays(); + + _vm->_script->run(_currentRoom._program, _currentRoom._init); +} + +int Game::getRoomNum() { + return _currentRoom._roomNum; } Game::~Game() { diff --git a/engines/draci/game.h b/engines/draci/game.h index 8f02dd579a..14140f44e3 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -91,6 +91,7 @@ struct Room { double _pers0, _persStep; byte _escRoom; byte _numGates; + GPL2Program _program; }; class Game { @@ -103,6 +104,8 @@ public: void changeRoom(uint roomNum); + int getRoomNum(); + void loadRoom(uint roomNum); int loadAnimation(uint animNum); void loadOverlays(); @@ -118,7 +121,7 @@ private: uint16 *_dialogOffsets; int16 *_variables; byte *_itemStatus; - GameObject *_objects; + GameObject *_objects; Room _currentRoom; }; -- cgit v1.2.3 From 82e6bcea2f0cf3fb0d44cbdd6fc5ad9240ef20e2 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 14:52:36 +0000 Subject: * Added AnimationManager::deleteOverlays(). * Fixed bug in AnimationManager::deleteAnimation() that could result in accessing the Common::List::end() sentinel value. svn-id: r42223 --- engines/draci/animation.cpp | 19 +++++++++++++++---- engines/draci/animation.h | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index e553942c63..bb0cb44b10 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -232,15 +232,26 @@ void AnimationManager::deleteAnimation(int id) { Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { - if ((*it)->getID() == id) + if ((*it)->getID() == id) { + (*it)->deleteFrames(); + _animations.erase(it); break; + } } +} + +void AnimationManager::deleteOverlays() { - (*it)->deleteFrames(); + Common::List::iterator it; - _animations.erase(it); + for (it = _animations.begin(); it != _animations.end(); ++it) { + if((*it)->getID() == kOverlayImage) + (*it)->deleteFrames(); + + _animations.erase(it); + } } - + void AnimationManager::deleteAll() { Common::List::iterator it; diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 6fbd185b1f..cef8182f7b 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -91,6 +91,7 @@ public: void stop(int id); void deleteAnimation(int id); + void deleteOverlays(); void deleteAll(); void drawScene(Surface *surf); -- cgit v1.2.3 From 7f3af129f218ee47f806e7672ffe4074b86194c2 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 15:21:41 +0000 Subject: mplemented changing rooms properly (overlays and objects' animations are deleted before a new room is loaded) and set up a quick demonstration (left click advances to the next room, right click goes back). svn-id: r42224 --- engines/draci/game.cpp | 15 +++++++++++++++ engines/draci/game.h | 14 ++++++++++++++ engines/draci/mouse.cpp | 20 +++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index ab2302cae4..ddb5a58a5a 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -319,6 +319,21 @@ void Game::loadOverlays() { } void Game::changeRoom(uint roomNum) { + _vm->_roomsArchive->clearCache(); + _vm->_anims->deleteOverlays(); + + int oldRoomNum = _currentRoom._roomNum; + + for (uint i = 0; i < _info->_numObjects; ++i) { + GameObject *obj = &_objects[i]; + + if (i != 0 && obj->_location == oldRoomNum) { + for (uint j = 0; j < obj->_numSeq; ++j) { + _vm->_anims->deleteAnimation(obj->_seqTab[j]); + } + } + } + _currentRoom._roomNum = roomNum; loadRoom(roomNum); loadOverlays(); diff --git a/engines/draci/game.h b/engines/draci/game.h index 14140f44e3..5ba0626557 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -106,6 +106,20 @@ public: int getRoomNum(); + // HACK: this is only for testing + void incRoomNum() { + int n = _currentRoom._roomNum; + n = n < 25 ? n+1 : n; + _currentRoom._roomNum = n; + } + + // HACK: same as above + void decRoomNum() { + int n = _currentRoom._roomNum; + n = n > 0 ? n-1 : n; + _currentRoom._roomNum = n; + } + void loadRoom(uint roomNum); int loadAnimation(uint animNum); void loadOverlays(); diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index b342487209..09216085a7 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -41,27 +41,45 @@ Mouse::Mouse(DraciEngine *vm) { void Mouse::handleEvent(Common::Event event) { _x = (uint16) event.mouse.x; _y = (uint16) event.mouse.y; - + int room; + switch (event.type) { case Common::EVENT_LBUTTONDOWN: debugC(6, kDraciGeneralDebugLevel, "Left button down (x: %u y: %u)", _x, _y); _lButton = true; + + // HACK: We change to the next room when the left mouse button is pressed. + // This is only for testing. + _vm->_game->incRoomNum(); + room = _vm->_game->getRoomNum(); + _vm->_game->changeRoom(room); break; + case Common::EVENT_LBUTTONUP: debugC(6, kDraciGeneralDebugLevel, "Left button up (x: %u y: %u)", _x, _y); _lButton = false; break; + case Common::EVENT_RBUTTONDOWN: debugC(6, kDraciGeneralDebugLevel, "Right button down (x: %u y: %u)", _x, _y); _rButton = true; + + // HACK: We change to the previous room when the right mouse button is pressed. + // This is only for testing. + _vm->_game->decRoomNum(); + room = _vm->_game->getRoomNum(); + _vm->_game->changeRoom(room); break; + case Common::EVENT_RBUTTONUP: debugC(6, kDraciGeneralDebugLevel, "Right button up (x: %u y: %u)", _x, _y); _rButton = false; break; + case Common::EVENT_MOUSEMOVE: setPosition(_x, _y); break; + default: break; } -- cgit v1.2.3 From 2e552bf643cc5763f32a8ffa16b12af71165186f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 15:31:13 +0000 Subject: Stopped running the room init scripts twice. svn-id: r42225 --- engines/draci/game.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index ddb5a58a5a..0f78f18880 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -183,6 +183,7 @@ void Game::loadRoom(uint roomNum) { } } + // Run the init scripts for room objects // We can't do this in the above loop because some objects' scripts reference // other objects that may not yet be loaded for (uint i = 0; i < _info->_numObjects; ++i) { @@ -337,8 +338,6 @@ void Game::changeRoom(uint roomNum) { _currentRoom._roomNum = roomNum; loadRoom(roomNum); loadOverlays(); - - _vm->_script->run(_currentRoom._program, _currentRoom._init); } int Game::getRoomNum() { -- cgit v1.2.3 From 4cfdf8c855143d93185f2d0bc70d06976885da67 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 15:35:35 +0000 Subject: Shortened AnimationManager::{play,stop}(). Removed some excessive newlines. svn-id: r42226 --- engines/draci/animation.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index bb0cb44b10..cfc6619c80 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -103,42 +103,34 @@ void Animation::drawFrame(Surface *surface) { } void Animation::setID(int id) { - _id = id; } int Animation::getID() { - return _id; } void Animation::setZ(uint z) { - _z = z; } uint Animation::getZ() { - return _z; } bool Animation::isPlaying() { - return _playing; } void Animation::setPlaying(bool playing) { - _playing = playing; } void Animation::addFrame(Drawable *frame) { - _frames.push_back(frame); } uint Animation::getFramesNum() { - return _frames.size(); } @@ -165,17 +157,11 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { } void AnimationManager::play(int id) { - - Animation *anim = getAnimation(id); - - anim->setPlaying(true); + getAnimation(id)->setPlaying(true); } void AnimationManager::stop(int id) { - - Animation *anim = getAnimation(id); - - anim->setPlaying(false); + getAnimation(id)->setPlaying(false); } Animation *AnimationManager::getAnimation(int id) { -- cgit v1.2.3 From d519626c55831653c9a595822f502f84a1e51c9c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 15:37:50 +0000 Subject: Added const keyword to "transparent" local variable in Sprite::draw() and removed leading underscore. svn-id: r42227 --- engines/draci/sprite.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 32f9d04171..aad7753b03 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -142,14 +142,14 @@ void Sprite::draw(Surface *surface, bool markDirty) const { byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); byte *src = _data; - int _transparent = surface->getTransparentColour(); + const int transparent = surface->getTransparentColour(); // Blit the sprite to the surface for (int i = sourceRect.top; i < sourceRect.bottom; ++i) { for (int j = sourceRect.left; j < sourceRect.right; ++j) { // Don't blit if the pixel is transparent on the target surface - if (src[i * _width + j] != _transparent) { + if (src[i * _width + j] != transparent) { // Draw the sprite mirrored if the _mirror flag is set if (_mirror) { -- cgit v1.2.3 From c258eefc82517274f2b98fd13e4959686ba9e4a5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 15:39:18 +0000 Subject: Made AnimationManager::getAnimation() return NULL when an animation is not found instead of Common::List<>::end(). svn-id: r42228 --- engines/draci/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index cfc6619c80..09ee48ab55 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -174,7 +174,7 @@ Animation *AnimationManager::getAnimation(int id) { } } - return *_animations.end(); + return NULL; } void AnimationManager::insertAnimation(Animation *animObj) { -- cgit v1.2.3 From fd2ab9e3c09e290523d72e39c961e1043be0a7f6 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 19:50:12 +0000 Subject: Added enum constant for the dragon object (kDragonObject) and made Script::start() a bit more readable. svn-id: r42236 --- engines/draci/game.cpp | 2 +- engines/draci/game.h | 4 ++++ engines/draci/script.cpp | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 0f78f18880..36b5890a82 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -134,7 +134,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { } void Game::init() { - loadObject(0); + loadObject(kDragonObject); _vm->_script->run(getObject(0)->_program, getObject(0)->_init); diff --git a/engines/draci/game.h b/engines/draci/game.h index 5ba0626557..e47f14bd98 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -35,6 +35,10 @@ namespace Draci { class DraciEngine; +enum { + kDragonObject +}; + enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index d0fad493fe..4b05c46b30 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -234,8 +234,10 @@ void Script::start(Common::Queue ¶ms) { int animID = params.pop() - 1; GameObject *obj = _vm->_game->getObject(objID); + + bool visible = (objID == kDragonObject || obj->_visible); - if ( ((objID == 0) || (obj->_visible)) && (obj->_location == _vm->_game->getRoomNum())) + if (visible && (obj->_location == _vm->_game->getRoomNum())) _vm->_anims->play(animID); } -- cgit v1.2.3 From d37d49e50c9352cd1f6ef46b40cb06e5d0a5ba88 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 19:53:40 +0000 Subject: Removed testing hack from Game::init() that displayed the dragon in the upper left corner. Replaced some more instances of magic numbers with kDragonObject. Made Game::init() a bit more readable. svn-id: r42237 --- engines/draci/game.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 36b5890a82..cbdeff22ef 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -136,10 +136,8 @@ Game::Game(DraciEngine *vm) : _vm(vm) { void Game::init() { loadObject(kDragonObject); - _vm->_script->run(getObject(0)->_program, getObject(0)->_init); - - // HACK: this is only for testing - _vm->_anims->play(getObject(0)->_seqTab[9]); + GameObject *dragon = getObject(kDragonObject); + _vm->_script->run(dragon->_program, dragon->_init); changeRoom(0); } -- cgit v1.2.3 From 318d40624212d34df16721d8f7ac2d0fb3ee486a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 20:46:26 +0000 Subject: Made GPL interpreter exit on both gplend and exit instructions. svn-id: r42241 --- engines/draci/script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 4b05c46b30..5ffed256ea 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -458,7 +458,7 @@ int Script::run(GPL2Program program, uint16 offset) { (this->*(cmd->_handler))(params); } - } while (cmd->_name != "gplend"); + } while (cmd->_name != "gplend" || cmd->_name != "exit"); return 0; } -- cgit v1.2.3 From b6b1402368b8f33c825af095bec210829ad33cd3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 20:57:14 +0000 Subject: * Changed Game::_variables to public since the GPL interpreter needs to use it and made it int instead of uint16 * Implemented variable accessing by the math evaluator * Fixed bug from previous commit (should have used && when checking for ending instructions, not ||) svn-id: r42242 --- engines/draci/game.cpp | 2 +- engines/draci/game.h | 3 ++- engines/draci/script.cpp | 9 ++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index cbdeff22ef..072d205436 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -96,7 +96,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { file = initArchive.getFile(2); unsigned int numVariables = file->_length / sizeof (int16); - _variables = new int16[numVariables]; + _variables = new int[numVariables]; Common::MemoryReadStream variableData(file->_data, file->_length); for (i = 0; i < numVariables; ++i) { diff --git a/engines/draci/game.h b/engines/draci/game.h index e47f14bd98..1c572f95e9 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -131,13 +131,14 @@ public: GameObject *getObject(uint objNum); + int *_variables; + private: DraciEngine *_vm; GameInfo *_info; Person *_persons; uint16 *_dialogOffsets; - int16 *_variables; byte *_itemStatus; GameObject *_objects; Room _currentRoom; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 5ffed256ea..f45f45cb76 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -297,8 +297,11 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathVariable: value = reader.readUint16LE(); - stk.push(value); - debugC(3, kDraciBytecodeDebugLevel, "\t\tvariable: %d", value); + + stk.push(_vm->_game->_variables[value-1]); + + debugC(3, kDraciBytecodeDebugLevel, "\t\tvariable: %d (%d)", value, + _vm->_game->_variables[value-1]); break; case kMathFunctionCall: @@ -458,7 +461,7 @@ int Script::run(GPL2Program program, uint16 offset) { (this->*(cmd->_handler))(params); } - } while (cmd->_name != "gplend" || cmd->_name != "exit"); + } while (cmd->_name != "gplend" && cmd->_name != "exit"); return 0; } -- cgit v1.2.3 From 9246e9cf4a6f6a561274274019309b16ae1b96c4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 21:11:36 +0000 Subject: * Added some more animation debug info * Reordered Animation::nextFrame() a bit to make sure the timings are correct (particularly the last frame) * Added checks to AnimationManager::play() and AnimationManager::stop() so it doesn't dereference a null pointer. svn-id: r42243 --- engines/draci/animation.cpp | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 09ee48ab55..d48560a550 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -48,10 +48,14 @@ bool Animation::isLooping() { void Animation::setLooping(bool looping) { _looping = looping; + debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", + looping, _id); } void Animation::setDelay(uint delay) { _delay = delay; + debugC(7, kDraciAnimationDebugLevel, "Setting delay to %u on animation %d", + delay, _id); } void Animation::nextFrame(bool force) { @@ -62,23 +66,22 @@ void Animation::nextFrame(bool force) { Common::Rect frameRect = _frames[_currentFrame]->getRect(); - // If we are at the last frame and not looping, stop the animation - // The animation is also restarted to frame zero - if ((_currentFrame == nextFrameNum() - 1) && !_looping) { - _currentFrame = 0; - _playing = false; - return; - } - if (force || (_tick + _delay <= _vm->_system->getMillis())) { - _vm->_screen->getSurface()->markDirtyRect(frameRect); - _currentFrame = nextFrameNum(); - _tick = _vm->_system->getMillis(); + // If we are at the last frame and not looping, stop the animation + // The animation is also restarted to frame zero + if ((_currentFrame == getFramesNum() - 1) && !_looping) { + _currentFrame = 0; + _playing = false; + } else { + _vm->_screen->getSurface()->markDirtyRect(frameRect); + _currentFrame = nextFrameNum(); + _tick += _delay; + } } debugC(6, kDraciAnimationDebugLevel, - "tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d", - _tick, _delay, _tick + _delay, _vm->_system->getMillis(), _currentFrame, _frames.size()); + "anim=%d tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d", + _id, _tick, _delay, _tick + _delay, _vm->_system->getMillis(), _currentFrame, _frames.size()); } uint Animation::nextFrameNum() { @@ -157,11 +160,21 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { } void AnimationManager::play(int id) { - getAnimation(id)->setPlaying(true); + Animation *anim = getAnimation(id); + + if (anim) + anim->setPlaying(true); + + debugC(5, kDraciAnimationDebugLevel, "Playing animation %d...", id); } void AnimationManager::stop(int id) { - getAnimation(id)->setPlaying(false); + Animation *anim = getAnimation(id); + + if (anim) + anim->setPlaying(false); + + debugC(5, kDraciAnimationDebugLevel, "Stopping animation %d...", id); } Animation *AnimationManager::getAnimation(int id) { -- cgit v1.2.3 From 586af0ab4264e022efe84fff8cdf080d580e8432 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 21:18:28 +0000 Subject: * From Game::GameObject removed the following _idxSeq, _numSeq, _animObj, _seqTab (not used anymore), added Common::Array _anims. * Handled cylic animations properly * Handled the Z coordinate properly svn-id: r42244 --- engines/draci/game.cpp | 22 +++++++++------------- engines/draci/game.h | 8 +++----- engines/draci/script.cpp | 3 ++- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 072d205436..ce09ff42a5 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -201,7 +201,7 @@ void Game::loadRoom(uint roomNum) { _vm->_screen->setPalette(f->_data, 0, kNumColours); } -int Game::loadAnimation(uint animNum) { +int Game::loadAnimation(uint animNum, uint z) { BAFile *animFile = _vm->_animationsArchive->getFile(animNum); Common::MemoryReadStream animationReader(animFile->_data, animFile->_length); @@ -211,10 +211,10 @@ int Game::loadAnimation(uint animNum) { // FIXME: handle these properly animationReader.readByte(); // Memory logic field, not used animationReader.readByte(); // Disable erasing field, not used - animationReader.readByte(); // Cyclic field, not used + bool cyclic = animationReader.readByte(); // Cyclic field, not used animationReader.readByte(); // Relative field, not used - Animation *anim = _vm->_anims->addAnimation(animNum, 254, false); + Animation *anim = _vm->_anims->addAnimation(animNum, z, false); for (uint i = 0; i < numFrames; ++i) { uint spriteNum = animationReader.readUint16LE() - 1; @@ -236,8 +236,7 @@ int Game::loadAnimation(uint animNum) { if (mirror) sp->setMirrorOn(); - // HACK: This is only for testing - anim->setLooping(true); + anim->setLooping(cyclic); anim->addFrame(sp); } @@ -262,8 +261,8 @@ void Game::loadObject(uint objNum) { obj->_imUse = objReader.readByte(); obj->_walkDir = objReader.readByte(); obj->_priority = objReader.readByte(); - obj->_idxSeq = objReader.readUint16LE(); - obj->_numSeq = objReader.readUint16LE(); + objReader.readUint16LE(); // idxSeq field, not used + objReader.readUint16LE(); // numSeq field, not used obj->_lookX = objReader.readUint16LE(); obj->_lookY = objReader.readUint16LE(); obj->_useX = objReader.readUint16LE(); @@ -272,10 +271,7 @@ void Game::loadObject(uint objNum) { obj->_useDir = objReader.readByte(); obj->_absNum = objNum; - obj->_animObj = 0; - obj->_seqTab = new uint16[obj->_numSeq]; - file = _vm->_objectsArchive->getFile(objNum * 3 + 1); obj->_title = new byte[file->_length]; memcpy(obj->_title, file->_data, file->_length); @@ -327,8 +323,9 @@ void Game::changeRoom(uint roomNum) { GameObject *obj = &_objects[i]; if (i != 0 && obj->_location == oldRoomNum) { - for (uint j = 0; j < obj->_numSeq; ++j) { - _vm->_anims->deleteAnimation(obj->_seqTab[j]); + for (uint j = 0; j < obj->_anims.size(); ++j) { + _vm->_anims->deleteAnimation(obj->_anims[j]); + obj->_anims.pop_back(); } } } @@ -352,7 +349,6 @@ Game::~Game() { } GameObject::~GameObject() { - delete[] _seqTab; delete[] _title; delete[] _program._bytecode; } diff --git a/engines/draci/game.h b/engines/draci/game.h index 1c572f95e9..124aa5c769 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -45,19 +45,17 @@ enum StructSizes { struct GameObject { - GameObject() : _seqTab(NULL), _title(NULL) {} + GameObject() : _title(NULL) {} ~GameObject(); uint16 _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; byte _walkDir; byte _priority; - uint16 _idxSeq, _numSeq; uint16 _lookX, _lookY, _useX, _useY; byte _lookDir, _useDir; uint16 _absNum; - byte _animObj; - uint16 *_seqTab; + Common::Array _anims; GPL2Program _program; byte *_title; byte _location; @@ -125,7 +123,7 @@ public: } void loadRoom(uint roomNum); - int loadAnimation(uint animNum); + int loadAnimation(uint animNum, uint z); void loadOverlays(); void loadObject(uint numObj); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index f45f45cb76..ed6e2b2802 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -226,7 +226,8 @@ void Script::load(Common::Queue ¶ms) { GameObject *obj = _vm->_game->getObject(objID); - obj->_seqTab[animID - obj->_idxSeq] = _vm->_game->loadAnimation(animID); + _vm->_game->loadAnimation(animID, obj->_priority); + obj->_anims.push_back(animID); } void Script::start(Common::Queue ¶ms) { -- cgit v1.2.3 From bab9293f979f706f9e2334011e4a34cf249ecddb Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 21:24:39 +0000 Subject: Implementend F_Not GPL function. svn-id: r42245 --- engines/draci/script.cpp | 6 +++++- engines/draci/script.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index ed6e2b2802..028d4a0b43 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -116,7 +116,7 @@ void Script::setupCommandList() { /** Functions used by the mathematical evaluator */ static const GPL2Function gplFunctions[] = { - { "Not", NULL }, + { "Not", &Script::funcNot }, { "Random", &Script::funcRandom }, { "IsIcoOn", NULL }, { "IsIcoAct", NULL }, @@ -218,6 +218,10 @@ int Script::funcRandom(int n) { return _vm->_rnd.getRandomNumber(n); } +int Script::funcNot(int n) { + return !n; +} + /* GPL commands */ void Script::load(Common::Queue ¶ms) { diff --git a/engines/draci/script.h b/engines/draci/script.h index 16bef9c7ff..89109aebc5 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -116,6 +116,7 @@ private: int operMod(int op1, int op2); int funcRandom(int n); + int funcNot(int n); void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From dd955bb08e57a13476afa4f852a97764fe6ad2a6 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 21:30:36 +0000 Subject: * Made Game::_variables private and, instead, added Game::{get,set}Variable() methods. * Removed obsolete comment about the cyclic field not being used in Game::loadAnimation() svn-id: r42246 --- engines/draci/game.cpp | 12 +++++++++++- engines/draci/game.h | 5 +++-- engines/draci/script.cpp | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index ce09ff42a5..cb8385b741 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -211,7 +211,9 @@ int Game::loadAnimation(uint animNum, uint z) { // FIXME: handle these properly animationReader.readByte(); // Memory logic field, not used animationReader.readByte(); // Disable erasing field, not used - bool cyclic = animationReader.readByte(); // Cyclic field, not used + + bool cyclic = animationReader.readByte(); + animationReader.readByte(); // Relative field, not used Animation *anim = _vm->_anims->addAnimation(animNum, z, false); @@ -339,6 +341,14 @@ int Game::getRoomNum() { return _currentRoom._roomNum; } +int Game::getVariable(int numVar) { + return _variables[numVar]; +} + +void Game::setVariable(int numVar, int value) { + _variables[numVar] = value; +} + Game::~Game() { delete[] _persons; delete[] _variables; diff --git a/engines/draci/game.h b/engines/draci/game.h index 124aa5c769..48f127666d 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -129,11 +129,12 @@ public: GameObject *getObject(uint objNum); - int *_variables; + int getVariable(int varNum); + void setVariable(int varNum, int value); private: DraciEngine *_vm; - + int *_variables; GameInfo *_info; Person *_persons; uint16 *_dialogOffsets; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 028d4a0b43..9047d6c8cc 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -303,10 +303,10 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathVariable: value = reader.readUint16LE(); - stk.push(_vm->_game->_variables[value-1]); + stk.push(_vm->_game->getVariable(value-1)); debugC(3, kDraciBytecodeDebugLevel, "\t\tvariable: %d (%d)", value, - _vm->_game->_variables[value-1]); + _vm->_game->getVariable(value-1)); break; case kMathFunctionCall: -- cgit v1.2.3 From 68ec1350c057c8342f6bf280f8a713922ce05a3d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 7 Jul 2009 21:46:34 +0000 Subject: Fixed two mismatched (de)allocations in BArchive and BAFile. svn-id: r42247 --- engines/draci/barchive.cpp | 2 +- engines/draci/barchive.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index cd0d4b2172..cbe019f8b2 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -251,7 +251,7 @@ void BArchive::closeArchive(void) { for (unsigned int i = 0; i < _fileCount; ++i) { if (_files[i]._data) { - delete _files[i]._data; + delete[] _files[i]._data; } } diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 185cfcb38d..5a4f5155f7 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -44,7 +44,7 @@ struct BAFile { /** Releases the file data (for memory considerations) */ void closeFile(void) { - delete _data; + delete[] _data; _data = NULL; } }; -- cgit v1.2.3 From d8c33f6836c821287ecb5fd8cfee12fb4dea2ef2 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 8 Jul 2009 00:34:53 +0000 Subject: * Implemented GPL jumps * Implemented c_If, c_Goto and c_Let opcodes * Changed the interpreter to work with signed ints instead of uints (the interpreter uses negative values sometimes) * Fixed documentation of Script::run() which said it is a disassembler (forgot to change it earlier) svn-id: r42249 --- engines/draci/script.cpp | 64 ++++++++++++++++++++++++++++++++++++------------ engines/draci/script.h | 7 +++++- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 9047d6c8cc..c676ef9d46 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -41,9 +41,9 @@ void Script::setupCommandList() { static const GPL2Command gplCommands[] = { { 0, 0, "gplend", 0, { 0 }, NULL }, { 0, 1, "exit", 0, { 0 }, NULL }, - { 1, 1, "goto", 1, { 3 }, NULL }, - { 2, 1, "Let", 2, { 3, 4 }, NULL }, - { 3, 1, "if", 2, { 4, 3 }, NULL }, + { 1, 1, "goto", 1, { 3 }, &Script::c_Goto }, + { 2, 1, "Let", 2, { 3, 4 }, &Script::c_Let }, + { 3, 1, "if", 2, { 4, 3 }, &Script::c_If }, { 4, 1, "Start", 2, { 3, 2 }, &Script::start }, { 5, 1, "Load", 2, { 3, 2 }, &Script::load }, { 5, 2, "StartPlay", 2, { 3, 2 }, NULL }, @@ -246,6 +246,27 @@ void Script::start(Common::Queue ¶ms) { _vm->_anims->play(animID); } +void Script::c_If(Common::Queue ¶ms) { + int expression = params.pop(); + int jump = params.pop(); + + if (expression) + _jump = jump; +} + +void Script::c_Goto(Common::Queue ¶ms) { + int jump = params.pop(); + + _jump = jump; +} + +void Script::c_Let(Common::Queue ¶ms) { + int var = params.pop() - 1; + int value = params.pop(); + + _vm->_game->setVariable(var, value); +} + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression @@ -258,7 +279,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { GPL2Function func; // Read in initial math object - obj = (mathExpressionObject)reader.readUint16LE(); + obj = (mathExpressionObject)reader.readSint16LE(); int value; int arg1, arg2, res; @@ -277,13 +298,13 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { // If the object type is not known, assume that it's a number default: case kMathNumber: - value = reader.readUint16LE(); + value = reader.readSint16LE(); stk.push(value); debugC(3, kDraciBytecodeDebugLevel, "\t\tnumber: %d", value); break; case kMathOperator: - value = reader.readUint16LE(); + value = reader.readSint16LE(); arg1 = stk.pop(); arg2 = stk.pop(); @@ -301,7 +322,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { break; case kMathVariable: - value = reader.readUint16LE(); + value = reader.readSint16LE(); stk.push(_vm->_game->getVariable(value-1)); @@ -310,7 +331,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { break; case kMathFunctionCall: - value = reader.readUint16LE(); + value = reader.readSint16LE(); // Fetch function func = _functionList[value-1]; @@ -337,7 +358,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { break; } - obj = (mathExpressionObject) reader.readUint16LE(); + obj = (mathExpressionObject) reader.readSint16LE(); } return stk.pop(); @@ -374,12 +395,12 @@ const GPL2Command *Script::findCommand(byte num, byte subnum) { } /** - * @brief GPL2 bytecode disassembler + * @brief GPL2 bytecode interpreter * @param program GPL program in the form of a GPL2Program struct * offset Offset into the program where execution should begin * * GPL2 is short for Game Programming Language 2 which is the script language - * used by Draci Historie. This is a simple disassembler for the language. + * used by Draci Historie. This is the interpreter for the language. * * A compiled GPL2 program consists of a stream of bytes representing commands * and their parameters. The syntax is as follows: @@ -423,6 +444,17 @@ int Script::run(GPL2Program program, uint16 offset) { const GPL2Command *cmd; do { + debugC(3, kDraciBytecodeDebugLevel, + "Program length = %d Current position = %d " + "Jump = %d New Position = %d", program._length, + reader.pos(), _jump, reader.pos() + _jump); + + // Account for GPL jump that some commands set + reader.seek(reader.pos() + _jump); + + // Reset jump + _jump = 0; + // Clear any parameters left on the stack from the previous command // This likely won't be needed once all commands are implemented params.clear(); @@ -440,22 +472,22 @@ int Script::run(GPL2Program program, uint16 offset) { int tmp; // Print command name - debugC(2, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); + debugC(1, kDraciBytecodeDebugLevel, "%s", cmd->_name.c_str()); for (int i = 0; i < cmd->_numParams; ++i) { if (cmd->_paramTypes[i] == 4) { - debugC(3, kDraciBytecodeDebugLevel, "\t"); + debugC(2, kDraciBytecodeDebugLevel, "\t"); params.push(handleMathExpression(reader)); } else { - tmp = reader.readUint16LE(); + tmp = reader.readSint16LE(); params.push(tmp); - debugC(3, kDraciBytecodeDebugLevel, "\t%hu", tmp); + debugC(2, kDraciBytecodeDebugLevel, "\t%d", tmp); } } } else { - debugC(2, kDraciBytecodeDebugLevel, "Unknown opcode %hu, %hu", + debugC(1, kDraciBytecodeDebugLevel, "Unknown opcode %d, %d", num, subnum); } diff --git a/engines/draci/script.h b/engines/draci/script.h index 89109aebc5..7007e563c4 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -86,17 +86,22 @@ struct GPL2Program { class Script { public: - Script(DraciEngine *vm) : _vm(vm) { setupCommandList(); }; + Script(DraciEngine *vm) : _vm(vm), _jump(0) { setupCommandList(); }; int run(GPL2Program program, uint16 offset); private: + int _jump; + /** List of all GPL commands. Initialised in the constructor. */ const GPL2Command *_commandList; const GPL2Operator *_operatorList; const GPL2Function *_functionList; + void c_If(Common::Queue ¶ms); + void c_Goto(Common::Queue ¶ms); + void c_Let(Common::Queue ¶ms); void load(Common::Queue ¶ms); void start(Common::Queue ¶ms); -- cgit v1.2.3 From 32d692aea6f57b41360f433ba65ad1b3459a7e86 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 8 Jul 2009 00:40:22 +0000 Subject: Made the engine clear some more caches when it changes rooms (room, sprites and palette caches). Made the DraciEngine destructor delete the rooms, overlays and animations archives. svn-id: r42250 --- engines/draci/draci.cpp | 3 +++ engines/draci/game.cpp | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index cef66c6092..e9df63f9cd 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -176,6 +176,9 @@ DraciEngine::~DraciEngine() { delete _paletteArchive; delete _objectsArchive; delete _spritesArchive; + delete _roomsArchive; + delete _overlaysArchive; + delete _animationsArchive; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index cb8385b741..ac26fb5871 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -316,7 +316,10 @@ void Game::loadOverlays() { } void Game::changeRoom(uint roomNum) { - _vm->_roomsArchive->clearCache(); + _vm->_roomsArchive->clearCache(); + _vm->_spritesArchive->clearCache(); + _vm->_paletteArchive->clearCache(); + _vm->_anims->deleteOverlays(); int oldRoomNum = _currentRoom._roomNum; -- cgit v1.2.3 From 0ec737db69cd838a9522aea7cdebe6d5bd9a1b60 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 8 Jul 2009 00:48:03 +0000 Subject: Stopped doing a screen update immediately after changing the palette. This caused a noisy effect when changing rooms because the palette was changed before the new scene was loaded. svn-id: r42251 --- engines/draci/screen.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index bc10249332..b6c740e20c 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -52,7 +52,6 @@ void Screen::setPaletteEmpty(unsigned int numEntries) { } _vm->_system->setPalette(_palette, 0, numEntries); - copyToScreen(); } /** @@ -81,7 +80,6 @@ void Screen::setPalette(byte *data, uint16 start, uint16 num) { } _vm->_system->setPalette(_palette, start, num); - copyToScreen(); } /** -- cgit v1.2.3 From 6b2991f488c4634f5663eb0734e543d311b82f84 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 8 Jul 2009 06:14:17 +0000 Subject: Made Script::run() seek in SEEK_CUR mode when jumping instead of the default SEEK_SET. It also now checks whether there is a non-zero jump value set before doing the jump. svn-id: r42254 --- engines/draci/script.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index c676ef9d46..c63c9faea6 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -450,7 +450,8 @@ int Script::run(GPL2Program program, uint16 offset) { reader.pos(), _jump, reader.pos() + _jump); // Account for GPL jump that some commands set - reader.seek(reader.pos() + _jump); + if (_jump != 0) + reader.seek(_jump, SEEK_CUR); // Reset jump _jump = 0; -- cgit v1.2.3 From a41d36de0f2db1ef6572d0a19a1015dd9500e129 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 12 Jul 2009 18:55:44 +0000 Subject: Fixed bug in the GPL math evaluator (GPL function results were not pushed onto the evaluation stack). svn-id: r42424 --- engines/draci/script.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index c63c9faea6..e9d35226ba 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -350,6 +350,9 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { // Calculate result res = (this->*(func._handler))(arg1); + + // Push the result on the evaluation stack + stk.push(res); debugC(3, kDraciBytecodeDebugLevel, "\t\tcall: %s(%d) (res: %d)", func._name.c_str(), arg1, res); -- cgit v1.2.3 From d369a257d1e9eb01b6104653ba2e0fcd6efb5980 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 12 Jul 2009 19:00:24 +0000 Subject: Enabled clearing the screen when the room changes since some rooms do not draw anything on some parts of the screen. svn-id: r42425 --- engines/draci/game.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index ac26fb5871..3832768f23 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -320,6 +320,8 @@ void Game::changeRoom(uint roomNum) { _vm->_spritesArchive->clearCache(); _vm->_paletteArchive->clearCache(); + _vm->_screen->clearScreen(); + _vm->_anims->deleteOverlays(); int oldRoomNum = _currentRoom._roomNum; -- cgit v1.2.3 From eef64cc737fd9a4877822281c88395b73f0720f7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 12 Jul 2009 19:02:08 +0000 Subject: Enabled some more rooms in the demo and disabled loading the former distributor logo. svn-id: r42426 --- engines/draci/game.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.h b/engines/draci/game.h index 48f127666d..e6eee9e041 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -111,7 +111,12 @@ public: // HACK: this is only for testing void incRoomNum() { int n = _currentRoom._roomNum; - n = n < 25 ? n+1 : n; + n = n < 37 ? n+1 : n; + + // disable former distributor logo + if (n == 30) + ++n; + _currentRoom._roomNum = n; } @@ -119,6 +124,11 @@ public: void decRoomNum() { int n = _currentRoom._roomNum; n = n > 0 ? n-1 : n; + + // disable former distributor logo + if (n == 30) + --n; + _currentRoom._roomNum = n; } -- cgit v1.2.3 From 77a810c0c9beed930a4b0ffe8e715bd22d7be448 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 12 Jul 2009 19:32:01 +0000 Subject: Moved the delay mechanism from Animation to Drawable since each frame in an animation can have a different delay. svn-id: r42427 --- engines/draci/animation.cpp | 15 +++++---------- engines/draci/animation.h | 3 --- engines/draci/game.cpp | 8 ++++---- engines/draci/sprite.cpp | 3 +++ engines/draci/sprite.h | 8 ++++++++ 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index d48560a550..c3f5a2dc95 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,7 +33,6 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _playing = false; _looping = false; - _delay = 0; _tick = _vm->_system->getMillis(); _currentFrame = 0; } @@ -52,12 +51,6 @@ void Animation::setLooping(bool looping) { looping, _id); } -void Animation::setDelay(uint delay) { - _delay = delay; - debugC(7, kDraciAnimationDebugLevel, "Setting delay to %u on animation %d", - delay, _id); -} - void Animation::nextFrame(bool force) { // If there's only one or no frames, return @@ -65,8 +58,9 @@ void Animation::nextFrame(bool force) { return; Common::Rect frameRect = _frames[_currentFrame]->getRect(); + Drawable *frame = _frames[_currentFrame]; - if (force || (_tick + _delay <= _vm->_system->getMillis())) { + if (force || (_tick + frame->getDelay() <= _vm->_system->getMillis())) { // If we are at the last frame and not looping, stop the animation // The animation is also restarted to frame zero if ((_currentFrame == getFramesNum() - 1) && !_looping) { @@ -75,13 +69,14 @@ void Animation::nextFrame(bool force) { } else { _vm->_screen->getSurface()->markDirtyRect(frameRect); _currentFrame = nextFrameNum(); - _tick += _delay; + _tick += frame->getDelay(); } } debugC(6, kDraciAnimationDebugLevel, "anim=%d tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d", - _id, _tick, _delay, _tick + _delay, _vm->_system->getMillis(), _currentFrame, _frames.size()); + _id, _tick, frame->getDelay(), _tick + frame->getDelay(), _vm->_system->getMillis(), + _currentFrame, _frames.size()); } uint Animation::nextFrameNum() { diff --git a/engines/draci/animation.h b/engines/draci/animation.h index cef8182f7b..fea7fb3f89 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -46,8 +46,6 @@ public: void setID(int id); int getID(); - void setDelay(uint delay); - void nextFrame(bool force = false); void drawFrame(Surface *surface); @@ -68,7 +66,6 @@ private: int _id; uint _currentFrame; uint _z; - uint _delay; uint _tick; bool _playing; bool _looping; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3832768f23..2fbb65b829 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -217,7 +217,9 @@ int Game::loadAnimation(uint animNum, uint z) { animationReader.readByte(); // Relative field, not used Animation *anim = _vm->_anims->addAnimation(animNum, z, false); - + + anim->setLooping(cyclic); + for (uint i = 0; i < numFrames; ++i) { uint spriteNum = animationReader.readUint16LE() - 1; int x = animationReader.readSint16LE(); @@ -229,8 +231,6 @@ int Game::loadAnimation(uint animNum, uint z) { uint freq = animationReader.readUint16LE(); uint delay = animationReader.readUint16LE(); - anim->setDelay(delay * 10); - BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, true); @@ -238,7 +238,7 @@ int Game::loadAnimation(uint animNum, uint z) { if (mirror) sp->setMirrorOn(); - anim->setLooping(cyclic); + sp->setDelay(delay * 10); anim->addFrame(sp); } diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index aad7753b03..dae7a289a2 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -61,6 +61,7 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, int x, int y, _height = height; _x = x; _y = y; + _delay = 0; _mirror = false; @@ -83,6 +84,7 @@ Sprite::Sprite(byte *sprite_data, uint16 length, int x, int y, bool columnwise) _x = x; _y = y; + _delay = 0; _mirror = false; @@ -180,6 +182,7 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, _x = x; _y = y; + _delay = 0; _text = new byte[len]; memcpy(_text, str.c_str(), len); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 3e881914ca..38ee2736ea 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -49,12 +49,20 @@ public: virtual void setX(int x) { _x = x; } virtual void setY(int y) { _y = y; } + void setDelay(int delay) { _delay = delay; } + int getDelay() { return _delay; } + virtual Common::Rect getRect() const = 0; private: uint16 _width; //!< Width of the sprite uint16 _height; //!< Height of the sprite int _x, _y; //!< Sprite coordinates + + /** The time a drawable should stay on the screen + * before being replaced by another or deleted + */ + int _delay; }; /** -- cgit v1.2.3 From 224d8c087acac4e3f21913b6268f82c1ab9faca8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 13 Jul 2009 19:08:04 +0000 Subject: Added Surface::fill() method and made Screen::fillScreen() use that instead of filling the surface manually. Changed Surface to use uint instead of uint8 throughout. svn-id: r42447 --- engines/draci/screen.cpp | 5 +---- engines/draci/surface.cpp | 13 +++++++++++-- engines/draci/surface.h | 7 ++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/engines/draci/screen.cpp b/engines/draci/screen.cpp index b6c740e20c..781147806f 100644 --- a/engines/draci/screen.cpp +++ b/engines/draci/screen.cpp @@ -134,11 +134,8 @@ void Screen::clearScreen() const { * Fills the screen with the specified colour and marks the whole screen dirty. */ void Screen::fillScreen(uint8 colour) const { - byte *ptr = (byte *)_surface->getBasePtr(0, 0); - + _surface->fill(colour); _surface->markDirty(); - - memset(ptr, colour, kScreenWidth * kScreenHeight); } /** diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp index 148c24633b..636ec0c4ac 100644 --- a/engines/draci/surface.cpp +++ b/engines/draci/surface.cpp @@ -106,15 +106,24 @@ Common::List *Surface::getDirtyRects() { /** * @brief Returns the current transparent colour of the surface */ -uint8 Surface::getTransparentColour() { +uint Surface::getTransparentColour() { return _transparentColour; } /** * @brief Sets the surface's transparent colour */ -void Surface::setTransparentColour(uint8 colour) { +void Surface::setTransparentColour(uint colour) { _transparentColour = colour; } +/** + * @ brief Fills the surface with the specified colour + */ +void Surface::fill(uint colour) { + byte *ptr = (byte *)getBasePtr(0, 0); + + memset(ptr, colour, w * h); +} + } // End of namespace Draci diff --git a/engines/draci/surface.h b/engines/draci/surface.h index 20df29d7f9..db564ec2e5 100644 --- a/engines/draci/surface.h +++ b/engines/draci/surface.h @@ -42,14 +42,15 @@ public: void markDirty(); void markClean(); bool needsFullUpdate(); - uint8 getTransparentColour(); - void setTransparentColour(uint8 colour); + uint getTransparentColour(); + void setTransparentColour(uint colour); + void fill(uint colour); private: /** The current transparent colour of the surface. See getTransparentColour() and * setTransparentColour(). */ - uint8 _transparentColour; + uint _transparentColour; /** Set when the surface is scheduled for a full update. * See markDirty(), markClean(). Accessed via needsFullUpdate(). -- cgit v1.2.3 From f655999c1581f4600e0c4abca1cc67591631126c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 13 Jul 2009 19:11:24 +0000 Subject: Fixed bug in the NoScene logo room; the screen surface is now cleared between scene redraws (filled with the colour 0) to fix artifacts when animating the logo. svn-id: r42448 --- engines/draci/animation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index c3f5a2dc95..c6528fae46 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -208,7 +208,11 @@ void AnimationManager::addOverlay(Drawable *overlay, uint z) { } void AnimationManager::drawScene(Surface *surf) { - + + // Fill the screen with colour zero since some rooms may rely on the screen being black + _vm->_screen->getSurface()->fill(0); + + Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { -- cgit v1.2.3 From f8c20b9e9c68dc670ddb0179abed6dc12509c244 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 13 Jul 2009 19:24:22 +0000 Subject: Renamed Game::_itemStatus to _iconStatus. Added an assert to check if the number of icons is correct. svn-id: r42449 --- engines/draci/game.cpp | 12 +++++++----- engines/draci/game.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 2fbb65b829..4d6c77a169 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -103,11 +103,12 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _variables[i] = variableData.readUint16LE(); } - // Read in item status + // Read in item icon status file = initArchive.getFile(1); - _itemStatus = new byte[file->_length]; - memcpy(_itemStatus, file->_data, file->_length); + _iconStatus = new byte[file->_length]; + memcpy(_iconStatus, file->_data, file->_length); + uint numIcons = file->_length; // Read in object status @@ -130,7 +131,8 @@ Game::Game(DraciEngine *vm) : _vm(vm) { assert(numDialogs == _info->_numDialogs); assert(numPersons == _info->_numPersons); assert(numVariables == _info->_numVariables); - assert(numObjects == _info->_numObjects); + assert(numObjects == _info->_numObjects); + assert(numIcons == _info->_numIcons); } void Game::init() { @@ -358,7 +360,7 @@ Game::~Game() { delete[] _persons; delete[] _variables; delete[] _dialogOffsets; - delete[] _itemStatus; + delete[] _iconStatus; delete[] _objects; delete _info; } diff --git a/engines/draci/game.h b/engines/draci/game.h index e6eee9e041..da12771fc7 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -148,7 +148,7 @@ private: GameInfo *_info; Person *_persons; uint16 *_dialogOffsets; - byte *_itemStatus; + byte *_iconStatus; GameObject *_objects; Room _currentRoom; }; -- cgit v1.2.3 From 04e4bfdbbed01d71f3d5c74d4e3a2090430a1b35 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 13 Jul 2009 19:53:53 +0000 Subject: * Implemented the following GPL functions: IsIcoOn, IcoStat, IsObjOn, IsObjOff, IsObjAway * Changed GameObject::_location to an int since we sometimes use location -1. * Some more uint <-> int changes to prevent comparisons between signed and unsigned. svn-id: r42452 --- engines/draci/game.cpp | 8 ++++++-- engines/draci/game.h | 6 ++++-- engines/draci/script.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++----- engines/draci/script.h | 6 ++++++ 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 4d6c77a169..e7f1b2d454 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -144,7 +144,7 @@ void Game::init() { changeRoom(0); } -void Game::loadRoom(uint roomNum) { +void Game::loadRoom(int roomNum) { BAFile *f; f = _vm->_roomsArchive->getFile(roomNum * 4); @@ -208,7 +208,7 @@ int Game::loadAnimation(uint animNum, uint z) { BAFile *animFile = _vm->_animationsArchive->getFile(animNum); Common::MemoryReadStream animationReader(animFile->_data, animFile->_length); - int numFrames = animationReader.readByte(); + uint numFrames = animationReader.readByte(); // FIXME: handle these properly animationReader.readByte(); // Memory logic field, not used @@ -356,6 +356,10 @@ void Game::setVariable(int numVar, int value) { _variables[numVar] = value; } +int Game::getIconStatus(int iconID) { + return _iconStatus[iconID]; +} + Game::~Game() { delete[] _persons; delete[] _variables; diff --git a/engines/draci/game.h b/engines/draci/game.h index da12771fc7..c9f913dbc8 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -58,7 +58,7 @@ struct GameObject { Common::Array _anims; GPL2Program _program; byte *_title; - byte _location; + int _location; bool _visible; }; @@ -132,7 +132,7 @@ public: _currentRoom._roomNum = n; } - void loadRoom(uint roomNum); + void loadRoom(int roomNum); int loadAnimation(uint animNum, uint z); void loadOverlays(); void loadObject(uint numObj); @@ -142,6 +142,8 @@ public: int getVariable(int varNum); void setVariable(int varNum, int value); + int getIconStatus(int iconID); + private: DraciEngine *_vm; int *_variables; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index e9d35226ba..e2c902cf6f 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -118,13 +118,13 @@ void Script::setupCommandList() { static const GPL2Function gplFunctions[] = { { "Not", &Script::funcNot }, { "Random", &Script::funcRandom }, - { "IsIcoOn", NULL }, + { "IsIcoOn", &Script::funcIsIcoOn }, { "IsIcoAct", NULL }, - { "IcoStat", NULL }, + { "IcoStat", &Script::funcIcoStat }, { "ActIco", NULL }, - { "IsObjOn", NULL }, - { "IsObjOff", NULL }, - { "IsObjAway", NULL }, + { "IsObjOn", &Script::funcIsObjOn }, + { "IsObjOff", &Script::funcIsObjOff }, + { "IsObjAway", &Script::funcIsObjAway }, { "ObjStat", NULL }, { "LastBlock", NULL }, { "AtBegin", NULL }, @@ -222,6 +222,46 @@ int Script::funcNot(int n) { return !n; } +int Script::funcIsIcoOn(int iconID) { + iconID -= 1; + + return _vm->_game->getIconStatus(iconID) == 1; +} + +int Script::funcIcoStat(int iconID) { + iconID -= 1; + + int status = _vm->_game->getIconStatus(iconID); + return (status == 1) ? 1 : 2; +} + +int Script::funcIsObjOn(int objID) { + objID -= 1; + + GameObject *obj = _vm->_game->getObject(objID); + + return obj->_visible; +} + +int Script::funcIsObjOff(int objID) { + objID -= 1; + + GameObject *obj = _vm->_game->getObject(objID); + + // We index locations from 0 (as opposed to the original player where it was from 1) + // That's why the "invalid" location 0 from the data files is converted to -1 + return !obj->_visible && obj->_location != -1; +} + +int Script::funcIsObjAway(int objID) { + objID -= 1; + + GameObject *obj = _vm->_game->getObject(objID); + + // see Script::funcIsObjOff + return !obj->_visible && obj->_location == -1; +} + /* GPL commands */ void Script::load(Common::Queue ¶ms) { diff --git a/engines/draci/script.h b/engines/draci/script.h index 7007e563c4..d8e9a2f49f 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -122,6 +122,12 @@ private: int funcRandom(int n); int funcNot(int n); + int funcIsIcoOn(int iconID); + int funcIcoStat(int iconID); + int funcIsObjOn(int objID); + int funcIsObjOff(int objID); + int funcIsObjAway(int objID); + void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From 25b884512d10023fb0004337bbe4ec47f83c6650 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 14 Jul 2009 00:41:17 +0000 Subject: Made Game allocate its _info member statically instead of dinamically. svn-id: r42464 --- engines/draci/game.cpp | 50 ++++++++++++++++++++++++-------------------------- engines/draci/game.h | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index e7f1b2d454..8a4500c04c 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -72,24 +72,23 @@ Game::Game(DraciEngine *vm) : _vm(vm) { file = initArchive.getFile(3); Common::MemoryReadStream gameData(file->_data, file->_length); - _info = new GameInfo(); - _info->_currentRoom = gameData.readByte() - 1; - _info->_mapRoom = gameData.readByte() - 1; - _info->_numObjects = gameData.readUint16LE(); - _info->_numIcons = gameData.readUint16LE(); - _info->_numVariables = gameData.readByte(); - _info->_numPersons = gameData.readByte(); - _info->_numDialogs = gameData.readByte(); - _info->_maxIconWidth = gameData.readUint16LE(); - _info->_maxIconHeight = gameData.readUint16LE(); - _info->_musicLength = gameData.readUint16LE(); - _info->_crc[0] = gameData.readUint16LE(); - _info->_crc[1] = gameData.readUint16LE(); - _info->_crc[2] = gameData.readUint16LE(); - _info->_crc[3] = gameData.readUint16LE(); - - _info->_numDialogBlocks = curOffset; + _info._currentRoom = gameData.readByte() - 1; + _info._mapRoom = gameData.readByte() - 1; + _info._numObjects = gameData.readUint16LE(); + _info._numIcons = gameData.readUint16LE(); + _info._numVariables = gameData.readByte(); + _info._numPersons = gameData.readByte(); + _info._numDialogs = gameData.readByte(); + _info._maxIconWidth = gameData.readUint16LE(); + _info._maxIconHeight = gameData.readUint16LE(); + _info._musicLength = gameData.readUint16LE(); + _info._crc[0] = gameData.readUint16LE(); + _info._crc[1] = gameData.readUint16LE(); + _info._crc[2] = gameData.readUint16LE(); + _info._crc[3] = gameData.readUint16LE(); + + _info._numDialogBlocks = curOffset; // Read in variables @@ -128,11 +127,11 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _objects[i]._location = (~(1 << 7) & tmp) - 1; } - assert(numDialogs == _info->_numDialogs); - assert(numPersons == _info->_numPersons); - assert(numVariables == _info->_numVariables); - assert(numObjects == _info->_numObjects); - assert(numIcons == _info->_numIcons); + assert(numDialogs == _info._numDialogs); + assert(numPersons == _info._numPersons); + assert(numVariables == _info._numVariables); + assert(numObjects == _info._numObjects); + assert(numIcons == _info._numIcons); } void Game::init() { @@ -172,7 +171,7 @@ void Game::loadRoom(int roomNum) { _currentRoom._escRoom = roomReader.readByte() - 1; _currentRoom._numGates = roomReader.readByte(); - for (uint i = 0; i < _info->_numObjects; ++i) { + for (uint i = 0; i < _info._numObjects; ++i) { debugC(1, kDraciLogicDebugLevel, "Checking if object %d (%d) is at the current location (%d)", i, _objects[i]._location, roomNum); @@ -186,7 +185,7 @@ void Game::loadRoom(int roomNum) { // Run the init scripts for room objects // We can't do this in the above loop because some objects' scripts reference // other objects that may not yet be loaded - for (uint i = 0; i < _info->_numObjects; ++i) { + for (uint i = 0; i < _info._numObjects; ++i) { if (_objects[i]._location == roomNum) { _vm->_script->run(getObject(i)->_program, getObject(i)->_init); } @@ -328,7 +327,7 @@ void Game::changeRoom(uint roomNum) { int oldRoomNum = _currentRoom._roomNum; - for (uint i = 0; i < _info->_numObjects; ++i) { + for (uint i = 0; i < _info._numObjects; ++i) { GameObject *obj = &_objects[i]; if (i != 0 && obj->_location == oldRoomNum) { @@ -366,7 +365,6 @@ Game::~Game() { delete[] _dialogOffsets; delete[] _iconStatus; delete[] _objects; - delete _info; } GameObject::~GameObject() { diff --git a/engines/draci/game.h b/engines/draci/game.h index c9f913dbc8..c68990dace 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -147,7 +147,7 @@ public: private: DraciEngine *_vm; int *_variables; - GameInfo *_info; + GameInfo _info; Person *_persons; uint16 *_dialogOffsets; byte *_iconStatus; -- cgit v1.2.3 From d5e16118461290b13af19bd37b8b30bea6c15528 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 14 Jul 2009 00:51:35 +0000 Subject: Renamed GameInfo::_currentRoom to _startRoom to better reflect its purpose. svn-id: r42465 --- engines/draci/game.cpp | 2 +- engines/draci/game.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 8a4500c04c..0df1d64879 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -73,7 +73,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { file = initArchive.getFile(3); Common::MemoryReadStream gameData(file->_data, file->_length); - _info._currentRoom = gameData.readByte() - 1; + _info._startRoom = gameData.readByte() - 1; _info._mapRoom = gameData.readByte() - 1; _info._numObjects = gameData.readUint16LE(); _info._numIcons = gameData.readUint16LE(); diff --git a/engines/draci/game.h b/engines/draci/game.h index c68990dace..4f1ec66aa3 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -63,7 +63,7 @@ struct GameObject { }; struct GameInfo { - byte _currentRoom; + byte _startRoom; byte _mapRoom; uint16 _numObjects; uint16 _numIcons; -- cgit v1.2.3 From 6d51a3ead4eae4a2c8fbb8cce20b4c1e4bbd4c64 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 14 Jul 2009 18:11:33 +0000 Subject: * Fixed bug in Animation which made the first frame of an animation being drawn after it's stopped * Fixed debugging info when starting and stopping animations svn-id: r42485 --- engines/draci/animation.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index c6528fae46..2a333445ec 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -53,8 +53,8 @@ void Animation::setLooping(bool looping) { void Animation::nextFrame(bool force) { - // If there's only one or no frames, return - if (getFramesNum() < 2) + // If there's only one or no frames, or if the animation is not playing, return + if (getFramesNum() < 2 || !_playing) return; Common::Rect frameRect = _frames[_currentFrame]->getRect(); @@ -89,7 +89,8 @@ uint Animation::nextFrameNum() { void Animation::drawFrame(Surface *surface) { - if (_frames.size() == 0) + // If there are no frames or the animation is not playing, return + if (_frames.size() == 0 || !_playing) return; if (_id == kOverlayImage) { @@ -157,19 +158,21 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { void AnimationManager::play(int id) { Animation *anim = getAnimation(id); - if (anim) + if (anim) { anim->setPlaying(true); - debugC(5, kDraciAnimationDebugLevel, "Playing animation %d...", id); + debugC(5, kDraciAnimationDebugLevel, "Playing animation %d...", id); + } } void AnimationManager::stop(int id) { Animation *anim = getAnimation(id); - if (anim) + if (anim) { anim->setPlaying(false); - - debugC(5, kDraciAnimationDebugLevel, "Stopping animation %d...", id); + + debugC(5, kDraciAnimationDebugLevel, "Stopping animation %d...", id); + } } Animation *AnimationManager::getAnimation(int id) { @@ -212,7 +215,6 @@ void AnimationManager::drawScene(Surface *surf) { // Fill the screen with colour zero since some rooms may rely on the screen being black _vm->_screen->getSurface()->fill(0); - Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { -- cgit v1.2.3 From 4ef46f4bb07f3736f7a90d70b6907bb03ff04632 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 14 Jul 2009 19:13:49 +0000 Subject: Adjusted levels for some Game debug messages and added some new ones. svn-id: r42489 --- engines/draci/game.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 0df1d64879..f5d3a15c85 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -172,12 +172,12 @@ void Game::loadRoom(int roomNum) { _currentRoom._numGates = roomReader.readByte(); for (uint i = 0; i < _info._numObjects; ++i) { - debugC(1, kDraciLogicDebugLevel, + debugC(2, kDraciLogicDebugLevel, "Checking if object %d (%d) is at the current location (%d)", i, _objects[i]._location, roomNum); if (_objects[i]._location == roomNum) { - debugC(1, kDraciLogicDebugLevel, "Loading object %d from room %d", i, roomNum); + debugC(2, kDraciLogicDebugLevel, "Loading object %d from room %d", i, roomNum); loadObject(i); } } @@ -317,6 +317,9 @@ void Game::loadOverlays() { } void Game::changeRoom(uint roomNum) { + + debugC(1, kDraciLogicDebugLevel, "Changing to room %d", roomNum); + _vm->_roomsArchive->clearCache(); _vm->_spritesArchive->clearCache(); _vm->_paletteArchive->clearCache(); -- cgit v1.2.3 From a4a3ad123cb407fc9862acb43d3ca2ea27d2da2b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 15 Jul 2009 18:16:54 +0000 Subject: Renamed Font::setFont() to loadFont(). Removed DraciEngine::_font and added _smallFont and _bigFont so each font can be handled separately. svn-id: r42514 --- engines/draci/draci.cpp | 13 ++++++++----- engines/draci/draci.h | 4 +++- engines/draci/font.cpp | 16 ++-------------- engines/draci/font.h | 3 +-- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index e9df63f9cd..1575ee2545 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -85,16 +85,16 @@ int DraciEngine::init() { _overlaysArchive = new BArchive(overlaysPath); _animationsArchive = new BArchive(animationsPath); + // Load the game's fonts + _smallFont = new Font(kFontSmall); + _bigFont = new Font(kFontBig); + _screen = new Screen(this); - _font = new Font(); _anims = new AnimationManager(this); _mouse = new Mouse(this); _script = new Script(this); _game = new Game(this); - // Load default font - _font->setFont(kFontBig); - if(!_objectsArchive->isOpen()) { debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening objects archive failed"); return Common::kUnknownError; @@ -166,8 +166,11 @@ DraciEngine::~DraciEngine() { // Dispose your resources here // TODO: Investigate possibility of using sharedPtr or similar + + delete _smallFont; + delete _bigFont; + delete _screen; - delete _font; delete _mouse; delete _game; delete _script; diff --git a/engines/draci/draci.h b/engines/draci/draci.h index bdab419e64..c01a30a7e4 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -51,13 +51,15 @@ public: bool hasFeature(Engine::EngineFeature f) const; - Font *_font; Screen *_screen; Mouse *_mouse; Game *_game; Script *_script; AnimationManager *_anims; + Font *_smallFont; + Font *_bigFont; + BArchive *_objectsArchive; BArchive *_spritesArchive; BArchive *_paletteArchive; diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 8a6f353876..f1ef984adf 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -33,18 +33,6 @@ namespace Draci { const Common::String kFontSmall("Small.fon"); const Common::String kFontBig("Big.fon"); -Font::Font() { - - _fontHeight = 0; - _maxCharWidth = 0; - _charWidths = NULL; - _charData = NULL; - - setFont(kFontBig); - - _currentFontColour = kFontColour1; -} - Font::Font(const Common::String &filename) { _fontHeight = 0; @@ -52,7 +40,7 @@ Font::Font(const Common::String &filename) { _charWidths = NULL; _charData = NULL; - setFont(filename); + loadFont(filename); _currentFontColour = kFontColour1; } @@ -88,7 +76,7 @@ void Font::setColour(uint8 colour) { * [138 * fontHeight * maxWidth bytes] character data, stored row-wise */ -bool Font::setFont(const Common::String &filename) { +bool Font::loadFont(const Common::String &filename) { // Free previously loaded font (if any) freeFont(); diff --git a/engines/draci/font.h b/engines/draci/font.h index cdce071e5a..c269124919 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -53,11 +53,10 @@ class Font { public: - Font(); Font(const Common::String &filename); ~Font(); - bool setFont(const Common::String &filename); + bool loadFont(const Common::String &filename); uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; -- cgit v1.2.3 From ffffc1bea4056e6f00edc935371636352962790b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 15 Jul 2009 19:06:24 +0000 Subject: * Changed Game members _numMasks, _init, _look, _use and _canUse from uint16 to int * Modified Game::loadRoom to load gates and execute their scripts * The first room loaded is now Game::_info._startRoom instead of 0 * Fixed reading of _pers0 and _persStep from the data files (they are 6 instead of 12 bytes) * Added more debug info to Script and Game svn-id: r42515 --- engines/draci/game.cpp | 53 +++++++++++++++++++++++++++++++++++++++--------- engines/draci/game.h | 4 ++-- engines/draci/script.cpp | 14 +++++++------ 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index f5d3a15c85..31b2d612fa 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -138,9 +138,10 @@ void Game::init() { loadObject(kDragonObject); GameObject *dragon = getObject(kDragonObject); + debugC(4, kDraciLogicDebugLevel, "Running init program for the dragon object..."); _vm->_script->run(dragon->_program, dragon->_init); - changeRoom(0); + changeRoom(_info._startRoom); } void Game::loadRoom(int roomNum) { @@ -156,28 +157,52 @@ void Game::loadRoom(int roomNum) { _currentRoom._music = roomReader.readByte(); _currentRoom._map = roomReader.readByte(); _currentRoom._palette = roomReader.readByte() - 1; - _currentRoom._numMasks = roomReader.readUint16LE(); - _currentRoom._init = roomReader.readUint16LE(); - _currentRoom._look = roomReader.readUint16LE(); - _currentRoom._use = roomReader.readUint16LE(); - _currentRoom._canUse = roomReader.readUint16LE(); + _currentRoom._numMasks = roomReader.readSint16LE(); + _currentRoom._init = roomReader.readSint16LE(); + _currentRoom._look = roomReader.readSint16LE(); + _currentRoom._use = roomReader.readSint16LE(); + _currentRoom._canUse = roomReader.readSint16LE(); _currentRoom._imInit = roomReader.readByte(); _currentRoom._imLook = roomReader.readByte(); _currentRoom._imUse = roomReader.readByte(); _currentRoom._mouseOn = roomReader.readByte(); _currentRoom._heroOn = roomReader.readByte(); - roomReader.read(&_currentRoom._pers0, 12); - roomReader.read(&_currentRoom._persStep, 12); + roomReader.read(&_currentRoom._pers0, 6); + roomReader.read(&_currentRoom._persStep, 6); _currentRoom._escRoom = roomReader.readByte() - 1; _currentRoom._numGates = roomReader.readByte(); + debugC(4, kDraciLogicDebugLevel, "_music: %d", _currentRoom._music); + debugC(4, kDraciLogicDebugLevel, "_map: %d", _currentRoom._map); + debugC(4, kDraciLogicDebugLevel, "_palette: %d", _currentRoom._palette); + debugC(4, kDraciLogicDebugLevel, "_numMasks: %d", _currentRoom._numMasks); + debugC(4, kDraciLogicDebugLevel, "_init: %d", _currentRoom._init); + debugC(4, kDraciLogicDebugLevel, "_look: %d", _currentRoom._look); + debugC(4, kDraciLogicDebugLevel, "_use: %d", _currentRoom._use); + debugC(4, kDraciLogicDebugLevel, "_canUse: %d", _currentRoom._canUse); + debugC(4, kDraciLogicDebugLevel, "_imInit: %d", _currentRoom._imInit); + debugC(4, kDraciLogicDebugLevel, "_imLook: %d", _currentRoom._imLook); + debugC(4, kDraciLogicDebugLevel, "_imUse: %d", _currentRoom._imUse); + debugC(4, kDraciLogicDebugLevel, "_mouseOn: %d", _currentRoom._mouseOn); + debugC(4, kDraciLogicDebugLevel, "_heroOn: %d", _currentRoom._heroOn); + debugC(4, kDraciLogicDebugLevel, "_pers0: %f", _currentRoom._pers0); + debugC(4, kDraciLogicDebugLevel, "_persStep: %f", _currentRoom._persStep); + debugC(4, kDraciLogicDebugLevel, "_escRoom: %d", _currentRoom._escRoom); + debugC(4, kDraciLogicDebugLevel, "_numGates: %d", _currentRoom._numGates); + + Common::Array gates; + + for (uint i = 0; i < _currentRoom._numGates; ++i) { + gates.push_back(roomReader.readSint16LE()); + } + for (uint i = 0; i < _info._numObjects; ++i) { - debugC(2, kDraciLogicDebugLevel, + debugC(7, kDraciLogicDebugLevel, "Checking if object %d (%d) is at the current location (%d)", i, _objects[i]._location, roomNum); if (_objects[i]._location == roomNum) { - debugC(2, kDraciLogicDebugLevel, "Loading object %d from room %d", i, roomNum); + debugC(6, kDraciLogicDebugLevel, "Loading object %d from room %d", i, roomNum); loadObject(i); } } @@ -187,6 +212,8 @@ void Game::loadRoom(int roomNum) { // other objects that may not yet be loaded for (uint i = 0; i < _info._numObjects; ++i) { if (_objects[i]._location == roomNum) { + debugC(6, kDraciLogicDebugLevel, + "Running init program for object %d (offset %d)", i, getObject(i)->_init); _vm->_script->run(getObject(i)->_program, getObject(i)->_init); } } @@ -196,8 +223,14 @@ void Game::loadRoom(int roomNum) { _currentRoom._program._length = f->_length; memcpy(_currentRoom._program._bytecode, f->_data, f->_length); + debugC(4, kDraciLogicDebugLevel, "Running room init program..."); _vm->_script->run(_currentRoom._program, _currentRoom._init); + for (uint i = 0; i < _currentRoom._numGates; ++i) { + debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); + _vm->_script->run(_currentRoom._program, gates[i]); + } + f = _vm->_paletteArchive->getFile(_currentRoom._palette); _vm->_screen->setPalette(f->_data, 0, kNumColours); } diff --git a/engines/draci/game.h b/engines/draci/game.h index 4f1ec66aa3..d7d352ab6e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -86,8 +86,8 @@ struct Room { byte _music; byte _map; byte _palette; - uint16 _numMasks; - uint16 _init, _look, _use, _canUse; + int _numMasks; + int _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; bool _mouseOn, _heroOn; double _pers0, _persStep; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index e2c902cf6f..d22b7b4941 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -484,17 +484,19 @@ int Script::run(GPL2Program program, uint16 offset) { // Seek to the requested part of the program reader.seek(offset); + debugC(3, kDraciBytecodeDebugLevel, + "Starting GPL program at offset %d (program length: %d)", offset, program._length); + const GPL2Command *cmd; do { - debugC(3, kDraciBytecodeDebugLevel, - "Program length = %d Current position = %d " - "Jump = %d New Position = %d", program._length, - reader.pos(), _jump, reader.pos() + _jump); - // Account for GPL jump that some commands set - if (_jump != 0) + if (_jump != 0) { + debugC(6, kDraciBytecodeDebugLevel, + "Jumping from offset %d to %d (%d bytes)", + reader.pos(), reader.pos() + _jump, _jump); reader.seek(_jump, SEEK_CUR); + } // Reset jump _jump = 0; -- cgit v1.2.3 From 1bf574aaa9e956bf6f6bcf730382a5f7967f2aa6 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 16 Jul 2009 12:07:41 +0000 Subject: Added proper cursor state handling (when in rooms that don't use the mouse). Added a HACK note for running the gates' scripts. svn-id: r42532 --- engines/draci/draci.cpp | 3 --- engines/draci/game.cpp | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 1575ee2545..3041c70341 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -139,9 +139,6 @@ int DraciEngine::go() { _game->init(); - _mouse->setCursorType(kNormalCursor); - _mouse->cursorOn(); - Common::Event event; bool quit = false; while (!quit) { diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 31b2d612fa..c75b1df503 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -142,6 +142,8 @@ void Game::init() { _vm->_script->run(dragon->_program, dragon->_init); changeRoom(_info._startRoom); + + _vm->_mouse->setCursorType(kNormalCursor); } void Game::loadRoom(int roomNum) { @@ -190,6 +192,17 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "_escRoom: %d", _currentRoom._escRoom); debugC(4, kDraciLogicDebugLevel, "_numGates: %d", _currentRoom._numGates); + + // Set cursor state + if (_currentRoom._mouseOn) { + debugC(6, kDraciLogicDebugLevel, "Mouse: ON"); + _vm->_mouse->cursorOn(); + } else { + debugC(6, kDraciLogicDebugLevel, "Mouse: OFF"); + _vm->_mouse->cursorOff(); + } + + Common::Array gates; for (uint i = 0; i < _currentRoom._numGates; ++i) { @@ -226,6 +239,8 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "Running room init program..."); _vm->_script->run(_currentRoom._program, _currentRoom._init); + // HACK: Gates' scripts shouldn't be run unconditionally + // This is for testing for (uint i = 0; i < _currentRoom._numGates; ++i) { debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); _vm->_script->run(_currentRoom._program, gates[i]); -- cgit v1.2.3 From 3d36ad3e677a75f48018336b04d5137b33cbcfb9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 16 Jul 2009 15:00:46 +0000 Subject: Fixed loading the location's walking map index (needed to subtract 1). svn-id: r42534 --- engines/draci/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index c75b1df503..e7bafa17ee 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -157,7 +157,7 @@ void Game::loadRoom(int roomNum) { roomReader.readUint32LE(); // Pointer to room title, not used _currentRoom._music = roomReader.readByte(); - _currentRoom._map = roomReader.readByte(); + _currentRoom._map = roomReader.readByte() - 1; _currentRoom._palette = roomReader.readByte() - 1; _currentRoom._numMasks = roomReader.readSint16LE(); _currentRoom._init = roomReader.readSint16LE(); -- cgit v1.2.3 From e0317099899a2bb88e57bd1d8a1003c1cb180ee2 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 16 Jul 2009 16:06:29 +0000 Subject: Added _iconsArchive to DraciEngine and modified the Mouse class to use it. svn-id: r42535 --- engines/draci/draci.cpp | 3 +++ engines/draci/draci.h | 1 + engines/draci/mouse.cpp | 12 +----------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 3041c70341..2578d8a12e 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -50,6 +50,7 @@ const Common::String spritesPath("OBR_AN.DFW"); const Common::String overlaysPath("OBR_MAS.DFW"); const Common::String roomsPath("MIST.DFW"); const Common::String animationsPath("ANIM.DFW"); +const Common::String iconsPath("HRA.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { @@ -84,6 +85,7 @@ int DraciEngine::init() { _roomsArchive = new BArchive(roomsPath); _overlaysArchive = new BArchive(overlaysPath); _animationsArchive = new BArchive(animationsPath); + _iconsArchive = new BArchive(iconsPath); // Load the game's fonts _smallFont = new Font(kFontSmall); @@ -179,6 +181,7 @@ DraciEngine::~DraciEngine() { delete _roomsArchive; delete _overlaysArchive; delete _animationsArchive; + delete _iconsArchive; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index c01a30a7e4..b3e3b020a7 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -60,6 +60,7 @@ public: Font *_smallFont; Font *_bigFont; + BArchive *_iconsArchive; BArchive *_objectsArchive; BArchive *_spritesArchive; BArchive *_paletteArchive; diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 09216085a7..4a02f47444 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -98,21 +98,11 @@ void Mouse::setPosition(uint16 x, uint16 y) { } // FIXME: Handle hotspots properly -// TODO: Implement a resource manager void Mouse::setCursorType(CursorType cur) { _cursorType = cur; - Common::String path("HRA.DFW"); BAFile *f; - BArchive ar; - ar.openArchive(path); - - if(ar.isOpen()) { - f = ar.getFile(_cursorType); - } else { - debugC(2, kDraciGeneralDebugLevel, "ERROR - Archive not opened - %s", path.c_str()); - return; - } + f = _vm->_iconsArchive->getFile(_cursorType); Sprite sp(f->_data, f->_length, 0, 0, true); CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); -- cgit v1.2.3 From 652acfc4ca6e8b63fb7d02103fe5a07c2f4cd312 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 16 Jul 2009 18:31:15 +0000 Subject: * Added WalkingMaps class * Added DraciEngine::walkingMapsArchive * Made Game::loadRoom() read in the current walking map svn-id: r42541 --- engines/draci/draci.cpp | 3 +++ engines/draci/draci.h | 1 + engines/draci/game.cpp | 40 ++++++++++++++++++++++------------------ engines/draci/game.h | 35 ++++++++++++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 2578d8a12e..339962ac52 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -51,6 +51,7 @@ const Common::String overlaysPath("OBR_MAS.DFW"); const Common::String roomsPath("MIST.DFW"); const Common::String animationsPath("ANIM.DFW"); const Common::String iconsPath("HRA.DFW"); +const Common::String walkingMapsPath("MAPY.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { @@ -86,6 +87,7 @@ int DraciEngine::init() { _overlaysArchive = new BArchive(overlaysPath); _animationsArchive = new BArchive(animationsPath); _iconsArchive = new BArchive(iconsPath); + _walkingMapsArchive = new BArchive(walkingMapsPath); // Load the game's fonts _smallFont = new Font(kFontSmall); @@ -182,6 +184,7 @@ DraciEngine::~DraciEngine() { delete _overlaysArchive; delete _animationsArchive; delete _iconsArchive; + delete _walkingMapsArchive; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index b3e3b020a7..630ce0c29a 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -67,6 +67,7 @@ public: BArchive *_roomsArchive; BArchive *_overlaysArchive; BArchive *_animationsArchive; + BArchive *_walkingMapsArchive; Common::RandomSource _rnd; }; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index e7bafa17ee..9e06f44a1e 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -157,7 +157,11 @@ void Game::loadRoom(int roomNum) { roomReader.readUint32LE(); // Pointer to room title, not used _currentRoom._music = roomReader.readByte(); - _currentRoom._map = roomReader.readByte() - 1; + + int mapIdx = roomReader.readByte() - 1; + f = _vm->_walkingMapsArchive->getFile(mapIdx); + _currentRoom._walkingMap.load(f->_data, f->_length); + _currentRoom._palette = roomReader.readByte() - 1; _currentRoom._numMasks = roomReader.readSint16LE(); _currentRoom._init = roomReader.readSint16LE(); @@ -174,23 +178,23 @@ void Game::loadRoom(int roomNum) { _currentRoom._escRoom = roomReader.readByte() - 1; _currentRoom._numGates = roomReader.readByte(); - debugC(4, kDraciLogicDebugLevel, "_music: %d", _currentRoom._music); - debugC(4, kDraciLogicDebugLevel, "_map: %d", _currentRoom._map); - debugC(4, kDraciLogicDebugLevel, "_palette: %d", _currentRoom._palette); - debugC(4, kDraciLogicDebugLevel, "_numMasks: %d", _currentRoom._numMasks); - debugC(4, kDraciLogicDebugLevel, "_init: %d", _currentRoom._init); - debugC(4, kDraciLogicDebugLevel, "_look: %d", _currentRoom._look); - debugC(4, kDraciLogicDebugLevel, "_use: %d", _currentRoom._use); - debugC(4, kDraciLogicDebugLevel, "_canUse: %d", _currentRoom._canUse); - debugC(4, kDraciLogicDebugLevel, "_imInit: %d", _currentRoom._imInit); - debugC(4, kDraciLogicDebugLevel, "_imLook: %d", _currentRoom._imLook); - debugC(4, kDraciLogicDebugLevel, "_imUse: %d", _currentRoom._imUse); - debugC(4, kDraciLogicDebugLevel, "_mouseOn: %d", _currentRoom._mouseOn); - debugC(4, kDraciLogicDebugLevel, "_heroOn: %d", _currentRoom._heroOn); - debugC(4, kDraciLogicDebugLevel, "_pers0: %f", _currentRoom._pers0); - debugC(4, kDraciLogicDebugLevel, "_persStep: %f", _currentRoom._persStep); - debugC(4, kDraciLogicDebugLevel, "_escRoom: %d", _currentRoom._escRoom); - debugC(4, kDraciLogicDebugLevel, "_numGates: %d", _currentRoom._numGates); + debugC(4, kDraciLogicDebugLevel, "Music: %d", _currentRoom._music); + debugC(4, kDraciLogicDebugLevel, "Map: %d", mapIdx); + debugC(4, kDraciLogicDebugLevel, "Palette: %d", _currentRoom._palette); + debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _currentRoom._numMasks); + debugC(4, kDraciLogicDebugLevel, "Init: %d", _currentRoom._init); + debugC(4, kDraciLogicDebugLevel, "Look: %d", _currentRoom._look); + debugC(4, kDraciLogicDebugLevel, "Use: %d", _currentRoom._use); + debugC(4, kDraciLogicDebugLevel, "CanUse: %d", _currentRoom._canUse); + debugC(4, kDraciLogicDebugLevel, "ImInit: %d", _currentRoom._imInit); + debugC(4, kDraciLogicDebugLevel, "ImLook: %d", _currentRoom._imLook); + debugC(4, kDraciLogicDebugLevel, "ImUse: %d", _currentRoom._imUse); + debugC(4, kDraciLogicDebugLevel, "MouseOn: %d", _currentRoom._mouseOn); + debugC(4, kDraciLogicDebugLevel, "HeroOn: %d", _currentRoom._heroOn); + debugC(4, kDraciLogicDebugLevel, "Pers0: %f", _currentRoom._pers0); + debugC(4, kDraciLogicDebugLevel, "PersStep: %f", _currentRoom._persStep); + debugC(4, kDraciLogicDebugLevel, "EscRoom: %d", _currentRoom._escRoom); + debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); // Set cursor state diff --git a/engines/draci/game.h b/engines/draci/game.h index d7d352ab6e..2b17002ef6 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -43,6 +43,39 @@ enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; +class WalkingMap { + +public: + WalkingMap() { + _realWidth = 0; + _realHeight = 0; + _mapWidth = 0; + _mapHeight = 0; + _byteWidth = 0; + _data = NULL; + } + + void load(byte *data, uint length) { + Common::MemoryReadStream mapReader(data, length); + + _realWidth = mapReader.readUint16LE(); + _realHeight = mapReader.readUint16LE(); + _mapWidth = mapReader.readUint16LE(); + _mapHeight = mapReader.readUint16LE(); + _byteWidth = mapReader.readUint16LE(); + + // Set the data pointer to raw map data + _data = data + mapReader.pos(); + } + +private: + int _realWidth, _realHeight; + int _deltaX, _deltaY; + int _mapWidth, _mapHeight; + int _byteWidth; + byte *_data; +}; + struct GameObject { GameObject() : _title(NULL) {} @@ -84,7 +117,7 @@ struct Person { struct Room { byte _roomNum; byte _music; - byte _map; + WalkingMap _walkingMap; byte _palette; int _numMasks; int _init, _look, _use, _canUse; -- cgit v1.2.3 From c420a4fba13e8f1307b2325d22d2a928d95d1cee Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 16 Jul 2009 18:39:39 +0000 Subject: Renamed GameObject::_priority to _z. svn-id: r42542 --- engines/draci/game.cpp | 2 +- engines/draci/game.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 9e06f44a1e..53c0f903fc 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -315,7 +315,7 @@ void Game::loadObject(uint objNum) { obj->_imLook = objReader.readByte(); obj->_imUse = objReader.readByte(); obj->_walkDir = objReader.readByte(); - obj->_priority = objReader.readByte(); + obj->_z = objReader.readByte(); objReader.readUint16LE(); // idxSeq field, not used objReader.readUint16LE(); // numSeq field, not used obj->_lookX = objReader.readUint16LE(); diff --git a/engines/draci/game.h b/engines/draci/game.h index 2b17002ef6..950fe4c817 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -68,6 +68,7 @@ public: _data = data + mapReader.pos(); } + private: int _realWidth, _realHeight; int _deltaX, _deltaY; @@ -84,7 +85,7 @@ struct GameObject { uint16 _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; byte _walkDir; - byte _priority; + byte _z; uint16 _lookX, _lookY, _useX, _useY; byte _lookDir, _useDir; uint16 _absNum; -- cgit v1.2.3 From e419110569067fe98a0b009ee5a7e90b507aea49 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 17 Jul 2009 00:20:57 +0000 Subject: * Added Game::loop() * Added WalkingMap::isWalkable() * Renamed remaining _priority identifiers to _z which were left by mistake in the previous commit svn-id: r42546 --- engines/draci/draci.cpp | 1 + engines/draci/game.cpp | 24 ++++++++++++++++++++++++ engines/draci/game.h | 6 +++++- engines/draci/script.cpp | 2 +- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 339962ac52..045640f568 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -155,6 +155,7 @@ int DraciEngine::go() { _mouse->handleEvent(event); } } + _game->loop(); _anims->drawScene(_screen->getSurface()); _screen->copyToScreen(); _system->delayMillis(20); diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 53c0f903fc..d80408b649 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -146,6 +146,17 @@ void Game::init() { _vm->_mouse->setCursorType(kNormalCursor); } +void Game::loop() { + + if (_currentRoom._mouseOn) { + int x = _vm->_mouse->getPosX(); + int y = _vm->_mouse->getPosY(); + if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { + debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); + } + } +} + void Game::loadRoom(int roomNum) { BAFile *f; @@ -427,4 +438,17 @@ GameObject::~GameObject() { delete[] _program._bytecode; } +bool WalkingMap::isWalkable(int x, int y) { + + // Convert to map pixels + x = x / _deltaX; + y = y / _deltaY; + + int pixelIndex = _mapWidth * y + x; + int byteIndex = pixelIndex / 8; + int mapByte = _data[byteIndex]; + + return mapByte & (1 << pixelIndex % 8); +} + } diff --git a/engines/draci/game.h b/engines/draci/game.h index 950fe4c817..6a4285f6b0 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -60,6 +60,8 @@ public: _realWidth = mapReader.readUint16LE(); _realHeight = mapReader.readUint16LE(); + _deltaX = mapReader.readUint16LE(); + _deltaY = mapReader.readUint16LE(); _mapWidth = mapReader.readUint16LE(); _mapHeight = mapReader.readUint16LE(); _byteWidth = mapReader.readUint16LE(); @@ -68,6 +70,7 @@ public: _data = data + mapReader.pos(); } + bool isWalkable(int x, int y); private: int _realWidth, _realHeight; @@ -137,6 +140,7 @@ public: ~Game(); void init(); + void loop(); void changeRoom(uint roomNum); @@ -186,7 +190,7 @@ private: uint16 *_dialogOffsets; byte *_iconStatus; GameObject *_objects; - Room _currentRoom; + Room _currentRoom; }; } // End of namespace Draci diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index d22b7b4941..2d0a33db86 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -270,7 +270,7 @@ void Script::load(Common::Queue ¶ms) { GameObject *obj = _vm->_game->getObject(objID); - _vm->_game->loadAnimation(animID, obj->_priority); + _vm->_game->loadAnimation(animID, obj->_z); obj->_anims.push_back(animID); } -- cgit v1.2.3 From cfa4d5eba0352128142d967434483c8c111e8160 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 17 Jul 2009 00:24:56 +0000 Subject: Added sanity checks for all archives (whether opening succeeded). svn-id: r42547 --- engines/draci/draci.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 045640f568..f090e587d8 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -114,6 +114,31 @@ int DraciEngine::init() { return Common::kUnknownError; } + if(!_roomsArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening rooms archive failed"); + return Common::kUnknownError; + } + + if(!_overlaysArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening overlays archive failed"); + return Common::kUnknownError; + } + + if(!_animationsArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening animations archive failed"); + return Common::kUnknownError; + } + + if(!_iconsArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening icons archive failed"); + return Common::kUnknownError; + } + + if(!_walkingMapsArchive->isOpen()) { + debugC(2, kDraciGeneralDebugLevel, "ERROR - Opening walking maps archive failed"); + return Common::kUnknownError; + } + // Basic archive test debugC(2, kDraciGeneralDebugLevel, "Running archive tests..."); Common::String path("INIT.DFW"); -- cgit v1.2.3 From 8018216dea7ab54940ff8802685dd50a27522509 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 17 Jul 2009 00:27:21 +0000 Subject: * Renamed Room::_numMasks to _numOverlays for consistency. * Fixed unsigned to signed comparison. svn-id: r42549 --- engines/draci/game.cpp | 6 +++--- engines/draci/game.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d80408b649..7f0d2a1be1 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -174,7 +174,7 @@ void Game::loadRoom(int roomNum) { _currentRoom._walkingMap.load(f->_data, f->_length); _currentRoom._palette = roomReader.readByte() - 1; - _currentRoom._numMasks = roomReader.readSint16LE(); + _currentRoom._numOverlays = roomReader.readSint16LE(); _currentRoom._init = roomReader.readSint16LE(); _currentRoom._look = roomReader.readSint16LE(); _currentRoom._use = roomReader.readSint16LE(); @@ -192,7 +192,7 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "Music: %d", _currentRoom._music); debugC(4, kDraciLogicDebugLevel, "Map: %d", mapIdx); debugC(4, kDraciLogicDebugLevel, "Palette: %d", _currentRoom._palette); - debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _currentRoom._numMasks); + debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _currentRoom._numOverlays); debugC(4, kDraciLogicDebugLevel, "Init: %d", _currentRoom._init); debugC(4, kDraciLogicDebugLevel, "Look: %d", _currentRoom._look); debugC(4, kDraciLogicDebugLevel, "Use: %d", _currentRoom._use); @@ -361,7 +361,7 @@ void Game::loadOverlays() { Common::MemoryReadStream overlayReader(overlayHeader->_data, overlayHeader->_length); BAFile *overlayFile; - for (uint i = 0; i < _currentRoom._numMasks; i++) { + for (int i = 0; i < _currentRoom._numOverlays; i++) { num = overlayReader.readUint16LE() - 1; x = overlayReader.readUint16LE(); diff --git a/engines/draci/game.h b/engines/draci/game.h index 6a4285f6b0..f843da01cf 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -123,7 +123,7 @@ struct Room { byte _music; WalkingMap _walkingMap; byte _palette; - int _numMasks; + int _numOverlays; int _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; bool _mouseOn, _heroOn; -- cgit v1.2.3 From 16530846acc8a9d0ededdf3de82f11d3260fee87 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 17 Jul 2009 01:05:13 +0000 Subject: * Renamed BAFile::closeFile() to close() * Fixed leak in BArchive::loadFileDFW() svn-id: r42554 --- engines/draci/barchive.cpp | 4 +++- engines/draci/barchive.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/engines/draci/barchive.cpp b/engines/draci/barchive.cpp index cbe019f8b2..2a27e6a383 100644 --- a/engines/draci/barchive.cpp +++ b/engines/draci/barchive.cpp @@ -375,6 +375,8 @@ BAFile *BArchive::loadFileDFW(unsigned int i) const { assert(len == _files[i]._length && "Uncompressed file not of the expected length"); + delete[] buf; + return _files + i; } @@ -386,7 +388,7 @@ void BArchive::clearCache() { // Delete all cached data for (unsigned int i = 0; i < _fileCount; ++i) { - _files[i].closeFile(); + _files[i].close(); } } diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 5a4f5155f7..7d26b65884 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -43,7 +43,7 @@ struct BAFile { byte _stopper; //!< Not used in BAR files, needed for DFW /** Releases the file data (for memory considerations) */ - void closeFile(void) { + void close(void) { delete[] _data; _data = NULL; } -- cgit v1.2.3 From aa82c39857513525d5212b543f4438f916409250 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 17 Jul 2009 01:20:51 +0000 Subject: * Made Game::changeRoom() clear some more archives * Modified the engine to leverage BArchive's memory management capabilities by using its pointers to data directly instead of copying * Removed GameObject destructor (not needed because of the above change) * Changed some more data members from uint16 to uint svn-id: r42555 --- engines/draci/game.cpp | 38 +++++++++++++++++++++++--------------- engines/draci/game.h | 5 ++--- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 7f0d2a1be1..28448835be 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -53,6 +53,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _persons[i]._y = personData.readByte(); _persons[i]._fontColour = personData.readUint16LE(); } + + // Close persons file + file->close(); // Read in dialog offsets @@ -60,7 +63,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { Common::MemoryReadStream dialogData(file->_data, file->_length); unsigned int numDialogs = file->_length / sizeof(uint16); - _dialogOffsets = new uint16[numDialogs]; + _dialogOffsets = new uint[numDialogs]; unsigned int curOffset; for (i = 0, curOffset = 0; i < numDialogs; ++i) { @@ -68,6 +71,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { curOffset += dialogData.readUint16LE(); } + // Close dialogs file + file->close(); + // Read in game info file = initArchive.getFile(3); @@ -90,6 +96,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info._numDialogBlocks = curOffset; + // Close game info file + file->close(); + // Read in variables file = initArchive.getFile(2); @@ -102,11 +111,13 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _variables[i] = variableData.readUint16LE(); } + // Close variables file + file->close(); + // Read in item icon status file = initArchive.getFile(1); - _iconStatus = new byte[file->_length]; - memcpy(_iconStatus, file->_data, file->_length); + _iconStatus = file->_data; uint numIcons = file->_length; // Read in object status @@ -126,6 +137,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Set object location _objects[i]._location = (~(1 << 7) & tmp) - 1; } + + // Close object status file + file->close(); assert(numDialogs == _info._numDialogs); assert(numPersons == _info._numPersons); @@ -247,9 +261,8 @@ void Game::loadRoom(int roomNum) { } f = _vm->_roomsArchive->getFile(roomNum * 4 + 3); - _currentRoom._program._bytecode = new byte[f->_length]; + _currentRoom._program._bytecode = f->_data; _currentRoom._program._length = f->_length; - memcpy(_currentRoom._program._bytecode, f->_data, f->_length); debugC(4, kDraciLogicDebugLevel, "Running room init program..."); _vm->_script->run(_currentRoom._program, _currentRoom._init); @@ -339,13 +352,11 @@ void Game::loadObject(uint objNum) { obj->_absNum = objNum; file = _vm->_objectsArchive->getFile(objNum * 3 + 1); - obj->_title = new byte[file->_length]; - memcpy(obj->_title, file->_data, file->_length); + obj->_title = file->_data; file = _vm->_objectsArchive->getFile(objNum * 3 + 2); - obj->_program._bytecode = new byte[file->_length]; + obj->_program._bytecode = file->_data; obj->_program._length = file->_length; - memcpy(obj->_program._bytecode, file->_data, file->_length); } GameObject *Game::getObject(uint objNum) { @@ -383,9 +394,12 @@ void Game::changeRoom(uint roomNum) { debugC(1, kDraciLogicDebugLevel, "Changing to room %d", roomNum); + // Clear archives _vm->_roomsArchive->clearCache(); _vm->_spritesArchive->clearCache(); _vm->_paletteArchive->clearCache(); + _vm->_animationsArchive->clearCache(); + _vm->_walkingMapsArchive->clearCache(); _vm->_screen->clearScreen(); @@ -429,15 +443,9 @@ Game::~Game() { delete[] _persons; delete[] _variables; delete[] _dialogOffsets; - delete[] _iconStatus; delete[] _objects; } -GameObject::~GameObject() { - delete[] _title; - delete[] _program._bytecode; -} - bool WalkingMap::isWalkable(int x, int y) { // Convert to map pixels diff --git a/engines/draci/game.h b/engines/draci/game.h index f843da01cf..276efa1356 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -83,9 +83,8 @@ private: struct GameObject { GameObject() : _title(NULL) {} - ~GameObject(); - uint16 _init, _look, _use, _canUse; + uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; byte _walkDir; byte _z; @@ -187,7 +186,7 @@ private: int *_variables; GameInfo _info; Person *_persons; - uint16 *_dialogOffsets; + uint *_dialogOffsets; byte *_iconStatus; GameObject *_objects; Room _currentRoom; -- cgit v1.2.3 From 8e1f29630869481f88911476d900f421fa0c2164 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 01:11:45 +0000 Subject: Removed room switching hack from Mouse and re-added it to DraciEngine::go() (right arrow switches to the next room, left to the previous. svn-id: r42577 --- engines/draci/draci.cpp | 7 +++++++ engines/draci/game.h | 10 +++++----- engines/draci/mouse.cpp | 13 ------------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index f090e587d8..b2b0083c22 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -28,6 +28,7 @@ #include "common/config-manager.h" #include "common/events.h" #include "common/file.h" +#include "common/keyboard.h" #include "graphics/cursorman.h" #include "graphics/font.h" @@ -176,6 +177,12 @@ int DraciEngine::go() { case Common::EVENT_QUIT: quit = true; break; + case Common::EVENT_KEYDOWN: + if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _game->changeRoom(_game->nextRoomNum()); + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _game->changeRoom(_game->prevRoomNum()); + break; default: _mouse->handleEvent(event); } diff --git a/engines/draci/game.h b/engines/draci/game.h index 276efa1356..0c3dddae20 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -135,6 +135,7 @@ struct Room { class Game { public: + Game(DraciEngine *vm); ~Game(); @@ -142,11 +143,10 @@ public: void loop(); void changeRoom(uint roomNum); - int getRoomNum(); // HACK: this is only for testing - void incRoomNum() { + int nextRoomNum() { int n = _currentRoom._roomNum; n = n < 37 ? n+1 : n; @@ -154,11 +154,11 @@ public: if (n == 30) ++n; - _currentRoom._roomNum = n; + return n; } // HACK: same as above - void decRoomNum() { + int prevRoomNum() { int n = _currentRoom._roomNum; n = n > 0 ? n-1 : n; @@ -166,7 +166,7 @@ public: if (n == 30) --n; - _currentRoom._roomNum = n; + return n; } void loadRoom(int roomNum); diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 4a02f47444..352dbf4e80 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -41,18 +41,11 @@ Mouse::Mouse(DraciEngine *vm) { void Mouse::handleEvent(Common::Event event) { _x = (uint16) event.mouse.x; _y = (uint16) event.mouse.y; - int room; switch (event.type) { case Common::EVENT_LBUTTONDOWN: debugC(6, kDraciGeneralDebugLevel, "Left button down (x: %u y: %u)", _x, _y); _lButton = true; - - // HACK: We change to the next room when the left mouse button is pressed. - // This is only for testing. - _vm->_game->incRoomNum(); - room = _vm->_game->getRoomNum(); - _vm->_game->changeRoom(room); break; case Common::EVENT_LBUTTONUP: @@ -63,12 +56,6 @@ void Mouse::handleEvent(Common::Event event) { case Common::EVENT_RBUTTONDOWN: debugC(6, kDraciGeneralDebugLevel, "Right button down (x: %u y: %u)", _x, _y); _rButton = true; - - // HACK: We change to the previous room when the right mouse button is pressed. - // This is only for testing. - _vm->_game->decRoomNum(); - room = _vm->_game->getRoomNum(); - _vm->_game->changeRoom(room); break; case Common::EVENT_RBUTTONUP: -- cgit v1.2.3 From adf9e91e1fd1bc9e23147ef4ce100a5343a23ffa Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 02:53:37 +0000 Subject: * Added Animation::getFrame() * Added support for sorting animations when Z is changed later on (AnimationManager::sortAnimations()) * Added support for relative coordinates (Animation::setRelative()) * Fixed bug where AnimationManager::deleteOverlays() deleted all animations svn-id: r42579 --- engines/draci/animation.cpp | 91 +++++++++++++++++++++++++++++++++++++++++---- engines/draci/animation.h | 11 +++++- 2 files changed, 94 insertions(+), 8 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 2a333445ec..74bd8c0534 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -31,6 +31,8 @@ namespace Draci { Animation::Animation(DraciEngine *vm) : _vm(vm) { _id = kUnused; _z = 0; + _relX = 0; + _relY = 0; _playing = false; _looping = false; _tick = _vm->_system->getMillis(); @@ -45,6 +47,17 @@ bool Animation::isLooping() { return _looping; } +void Animation::setRelative(int relx, int rely) { + + // Delete the previous frame + Common::Rect frameRect = _frames[_currentFrame]->getRect(); + frameRect.translate(_relX, _relY); + _vm->_screen->getSurface()->markDirtyRect(frameRect); + + _relX = relx; + _relY = rely; +} + void Animation::setLooping(bool looping) { _looping = looping; debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", @@ -57,9 +70,13 @@ void Animation::nextFrame(bool force) { if (getFramesNum() < 2 || !_playing) return; - Common::Rect frameRect = _frames[_currentFrame]->getRect(); Drawable *frame = _frames[_currentFrame]; + Common::Rect frameRect = frame->getRect(); + + // Translate rectangle to compensate for relative coordinates + frameRect.translate(_relX, _relY); + if (force || (_tick + frame->getDelay() <= _vm->_system->getMillis())) { // If we are at the last frame and not looping, stop the animation // The animation is also restarted to frame zero @@ -97,7 +114,18 @@ void Animation::drawFrame(Surface *surface) { _frames[_currentFrame]->draw(surface, false); } else { - _frames[_currentFrame]->draw(surface, true); + Drawable *ptr = _frames[_currentFrame]; + int x = ptr->getX(); + int y = ptr->getY(); + int newX = x + _relX; + int newY = y + _relY; + + ptr->setX(newX); + ptr->setY(newY); + ptr->draw(surface, true); + + ptr->setX(x); + ptr->setY(y); } } @@ -129,13 +157,23 @@ void Animation::addFrame(Drawable *frame) { _frames.push_back(frame); } +Drawable *Animation::getFrame(int frameNum) { + + // If no argument is passed, return the current frame + if (frameNum == kCurrentFrame) { + return _frames[_currentFrame]; + } else { + return _frames[frameNum]; + } +} + uint Animation::getFramesNum() { return _frames.size(); } void Animation::deleteFrames() { - for (uint i = 0; i < getFramesNum(); ++i) { + for (int i = getFramesNum() - 1; i >= 0; --i) { delete _frames[i]; _frames.pop_back(); } @@ -168,6 +206,11 @@ void AnimationManager::play(int id) { void AnimationManager::stop(int id) { Animation *anim = getAnimation(id); + // Clean up the last frame that was drawn before stopping + Common::Rect frameRect = anim->getFrame()->getRect(); + frameRect.translate(anim->_relX, anim->_relY); + _vm->_screen->getSurface()->markDirtyRect(frameRect); + if (anim) { anim->setPlaying(false); @@ -215,6 +258,8 @@ void AnimationManager::drawScene(Surface *surf) { // Fill the screen with colour zero since some rooms may rely on the screen being black _vm->_screen->getSurface()->fill(0); + sortAnimations(); + Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { @@ -227,10 +272,42 @@ void AnimationManager::drawScene(Surface *surf) { } } +void AnimationManager::sortAnimations() { + Common::List::iterator cur; + Common::List::iterator next; + + cur = _animations.begin(); + + // If the list is empty, we're done + if (cur == _animations.end()) + return; + + while(1) { + next = cur; + next++; + + // If we are at the last element, we're done + if (next == _animations.end()) + break; + + // If we find an animation out of order, reinsert it + if ((*next)->getZ() < (*cur)->getZ()) { + + Animation *anim = *cur; + _animations.erase(cur); + + insertAnimation(anim); + } + + // Advance to next animation + cur = next; + } +} + void AnimationManager::deleteAnimation(int id) { Common::List::iterator it; - + for (it = _animations.begin(); it != _animations.end(); ++it) { if ((*it)->getID() == id) { (*it)->deleteFrames(); @@ -245,10 +322,10 @@ void AnimationManager::deleteOverlays() { Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { - if((*it)->getID() == kOverlayImage) + if ((*it)->getID() == kOverlayImage) { (*it)->deleteFrames(); - - _animations.erase(it); + _animations.erase(it); + } } } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index fea7fb3f89..66988482f0 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -32,6 +32,8 @@ namespace Draci { enum { kOverlayImage = -1, kUnused = -2 }; +enum { kCurrentFrame = -1 }; + class DraciEngine; class Animation { @@ -50,6 +52,7 @@ public: void drawFrame(Surface *surface); void addFrame(Drawable *frame); + Drawable *getFrame(int frameNum = kCurrentFrame); uint getFramesNum(); void deleteFrames(); @@ -59,6 +62,11 @@ public: bool isLooping(); void setLooping(bool looping); + void setRelative(int relx, int rely); + + int _relX; + int _relY; + private: uint nextFrameNum(); @@ -66,6 +74,7 @@ private: int _id; uint _currentFrame; uint _z; + uint _tick; bool _playing; bool _looping; @@ -96,7 +105,7 @@ public: Animation *getAnimation(int id); private: - + void sortAnimations(); void insertAnimation(Animation *anim); DraciEngine *_vm; -- cgit v1.2.3 From 3cde84fec4a06c9a95d8f6e2f61a3a990c8f3bff Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 02:58:11 +0000 Subject: Fixed bug where certain animations were played very fast when not played immediately when they are created. svn-id: r42580 --- engines/draci/animation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 74bd8c0534..12661aff66 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,7 +33,7 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _relX = 0; _relY = 0; - _playing = false; + setPlaying(false); _looping = false; _tick = _vm->_system->getMillis(); _currentFrame = 0; @@ -82,7 +82,7 @@ void Animation::nextFrame(bool force) { // The animation is also restarted to frame zero if ((_currentFrame == getFramesNum() - 1) && !_looping) { _currentFrame = 0; - _playing = false; + setPlaying(false); } else { _vm->_screen->getSurface()->markDirtyRect(frameRect); _currentFrame = nextFrameNum(); @@ -150,6 +150,7 @@ bool Animation::isPlaying() { } void Animation::setPlaying(bool playing) { + _tick = _vm->_system->getMillis(); _playing = playing; } -- cgit v1.2.3 From 94417e77438e779ee1a03e366d96dc49bff04e03 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 03:00:12 +0000 Subject: * Added support for "walking" with the hero (i.e. moving the sprite to locations allowed by the walking map) * Enabled drawing the walking map with the 'w' hotkey for testing svn-id: r42581 --- engines/draci/draci.cpp | 13 ++++++++++++- engines/draci/game.cpp | 45 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index b2b0083c22..1e7b292229 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -171,6 +171,7 @@ int DraciEngine::go() { Common::Event event; bool quit = false; + bool showWalkingMap = false; while (!quit) { while (_eventMan->pollEvent(event)) { switch (event.type) { @@ -182,7 +183,17 @@ int DraciEngine::go() { _game->changeRoom(_game->nextRoomNum()); else if (event.kbd.keycode == Common::KEYCODE_LEFT) _game->changeRoom(_game->prevRoomNum()); - break; + else if (event.kbd.keycode == Common::KEYCODE_w) { // Show walking map toggle + // Toggle + showWalkingMap = !showWalkingMap; + + if (showWalkingMap) { + _anims->play(-2); + } else { + _anims->stop(-2); + } + } + break; default: _mouse->handleEvent(event); } diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 28448835be..161f1d82d7 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -155,6 +155,7 @@ void Game::init() { debugC(4, kDraciLogicDebugLevel, "Running init program for the dragon object..."); _vm->_script->run(dragon->_program, dragon->_init); + _currentRoom._roomNum = _info._startRoom; changeRoom(_info._startRoom); _vm->_mouse->setCursorType(kNormalCursor); @@ -165,7 +166,22 @@ void Game::loop() { if (_currentRoom._mouseOn) { int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); + if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { + + int animID = getObject(kDragonObject)->_anims[0]; + + Animation *anim = _vm->_anims->getAnimation(animID); + Drawable *frame = anim->getFrame(); + y -= frame->getHeight(); + + // HACK: Z needs to be handled according to Y position + anim->setZ(256); + + anim->setRelative(x, y); + + _vm->_anims->play(animID); + debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); } } @@ -221,7 +237,6 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "EscRoom: %d", _currentRoom._escRoom); debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); - // Set cursor state if (_currentRoom._mouseOn) { debugC(6, kDraciLogicDebugLevel, "Mouse: ON"); @@ -231,7 +246,6 @@ void Game::loadRoom(int roomNum) { _vm->_mouse->cursorOff(); } - Common::Array gates; for (uint i = 0; i < _currentRoom._numGates; ++i) { @@ -276,6 +290,23 @@ void Game::loadRoom(int roomNum) { f = _vm->_paletteArchive->getFile(_currentRoom._palette); _vm->_screen->setPalette(f->_data, 0, kNumColours); + + // HACK: Create a visible overlay from the walking map so we can test it + byte *wlk = new byte[kScreenWidth * kScreenHeight]; + memset(wlk, 255, kScreenWidth * kScreenHeight); + + for (uint i = 0; i < kScreenWidth; ++i) { + for (uint j = 0; j < kScreenHeight; ++j) { + if (_currentRoom._walkingMap.isWalkable(i, j)) { + wlk[j * kScreenWidth + i] = 2; + } + } + } + + Sprite *ov = new Sprite(wlk, kScreenWidth, kScreenHeight, 0, 0, false); + + Animation *map = _vm->_anims->addAnimation(-2, 255, false); + map->addFrame(ov); } int Game::loadAnimation(uint animNum, uint z) { @@ -404,17 +435,20 @@ void Game::changeRoom(uint roomNum) { _vm->_screen->clearScreen(); _vm->_anims->deleteOverlays(); + + // Delete walking map testing overlay + _vm->_anims->deleteAnimation(-2); int oldRoomNum = _currentRoom._roomNum; for (uint i = 0; i < _info._numObjects; ++i) { GameObject *obj = &_objects[i]; - - if (i != 0 && obj->_location == oldRoomNum) { + + if (i != 0 && (obj->_location == oldRoomNum)) { for (uint j = 0; j < obj->_anims.size(); ++j) { _vm->_anims->deleteAnimation(obj->_anims[j]); - obj->_anims.pop_back(); } + obj->_anims.clear(); } } @@ -459,4 +493,5 @@ bool WalkingMap::isWalkable(int x, int y) { return mapByte & (1 << pixelIndex % 8); } + } -- cgit v1.2.3 From 18fda1b2f374e57b10f7ed3bce7e193998cb0014 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 03:05:20 +0000 Subject: Fixed a bug where the cursor was not shown when the first room is loaded and has mouse enabled. svn-id: r42582 --- engines/draci/game.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 161f1d82d7..c322a5b286 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -157,8 +157,6 @@ void Game::init() { _currentRoom._roomNum = _info._startRoom; changeRoom(_info._startRoom); - - _vm->_mouse->setCursorType(kNormalCursor); } void Game::loop() { @@ -237,21 +235,15 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "EscRoom: %d", _currentRoom._escRoom); debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); - // Set cursor state - if (_currentRoom._mouseOn) { - debugC(6, kDraciLogicDebugLevel, "Mouse: ON"); - _vm->_mouse->cursorOn(); - } else { - debugC(6, kDraciLogicDebugLevel, "Mouse: OFF"); - _vm->_mouse->cursorOff(); - } + // Read in the gates' numbers Common::Array gates; for (uint i = 0; i < _currentRoom._numGates; ++i) { gates.push_back(roomReader.readSint16LE()); } + // Load the room's objects for (uint i = 0; i < _info._numObjects; ++i) { debugC(7, kDraciLogicDebugLevel, "Checking if object %d (%d) is at the current location (%d)", i, @@ -274,6 +266,7 @@ void Game::loadRoom(int roomNum) { } } + // Load the room's GPL program and run the init part f = _vm->_roomsArchive->getFile(roomNum * 4 + 3); _currentRoom._program._bytecode = f->_data; _currentRoom._program._length = f->_length; @@ -288,9 +281,22 @@ void Game::loadRoom(int roomNum) { _vm->_script->run(_currentRoom._program, gates[i]); } + // Set room palette f = _vm->_paletteArchive->getFile(_currentRoom._palette); _vm->_screen->setPalette(f->_data, 0, kNumColours); + // Set cursor state + // Need to do this after we set the palette since the cursors use it + if (_currentRoom._mouseOn) { + debugC(6, kDraciLogicDebugLevel, "Mouse: ON"); + _vm->_mouse->cursorOn(); + } else { + debugC(6, kDraciLogicDebugLevel, "Mouse: OFF"); + _vm->_mouse->cursorOff(); + } + + _vm->_mouse->setCursorType(kNormalCursor); + // HACK: Create a visible overlay from the walking map so we can test it byte *wlk = new byte[kScreenWidth * kScreenHeight]; memset(wlk, 255, kScreenWidth * kScreenHeight); -- cgit v1.2.3 From 10e9a780ce870a0273c5d35cbb0ccfb45391087b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 03:12:12 +0000 Subject: Made the engine stop the dragon animation when the room changes. svn-id: r42583 --- engines/draci/game.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index c322a5b286..008c1b6389 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -235,7 +235,6 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "EscRoom: %d", _currentRoom._escRoom); debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); - // Read in the gates' numbers Common::Array gates; @@ -447,6 +446,12 @@ void Game::changeRoom(uint roomNum) { int oldRoomNum = _currentRoom._roomNum; + // TODO: Make objects capable of stopping their own animations + GameObject *dragon = getObject(kDragonObject); + for (uint i = 0; i < dragon->_anims.size(); ++i) { + _vm->_anims->stop(dragon->_anims[i]); + } + for (uint i = 0; i < _info._numObjects; ++i) { GameObject *obj = &_objects[i]; -- cgit v1.2.3 From 128fe6ea21f885c020f821f75f5a47427825eef6 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 03:20:26 +0000 Subject: Made the engine handle the Z coordinate for the hero properly. svn-id: r42584 --- engines/draci/game.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 008c1b6389..e532dd907c 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -171,11 +171,10 @@ void Game::loop() { Animation *anim = _vm->_anims->getAnimation(animID); Drawable *frame = anim->getFrame(); - y -= frame->getHeight(); - - // HACK: Z needs to be handled according to Y position - anim->setZ(256); + anim->setZ(y+1); + + y -= frame->getHeight(); anim->setRelative(x, y); _vm->_anims->play(animID); -- cgit v1.2.3 From a44cda552561d13a596acafa5b8d1ce918585d92 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 05:21:01 +0000 Subject: Fixed bug which caused animations to sometimes be played too fast if the engine was busier than usual (like when redrawing the whole screen when returning from minimized state). svn-id: r42585 --- engines/draci/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 12661aff66..0d56ea810f 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -86,7 +86,7 @@ void Animation::nextFrame(bool force) { } else { _vm->_screen->getSurface()->markDirtyRect(frameRect); _currentFrame = nextFrameNum(); - _tick += frame->getDelay(); + _tick = _vm->_system->getMillis(); } } -- cgit v1.2.3 From cb185f18cde68c40590959a700226e24912d2688 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 18 Jul 2009 12:08:18 +0000 Subject: Fixed bug which caused the dragon to be animated with the wrong Z coordinate for short periods of time when moved to a new location. svn-id: r42586 --- engines/draci/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 0d56ea810f..b5f0d6b806 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -294,8 +294,8 @@ void AnimationManager::sortAnimations() { // If we find an animation out of order, reinsert it if ((*next)->getZ() < (*cur)->getZ()) { - Animation *anim = *cur; - _animations.erase(cur); + Animation *anim = *next; + _animations.erase(next); insertAnimation(anim); } -- cgit v1.2.3 From 1ec375bbd5ee497e6ce29771fbc584a3cb6de961 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 19 Jul 2009 13:28:05 +0000 Subject: Added capability for reading in Pascal 6-byte floats and made Game::loadRoom() read in pers0 and persStep correctly. svn-id: r42612 --- engines/draci/game.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-- engines/draci/game.h | 2 ++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index e532dd907c..03d87b8c6b 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -31,6 +31,8 @@ #include "draci/script.h" #include "draci/animation.h" +#include + namespace Draci { Game::Game(DraciEngine *vm) : _vm(vm) { @@ -211,8 +213,22 @@ void Game::loadRoom(int roomNum) { _currentRoom._imUse = roomReader.readByte(); _currentRoom._mouseOn = roomReader.readByte(); _currentRoom._heroOn = roomReader.readByte(); - roomReader.read(&_currentRoom._pers0, 6); - roomReader.read(&_currentRoom._persStep, 6); + + // Read in pers0 and persStep (stored as 6-byte Pascal reals) + byte real[6]; + + for (int i = 5; i >= 0; --i) { + real[i] = roomReader.readByte(); + } + + _currentRoom._pers0 = real_to_double(real); + + for (int i = 5; i >= 0; --i) { + real[i] = roomReader.readByte(); + } + + _currentRoom._persStep = real_to_double(real); + _currentRoom._escRoom = roomReader.readByte() - 1; _currentRoom._numGates = roomReader.readByte(); @@ -503,5 +519,45 @@ bool WalkingMap::isWalkable(int x, int y) { return mapByte & (1 << pixelIndex % 8); } +static double real_to_double(byte real[6]) { + + // Extract sign bit + int sign = real[0] & (1 << 7); + + // Extract exponent and adjust for bias + int exp = real[5] - 129; + + double mantissa; + double tmp = 0.0; + + if (real[5] == 0) { + mantissa = 0.0; + } else { + + // Process the first four least significant bytes + for (int i = 4; i >= 1; --i) { + tmp += real[i]; + tmp /= 1 << 8; + } + + // Process the most significant byte (remove the sign bit) + tmp += real[0] & ((1 << 7) - 1); + tmp /= 1 << 8; + + // Calculate mantissa + mantissa = 1.0; + mantissa += 2.0 * tmp; + } + + // Flip sign if necessary + if (sign) { + mantissa = -mantissa; + } + + // Calculate final value + return mantissa * pow(2.0, exp); +} + + } diff --git a/engines/draci/game.h b/engines/draci/game.h index 0c3dddae20..6600813b8f 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -43,6 +43,8 @@ enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; +static double real_to_double(byte real[6]); + class WalkingMap { public: -- cgit v1.2.3 From 18301b6f78fd6d7eb77b5055129b71d2b8dce270 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 19 Jul 2009 14:54:16 +0000 Subject: * Used ldexp() in real_to_double() instead of doing the calculation manually * Moved static declaration of real_to_double() to game.cpp svn-id: r42616 --- engines/draci/game.cpp | 6 +++--- engines/draci/game.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 03d87b8c6b..d913eb904f 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -35,6 +35,8 @@ namespace Draci { +static double real_to_double(byte real[6]); + Game::Game(DraciEngine *vm) : _vm(vm) { unsigned int i; Common::String path("INIT.DFW"); @@ -555,9 +557,7 @@ static double real_to_double(byte real[6]) { } // Calculate final value - return mantissa * pow(2.0, exp); + return ldexp(mantissa, exp); } - - } diff --git a/engines/draci/game.h b/engines/draci/game.h index 6600813b8f..0c3dddae20 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -43,8 +43,6 @@ enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; -static double real_to_double(byte real[6]); - class WalkingMap { public: -- cgit v1.2.3 From a2a71cb8fbdbf1426d73c6f09f315abf04cfcbb9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 20 Jul 2009 17:25:57 +0000 Subject: * Added scaling support * Made the dragon scale when it is in different parts of the room * Added getters for relative coordinates (Animation::getRelativeX() and Animation::getRelativeY()) * Commented Game::loop() and Sprite::draw*() methods in more detail svn-id: r42627 --- engines/draci/animation.cpp | 70 ++++++++++++++++++++++++++--- engines/draci/animation.h | 18 ++++++-- engines/draci/game.cpp | 22 ++++++++- engines/draci/game.h | 3 ++ engines/draci/sprite.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++-- engines/draci/sprite.h | 13 ++++++ 6 files changed, 217 insertions(+), 16 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index b5f0d6b806..3faa85ac63 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,6 +33,8 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _relX = 0; _relY = 0; + _scaleX = 1.0; + _scaleY = 1.0; setPlaying(false); _looping = false; _tick = _vm->_system->getMillis(); @@ -50,7 +52,14 @@ bool Animation::isLooping() { void Animation::setRelative(int relx, int rely) { // Delete the previous frame - Common::Rect frameRect = _frames[_currentFrame]->getRect(); + Common::Rect frameRect; + + if (isScaled()) { + frameRect = getFrame()->getScaledRect(_scaleX, _scaleY); + } else { + frameRect = getFrame()->getRect(); + } + frameRect.translate(_relX, _relY); _vm->_screen->getSurface()->markDirtyRect(frameRect); @@ -58,6 +67,24 @@ void Animation::setRelative(int relx, int rely) { _relY = rely; } +void Animation::setScaling(double scalex, double scaley) { + + _scaleX = scalex; + _scaleY = scaley; +} + +bool Animation::isScaled() const { + return !(_scaleX == 1.0 && _scaleY == 1.0); +} + +double Animation::getScaleX() const { + return _scaleX; +} + +double Animation::getScaleY() const { + return _scaleY; +} + void Animation::setLooping(bool looping) { _looping = looping; debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", @@ -72,7 +99,13 @@ void Animation::nextFrame(bool force) { Drawable *frame = _frames[_currentFrame]; - Common::Rect frameRect = frame->getRect(); + Common::Rect frameRect; + + if (isScaled()) { + frameRect = frame->getScaledRect(_scaleX, _scaleY); + } else { + frameRect = frame->getRect(); + } // Translate rectangle to compensate for relative coordinates frameRect.translate(_relX, _relY); @@ -111,19 +144,29 @@ void Animation::drawFrame(Surface *surface) { return; if (_id == kOverlayImage) { - _frames[_currentFrame]->draw(surface, false); + _frames[_currentFrame]->drawScaled(surface, _scaleX, _scaleY, false); } else { Drawable *ptr = _frames[_currentFrame]; + int x = ptr->getX(); int y = ptr->getY(); + + // Take account relative coordinates int newX = x + _relX; int newY = y + _relY; + // Translate the frame to those relative coordinates ptr->setX(newX); ptr->setY(newY); - ptr->draw(surface, true); + // Draw frame + if (isScaled()) + ptr->drawScaled(surface, _scaleX, _scaleY, true); + else + ptr->drawScaled(surface, _scaleX, _scaleY, true); + + // Revert back to old coordinates ptr->setX(x); ptr->setY(y); } @@ -145,6 +188,14 @@ uint Animation::getZ() { return _z; } +int Animation::getRelativeX() { + return _relX; +} + +int Animation::getRelativeY() { + return _relY; +} + bool Animation::isPlaying() { return _playing; } @@ -208,8 +259,15 @@ void AnimationManager::stop(int id) { Animation *anim = getAnimation(id); // Clean up the last frame that was drawn before stopping - Common::Rect frameRect = anim->getFrame()->getRect(); - frameRect.translate(anim->_relX, anim->_relY); + Common::Rect frameRect; + + if (anim->isScaled()) { + frameRect = anim->getFrame()->getScaledRect(anim->getScaleX(), anim->getScaleY()); + } else { + frameRect = anim->getFrame()->getRect(); + } + + frameRect.translate(anim->getRelativeX(), anim->getRelativeY()); _vm->_screen->getSurface()->markDirtyRect(frameRect); if (anim) { diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 66988482f0..0aab82f5e7 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -37,7 +37,7 @@ enum { kCurrentFrame = -1 }; class DraciEngine; class Animation { - + public: Animation(DraciEngine *vm); ~Animation(); @@ -62,10 +62,14 @@ public: bool isLooping(); void setLooping(bool looping); - void setRelative(int relx, int rely); + double getScaleX() const; + double getScaleY() const; + void setScaling(double scalex, double scaley); + bool isScaled() const; - int _relX; - int _relY; + void setRelative(int relx, int rely); + int getRelativeX(); + int getRelativeY(); private: @@ -75,6 +79,12 @@ private: uint _currentFrame; uint _z; + int _relX; + int _relY; + + double _scaleX; + double _scaleY; + uint _tick; bool _playing; bool _looping; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d913eb904f..46de4825fc 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -171,16 +171,33 @@ void Game::loop() { if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { + // Fetch dragon's animation ID + // FIXME: Need to add proper walking (this only warps the dragon to position) int animID = getObject(kDragonObject)->_anims[0]; Animation *anim = _vm->_anims->getAnimation(animID); Drawable *frame = anim->getFrame(); + // Calculate scaling factor + double scaleX = _currentRoom._pers0 + _currentRoom._persStep * y; + double scaleY = scaleX; + + // Calculate scaled height of sprite + int height = frame->getScaledHeight(scaleY); + + // Set the Z coordinate for the dragon's animation anim->setZ(y+1); - y -= frame->getHeight(); - anim->setRelative(x, y); + // We naturally want the dragon to position its feet to the location of the + // click but sprites are drawn from their top-left corner so we subtract + // the height of the dragon's sprite + y -= height; + anim->setRelative(x, y); + + // Set the scaling factor + anim->setScaling(scaleX, scaleY); + // Play the animation _vm->_anims->play(animID); debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); @@ -221,6 +238,7 @@ void Game::loadRoom(int roomNum) { for (int i = 5; i >= 0; --i) { real[i] = roomReader.readByte(); + debug(2, "%d", real[i]); } _currentRoom._pers0 = real_to_double(real); diff --git a/engines/draci/game.h b/engines/draci/game.h index 0c3dddae20..511ce95e85 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -134,6 +134,9 @@ struct Room { class Game { + // HACK: Remove this before committing; if anyone sees this, remind me :D + friend class Animation; + public: Game(DraciEngine *vm); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index dae7a289a2..9f1cb3371d 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -29,6 +29,8 @@ #include "draci/sprite.h" #include "draci/font.h" +#include + namespace Draci { /** @@ -115,6 +117,87 @@ void Sprite::setMirrorOff() { _mirror = false; } +// TODO: Research what kind of sampling the original player uses +void Sprite::drawScaled(Surface *surface, double scaleX, double scaleY, bool markDirty) const { + + Common::Rect sourceRect(0, 0, _width, _height); + Common::Rect destRect(_x, _y, _x + getScaledWidth(scaleX), _y + getScaledHeight(scaleY)); + Common::Rect surfaceRect(0, 0, surface->w, surface->h); + Common::Rect clippedDestRect(destRect); + + clippedDestRect.clip(surfaceRect); + + // Calculate by how much we need to adjust the source rectangle to account for cropping + const int adjustLeft = clippedDestRect.left - destRect.left; + const int adjustRight = clippedDestRect.right - destRect.right; + const int adjustTop = clippedDestRect.top - destRect.top; + const int adjustBottom = clippedDestRect.bottom - destRect.bottom; + + // Resize source rectangle + sourceRect.left += adjustLeft; + sourceRect.right += adjustRight; + sourceRect.top += adjustTop; + sourceRect.bottom += adjustBottom; + + // Get pointers to source and destination buffers + byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); + byte *src = _data; + + const int transparent = surface->getTransparentColour(); + + // Calculate how many rows and columns we need to draw + const int rows = clippedDestRect.bottom - clippedDestRect.top; + const int columns = clippedDestRect.right - clippedDestRect.left; + + int *rowIndices = new int[rows]; + int *columnIndices = new int[columns]; + + // Precalculate pixel indexes + for (int i = 0; i < rows; ++i) { + rowIndices[i] = lround(i / scaleY); + } + + for (int j = 0; j < columns; ++j) { + columnIndices[j] = lround(j / scaleX); + } + + // Blit the sprite to the surface + for (int i = 0; i < rows; ++i) { + + // Fetch index of current row to be drawn + int row = rowIndices[i]; + + for (int j = 0, q = sourceRect.left; j < columns; ++j, ++q) { + + // Fetch index of current column to be drawn + int column = columnIndices[j]; + + // Don't blit if the pixel is transparent on the target surface + if (src[row * _width + column] != transparent) { + + // Draw the sprite mirrored if the _mirror flag is set + if (_mirror) { + dst[sourceRect.right - q - 1] = src[row * _width + column]; + } else { + dst[q] = src[row * _width + column]; + } + } + } + + // Advance to next row + dst += surface->pitch; + } + + // Mark the sprite's rectangle dirty + if (markDirty) { + surface->markDirtyRect(destRect); + } + + delete[] rowIndices; + delete[] columnIndices; +} + + /** * @brief Draws the sprite to a Draci::Surface * @param surface Pointer to a Draci::Surface @@ -131,16 +214,19 @@ void Sprite::draw(Surface *surface, bool markDirty) const { clippedDestRect.clip(surfaceRect); - int adjustLeft = clippedDestRect.left - destRect.left; - int adjustRight = clippedDestRect.right - destRect.right; - int adjustTop = clippedDestRect.top - destRect.top; - int adjustBottom = clippedDestRect.bottom - destRect.bottom; + // Calculate by how much we need to adjust the source rectangle to account for cropping + const int adjustLeft = clippedDestRect.left - destRect.left; + const int adjustRight = clippedDestRect.right - destRect.right; + const int adjustTop = clippedDestRect.top - destRect.top; + const int adjustBottom = clippedDestRect.bottom - destRect.bottom; + // Resize source rectangle sourceRect.left += adjustLeft; sourceRect.right += adjustRight; sourceRect.top += adjustTop; sourceRect.bottom += adjustBottom; + // Get pointers to source and destination buffers byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); byte *src = _data; @@ -162,6 +248,7 @@ void Sprite::draw(Surface *surface, bool markDirty) const { } } + // Advance to next row dst += surface->pitch; } @@ -175,6 +262,18 @@ Common::Rect Sprite::getRect() const { return Common::Rect(_x, _y, _x + _width, _y + _height); } +Common::Rect Sprite::getScaledRect(double scaleX, double scaleY) const { + return Common::Rect(_x, _y, _x + getScaledWidth(scaleX), _y + getScaledHeight(scaleY)); +} + +uint Sprite::getScaledHeight(double scaleY) const { + return lround(scaleY * _height); +} + +uint Sprite::getScaledWidth(double scaleX) const { + return lround(scaleX * _width); +} + Text::Text(const Common::String &str, Font *font, byte fontColour, int x, int y, uint spacing) { uint len = str.size(); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 38ee2736ea..88a2858671 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -38,11 +38,17 @@ friend class Text; public: virtual void draw(Surface *surface, bool markDirty = true) const = 0; + virtual void drawScaled(Surface *surface, double scaleX, double scaleY, + bool markDirty = true) const = 0; + virtual ~Drawable() {}; virtual uint16 getWidth() { return _width; } virtual uint16 getHeight() { return _height; } + virtual uint getScaledWidth(double scaleX) const = 0; + virtual uint getScaledHeight(double scaleY) const = 0; + virtual int getX() { return _x; } virtual int getY() { return _y; } @@ -53,6 +59,7 @@ public: int getDelay() { return _delay; } virtual Common::Rect getRect() const = 0; + virtual Common::Rect getScaledRect(double scaleX, double scaleY) const = 0; private: uint16 _width; //!< Width of the sprite @@ -89,11 +96,17 @@ public: ~Sprite(); void draw(Surface *surface, bool markDirty = true) const; + void drawScaled(Surface *surface, double scaleX, double scaleY, bool markDirty = true) const; void setMirrorOn(); void setMirrorOff(); virtual Common::Rect getRect() const; + Common::Rect getScaledRect(double scaleX, double scaleY) const; + + virtual uint getScaledWidth(double scaleX) const; + virtual uint getScaledHeight(double scaleY) const; + const byte *getBuffer() const { return _data; } private: -- cgit v1.2.3 From 6097828f546fd6f135bc907d6cd0586bb473d9b5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 20 Jul 2009 17:34:19 +0000 Subject: Made 'show walking map overlay' setting persist when changing rooms. svn-id: r42628 --- engines/draci/animation.h | 2 +- engines/draci/draci.cpp | 20 ++++++++++++-------- engines/draci/game.cpp | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 0aab82f5e7..b54b72947d 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -30,7 +30,7 @@ namespace Draci { -enum { kOverlayImage = -1, kUnused = -2 }; +enum { kOverlayImage = -1, kWalkingMapOverlay = -2, kUnused = -3 }; enum { kCurrentFrame = -1 }; diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 1e7b292229..7e892a7e1e 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -181,23 +181,27 @@ int DraciEngine::go() { case Common::EVENT_KEYDOWN: if (event.kbd.keycode == Common::KEYCODE_RIGHT) _game->changeRoom(_game->nextRoomNum()); + else if (event.kbd.keycode == Common::KEYCODE_LEFT) _game->changeRoom(_game->prevRoomNum()); - else if (event.kbd.keycode == Common::KEYCODE_w) { // Show walking map toggle - // Toggle - showWalkingMap = !showWalkingMap; - if (showWalkingMap) { - _anims->play(-2); - } else { - _anims->stop(-2); - } + // Show walking map toggle + else if (event.kbd.keycode == Common::KEYCODE_w) { + showWalkingMap = !showWalkingMap; } break; default: _mouse->handleEvent(event); } } + + // Show walking map overlay + if (showWalkingMap) { + _anims->play(kWalkingMapOverlay); + } else { + _anims->stop(kWalkingMapOverlay); + } + _game->loop(); _anims->drawScene(_screen->getSurface()); _screen->copyToScreen(); diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 46de4825fc..318246cc16 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -345,7 +345,7 @@ void Game::loadRoom(int roomNum) { Sprite *ov = new Sprite(wlk, kScreenWidth, kScreenHeight, 0, 0, false); - Animation *map = _vm->_anims->addAnimation(-2, 255, false); + Animation *map = _vm->_anims->addAnimation(kWalkingMapOverlay, 255, false); map->addFrame(ov); } -- cgit v1.2.3 From b3a2d186bbca722b0cc172f07222e782e79b96c1 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 04:42:33 +0000 Subject: * Moved scaling support from Animation to Sprite * Now each Sprite (and hence frame in an animation) can have a separate zoom (which is needed for some animations in the game) * Scale factors are not stored any more; instead, we only store scaled dimensions (since these are stored in the data files) and calculate the factors from those. svn-id: r42647 --- engines/draci/animation.cpp | 69 +++++++++++---------------------------------- engines/draci/animation.h | 8 ------ engines/draci/game.cpp | 31 ++++++++++++-------- engines/draci/sprite.cpp | 39 ++++++++++++++----------- engines/draci/sprite.h | 32 ++++++++++----------- 5 files changed, 74 insertions(+), 105 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 3faa85ac63..5b1814f4c4 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,8 +33,6 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _relX = 0; _relY = 0; - _scaleX = 1.0; - _scaleY = 1.0; setPlaying(false); _looping = false; _tick = _vm->_system->getMillis(); @@ -54,12 +52,7 @@ void Animation::setRelative(int relx, int rely) { // Delete the previous frame Common::Rect frameRect; - if (isScaled()) { - frameRect = getFrame()->getScaledRect(_scaleX, _scaleY); - } else { - frameRect = getFrame()->getRect(); - } - + frameRect = getFrame()->getRect(); frameRect.translate(_relX, _relY); _vm->_screen->getSurface()->markDirtyRect(frameRect); @@ -67,24 +60,6 @@ void Animation::setRelative(int relx, int rely) { _relY = rely; } -void Animation::setScaling(double scalex, double scaley) { - - _scaleX = scalex; - _scaleY = scaley; -} - -bool Animation::isScaled() const { - return !(_scaleX == 1.0 && _scaleY == 1.0); -} - -double Animation::getScaleX() const { - return _scaleX; -} - -double Animation::getScaleY() const { - return _scaleY; -} - void Animation::setLooping(bool looping) { _looping = looping; debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", @@ -100,12 +75,7 @@ void Animation::nextFrame(bool force) { Drawable *frame = _frames[_currentFrame]; Common::Rect frameRect; - - if (isScaled()) { - frameRect = frame->getScaledRect(_scaleX, _scaleY); - } else { - frameRect = frame->getRect(); - } + frameRect = frame->getRect(); // Translate rectangle to compensate for relative coordinates frameRect.translate(_relX, _relY); @@ -124,9 +94,9 @@ void Animation::nextFrame(bool force) { } debugC(6, kDraciAnimationDebugLevel, - "anim=%d tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d", + "anim=%d tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d x=%d y=%d", _id, _tick, frame->getDelay(), _tick + frame->getDelay(), _vm->_system->getMillis(), - _currentFrame, _frames.size()); + _currentFrame, _frames.size(), frame->getX(), frame->getY()); } uint Animation::nextFrameNum() { @@ -143,32 +113,29 @@ void Animation::drawFrame(Surface *surface) { if (_frames.size() == 0 || !_playing) return; + Drawable *frame = _frames[_currentFrame]; + if (_id == kOverlayImage) { - _frames[_currentFrame]->drawScaled(surface, _scaleX, _scaleY, false); - } - else { - Drawable *ptr = _frames[_currentFrame]; + frame->draw(surface, false); + } else { - int x = ptr->getX(); - int y = ptr->getY(); + int x = frame->getX(); + int y = frame->getY(); // Take account relative coordinates int newX = x + _relX; int newY = y + _relY; // Translate the frame to those relative coordinates - ptr->setX(newX); - ptr->setY(newY); + frame->setX(newX); + frame->setY(newY); // Draw frame - if (isScaled()) - ptr->drawScaled(surface, _scaleX, _scaleY, true); - else - ptr->drawScaled(surface, _scaleX, _scaleY, true); + frame->drawScaled(surface, true); // Revert back to old coordinates - ptr->setX(x); - ptr->setY(y); + frame->setX(x); + frame->setY(y); } } @@ -261,11 +228,7 @@ void AnimationManager::stop(int id) { // Clean up the last frame that was drawn before stopping Common::Rect frameRect; - if (anim->isScaled()) { - frameRect = anim->getFrame()->getScaledRect(anim->getScaleX(), anim->getScaleY()); - } else { - frameRect = anim->getFrame()->getRect(); - } + frameRect = anim->getFrame()->getRect(); frameRect.translate(anim->getRelativeX(), anim->getRelativeY()); _vm->_screen->getSurface()->markDirtyRect(frameRect); diff --git a/engines/draci/animation.h b/engines/draci/animation.h index b54b72947d..fa28a61599 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -62,11 +62,6 @@ public: bool isLooping(); void setLooping(bool looping); - double getScaleX() const; - double getScaleY() const; - void setScaling(double scalex, double scaley); - bool isScaled() const; - void setRelative(int relx, int rely); int getRelativeX(); int getRelativeY(); @@ -82,9 +77,6 @@ private: int _relX; int _relY; - double _scaleX; - double _scaleY; - uint _tick; bool _playing; bool _looping; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 318246cc16..561ea78c62 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -176,27 +176,33 @@ void Game::loop() { int animID = getObject(kDragonObject)->_anims[0]; Animation *anim = _vm->_anims->getAnimation(animID); - Drawable *frame = anim->getFrame(); - // Calculate scaling factor + // Calculate scaling factors double scaleX = _currentRoom._pers0 + _currentRoom._persStep * y; double scaleY = scaleX; - // Calculate scaled height of sprite - int height = frame->getScaledHeight(scaleY); + Drawable *frame; + + // Set the scaled dimensions for all frames + for (uint i = 0; i < anim->getFramesNum(); ++i) { + frame = anim->getFrame(i); + + // Calculate scaled dimensions + uint scaledWidth = scaleX * frame->getWidth(); + uint scaledHeight = scaleY * frame->getHeight(); + + frame->setScaled(scaledWidth, scaledHeight); + } // Set the Z coordinate for the dragon's animation anim->setZ(y+1); // We naturally want the dragon to position its feet to the location of the // click but sprites are drawn from their top-left corner so we subtract - // the height of the dragon's sprite - y -= height; + // the current height of the dragon's sprite + y -= frame->getScaledHeight(); anim->setRelative(x, y); - // Set the scaling factor - anim->setScaling(scaleX, scaleY); - // Play the animation _vm->_anims->play(animID); @@ -238,7 +244,6 @@ void Game::loadRoom(int roomNum) { for (int i = 5; i >= 0; --i) { real[i] = roomReader.readByte(); - debug(2, "%d", real[i]); } _currentRoom._pers0 = real_to_double(real); @@ -372,8 +377,8 @@ int Game::loadAnimation(uint animNum, uint z) { uint spriteNum = animationReader.readUint16LE() - 1; int x = animationReader.readSint16LE(); int y = animationReader.readSint16LE(); - uint zoomX = animationReader.readUint16LE(); - uint zoomY = animationReader.readUint16LE(); + uint scaledWidth = animationReader.readUint16LE(); + uint scaledHeight = animationReader.readUint16LE(); byte mirror = animationReader.readByte(); uint sample = animationReader.readUint16LE(); uint freq = animationReader.readUint16LE(); @@ -383,6 +388,8 @@ int Game::loadAnimation(uint animNum, uint z) { Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, true); + sp->setScaled(scaledWidth, scaledHeight); + if (mirror) sp->setMirrorOn(); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 9f1cb3371d..23cc386a67 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -61,8 +61,13 @@ Sprite::Sprite(byte *raw_data, uint16 width, uint16 height, int x, int y, _width = width; _height = height; + + _scaledWidth = _width; + _scaledHeight = _height; + _x = x; _y = y; + _delay = 0; _mirror = false; @@ -86,6 +91,7 @@ Sprite::Sprite(byte *sprite_data, uint16 length, int x, int y, bool columnwise) _x = x; _y = y; + _delay = 0; _mirror = false; @@ -95,6 +101,9 @@ Sprite::Sprite(byte *sprite_data, uint16 length, int x, int y, bool columnwise) _width = reader.readSint16LE(); _height = reader.readSint16LE(); + _scaledWidth = _width; + _scaledHeight = _height; + _data = new byte[_width * _height]; reader.read(_data, _width * _height); @@ -118,10 +127,10 @@ void Sprite::setMirrorOff() { } // TODO: Research what kind of sampling the original player uses -void Sprite::drawScaled(Surface *surface, double scaleX, double scaleY, bool markDirty) const { +void Sprite::drawScaled(Surface *surface, bool markDirty) const { Common::Rect sourceRect(0, 0, _width, _height); - Common::Rect destRect(_x, _y, _x + getScaledWidth(scaleX), _y + getScaledHeight(scaleY)); + Common::Rect destRect(_x, _y, _x + _scaledWidth, _y + _scaledHeight); Common::Rect surfaceRect(0, 0, surface->w, surface->h); Common::Rect clippedDestRect(destRect); @@ -152,6 +161,10 @@ void Sprite::drawScaled(Surface *surface, double scaleX, double scaleY, bool mar int *rowIndices = new int[rows]; int *columnIndices = new int[columns]; + // Calculate scaling factors + double scaleX = double(_scaledWidth) / _width; + double scaleY = double(_scaledHeight) / _height; + // Precalculate pixel indexes for (int i = 0; i < rows; ++i) { rowIndices[i] = lround(i / scaleY); @@ -258,20 +271,11 @@ void Sprite::draw(Surface *surface, bool markDirty) const { } } -Common::Rect Sprite::getRect() const { - return Common::Rect(_x, _y, _x + _width, _y + _height); -} - -Common::Rect Sprite::getScaledRect(double scaleX, double scaleY) const { - return Common::Rect(_x, _y, _x + getScaledWidth(scaleX), _y + getScaledHeight(scaleY)); -} - -uint Sprite::getScaledHeight(double scaleY) const { - return lround(scaleY * _height); -} - -uint Sprite::getScaledWidth(double scaleX) const { - return lround(scaleX * _width); +Common::Rect Sprite::getRect(bool scaled) const { + if (scaled) + return Common::Rect(_x, _y, _x + _scaledWidth, _y + _scaledHeight); + else + return Common::Rect(_x, _y, _x + _width, _y + _height); } Text::Text(const Common::String &str, Font *font, byte fontColour, @@ -293,6 +297,9 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, _width = _font->getStringWidth(str, _spacing); _height = _font->getFontHeight(); + + _scaledWidth = _width; + _scaledHeight = _height; } Text::~Text() { diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 88a2858671..717eebaaf0 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -38,16 +38,20 @@ friend class Text; public: virtual void draw(Surface *surface, bool markDirty = true) const = 0; - virtual void drawScaled(Surface *surface, double scaleX, double scaleY, - bool markDirty = true) const = 0; + virtual void drawScaled(Surface *surface, bool markDirty = true) const = 0; virtual ~Drawable() {}; virtual uint16 getWidth() { return _width; } virtual uint16 getHeight() { return _height; } - virtual uint getScaledWidth(double scaleX) const = 0; - virtual uint getScaledHeight(double scaleY) const = 0; + virtual uint getScaledWidth() const { return _scaledWidth; } + virtual uint getScaledHeight() const { return _scaledHeight; } + + virtual void setScaled(uint width, uint height) { + _scaledWidth = width; + _scaledHeight = height; + } virtual int getX() { return _x; } virtual int getY() { return _y; } @@ -58,13 +62,14 @@ public: void setDelay(int delay) { _delay = delay; } int getDelay() { return _delay; } - virtual Common::Rect getRect() const = 0; - virtual Common::Rect getScaledRect(double scaleX, double scaleY) const = 0; + virtual Common::Rect getRect(bool scaled = true) const = 0; private: - uint16 _width; //!< Width of the sprite - uint16 _height; //!< Height of the sprite - int _x, _y; //!< Sprite coordinates + uint16 _width; //!< Width of the sprite + uint16 _height; //!< Height of the sprite + uint _scaledWidth; //!< Scaled width of the sprite + uint _scaledHeight; //!< Scaled height of the sprite + int _x, _y; //!< Sprite coordinates /** The time a drawable should stay on the screen * before being replaced by another or deleted @@ -89,23 +94,18 @@ class Sprite : public Drawable { public: Sprite(byte *raw_data, uint16 width, uint16 height, int x, int y, bool columnwise); - Sprite(byte *sprite_data, uint16 length, int x, int y, bool columnwise); ~Sprite(); void draw(Surface *surface, bool markDirty = true) const; - void drawScaled(Surface *surface, double scaleX, double scaleY, bool markDirty = true) const; + void drawScaled(Surface *surface, bool markDirty = true) const; void setMirrorOn(); void setMirrorOff(); - virtual Common::Rect getRect() const; - Common::Rect getScaledRect(double scaleX, double scaleY) const; - - virtual uint getScaledWidth(double scaleX) const; - virtual uint getScaledHeight(double scaleY) const; + virtual Common::Rect getRect(bool scaled = true) const; const byte *getBuffer() const { return _data; } -- cgit v1.2.3 From 348cbc2b197903252202c041c96b943685dd6fb4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 04:47:01 +0000 Subject: * Removed some unnecessary virtual qualifiers from methods in Drawable, Sprite and Text. * Changed some Drawable members from uint16 to uint. * Added some const qualifiers to methods of Drawable. svn-id: r42648 --- engines/draci/sprite.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 717eebaaf0..e1086cab15 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -42,31 +42,31 @@ public: virtual ~Drawable() {}; - virtual uint16 getWidth() { return _width; } - virtual uint16 getHeight() { return _height; } + uint getWidth() const { return _width; } + uint getHeight() const { return _height; } - virtual uint getScaledWidth() const { return _scaledWidth; } - virtual uint getScaledHeight() const { return _scaledHeight; } + uint getScaledWidth() const { return _scaledWidth; } + uint getScaledHeight() const { return _scaledHeight; } - virtual void setScaled(uint width, uint height) { + void setScaled(uint width, uint height) { _scaledWidth = width; _scaledHeight = height; } - virtual int getX() { return _x; } - virtual int getY() { return _y; } + int getX() const { return _x; } + int getY() const { return _y; } - virtual void setX(int x) { _x = x; } - virtual void setY(int y) { _y = y; } + void setX(int x) { _x = x; } + void setY(int y) { _y = y; } void setDelay(int delay) { _delay = delay; } - int getDelay() { return _delay; } + int getDelay() const { return _delay; } virtual Common::Rect getRect(bool scaled = true) const = 0; private: - uint16 _width; //!< Width of the sprite - uint16 _height; //!< Height of the sprite + uint _width; //!< Width of the sprite + uint _height; //!< Height of the sprite uint _scaledWidth; //!< Scaled width of the sprite uint _scaledHeight; //!< Scaled height of the sprite int _x, _y; //!< Sprite coordinates @@ -105,7 +105,7 @@ public: void setMirrorOn(); void setMirrorOff(); - virtual Common::Rect getRect(bool scaled = true) const; + Common::Rect getRect(bool scaled = true) const; const byte *getBuffer() const { return _data; } @@ -127,7 +127,7 @@ public: void draw(Surface *surface, bool markDirty = true) const; - virtual Common::Rect getRect() const; + Common::Rect getRect() const; private: byte *_text; -- cgit v1.2.3 From 9b32771017de2db833c787c338b01cdcf76d27a9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 04:50:11 +0000 Subject: Fixed scaled mirrored sprite drawing. This change enables the NoSense logo animation to be played correctly. svn-id: r42649 --- engines/draci/sprite.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 23cc386a67..97118dd506 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -180,7 +180,7 @@ void Sprite::drawScaled(Surface *surface, bool markDirty) const { // Fetch index of current row to be drawn int row = rowIndices[i]; - for (int j = 0, q = sourceRect.left; j < columns; ++j, ++q) { + for (int j = 0; j < columns; ++j) { // Fetch index of current column to be drawn int column = columnIndices[j]; @@ -190,9 +190,9 @@ void Sprite::drawScaled(Surface *surface, bool markDirty) const { // Draw the sprite mirrored if the _mirror flag is set if (_mirror) { - dst[sourceRect.right - q - 1] = src[row * _width + column]; + dst[sourceRect.left + columns - j - 1] = src[row * _width + column]; } else { - dst[q] = src[row * _width + column]; + dst[sourceRect.left + j] = src[row * _width + column]; } } } -- cgit v1.2.3 From 42e8e1e126ad71fd39e3afdd2031b4f7ac7f9b6a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 05:00:11 +0000 Subject: If a frame has scaled dimensions set to 0, the engine now does no scaling instead of scaling it to nothing. Fixes the disappearing chair bug. svn-id: r42650 --- engines/draci/game.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 561ea78c62..c01e544986 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -388,6 +388,17 @@ int Game::loadAnimation(uint animNum, uint z) { Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, true); + // Some frames set the scaled dimensions to 0 even though other frames + // from the same animations have them set to normal values + // We work around this by assuming it means no scaling is necessary + if (scaledWidth == 0) { + scaledWidth = sp->getWidth(); + } + + if (scaledHeight == 0) { + scaledHeight = sp->getHeight(); + } + sp->setScaled(scaledWidth, scaledHeight); if (mirror) -- cgit v1.2.3 From 5a77f089e1c6ea851851c55084a12023380656f1 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 05:03:34 +0000 Subject: Check whether the walking map overlay is already in the desired state so we don't start/stop it over and over. svn-id: r42651 --- engines/draci/draci.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 7e892a7e1e..88fe731b40 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -196,9 +196,11 @@ int DraciEngine::go() { } // Show walking map overlay - if (showWalkingMap) { + // If the walking map overlay is already in the wanted state don't + // start / stop it constantly + if (showWalkingMap && !_anims->getAnimation(kWalkingMapOverlay)->isPlaying()) { _anims->play(kWalkingMapOverlay); - } else { + } else if (!showWalkingMap && _anims->getAnimation(kWalkingMapOverlay)->isPlaying()) { _anims->stop(kWalkingMapOverlay); } -- cgit v1.2.3 From ef37d0a9b05607141558ba358a7dfd361aa26d9e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 07:18:00 +0000 Subject: * Stopped AnimationManager::drawScene() from marking its own dirtiness. * Instead, Animation::nextFrame() marks both the old and the new frame dirty. This makes it possible to only update the real screen when the animation changes and results in a pretty big speedup. * Added utility method Animation::markDirtyRect() which takes a (Surface *) and marks a dirty rect on it for the current frame. * Fixed artifacts when moving the dragon. svn-id: r42652 --- engines/draci/animation.cpp | 44 +++++++++++++++++++++++++------------------- engines/draci/animation.h | 2 ++ engines/draci/game.cpp | 26 ++++++++++++++++---------- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 5b1814f4c4..9cf8f35a8d 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -50,11 +50,7 @@ bool Animation::isLooping() { void Animation::setRelative(int relx, int rely) { // Delete the previous frame - Common::Rect frameRect; - - frameRect = getFrame()->getRect(); - frameRect.translate(_relX, _relY); - _vm->_screen->getSurface()->markDirtyRect(frameRect); + markDirtyRect(_vm->_screen->getSurface()); _relX = relx; _relY = rely; @@ -66,6 +62,18 @@ void Animation::setLooping(bool looping) { looping, _id); } +void Animation::markDirtyRect(Surface *surface) { + // Fetch the current frame's rectangle + Drawable *frame = _frames[_currentFrame]; + Common::Rect frameRect = frame->getRect(); + + // Translate rectangle to compensate for relative coordinates + frameRect.translate(_relX, _relY); + + // Mark the rectangle dirty on the surface + surface->markDirtyRect(frameRect); +} + void Animation::nextFrame(bool force) { // If there's only one or no frames, or if the animation is not playing, return @@ -73,13 +81,8 @@ void Animation::nextFrame(bool force) { return; Drawable *frame = _frames[_currentFrame]; - - Common::Rect frameRect; - frameRect = frame->getRect(); + Surface *surface = _vm->_screen->getSurface(); - // Translate rectangle to compensate for relative coordinates - frameRect.translate(_relX, _relY); - if (force || (_tick + frame->getDelay() <= _vm->_system->getMillis())) { // If we are at the last frame and not looping, stop the animation // The animation is also restarted to frame zero @@ -87,9 +90,14 @@ void Animation::nextFrame(bool force) { _currentFrame = 0; setPlaying(false); } else { - _vm->_screen->getSurface()->markDirtyRect(frameRect); + // Mark old frame dirty so it gets deleted + markDirtyRect(surface); + _currentFrame = nextFrameNum(); _tick = _vm->_system->getMillis(); + + // Fetch new frame and mark it dirty + markDirtyRect(surface); } } @@ -131,7 +139,7 @@ void Animation::drawFrame(Surface *surface) { frame->setY(newY); // Draw frame - frame->drawScaled(surface, true); + frame->drawScaled(surface, false); // Revert back to old coordinates frame->setX(x); @@ -215,6 +223,9 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { void AnimationManager::play(int id) { Animation *anim = getAnimation(id); + // Mark the first frame dirty so it gets displayed + anim->markDirtyRect(_vm->_screen->getSurface()); + if (anim) { anim->setPlaying(true); @@ -226,12 +237,7 @@ void AnimationManager::stop(int id) { Animation *anim = getAnimation(id); // Clean up the last frame that was drawn before stopping - Common::Rect frameRect; - - frameRect = anim->getFrame()->getRect(); - - frameRect.translate(anim->getRelativeX(), anim->getRelativeY()); - _vm->_screen->getSurface()->markDirtyRect(frameRect); + anim->markDirtyRect(_vm->_screen->getSurface()); if (anim) { anim->setPlaying(false); diff --git a/engines/draci/animation.h b/engines/draci/animation.h index fa28a61599..0e29934699 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -66,6 +66,8 @@ public: int getRelativeX(); int getRelativeY(); + void markDirtyRect(Surface *surface); + private: uint nextFrameNum(); diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index c01e544986..360375f0b8 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -181,7 +181,22 @@ void Game::loop() { double scaleX = _currentRoom._pers0 + _currentRoom._persStep * y; double scaleY = scaleX; - Drawable *frame; + // Set the Z coordinate for the dragon's animation + anim->setZ(y+1); + + // Fetch current frame + Drawable *frame = anim->getFrame(); + + // Fetch base height of the frame + uint height = frame->getHeight(); + + // We naturally want the dragon to position its feet to the location of the + // click but sprites are drawn from their top-left corner so we subtract + // the current height of the dragon's sprite + // We also need to do this before we change the frames' scaled dimensions + // so setRelative() can correctly delete the old frame + y -= scaleY * height; + anim->setRelative(x, y); // Set the scaled dimensions for all frames for (uint i = 0; i < anim->getFramesNum(); ++i) { @@ -194,15 +209,6 @@ void Game::loop() { frame->setScaled(scaledWidth, scaledHeight); } - // Set the Z coordinate for the dragon's animation - anim->setZ(y+1); - - // We naturally want the dragon to position its feet to the location of the - // click but sprites are drawn from their top-left corner so we subtract - // the current height of the dragon's sprite - y -= frame->getScaledHeight(); - anim->setRelative(x, y); - // Play the animation _vm->_anims->play(animID); -- cgit v1.2.3 From 1c86a986d971aaa7ef77e4251b7069fe3ee33b88 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 22 Jul 2009 07:22:12 +0000 Subject: Fix warnings svn-id: r42653 --- engines/draci/game.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 360375f0b8..39e4c39f71 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -195,7 +195,7 @@ void Game::loop() { // the current height of the dragon's sprite // We also need to do this before we change the frames' scaled dimensions // so setRelative() can correctly delete the old frame - y -= scaleY * height; + y -= (int)(scaleY * height); anim->setRelative(x, y); // Set the scaled dimensions for all frames @@ -203,8 +203,8 @@ void Game::loop() { frame = anim->getFrame(i); // Calculate scaled dimensions - uint scaledWidth = scaleX * frame->getWidth(); - uint scaledHeight = scaleY * frame->getHeight(); + uint scaledWidth = (uint)(scaleX * frame->getWidth()); + uint scaledHeight = (uint)(scaleY * frame->getHeight()); frame->setScaled(scaledWidth, scaledHeight); } @@ -386,8 +386,8 @@ int Game::loadAnimation(uint animNum, uint z) { uint scaledWidth = animationReader.readUint16LE(); uint scaledHeight = animationReader.readUint16LE(); byte mirror = animationReader.readByte(); - uint sample = animationReader.readUint16LE(); - uint freq = animationReader.readUint16LE(); + /* uint sample = */ animationReader.readUint16LE(); + /* uint freq = */ animationReader.readUint16LE(); uint delay = animationReader.readUint16LE(); BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); -- cgit v1.2.3 From 1726cc8d247f2ad8ac5b4136b866055d3e30155b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 22 Jul 2009 11:30:57 +0000 Subject: * Disabled unconditional execution of gates' scripts * Fixed bug in Animation::nextFrame() which caused non-looping animations to linger on forever * Stopped setting looping to false explicitly in AnimationManager::addAnimation() since the Animation constructor already does that svn-id: r42657 --- engines/draci/animation.cpp | 8 +++++--- engines/draci/game.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 9cf8f35a8d..adcb8e2d82 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,7 +33,7 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _relX = 0; _relY = 0; - setPlaying(false); + _playing = false; _looping = false; _tick = _vm->_system->getMillis(); _currentFrame = 0; @@ -87,8 +87,11 @@ void Animation::nextFrame(bool force) { // If we are at the last frame and not looping, stop the animation // The animation is also restarted to frame zero if ((_currentFrame == getFramesNum() - 1) && !_looping) { + // When the animation reaches its end, stop it + _vm->_anims->stop(_id); + + // Reset the frame to 0 _currentFrame = 0; - setPlaying(false); } else { // Mark old frame dirty so it gets deleted markDirtyRect(surface); @@ -213,7 +216,6 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { anim->setID(id); anim->setZ(z); anim->setPlaying(playing); - anim->setLooping(false); insertAnimation(anim); diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 39e4c39f71..2a0e5dca6f 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -321,10 +321,10 @@ void Game::loadRoom(int roomNum) { // HACK: Gates' scripts shouldn't be run unconditionally // This is for testing - for (uint i = 0; i < _currentRoom._numGates; ++i) { - debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); - _vm->_script->run(_currentRoom._program, gates[i]); - } + //for (uint i = 0; i < _currentRoom._numGates; ++i) { + // debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); + // _vm->_script->run(_currentRoom._program, gates[i]); + //} // Set room palette f = _vm->_paletteArchive->getFile(_currentRoom._palette); -- cgit v1.2.3 From a2bca06b3fe00379d8accf29e7f442fe0a3cd781 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 24 Jul 2009 01:54:13 +0000 Subject: Added support for per-animation scaling (via scaling factors). I have decided to go for a mixed approach (where Animation has a global scaling factor for the whole animation which is separate from Drawable's scaled width and height) so the animation can be scaled more naturally when the scale often changes (like with perspective when the dragon is walking). Previously, one had to alter the sizes of each frame of the dragon's animation whenever the dragon moved which was unclean. svn-id: r42680 --- engines/draci/animation.cpp | 24 ++++++++++++++++++++++++ engines/draci/animation.h | 5 +++++ engines/draci/game.cpp | 14 ++------------ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index adcb8e2d82..74e876401d 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,6 +33,8 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _relX = 0; _relY = 0; + _scaleX = 1.0; + _scaleY = 1.0; _playing = false; _looping = false; _tick = _vm->_system->getMillis(); @@ -69,6 +71,10 @@ void Animation::markDirtyRect(Surface *surface) { // Translate rectangle to compensate for relative coordinates frameRect.translate(_relX, _relY); + + // Take animation scaling into account + frameRect.setWidth(frameRect.width() * _scaleX); + frameRect.setHeight(frameRect.height() * _scaleY); // Mark the rectangle dirty on the surface surface->markDirtyRect(frameRect); @@ -141,12 +147,23 @@ void Animation::drawFrame(Surface *surface) { frame->setX(newX); frame->setY(newY); + // Save scaled width and height + int scaledWidth = frame->getScaledWidth(); + int scaledHeight = frame->getScaledHeight(); + + // Take into account per-animation scaling and adjust the current frames dimensions + if (_scaleX != 1.0 || _scaleY != 1.0) + frame->setScaled(scaledWidth * _scaleX, scaledHeight * _scaleY); + // Draw frame frame->drawScaled(surface, false); // Revert back to old coordinates frame->setX(x); frame->setY(y); + + // Revert back to old dimensions + frame->setScaled(scaledWidth, scaledHeight); } } @@ -183,6 +200,13 @@ void Animation::setPlaying(bool playing) { _playing = playing; } +void Animation::setScaleFactors(double scaleX, double scaleY) { + markDirtyRect(_vm->_screen->getSurface()); + + _scaleX = scaleX; + _scaleY = scaleY; +} + void Animation::addFrame(Drawable *frame) { _frames.push_back(frame); } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 0e29934699..683af7c812 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -66,6 +66,8 @@ public: int getRelativeX(); int getRelativeY(); + void setScaleFactors(double scaleX, double scaleY); + void markDirtyRect(Surface *surface); private: @@ -79,6 +81,9 @@ private: int _relX; int _relY; + double _scaleX; + double _scaleY; + uint _tick; bool _playing; bool _looping; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 2a0e5dca6f..de925fe11f 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -193,21 +193,11 @@ void Game::loop() { // We naturally want the dragon to position its feet to the location of the // click but sprites are drawn from their top-left corner so we subtract // the current height of the dragon's sprite - // We also need to do this before we change the frames' scaled dimensions - // so setRelative() can correctly delete the old frame y -= (int)(scaleY * height); anim->setRelative(x, y); - // Set the scaled dimensions for all frames - for (uint i = 0; i < anim->getFramesNum(); ++i) { - frame = anim->getFrame(i); - - // Calculate scaled dimensions - uint scaledWidth = (uint)(scaleX * frame->getWidth()); - uint scaledHeight = (uint)(scaleY * frame->getHeight()); - - frame->setScaled(scaledWidth, scaledHeight); - } + // Set the per-animation scaling factor + anim->setScaleFactors(scaleX, scaleY); // Play the animation _vm->_anims->play(animID); -- cgit v1.2.3 From c1ad0c3926f4d53a9c5fdefefde9344d4abb6f10 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 24 Jul 2009 05:00:53 +0000 Subject: * Added tracking and deleting animations by index (which represents the order in which they were loaded). This is needed by some GPL commands. * Added Game::getNumObjects() which returns the number of objects in the game * Fixed segfault (accessing a null Animation *) * Added some docs to various things svn-id: r42683 --- engines/draci/animation.cpp | 91 +++++++++++++++++++++++++++++++++++++++------ engines/draci/animation.h | 40 ++++++++++++++++++-- engines/draci/game.cpp | 22 +++++++++++ engines/draci/game.h | 6 +++ engines/draci/script.cpp | 28 +++++++++++++- engines/draci/script.h | 2 + 6 files changed, 172 insertions(+), 17 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 74e876401d..83a21ee543 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -28,8 +28,9 @@ namespace Draci { -Animation::Animation(DraciEngine *vm) : _vm(vm) { +Animation::Animation(DraciEngine *vm, int index) : _vm(vm) { _id = kUnused; + _index = index; _z = 0; _relX = 0; _relY = 0; @@ -201,6 +202,11 @@ void Animation::setPlaying(bool playing) { } void Animation::setScaleFactors(double scaleX, double scaleY) { + + debugC(5, kDraciAnimationDebugLevel, + "Setting scaling factors on anim %d (scaleX: %.3f scaleY: %.3f)", + _id, scaleX, scaleY); + markDirtyRect(_vm->_screen->getSurface()); _scaleX = scaleX; @@ -211,6 +217,14 @@ void Animation::addFrame(Drawable *frame) { _frames.push_back(frame); } +int Animation::getIndex() { + return _index; +} + +void Animation::setIndex(int index) { + _index = index; +} + Drawable *Animation::getFrame(int frameNum) { // If no argument is passed, return the current frame @@ -235,7 +249,10 @@ void Animation::deleteFrames() { Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { - Animation *anim = new Animation(_vm); + // Increment animation index + ++_lastIndex; + + Animation *anim = new Animation(_vm, _lastIndex); anim->setID(id); anim->setZ(z); @@ -249,26 +266,26 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { void AnimationManager::play(int id) { Animation *anim = getAnimation(id); - // Mark the first frame dirty so it gets displayed - anim->markDirtyRect(_vm->_screen->getSurface()); - if (anim) { + // Mark the first frame dirty so it gets displayed + anim->markDirtyRect(_vm->_screen->getSurface()); + anim->setPlaying(true); - debugC(5, kDraciAnimationDebugLevel, "Playing animation %d...", id); + debugC(3, kDraciAnimationDebugLevel, "Playing animation %d...", id); } } void AnimationManager::stop(int id) { Animation *anim = getAnimation(id); - // Clean up the last frame that was drawn before stopping - anim->markDirtyRect(_vm->_screen->getSurface()); - if (anim) { + // Clean up the last frame that was drawn before stopping + anim->markDirtyRect(_vm->_screen->getSurface()); + anim->setPlaying(false); - debugC(5, kDraciAnimationDebugLevel, "Stopping animation %d...", id); + debugC(3, kDraciAnimationDebugLevel, "Stopping animation %d...", id); } } @@ -298,7 +315,11 @@ void AnimationManager::insertAnimation(Animation *animObj) { } void AnimationManager::addOverlay(Drawable *overlay, uint z) { - Animation *anim = new Animation(_vm); + // Since this is an overlay, we don't need it to be deleted + // when the GPL Release command is invoked so we pass the index + // as kIgnoreIndex + Animation *anim = new Animation(_vm, kIgnoreIndex); + anim->setID(kOverlayImage); anim->setZ(z); anim->setPlaying(true); @@ -362,17 +383,38 @@ void AnimationManager::deleteAnimation(int id) { Common::List::iterator it; + int index = -1; + + // Iterate for the first time to delete the animation for (it = _animations.begin(); it != _animations.end(); ++it) { if ((*it)->getID() == id) { (*it)->deleteFrames(); _animations.erase(it); + + // Remember index of the deleted animation + index = (*it)->getIndex(); + + debugC(3, kDraciAnimationDebugLevel, "Deleting animation %d...", id); + break; } } + + // Iterate the second time to decrease indexes greater than the deleted animation index + for (it = _animations.begin(); it != _animations.end(); ++it) { + if ((*it)->getIndex() == index && (*it)->getIndex() != kIgnoreIndex) { + (*it)->setIndex(index-1); + } + } + + // Decrement index of last animation + _lastIndex -= 1; } void AnimationManager::deleteOverlays() { + debugC(3, kDraciAnimationDebugLevel, "Deleting overlays..."); + Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { @@ -384,7 +426,9 @@ void AnimationManager::deleteOverlays() { } void AnimationManager::deleteAll() { - + + debugC(3, kDraciAnimationDebugLevel, "Deleting all animations..."); + Common::List::iterator it; for (it = _animations.begin(); it != _animations.end(); ++it) { @@ -392,6 +436,29 @@ void AnimationManager::deleteAll() { } _animations.clear(); + + _lastIndex = -1; +} + +int AnimationManager::getLastIndex() { + return _lastIndex; +} + +void AnimationManager::deleteAfterIndex(int index) { + + Common::List::iterator it; + + for (it = _animations.begin(); it != _animations.end(); ++it) { + if ((*it)->getIndex() > index) { + + debugC(3, kDraciAnimationDebugLevel, "Deleting animation %d...", (*it)->getID()); + + (*it)->deleteFrames(); + _animations.erase(it); + } + } + + _lastIndex = index; } } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 683af7c812..5229972543 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -30,16 +30,30 @@ namespace Draci { +/** + * Animation IDs for those animations that don't have their IDs + * specified in the data files. + */ enum { kOverlayImage = -1, kWalkingMapOverlay = -2, kUnused = -3 }; +/** + * Default argument to Animation::getFrame() that makes it return + * the current frame instead of the user specifying it. + */ enum { kCurrentFrame = -1 }; +/** + * Used by overlays as a neutral index that won't get + * released with the GPL Release command. + */ +enum { kIgnoreIndex = -2 }; + class DraciEngine; class Animation { public: - Animation(DraciEngine *vm); + Animation(DraciEngine *v, int index); ~Animation(); uint getZ(); @@ -66,6 +80,9 @@ public: int getRelativeX(); int getRelativeY(); + int getIndex(); + void setIndex(int index); + void setScaleFactors(double scaleX, double scaleY); void markDirtyRect(Surface *surface); @@ -74,7 +91,16 @@ private: uint nextFrameNum(); - int _id; + /** Internal animation ID + * (as specified in the data files and the bytecode) + */ + int _id; + + /** The recency index of an animation, i.e. the most recently added animation has + * the highest index. Some script commands need this. + */ + int _index; + uint _currentFrame; uint _z; @@ -96,7 +122,7 @@ private: class AnimationManager { public: - AnimationManager(DraciEngine *vm) : _vm(vm) {}; + AnimationManager(DraciEngine *vm) : _vm(vm), _lastIndex(-1) {} ~AnimationManager() { deleteAll(); } Animation *addAnimation(int id, uint z, bool playing = false); @@ -113,12 +139,20 @@ public: Animation *getAnimation(int id); + int getLastIndex(); + void deleteAfterIndex(int index); + private: void sortAnimations(); void insertAnimation(Animation *anim); DraciEngine *_vm; Common::List _animations; + + /** The index of the most recently added animation. + * See Animation::_index for details. + */ + int _lastIndex; }; } diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index de925fe11f..e85a1780db 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -448,6 +448,10 @@ GameObject *Game::getObject(uint objNum) { return _objects + objNum; } +uint Game::getNumObjects() { + return _info._numObjects; +} + void Game::loadOverlays() { uint x, y, z, num; @@ -533,6 +537,24 @@ int Game::getIconStatus(int iconID) { return _iconStatus[iconID]; } +/** + * The GPL command Mark sets the animation index (which specifies the order in which + * animations were loaded in) which is then used by the Release command to delete + * all animations that have an index greater than the one marked. + */ + +int Game::getMarkedAnimationIndex() { + return _markedAnimationIndex; +} + +/** + * See Game::getMarkedAnimationIndex(). + */ + +void Game::setMarkedAnimationIndex(int index) { + _markedAnimationIndex = index; +} + Game::~Game() { delete[] _persons; delete[] _variables; diff --git a/engines/draci/game.h b/engines/draci/game.h index 511ce95e85..d4c9c256ee 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -177,6 +177,7 @@ public: void loadOverlays(); void loadObject(uint numObj); + uint getNumObjects(); GameObject *getObject(uint objNum); int getVariable(int varNum); @@ -184,6 +185,9 @@ public: int getIconStatus(int iconID); + int getMarkedAnimationIndex(); + void setMarkedAnimationIndex(int index); + private: DraciEngine *_vm; int *_variables; @@ -193,6 +197,8 @@ private: byte *_iconStatus; GameObject *_objects; Room _currentRoom; + + int _markedAnimationIndex; //!< Used by the Mark GPL command }; } // End of namespace Draci diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 2d0a33db86..2dd5d9288a 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -78,8 +78,8 @@ void Script::setupCommandList() { { 18, 3, "StopMusic", 0, { 0 }, NULL }, { 18, 4, "FadeOutMusic", 1, { 1 }, NULL }, { 18, 5, "FadeInMusic", 1, { 1 }, NULL }, - { 19, 1, "Mark", 0, { 0 }, NULL }, - { 19, 2, "Release", 0, { 0 }, NULL }, + { 19, 1, "Mark", 0, { 0 }, &Script::mark }, + { 19, 2, "Release", 0, { 0 }, &Script::release }, { 20, 1, "Play", 0, { 0 }, NULL }, { 21, 1, "LoadMap", 1, { 2 }, NULL }, { 21, 2, "RoomMap", 0, { 0 }, NULL }, @@ -307,6 +307,30 @@ void Script::c_Let(Common::Queue ¶ms) { _vm->_game->setVariable(var, value); } +void Script::mark(Common::Queue ¶ms) { + _vm->_game->setMarkedAnimationIndex(_vm->_anims->getLastIndex()); +} + +void Script::release(Common::Queue ¶ms) { + int markedIndex = _vm->_game->getMarkedAnimationIndex(); + + // Also delete those animations from the game's objects + for (uint i = 0; i < _vm->_game->getNumObjects(); ++i) { + GameObject *obj = _vm->_game->getObject(i); + + for (uint j = 0; j < obj->_anims.size(); ++j) { + Animation *anim; + + anim = _vm->_anims->getAnimation(obj->_anims[j]); + if (anim != NULL && anim->getIndex() > markedIndex) + obj->_anims.remove_at(j); + } + } + + // Delete animations which have an index greater than the marked index + _vm->_anims->deleteAfterIndex(markedIndex); +} + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression diff --git a/engines/draci/script.h b/engines/draci/script.h index d8e9a2f49f..0cbb0b49fc 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -104,6 +104,8 @@ private: void c_Let(Common::Queue ¶ms); void load(Common::Queue ¶ms); void start(Common::Queue ¶ms); + void mark(Common::Queue ¶ms); + void release(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From 5faceb595f1cd92353876d3930dfa626d0d075a9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 24 Jul 2009 05:07:27 +0000 Subject: Temporary mapped GPL command StartPlay to handler for Start and reenabled gates' scripts (for added effects and testing). svn-id: r42684 --- engines/draci/game.cpp | 8 ++++---- engines/draci/script.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index e85a1780db..3f91bf1697 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -311,10 +311,10 @@ void Game::loadRoom(int roomNum) { // HACK: Gates' scripts shouldn't be run unconditionally // This is for testing - //for (uint i = 0; i < _currentRoom._numGates; ++i) { - // debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); - // _vm->_script->run(_currentRoom._program, gates[i]); - //} + for (uint i = 0; i < _currentRoom._numGates; ++i) { + debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); + _vm->_script->run(_currentRoom._program, gates[i]); + } // Set room palette f = _vm->_paletteArchive->getFile(_currentRoom._palette); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 2dd5d9288a..7081d7f769 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -46,7 +46,7 @@ void Script::setupCommandList() { { 3, 1, "if", 2, { 4, 3 }, &Script::c_If }, { 4, 1, "Start", 2, { 3, 2 }, &Script::start }, { 5, 1, "Load", 2, { 3, 2 }, &Script::load }, - { 5, 2, "StartPlay", 2, { 3, 2 }, NULL }, + { 5, 2, "StartPlay", 2, { 3, 2 }, &Script::start }, { 5, 3, "JustTalk", 0, { 0 }, NULL }, { 5, 4, "JustStay", 0, { 0 }, NULL }, { 6, 1, "Talk", 2, { 3, 2 }, NULL }, -- cgit v1.2.3 From b7e97efb7fbd26c91693082339466308c52e7e08 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 02:23:00 +0000 Subject: * Added handlers for the ObjStat and ObjStat_On GPL commands * Removed temporary hack I accidentally committed svn-id: r42730 --- engines/draci/game.h | 3 --- engines/draci/script.cpp | 36 +++++++++++++++++++++++++++++++++--- engines/draci/script.h | 2 ++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/engines/draci/game.h b/engines/draci/game.h index d4c9c256ee..2cee3e024d 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -134,9 +134,6 @@ struct Room { class Game { - // HACK: Remove this before committing; if anyone sees this, remind me :D - friend class Animation; - public: Game(DraciEngine *vm); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 7081d7f769..1d491b0efa 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -50,8 +50,8 @@ void Script::setupCommandList() { { 5, 3, "JustTalk", 0, { 0 }, NULL }, { 5, 4, "JustStay", 0, { 0 }, NULL }, { 6, 1, "Talk", 2, { 3, 2 }, NULL }, - { 7, 1, "ObjStat", 2, { 3, 3 }, NULL }, - { 7, 2, "ObjStat_On", 2, { 3, 3 }, NULL }, + { 7, 1, "ObjStat", 2, { 3, 3 }, &Script::objStat }, + { 7, 2, "ObjStat_On", 2, { 3, 3 }, &Script::objStatOn }, { 8, 1, "IcoStat", 2, { 3, 3 }, NULL }, { 9, 1, "Dialogue", 1, { 2 }, NULL }, { 9, 2, "ExitDialogue", 0, { 0 }, NULL }, @@ -249,7 +249,7 @@ int Script::funcIsObjOff(int objID) { GameObject *obj = _vm->_game->getObject(objID); // We index locations from 0 (as opposed to the original player where it was from 1) - // That's why the "invalid" location 0 from the data files is converted to -1 + // That's why the "away" location 0 from the data files is converted to -1 return !obj->_visible && obj->_location != -1; } @@ -331,6 +331,36 @@ void Script::release(Common::Queue ¶ms) { _vm->_anims->deleteAfterIndex(markedIndex); } +void Script::objStatOn(Common::Queue ¶ms) { + int objID = params.pop() - 1; + int roomID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + + obj->_location = roomID; + obj->_visible = true; +} + +void Script::objStat(Common::Queue ¶ms) { + int status = params.pop(); + int objID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + + if (status == 1) { + return; + } else if (status == 2) { + obj->_visible = false; + } else { + obj->_visible = false; + obj->_location = -1; + } + + for (uint i = 0; i < obj->_anims.size(); ++i) { + _vm->_anims->stop(obj->_anims[i]); + } +} + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression diff --git a/engines/draci/script.h b/engines/draci/script.h index 0cbb0b49fc..4e1943ed8f 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -106,6 +106,8 @@ private: void start(Common::Queue ¶ms); void mark(Common::Queue ¶ms); void release(Common::Queue ¶ms); + void objStat(Common::Queue ¶ms); + void objStatOn(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From d28658984dcceb7c090af9f7040d1490239a820b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 03:28:04 +0000 Subject: * Added DraciEngine::_initArchive and made Game use it. Fixes a memory bug because Game uses pointers from the init archive which should outlive it (but didn't previously). * Added support for setting loop status to Game. * Made some GPL commands check whether we are in the correct loop status before executing. svn-id: r42731 --- engines/draci/draci.cpp | 3 +++ engines/draci/draci.h | 1 + engines/draci/game.cpp | 25 +++++++++++++++++-------- engines/draci/game.h | 17 +++++++++++++++-- engines/draci/script.cpp | 8 ++++++++ 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 88fe731b40..deaa39bba1 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -53,6 +53,7 @@ const Common::String roomsPath("MIST.DFW"); const Common::String animationsPath("ANIM.DFW"); const Common::String iconsPath("HRA.DFW"); const Common::String walkingMapsPath("MAPY.DFW"); +const Common::String initPath("INIT.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { @@ -81,6 +82,7 @@ int DraciEngine::init() { initGraphics(kScreenWidth, kScreenHeight, false); // Open game's archives + _initArchive = new BArchive(initPath); _objectsArchive = new BArchive(objectsPath); _spritesArchive = new BArchive(spritesPath); _paletteArchive = new BArchive(palettePath); @@ -227,6 +229,7 @@ DraciEngine::~DraciEngine() { delete _script; delete _anims; + delete _initArchive; delete _paletteArchive; delete _objectsArchive; delete _spritesArchive; diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 630ce0c29a..e6b78f310a 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -68,6 +68,7 @@ public: BArchive *_overlaysArchive; BArchive *_animationsArchive; BArchive *_walkingMapsArchive; + BArchive *_initArchive; Common::RandomSource _rnd; }; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3f91bf1697..d7ae538209 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -39,14 +39,13 @@ static double real_to_double(byte real[6]); Game::Game(DraciEngine *vm) : _vm(vm) { unsigned int i; - Common::String path("INIT.DFW"); - BArchive initArchive(path); + BArchive *initArchive = _vm->_initArchive; BAFile *file; // Read in persons - file = initArchive.getFile(5); + file = initArchive->getFile(5); Common::MemoryReadStream personData(file->_data, file->_length); unsigned int numPersons = file->_length / personSize; @@ -63,7 +62,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in dialog offsets - file = initArchive.getFile(4); + file = initArchive->getFile(4); Common::MemoryReadStream dialogData(file->_data, file->_length); unsigned int numDialogs = file->_length / sizeof(uint16); @@ -80,7 +79,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in game info - file = initArchive.getFile(3); + file = initArchive->getFile(3); Common::MemoryReadStream gameData(file->_data, file->_length); _info._startRoom = gameData.readByte() - 1; @@ -105,7 +104,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in variables - file = initArchive.getFile(2); + file = initArchive->getFile(2); unsigned int numVariables = file->_length / sizeof (int16); _variables = new int[numVariables]; @@ -120,13 +119,13 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in item icon status - file = initArchive.getFile(1); + file = initArchive->getFile(1); _iconStatus = file->_data; uint numIcons = file->_length; // Read in object status - file = initArchive.getFile(0); + file = initArchive->getFile(0); unsigned int numObjects = file->_length; _objects = new GameObject[numObjects]; @@ -153,6 +152,8 @@ Game::Game(DraciEngine *vm) : _vm(vm) { } void Game::init() { + _loopStatus = kStatusOrdinary; + loadObject(kDragonObject); GameObject *dragon = getObject(kDragonObject); @@ -521,6 +522,14 @@ void Game::changeRoom(uint roomNum) { loadOverlays(); } +void Game::setLoopStatus(LoopStatus status) { + _loopStatus = status; +} + +LoopStatus Game::getLoopStatus() { + return _loopStatus; +} + int Game::getRoomNum() { return _currentRoom._roomNum; } diff --git a/engines/draci/game.h b/engines/draci/game.h index 2cee3e024d..6be44cdd68 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -132,6 +132,12 @@ struct Room { GPL2Program _program; }; +enum LoopStatus { + kStatusGate, kStatusOrdinary, kStatusInventory, + kStatusDialogue, kStatusTalk, kStatusStrange, + kStatusFade +}; + class Game { public: @@ -185,15 +191,22 @@ public: int getMarkedAnimationIndex(); void setMarkedAnimationIndex(int index); + void setLoopStatus(LoopStatus status); + LoopStatus getLoopStatus(); + private: DraciEngine *_vm; - int *_variables; + GameInfo _info; - Person *_persons; uint *_dialogOffsets; + + int *_variables; byte *_iconStatus; + Person *_persons; GameObject *_objects; + Room _currentRoom; + LoopStatus _loopStatus; int _markedAnimationIndex; //!< Used by the Mark GPL command }; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 1d491b0efa..ad601f093d 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -265,6 +265,10 @@ int Script::funcIsObjAway(int objID) { /* GPL commands */ void Script::load(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + int objID = params.pop() - 1; int animID = params.pop() - 1; @@ -275,6 +279,10 @@ void Script::load(Common::Queue ¶ms) { } void Script::start(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + int objID = params.pop() - 1; int animID = params.pop() - 1; -- cgit v1.2.3 From ed59a12d53e9dc26c53620333b6a94a11980f3a8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 03:37:22 +0000 Subject: Implemented ExecUse, ExecLook and ExecInit GPL commands. svn-id: r42732 --- engines/draci/script.cpp | 39 ++++++++++++++++++++++++++++++++++++--- engines/draci/script.h | 3 +++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index ad601f093d..a7bb8bda09 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -67,9 +67,9 @@ void Script::setupCommandList() { { 13, 1, "FadePalette", 3, { 1, 1, 1 }, NULL }, { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 }, NULL }, { 14, 1, "NewRoom", 2, { 3, 1 }, NULL }, - { 15, 1, "ExecInit", 1, { 3 }, NULL }, - { 15, 2, "ExecLook", 1, { 3 }, NULL }, - { 15, 3, "ExecUse", 1, { 3 }, NULL }, + { 15, 1, "ExecInit", 1, { 3 }, &Script::execInit }, + { 15, 2, "ExecLook", 1, { 3 }, &Script::execLook }, + { 15, 3, "ExecUse", 1, { 3 }, &Script::execUse }, { 16, 1, "RepaintInventory", 0, { 0 }, NULL }, { 16, 2, "ExitInventory", 0, { 0 }, NULL }, { 17, 1, "ExitMap", 0, { 0 }, NULL }, @@ -369,6 +369,39 @@ void Script::objStat(Common::Queue ¶ms) { } } +void Script::execInit(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int objID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + run(obj->_program, obj->_init); +} + +void Script::execLook(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int objID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + run(obj->_program, obj->_look); +} + +void Script::execUse(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int objID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + run(obj->_program, obj->_use); +} + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression diff --git a/engines/draci/script.h b/engines/draci/script.h index 4e1943ed8f..11a1c6f3a8 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -108,6 +108,9 @@ private: void release(Common::Queue ¶ms); void objStat(Common::Queue ¶ms); void objStatOn(Common::Queue ¶ms); + void execInit(Common::Queue ¶ms); + void execLook(Common::Queue ¶ms); + void execUse(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From ceb9f18132cb32df7d76a03d0371f41a29c5d120 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 03:41:28 +0000 Subject: Made Script::run() manually mark the last animation index before it executes a program. This is done to prevent Release wreaking havoc if it is unpaired (i.e. if the script forgot to call a Mark first). svn-id: r42733 --- engines/draci/script.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index a7bb8bda09..1d2f4a8892 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -565,6 +565,10 @@ const GPL2Command *Script::findCommand(byte num, byte subnum) { int Script::run(GPL2Program program, uint16 offset) { + // Mark the last animation index before we do anything so a Release command + // doesn't unload too many animations if we forget to use a Mark command first + _vm->_game->setMarkedAnimationIndex(_vm->_anims->getLastIndex()); + // Stream reader for the whole program Common::MemoryReadStream reader(program._bytecode, program._length); -- cgit v1.2.3 From 22c372137f2649fa614966b24918064c2bb44726 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 04:23:59 +0000 Subject: Added Movement enum that enumerates the animations for the dragon's movement. svn-id: r42734 --- engines/draci/game.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/engines/draci/game.h b/engines/draci/game.h index 6be44cdd68..5898c04bd0 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -138,6 +138,18 @@ enum LoopStatus { kStatusFade }; +/** + * Enumerates the animations for the dragon's movement. + */ + +enum Movement { + kMoveUndefined, kMoveDown, kMoveUp, kMoveRight, kMoveLeft, + kMoveRightDown, kMoveRightUp, kMoveLeftDown, kMoveLeftUp, + kMoveDownRight, kMoveUpRight, kMoveDownLeft, kMoveUpLeft, + kMoveLeftRight, kMoveRightLeft, kMoveUpStopLeft, kMoveUpStopRight, + kSpeakRight, kSpeakLeft, kStopRight, kStopLeft +}; + class Game { public: -- cgit v1.2.3 From 20baaf93f5df7871e93162db479fe1ab526fe35c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 04:36:43 +0000 Subject: * Moved walking code to Game::walkHero(). * Implemented WalkOn GPL command. * Temporarily remaped StayOn and WalkOnPlay to WalkOn (for testing). svn-id: r42735 --- engines/draci/game.cpp | 55 +++++++++++++++++++++++++----------------------- engines/draci/game.h | 2 ++ engines/draci/script.cpp | 17 ++++++++++++--- engines/draci/script.h | 1 + 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d7ae538209..5cfbefebad 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -171,41 +171,44 @@ void Game::loop() { int y = _vm->_mouse->getPosY(); if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { - - // Fetch dragon's animation ID - // FIXME: Need to add proper walking (this only warps the dragon to position) - int animID = getObject(kDragonObject)->_anims[0]; + walkHero(x, y); + } + } +} - Animation *anim = _vm->_anims->getAnimation(animID); +void Game::walkHero(int x, int y) { + // Fetch dragon's animation ID + // FIXME: Need to add proper walking (this only warps the dragon to position) + int animID = getObject(kDragonObject)->_anims[0]; - // Calculate scaling factors - double scaleX = _currentRoom._pers0 + _currentRoom._persStep * y; - double scaleY = scaleX; + Animation *anim = _vm->_anims->getAnimation(animID); - // Set the Z coordinate for the dragon's animation - anim->setZ(y+1); + // Calculate scaling factors + double scaleX = _currentRoom._pers0 + _currentRoom._persStep * y; + double scaleY = scaleX; - // Fetch current frame - Drawable *frame = anim->getFrame(); + // Set the Z coordinate for the dragon's animation + anim->setZ(y+1); - // Fetch base height of the frame - uint height = frame->getHeight(); + // Fetch current frame + Drawable *frame = anim->getFrame(); - // We naturally want the dragon to position its feet to the location of the - // click but sprites are drawn from their top-left corner so we subtract - // the current height of the dragon's sprite - y -= (int)(scaleY * height); - anim->setRelative(x, y); + // Fetch base height of the frame + uint height = frame->getHeight(); - // Set the per-animation scaling factor - anim->setScaleFactors(scaleX, scaleY); + // We naturally want the dragon to position its feet to the location of the + // click but sprites are drawn from their top-left corner so we subtract + // the current height of the dragon's sprite + y -= (int)(scaleY * height); + anim->setRelative(x, y); - // Play the animation - _vm->_anims->play(animID); + // Set the per-animation scaling factor + anim->setScaleFactors(scaleX, scaleY); - debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); - } - } + // Play the animation + _vm->_anims->play(animID); + + debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); } void Game::loadRoom(int roomNum) { diff --git a/engines/draci/game.h b/engines/draci/game.h index 5898c04bd0..d8e0d137b7 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -187,6 +187,8 @@ public: return n; } + void walkHero(int x, int y); + void loadRoom(int roomNum); int loadAnimation(uint animNum, uint z); void loadOverlays(); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 1d2f4a8892..6177a71a49 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -58,9 +58,9 @@ void Script::setupCommandList() { { 9, 3, "ResetDialogue", 0, { 0 }, NULL }, { 9, 4, "ResetDialogueFrom", 0, { 0 }, NULL }, { 9, 5, "ResetBlock", 1, { 3 }, NULL }, - { 10, 1, "WalkOn", 3, { 1, 1, 3 }, NULL }, - { 10, 2, "StayOn", 3, { 1, 1, 3 }, NULL }, - { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, NULL }, + { 10, 1, "WalkOn", 3, { 1, 1, 3 }, &Script::walkOn }, + { 10, 2, "StayOn", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation + { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation { 11, 1, "LoadPalette", 1, { 2 }, NULL }, { 12, 1, "SetPalette", 0, { 0 }, NULL }, { 12, 2, "BlackPalette", 0, { 0 }, NULL }, @@ -402,6 +402,17 @@ void Script::execUse(Common::Queue ¶ms) { run(obj->_program, obj->_use); } +void Script::walkOn(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int x = params.pop(); + int y = params.pop(); + params.pop(); // facing direction, not used yet + + _vm->_game->walkHero(x, y); +} /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression diff --git a/engines/draci/script.h b/engines/draci/script.h index 11a1c6f3a8..7ed194f68d 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -111,6 +111,7 @@ private: void execInit(Common::Queue ¶ms); void execLook(Common::Queue ¶ms); void execUse(Common::Queue ¶ms); + void walkOn(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From 6970e178dcb9c34eb5c021a27144bd64cd2534a7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 18:29:43 +0000 Subject: Replaced magic constant with enum kWalkingMapOverlay. svn-id: r42778 --- engines/draci/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 5cfbefebad..46c7887e46 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -499,7 +499,7 @@ void Game::changeRoom(uint roomNum) { _vm->_anims->deleteOverlays(); // Delete walking map testing overlay - _vm->_anims->deleteAnimation(-2); + _vm->_anims->deleteAnimation(kWalkingMapOverlay); int oldRoomNum = _currentRoom._roomNum; -- cgit v1.2.3 From 20a744bdd2bc889fdb1a460768c13f8be2d60d09 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 18:33:20 +0000 Subject: Simplified rectangle height and width calculation in Sprite::drawScaled() (use methods of Common::Rect instead of doing it manually). svn-id: r42779 --- engines/draci/sprite.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 97118dd506..1b9d0acefb 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -126,7 +126,6 @@ void Sprite::setMirrorOff() { _mirror = false; } -// TODO: Research what kind of sampling the original player uses void Sprite::drawScaled(Surface *surface, bool markDirty) const { Common::Rect sourceRect(0, 0, _width, _height); @@ -155,8 +154,8 @@ void Sprite::drawScaled(Surface *surface, bool markDirty) const { const int transparent = surface->getTransparentColour(); // Calculate how many rows and columns we need to draw - const int rows = clippedDestRect.bottom - clippedDestRect.top; - const int columns = clippedDestRect.right - clippedDestRect.left; + const int rows = clippedDestRect.height(); + const int columns = clippedDestRect.width(); int *rowIndices = new int[rows]; int *columnIndices = new int[columns]; -- cgit v1.2.3 From 3f571c7eae6ebdce030bf81cb0d7667dfc076bc7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 25 Jul 2009 23:43:21 +0000 Subject: Handled the '|' char correctly when drawing text (it serves as both a newline and end-of-string marker). svn-id: r42788 --- engines/draci/font.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index f1ef984adf..23d0740268 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -211,15 +211,24 @@ void Font::drawString(Surface *dst, const byte *str, uint len, assert(y >= 0); int curx = x; + int cury = y; for (unsigned int i = 0; i < len; ++i) { + + // If we encounter the '|' char (newline and end of string marker), + // skip it and go to the start of the next line + if (str[i] == '|') { + cury += getFontHeight() + 1; + curx = x; + continue; + } // Return early if there's no more space on the screen - if (curx >= dst->w) { + if (curx >= dst->w || cury >= dst->h) { return; } - - drawChar(dst, str[i], curx, y, markDirty); + + drawChar(dst, str[i], curx, cury, markDirty); curx += getCharWidth(str[i]) + spacing; } } -- cgit v1.2.3 From 2525ec46de6dc07cb2975d81619bafbc1c135846 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 26 Jul 2009 00:04:12 +0000 Subject: * Removed friend declarations in Drawable for Sprite and Text, and made Drawable's private members protected so they can access them * Added Text::drawScaled() and altered Text::getRect() so Text instances can be accessed through a Drawable pointer. Scaling text is planned for later because it's not essential. svn-id: r42789 --- engines/draci/sprite.cpp | 3 ++- engines/draci/sprite.h | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 1b9d0acefb..04308a3eed 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -331,7 +331,8 @@ void Text::draw(Surface *surface, bool markDirty) const { _font->drawString(surface, _text, _length, _x, _y, _spacing); } -Common::Rect Text::getRect() const { +// TODO: Handle scaled parameter properly by implementing Text scaling +Common::Rect Text::getRect(bool scaled) const { return Common::Rect(_x, _y, _x + _width, _y + _height); } diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index e1086cab15..44ae8a202b 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -33,9 +33,6 @@ namespace Draci { class Drawable { -friend class Sprite; -friend class Text; - public: virtual void draw(Surface *surface, bool markDirty = true) const = 0; virtual void drawScaled(Surface *surface, bool markDirty = true) const = 0; @@ -64,7 +61,7 @@ public: virtual Common::Rect getRect(bool scaled = true) const = 0; -private: +protected: uint _width; //!< Width of the sprite uint _height; //!< Height of the sprite uint _scaledWidth; //!< Scaled width of the sprite @@ -124,10 +121,14 @@ public: void setText(const Common::String &str); void setColour(byte fontColour); void setSpacing(uint spacing); - + void draw(Surface *surface, bool markDirty = true) const; - Common::Rect getRect() const; + // TODO: drawScaled just calls draw so Text can be accessed through a Drawable pointer. + // Handle scaling text sometimes (not essential). + + void drawScaled(Surface *surface, bool markDirty = true) const { draw(surface, markDirty); } + Common::Rect getRect(bool) const; private: byte *_text; -- cgit v1.2.3 From b14828c4ce1a12163bb898d02595ea24c3dfc50a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 03:08:19 +0000 Subject: * Added Font::getStringHeight() * Made Font::getStringWidth() calculate the width of the string properly now that handling of multi-row strings is in * Fixed bug which caused the last column of pixels in the last letter of a string to linger on the screen svn-id: r42832 --- engines/draci/font.cpp | 59 ++++++++++++++++++++++++++++++++++++++++---------- engines/draci/font.h | 2 ++ 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 23d0740268..66fbda30b7 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -29,7 +29,7 @@ #include "draci/font.h" namespace Draci { - +de const Common::String kFontSmall("Small.fon"); const Common::String kFontBig("Big.fon"); @@ -188,7 +188,7 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con } if (markDirty) { - Common::Rect r(tx, ty, tx + xPixelsToDraw, ty + yPixelsToDraw); + Common::Rect r(tx, ty, tx + xPixelsToDraw + 1, ty + yPixelsToDraw); dst->markDirtyRect(r); } } @@ -218,14 +218,14 @@ void Font::drawString(Surface *dst, const byte *str, uint len, // If we encounter the '|' char (newline and end of string marker), // skip it and go to the start of the next line if (str[i] == '|') { - cury += getFontHeight() + 1; + cury += getFontHeight(); curx = x; continue; } - // Return early if there's no more space on the screen - if (curx >= dst->w || cury >= dst->h) { - return; + // Break early if there's no more space on the screen + if (curx >= dst->w - 1 || cury >= dst->h - 1) { + break; } drawChar(dst, str[i], curx, cury, markDirty); @@ -260,16 +260,53 @@ void Font::drawString(Surface *dst, const Common::String &str, int Font::getStringWidth(const Common::String &str, int spacing) const { int width = 0; + + // Real length, including '|' separators uint len = str.size(); - for (unsigned int i = 0; i < len; ++i) { + + // Here we will store the in-game length of the longest line + uint lineLength = 0; + + for (unsigned int i = 0, tmp = 0; i < len; ++i) { + + // Newline char encountered, skip it and store the new length if it is greater + if (str[i] == '|') { + if (tmp > width) { + width = tmp; + } + continue; + } + uint8 charIndex = str[i] - kCharIndexOffset; - width += _charWidths[charIndex]; + tmp += _charWidths[charIndex]; + tmp += spacing; } - // Add width of spaces, if any - width += (len - 1) * spacing; + return width + 1; +} - return width; +/** + * @brief Calculate the height of a string by counting the number of '|' chars (which + * are used as newline characters and end-of-string markers) + * + * @param str String to draw + * @param spacing Space to leave between individual characters. Defaults to 0. + * + * @return The calculated height of the string + */ + + +int Font::getStringHeight(const Common::String &str) const { + uint len = str.size(); + int separators = 0; + + for (unsigned int i = 0; i < len; ++i) { + if (str[i] == '|') { + ++separators; + } + } + + return separators * getFontHeight(); } } // End of namespace Draci diff --git a/engines/draci/font.h b/engines/draci/font.h index c269124919..67c32aa791 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -68,6 +68,8 @@ public: int x, int y, int spacing, bool markDirty = true) const; int getStringWidth(const Common::String &str, int spacing = 0) const; + int getStringHeight(const Common::String &str) const; + void setColour(uint8 colour); private: -- cgit v1.2.3 From ddf8f1cbb539e60eada6dfeaea560498ac89e3bc Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 03:57:43 +0000 Subject: * Removed unused variable * Fixed unsigned to signed comparison warning svn-id: r42834 --- engines/draci/font.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 66fbda30b7..2a6e5989f0 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -29,7 +29,7 @@ #include "draci/font.h" namespace Draci { -de + const Common::String kFontSmall("Small.fon"); const Common::String kFontBig("Big.fon"); @@ -259,14 +259,11 @@ void Font::drawString(Surface *dst, const Common::String &str, */ int Font::getStringWidth(const Common::String &str, int spacing) const { - int width = 0; + unsigned int width = 0; // Real length, including '|' separators uint len = str.size(); - // Here we will store the in-game length of the longest line - uint lineLength = 0; - for (unsigned int i = 0, tmp = 0; i < len; ++i) { // Newline char encountered, skip it and store the new length if it is greater -- cgit v1.2.3 From fa59e4b16b502716c527bf2e809f684007039dac Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 04:14:59 +0000 Subject: * Added Sprite::getPixel() (takes into account whether a sprite is mirrored or scaled) * Made the Text class internally store a Common::String instead of a byte * svn-id: r42835 --- engines/draci/sprite.cpp | 48 +++++++++++++++++++++++++++++------------------- engines/draci/sprite.h | 13 +++++++++++-- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 04308a3eed..31a55bfddb 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -126,6 +126,28 @@ void Sprite::setMirrorOff() { _mirror = false; } + +int Sprite::getPixel(int x, int y) const { + + Common::Rect rect = getRect(); + + int dy = y - rect.top; + int dx = x - rect.left; + + // Calculate scaling factors + double scaleX = double(_scaledWidth) / _width; + double scaleY = double(_scaledHeight) / _height; + + int sy = lround(dy * scaleY); + int sx = lround(dx * scaleX); + + if (_mirror) + return _data[sy * _width + (_width - sx)]; + else + return _data[sy * _width + sx]; +} + + void Sprite::drawScaled(Surface *surface, bool markDirty) const { Common::Rect sourceRect(0, 0, _width, _height); @@ -269,6 +291,7 @@ void Sprite::draw(Surface *surface, bool markDirty) const { surface->markDirtyRect(destRect); } } + Common::Rect Sprite::getRect(bool scaled) const { if (scaled) @@ -279,15 +302,11 @@ Common::Rect Sprite::getRect(bool scaled) const { Text::Text(const Common::String &str, Font *font, byte fontColour, int x, int y, uint spacing) { - uint len = str.size(); - _length = len; - _x = x; _y = y; _delay = 0; - _text = new byte[len]; - memcpy(_text, str.c_str(), len); + _text = str; _spacing = spacing; _colour = fontColour; @@ -295,27 +314,17 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, _font = font; _width = _font->getStringWidth(str, _spacing); - _height = _font->getFontHeight(); + _height = _font->getStringHeight(str); _scaledWidth = _width; _scaledHeight = _height; } -Text::~Text() { - delete[] _text; -} - void Text::setText(const Common::String &str) { - delete[] _text; - - uint len = str.size(); - _length = len; - _width = _font->getStringWidth(str, _spacing); - _height = _font->getFontHeight(); + _height = _font->getStringHeight(str); - _text = new byte[len]; - memcpy(_text, str.c_str(), len); + _text = str; } void Text::setColour(byte fontColour) { @@ -328,7 +337,8 @@ void Text::setSpacing(uint spacing) { void Text::draw(Surface *surface, bool markDirty) const { _font->setColour(_colour); - _font->drawString(surface, _text, _length, _x, _y, _spacing); + + _font->drawString(surface, _text, _x, _y, _spacing); } // TODO: Handle scaled parameter properly by implementing Text scaling diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 44ae8a202b..77e45d6a7c 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -31,6 +31,8 @@ namespace Draci { +enum DrawableType { kDrawableText, kDrawableSprite }; + class Drawable { public: @@ -60,6 +62,8 @@ public: int getDelay() const { return _delay; } virtual Common::Rect getRect(bool scaled = true) const = 0; + + virtual DrawableType getType() const = 0; protected: uint _width; //!< Width of the sprite @@ -105,6 +109,9 @@ public: Common::Rect getRect(bool scaled = true) const; const byte *getBuffer() const { return _data; } + int getPixel(int x, int y) const; + + DrawableType getType() const { return kDrawableSprite; } private: byte *_data; //!< Pointer to a buffer containing raw sprite data (row-wise) @@ -116,7 +123,7 @@ class Text : public Drawable { public: Text(const Common::String &str, Font *font, byte fontColour, int x, int y, uint spacing = 0); - ~Text(); + ~Text() {}; void setText(const Common::String &str); void setColour(byte fontColour); @@ -130,8 +137,10 @@ public: void drawScaled(Surface *surface, bool markDirty = true) const { draw(surface, markDirty); } Common::Rect getRect(bool) const; + DrawableType getType() const { return kDrawableText; } + private: - byte *_text; + Common::String _text; uint _length; uint8 _colour; uint _spacing; -- cgit v1.2.3 From 673bae444379a522182b1cac47912f798ee46315 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 04:18:44 +0000 Subject: * Added AnimationManager::addText() for adding text animations * Added AnimationManager::getTopAnimationID(x, y) which returns the ID of the top layer animation located on a point * Added Animation::getScale{X,Y}() * Fixed a few bugs related to animations sometimes having no frames svn-id: r42836 --- engines/draci/animation.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++++ engines/draci/animation.h | 7 ++- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 83a21ee543..cb4035a475 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -213,6 +213,14 @@ void Animation::setScaleFactors(double scaleX, double scaleY) { _scaleY = scaleY; } +double Animation::getScaleX() { + return _scaleX; +} + +double Animation::getScaleY() { + return _scaleY; +} + void Animation::addFrame(Drawable *frame) { _frames.push_back(frame); } @@ -227,6 +235,11 @@ void Animation::setIndex(int index) { Drawable *Animation::getFrame(int frameNum) { + // If there are no frames stored, return NULL + if (_frames.size() == 0) { + return NULL; + } + // If no argument is passed, return the current frame if (frameNum == kCurrentFrame) { return _frames[_currentFrame]; @@ -241,6 +254,13 @@ uint Animation::getFramesNum() { void Animation::deleteFrames() { + // If there are no frames to delete, return + if (_frames.size() == 0) { + return; + } + + markDirtyRect(_vm->_screen->getSurface()); + for (int i = getFramesNum() - 1; i >= 0; --i) { delete _frames[i]; _frames.pop_back(); @@ -263,6 +283,19 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { return anim; } +Animation *AnimationManager::addText(int id, bool playing) { + + Animation *anim = new Animation(_vm, kIgnoreIndex); + + anim->setID(id); + anim->setZ(256); + anim->setPlaying(playing); + + insertAnimation(anim); + + return anim; +} + void AnimationManager::play(int id) { Animation *anim = getAnimation(id); @@ -461,4 +494,77 @@ void AnimationManager::deleteAfterIndex(int index) { _lastIndex = index; } +int AnimationManager::getTopAnimationID(int x, int y) { + + Common::List::iterator it; + + // The default return value if no animations were found on these coordinates (not even overlays) + // i.e. the black background shows through so treat it as an overlay + int retval = kOverlayImage; + + // Get transparent colour for the current screen + const int transparent = _vm->_screen->getSurface()->getTransparentColour(); + + for (it = _animations.reverse_begin(); it != _animations.end(); --it) { + + Animation *anim = *it; + + // If the animation is not playing, ignore it + if (!anim->isPlaying()) { + continue; + } + + Drawable *frame = anim->getFrame(); + + if (frame == NULL) { + continue; + } + + int oldX = frame->getX(); + int oldY = frame->getY(); + + // Take account relative coordinates + int newX = oldX + anim->getRelativeX(); + int newY = oldY + anim->getRelativeY(); + + // Translate the frame to those relative coordinates + frame->setX(newX); + frame->setY(newY); + + // Save scaled width and height + int scaledWidth = frame->getScaledWidth(); + int scaledHeight = frame->getScaledHeight(); + + // Take into account per-animation scaling and adjust the current frames dimensions + if (anim->getScaleX() != 1.0 || anim->getScaleY() != 1.0) + frame->setScaled(scaledWidth * anim->getScaleX(), scaledHeight * anim->getScaleY()); + + if (frame->getRect().contains(x, y)) { + + if (frame->getType() == kDrawableText) { + + retval = anim->getID(); + + } else if (frame->getType() == kDrawableSprite && + reinterpret_cast(frame)->getPixel(x, y) != transparent) { + + retval = anim->getID(); + } + } + + // Revert back to old coordinates + frame->setX(oldX); + frame->setY(oldY); + + // Revert back to old dimensions + frame->setScaled(scaledWidth, scaledHeight); + + // Found an animation + if (retval != kOverlayImage) + break; + } + + return retval; +} + } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 5229972543..66b16647bd 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -34,7 +34,7 @@ namespace Draci { * Animation IDs for those animations that don't have their IDs * specified in the data files. */ -enum { kOverlayImage = -1, kWalkingMapOverlay = -2, kUnused = -3 }; +enum { kOverlayImage = -1, kWalkingMapOverlay = -2, kTitleText = -3, kUnused = -4 }; /** * Default argument to Animation::getFrame() that makes it return @@ -84,6 +84,8 @@ public: void setIndex(int index); void setScaleFactors(double scaleX, double scaleY); + double getScaleX(); + double getScaleY(); void markDirtyRect(Surface *surface); @@ -126,6 +128,7 @@ public: ~AnimationManager() { deleteAll(); } Animation *addAnimation(int id, uint z, bool playing = false); + Animation *addText(int id, bool playing = false); void addOverlay(Drawable *overlay, uint z); void play(int id); @@ -142,6 +145,8 @@ public: int getLastIndex(); void deleteAfterIndex(int index); + int getTopAnimationID(int x, int y); + private: void sortAnimations(); void insertAnimation(Animation *anim); -- cgit v1.2.3 From aa6efa33f1b5bb7485cb60012d71fdc14f3b9e67 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 04:20:27 +0000 Subject: Fixed segfault when the screen is deleted before animations (the Animation destructor still needs to use the screen). svn-id: r42837 --- engines/draci/draci.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index deaa39bba1..057000c7ca 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -223,11 +223,11 @@ DraciEngine::~DraciEngine() { delete _smallFont; delete _bigFont; - delete _screen; delete _mouse; - delete _game; delete _script; delete _anims; + delete _game; + delete _screen; delete _initArchive; delete _paletteArchive; -- cgit v1.2.3 From 00980849699460f8e9919599a8d89dc3dd60bc2e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 04:47:38 +0000 Subject: Fixed one more bug related to animations having no frames. svn-id: r42838 --- engines/draci/animation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index cb4035a475..49a59b2b71 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -52,8 +52,9 @@ bool Animation::isLooping() { void Animation::setRelative(int relx, int rely) { - // Delete the previous frame - markDirtyRect(_vm->_screen->getSurface()); + // Delete the previous frame if there is one + if (_frames.size() > 0) + markDirtyRect(_vm->_screen->getSurface()); _relX = relx; _relY = rely; -- cgit v1.2.3 From 019b7f310b7b0443fda505341bdfcda5c0b755f8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 04:51:34 +0000 Subject: * Added Game::getObjectWithAnimation() which finds the object that owns an animation with a certain ID * Made GameObjects track their titles as Strings rather than byte * * Made the engine display the title of the object under the cursor (added a special animation ID for that, kTitleText) svn-id: r42839 --- engines/draci/game.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- engines/draci/game.h | 11 +++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 46c7887e46..09bcf4cf13 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -153,6 +153,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { void Game::init() { _loopStatus = kStatusOrdinary; + _objUnderCursor = kOverlayImage; + + _vm->_anims->addText(kTitleText, true); loadObject(kDragonObject); @@ -173,9 +176,42 @@ void Game::loop() { if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { walkHero(x, y); } + + int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + + int curObject = getObjectWithAnimation(animUnderCursor); + + Animation *atitle = _vm->_anims->getAnimation(kTitleText); + + // TODO: Handle displaying title in the proper location + + atitle->deleteFrames(); + if (curObject != kNotFound) { + GameObject *obj = &_objects[curObject]; + Text *title = new Text (obj->_title, _vm->_bigFont, kFontColour1, 0, 0); + atitle->addFrame(title); + } + + debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); + + } } +int Game::getObjectWithAnimation(int animID) { + for (uint i = 0; i < _info._numObjects; ++i) { + GameObject *obj = &_objects[i]; + + for (uint j = 0; j < obj->_anims.size(); ++j) { + if (obj->_anims[j] == animID) { + return i; + } + } + } + + return kNotFound; +} + void Game::walkHero(int x, int y) { // Fetch dragon's animation ID // FIXME: Need to add proper walking (this only warps the dragon to position) @@ -441,8 +477,12 @@ void Game::loadObject(uint objNum) { obj->_absNum = objNum; file = _vm->_objectsArchive->getFile(objNum * 3 + 1); - obj->_title = file->_data; + // The first byte of the file is the length of the string (without the length) + assert(file->_length - 1 == file->_data[0]); + + obj->_title = Common::String((char *)(file->_data+1), file->_length-1); + file = _vm->_objectsArchive->getFile(objNum * 3 + 2); obj->_program._bytecode = file->_data; obj->_program._length = file->_length; diff --git a/engines/draci/game.h b/engines/draci/game.h index d8e0d137b7..fbc1d3283e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -43,6 +43,10 @@ enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; +enum { + kNotFound = -1 +}; + class WalkingMap { public: @@ -82,7 +86,7 @@ private: struct GameObject { - GameObject() : _title(NULL) {} + GameObject() {} uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; @@ -93,7 +97,7 @@ struct GameObject { uint16 _absNum; Common::Array _anims; GPL2Program _program; - byte *_title; + Common::String _title; int _location; bool _visible; }; @@ -196,6 +200,7 @@ public: uint getNumObjects(); GameObject *getObject(uint objNum); + int getObjectWithAnimation(int animID); int getVariable(int varNum); void setVariable(int varNum, int value); @@ -222,6 +227,8 @@ private: Room _currentRoom; LoopStatus _loopStatus; + int _objUnderCursor; + int _markedAnimationIndex; //!< Used by the Mark GPL command }; -- cgit v1.2.3 From 21a22f7f77bd876414e6155747d4a037ae0c1f23 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 05:30:58 +0000 Subject: Added methods to Mouse for setting the state of the button. svn-id: r42840 --- engines/draci/mouse.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h index 918b10d75f..8135482929 100644 --- a/engines/draci/mouse.h +++ b/engines/draci/mouse.h @@ -53,6 +53,9 @@ public: CursorType getCursorType() { return _cursorType; } bool lButtonPressed() { return _lButton; } bool rButtonPressed() { return _rButton; } + void lButtonSet(bool state) { _lButton = state; } + void rButtonSet(bool state) { _rButton = state; } + uint16 getPosX() { return _x; } uint16 getPosY() { return _y; } -- cgit v1.2.3 From 5a44af4433cb61607c39894d87291d33b2d4010c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 27 Jul 2009 05:34:22 +0000 Subject: Enabled running of look/use scripts on left/right mouse button press for testing (Warning: unstable in some places). svn-id: r42841 --- engines/draci/game.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 09bcf4cf13..620a8ca9e7 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -178,8 +178,10 @@ void Game::loop() { } int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + Animation *anim = _vm->_anims->getAnimation(animUnderCursor); int curObject = getObjectWithAnimation(animUnderCursor); + GameObject *obj = &_objects[curObject]; Animation *atitle = _vm->_anims->getAnimation(kTitleText); @@ -187,9 +189,19 @@ void Game::loop() { atitle->deleteFrames(); if (curObject != kNotFound) { - GameObject *obj = &_objects[curObject]; Text *title = new Text (obj->_title, _vm->_bigFont, kFontColour1, 0, 0); atitle->addFrame(title); + + // HACK: Test running look and use scripts + if (_vm->_mouse->lButtonPressed()) { + _vm->_script->run(obj->_program, obj->_look); + _vm->_mouse->lButtonSet(false); + } + + if (_vm->_mouse->rButtonPressed()) { + _vm->_script->run(obj->_program, obj->_use); + _vm->_mouse->rButtonSet(false); + } } debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); -- cgit v1.2.3 From 33af83c65070458339a04d32db3e81260491641e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 00:46:36 +0000 Subject: * Added method Animation::currentFrameNum() * Renamed Animation::getFramesNum() to Animation::getFrameCount() for clarity. svn-id: r42873 --- engines/draci/animation.cpp | 14 +++++++++----- engines/draci/animation.h | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 49a59b2b71..6cde72a9d2 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -85,7 +85,7 @@ void Animation::markDirtyRect(Surface *surface) { void Animation::nextFrame(bool force) { // If there's only one or no frames, or if the animation is not playing, return - if (getFramesNum() < 2 || !_playing) + if (getFrameCount() < 2 || !_playing) return; Drawable *frame = _frames[_currentFrame]; @@ -94,7 +94,7 @@ void Animation::nextFrame(bool force) { if (force || (_tick + frame->getDelay() <= _vm->_system->getMillis())) { // If we are at the last frame and not looping, stop the animation // The animation is also restarted to frame zero - if ((_currentFrame == getFramesNum() - 1) && !_looping) { + if ((_currentFrame == getFrameCount() - 1) && !_looping) { // When the animation reaches its end, stop it _vm->_anims->stop(_id); @@ -120,7 +120,7 @@ void Animation::nextFrame(bool force) { uint Animation::nextFrameNum() { - if ((_currentFrame == getFramesNum() - 1) && _looping) + if ((_currentFrame == getFrameCount() - 1) && _looping) return 0; else return _currentFrame + 1; @@ -249,10 +249,14 @@ Drawable *Animation::getFrame(int frameNum) { } } -uint Animation::getFramesNum() { +uint Animation::getFrameCount() { return _frames.size(); } +uint Animation::currentFrameNum() { + return _currentFrame; +} + void Animation::deleteFrames() { // If there are no frames to delete, return @@ -262,7 +266,7 @@ void Animation::deleteFrames() { markDirtyRect(_vm->_screen->getSurface()); - for (int i = getFramesNum() - 1; i >= 0; --i) { + for (int i = getFrameCount() - 1; i >= 0; --i) { delete _frames[i]; _frames.pop_back(); } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 66b16647bd..6642107b25 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -67,7 +67,8 @@ public: void addFrame(Drawable *frame); Drawable *getFrame(int frameNum = kCurrentFrame); - uint getFramesNum(); + uint currentFrameNum(); + uint getFrameCount(); void deleteFrames(); bool isPlaying(); -- cgit v1.2.3 From dd9303d27e5b55175781b55c9da63468ce287a2a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 01:02:50 +0000 Subject: * Implemented GPL function ActPhase (as Script::funcActPhase()) * Trivial implementation of the Play GPL command * Fixed Script::load() to load animation IDs to objects in increasing order (needed by funcActPhase()) svn-id: r42874 --- engines/draci/script.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++----- engines/draci/script.h | 2 ++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 6177a71a49..7669dc4c1b 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -80,7 +80,7 @@ void Script::setupCommandList() { { 18, 5, "FadeInMusic", 1, { 1 }, NULL }, { 19, 1, "Mark", 0, { 0 }, &Script::mark }, { 19, 2, "Release", 0, { 0 }, &Script::release }, - { 20, 1, "Play", 0, { 0 }, NULL }, + { 20, 1, "Play", 0, { 0 }, &Script::play }, { 21, 1, "LoadMap", 1, { 2 }, NULL }, { 21, 2, "RoomMap", 0, { 0 }, NULL }, { 22, 1, "DisableQuickHero", 0, { 0 }, NULL }, @@ -131,7 +131,7 @@ void Script::setupCommandList() { { "BlockVar", NULL }, { "HasBeen", NULL }, { "MaxLine", NULL }, - { "ActPhase", NULL }, + { "ActPhase", &Script::funcActPhase }, { "Cheat", NULL }, }; @@ -262,8 +262,36 @@ int Script::funcIsObjAway(int objID) { return !obj->_visible && obj->_location == -1; } +int Script::funcActPhase(int objID) { + + objID -= 1; + + // Default return value + int ret = 0; + + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return ret; + } + + GameObject *obj = _vm->_game->getObject(objID); + + bool visible = (objID == kDragonObject || obj->_visible); + + if (visible && (obj->_location == _vm->_game->getRoomNum())) { + int animID = obj->_anims[0]; + Animation *anim = _vm->_anims->getAnimation(animID); + ret = anim->currentFrameNum(); + } + + return ret; +} + /* GPL commands */ +void Script::play(Common::Queue ¶ms) { + _vm->_game->loop(); +} + void Script::load(Common::Queue ¶ms) { if (_vm->_game->getLoopStatus() == kStatusInventory) { return; @@ -271,11 +299,33 @@ void Script::load(Common::Queue ¶ms) { int objID = params.pop() - 1; int animID = params.pop() - 1; - + + uint i; GameObject *obj = _vm->_game->getObject(objID); + // If the animation is already loaded, return + for(i = 0; i < obj->_anims.size(); ++i) { + if (obj->_anims[i] == animID) { + return; + } + } + + // Load the animation into memory + _vm->_game->loadAnimation(animID, obj->_z); - obj->_anims.push_back(animID); + + // We insert the ID of the loaded animation into the object's internal array + // of owned animation IDs. + // Care must be taken to store them sorted (increasing order) as some things + // depend on this. + + for(i = 0; i < obj->_anims.size(); ++i) { + if (obj->_anims[i] > animID) { + break; + } + } + + obj->_anims.insert_at(i, animID); } void Script::start(Common::Queue ¶ms) { @@ -287,11 +337,12 @@ void Script::start(Common::Queue ¶ms) { int animID = params.pop() - 1; GameObject *obj = _vm->_game->getObject(objID); - + bool visible = (objID == kDragonObject || obj->_visible); - if (visible && (obj->_location == _vm->_game->getRoomNum())) + if (visible && (obj->_location == _vm->_game->getRoomNum())) { _vm->_anims->play(animID); + } } void Script::c_If(Common::Queue ¶ms) { diff --git a/engines/draci/script.h b/engines/draci/script.h index 7ed194f68d..5c57ad7a1f 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -112,6 +112,7 @@ private: void execLook(Common::Queue ¶ms); void execUse(Common::Queue ¶ms); void walkOn(Common::Queue ¶ms); + void play(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); @@ -135,6 +136,7 @@ private: int funcIsObjOn(int objID); int funcIsObjOff(int objID); int funcIsObjAway(int objID); + int funcActPhase(int objID); void setupCommandList(); -- cgit v1.2.3 From e9669b8e2bcc4a65d5cc1225e9328d9171726690 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 01:11:53 +0000 Subject: * Moved event handling to DraciEngine::handleEvents() * Added Game::start() method which is called from DraciEngine::go() * Made Game::loop() suitable for calling from other places (like GPL scripts) by handling events, redrawing the screen, etc from inside. This way it doesn't freeze the game if it doesn't return immediately. * Added Game::shouldQuit() and Game::setQuit() which can be used to signal the engine to quit. * Fixed race condition related to mouse buttons not getting released. * Instead of deleting frames for the title animation and adding a new one, reset the text for its frame. svn-id: r42875 --- engines/draci/draci.cpp | 79 ++++++++++++++++++++++++------------------------- engines/draci/draci.h | 4 +++ engines/draci/game.cpp | 40 ++++++++++++++++++------- engines/draci/game.h | 9 ++++-- 4 files changed, 78 insertions(+), 54 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 057000c7ca..ae4f154755 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -142,6 +142,8 @@ int DraciEngine::init() { return Common::kUnknownError; } + _showWalkingMap = false; + // Basic archive test debugC(2, kDraciGeneralDebugLevel, "Running archive tests..."); Common::String path("INIT.DFW"); @@ -167,54 +169,49 @@ int DraciEngine::init() { int DraciEngine::go() { debugC(1, kDraciGeneralDebugLevel, "DraciEngine::go()"); - debugC(2, kDraciGeneralDebugLevel, "Running graphics/animation test..."); - _game->init(); + _game->start(); + + return Common::kNoError; +} +bool DraciEngine::handleEvents() { Common::Event event; bool quit = false; - bool showWalkingMap = false; - while (!quit) { - while (_eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_QUIT: - quit = true; - break; - case Common::EVENT_KEYDOWN: - if (event.kbd.keycode == Common::KEYCODE_RIGHT) - _game->changeRoom(_game->nextRoomNum()); - - else if (event.kbd.keycode == Common::KEYCODE_LEFT) - _game->changeRoom(_game->prevRoomNum()); - - // Show walking map toggle - else if (event.kbd.keycode == Common::KEYCODE_w) { - showWalkingMap = !showWalkingMap; - } - break; - default: - _mouse->handleEvent(event); - } - } - - // Show walking map overlay - // If the walking map overlay is already in the wanted state don't - // start / stop it constantly - if (showWalkingMap && !_anims->getAnimation(kWalkingMapOverlay)->isPlaying()) { - _anims->play(kWalkingMapOverlay); - } else if (!showWalkingMap && _anims->getAnimation(kWalkingMapOverlay)->isPlaying()) { - _anims->stop(kWalkingMapOverlay); - } - - _game->loop(); - _anims->drawScene(_screen->getSurface()); - _screen->copyToScreen(); - _system->delayMillis(20); + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + _game->setQuit(true); + break; + case Common::EVENT_KEYDOWN: + if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _game->changeRoom(_game->nextRoomNum()); + + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _game->changeRoom(_game->prevRoomNum()); + + // Show walking map toggle + else if (event.kbd.keycode == Common::KEYCODE_w) { + _showWalkingMap = !_showWalkingMap; + } + break; + default: + _mouse->handleEvent(event); + } } - return Common::kNoError; -} + // Show walking map overlay + // If the walking map overlay is already in the wanted state don't + // start / stop it constantly + if (_showWalkingMap && !_anims->getAnimation(kWalkingMapOverlay)->isPlaying()) { + _anims->play(kWalkingMapOverlay); + } else if (!_showWalkingMap && _anims->getAnimation(kWalkingMapOverlay)->isPlaying()) { + _anims->stop(kWalkingMapOverlay); + } + return quit; +} DraciEngine::~DraciEngine() { // Dispose your resources here diff --git a/engines/draci/draci.h b/engines/draci/draci.h index e6b78f310a..1f43fc8f68 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -50,6 +50,8 @@ public: Common::Error run(); bool hasFeature(Engine::EngineFeature f) const; + + bool handleEvents(); Screen *_screen; Mouse *_mouse; @@ -70,6 +72,8 @@ public: BArchive *_walkingMapsArchive; BArchive *_initArchive; + bool _showWalkingMap; + Common::RandomSource _rnd; }; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 620a8ca9e7..094364be6c 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -151,11 +151,21 @@ Game::Game(DraciEngine *vm) : _vm(vm) { assert(numIcons == _info._numIcons); } +void Game::start() { + while (!shouldQuit()) { + Game::loop(); + } +} + void Game::init() { + _shouldQuit = false; _loopStatus = kStatusOrdinary; _objUnderCursor = kOverlayImage; - _vm->_anims->addText(kTitleText, true); + // Initialize animation for object / room titles + Animation *titleAnim = _vm->_anims->addText(kTitleText, true); + Text *title = new Text ("", _vm->_bigFont, kFontColour3, 0, 0); + titleAnim->addFrame(title); loadObject(kDragonObject); @@ -169,6 +179,11 @@ void Game::init() { void Game::loop() { + _vm->handleEvents(); + + if (shouldQuit()) + return; + if (_currentRoom._mouseOn) { int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); @@ -178,36 +193,40 @@ void Game::loop() { } int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - Animation *anim = _vm->_anims->getAnimation(animUnderCursor); + //Animation *anim = _vm->_anims->getAnimation(animUnderCursor); int curObject = getObjectWithAnimation(animUnderCursor); GameObject *obj = &_objects[curObject]; - Animation *atitle = _vm->_anims->getAnimation(kTitleText); + Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); // TODO: Handle displaying title in the proper location - atitle->deleteFrames(); if (curObject != kNotFound) { - Text *title = new Text (obj->_title, _vm->_bigFont, kFontColour1, 0, 0); - atitle->addFrame(title); + titleAnim->markDirtyRect(_vm->_screen->getSurface()); + reinterpret_cast(titleAnim->getFrame())->setText(obj->_title); // HACK: Test running look and use scripts if (_vm->_mouse->lButtonPressed()) { - _vm->_script->run(obj->_program, obj->_look); _vm->_mouse->lButtonSet(false); + _vm->_script->run(obj->_program, obj->_look); } if (_vm->_mouse->rButtonPressed()) { + _vm->_mouse->rButtonSet(false); _vm->_script->run(obj->_program, obj->_use); - _vm->_mouse->rButtonSet(false); } + } else { + titleAnim->markDirtyRect(_vm->_screen->getSurface()); + reinterpret_cast(titleAnim->getFrame())->setText(""); } debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); - - } + + _vm->_anims->drawScene(_vm->_screen->getSurface()); + _vm->_screen->copyToScreen(); + _vm->_system->delayMillis(20); } int Game::getObjectWithAnimation(int animID) { @@ -626,6 +645,7 @@ Game::~Game() { delete[] _objects; } + bool WalkingMap::isWalkable(int x, int y) { // Convert to map pixels diff --git a/engines/draci/game.h b/engines/draci/game.h index fbc1d3283e..5cfa5d894e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -86,8 +86,6 @@ private: struct GameObject { - GameObject() {} - uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; byte _walkDir; @@ -162,6 +160,7 @@ public: ~Game(); void init(); + void start(); void loop(); void changeRoom(uint roomNum); @@ -213,6 +212,9 @@ public: void setLoopStatus(LoopStatus status); LoopStatus getLoopStatus(); + bool shouldQuit() { return _shouldQuit; } + void setQuit(bool quit) { _shouldQuit = quit; } + private: DraciEngine *_vm; @@ -227,8 +229,9 @@ private: Room _currentRoom; LoopStatus _loopStatus; - int _objUnderCursor; + bool _shouldQuit; + int _objUnderCursor; int _markedAnimationIndex; //!< Used by the Mark GPL command }; -- cgit v1.2.3 From bc89ce23d38c2d26ae5336297d628099cdbf8498 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 16:39:12 +0000 Subject: Fixed text bugs related to the fact that some strings in the data files don't end with '|' like they should. svn-id: r42897 --- engines/draci/font.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 2a6e5989f0..b867bf4877 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -266,17 +266,21 @@ int Font::getStringWidth(const Common::String &str, int spacing) const { for (unsigned int i = 0, tmp = 0; i < len; ++i) { - // Newline char encountered, skip it and store the new length if it is greater - if (str[i] == '|') { + if (str[i] != '|') { + uint8 charIndex = str[i] - kCharIndexOffset; + tmp += _charWidths[charIndex]; + tmp += spacing; + } + + // Newline char encountered, skip it and store the new length if it is greater. + // Also, all strings in the data files should end with '|' but not all do. + // This is why we check whether we are at the last char too. + if (str[i] == '|' || i == len - 1) { if (tmp > width) { width = tmp; } continue; } - - uint8 charIndex = str[i] - kCharIndexOffset; - tmp += _charWidths[charIndex]; - tmp += spacing; } return width + 1; @@ -298,7 +302,9 @@ int Font::getStringHeight(const Common::String &str) const { int separators = 0; for (unsigned int i = 0; i < len; ++i) { - if (str[i] == '|') { + // All strings in the data files should end with '|' but not all do. + // This is why we check whether we are at the last char too. + if (str[i] == '|' || i == len - 1) { ++separators; } } -- cgit v1.2.3 From 07042e31bcabd4c33f38a7c3a41ca6c603525011 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 19:38:02 +0000 Subject: * Made Game::loop() exit conditionally depending on whether the internal Game::_shouldExitLoop variable is set. * Added mechanisms for signalling whether the main game loop should exit or not (Game::setExitLoop() and Game::shouldExitLoop()) svn-id: r42899 --- engines/draci/game.cpp | 80 ++++++++++++++++++++++++++------------------------ engines/draci/game.h | 4 +++ 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 094364be6c..0122ae1626 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -159,6 +159,7 @@ void Game::start() { void Game::init() { _shouldQuit = false; + _shouldExitLoop = false; _loopStatus = kStatusOrdinary; _objUnderCursor = kOverlayImage; @@ -179,54 +180,57 @@ void Game::init() { void Game::loop() { - _vm->handleEvents(); + do { + _vm->handleEvents(); - if (shouldQuit()) - return; + if (_currentRoom._mouseOn) { + int x = _vm->_mouse->getPosX(); + int y = _vm->_mouse->getPosY(); - if (_currentRoom._mouseOn) { - int x = _vm->_mouse->getPosX(); - int y = _vm->_mouse->getPosY(); + if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { + walkHero(x, y); + } - if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { - walkHero(x, y); - } + int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + //Animation *anim = _vm->_anims->getAnimation(animUnderCursor); - int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - //Animation *anim = _vm->_anims->getAnimation(animUnderCursor); + int curObject = getObjectWithAnimation(animUnderCursor); + GameObject *obj = &_objects[curObject]; - int curObject = getObjectWithAnimation(animUnderCursor); - GameObject *obj = &_objects[curObject]; + Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); - Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); + // TODO: Handle displaying title in the proper location - // TODO: Handle displaying title in the proper location + if (curObject != kNotFound) { + titleAnim->markDirtyRect(_vm->_screen->getSurface()); + reinterpret_cast(titleAnim->getFrame())->setText(obj->_title); - if (curObject != kNotFound) { - titleAnim->markDirtyRect(_vm->_screen->getSurface()); - reinterpret_cast(titleAnim->getFrame())->setText(obj->_title); + // HACK: Test running look and use scripts + if (_vm->_mouse->lButtonPressed()) { + _vm->_mouse->lButtonSet(false); + _vm->_script->run(obj->_program, obj->_look); + } - // HACK: Test running look and use scripts - if (_vm->_mouse->lButtonPressed()) { - _vm->_mouse->lButtonSet(false); - _vm->_script->run(obj->_program, obj->_look); + if (_vm->_mouse->rButtonPressed()) { + _vm->_mouse->rButtonSet(false); + _vm->_script->run(obj->_program, obj->_use); + } + } else { + titleAnim->markDirtyRect(_vm->_screen->getSurface()); + reinterpret_cast(titleAnim->getFrame())->setText(""); } - if (_vm->_mouse->rButtonPressed()) { - _vm->_mouse->rButtonSet(false); - _vm->_script->run(obj->_program, obj->_use); - } - } else { - titleAnim->markDirtyRect(_vm->_screen->getSurface()); - reinterpret_cast(titleAnim->getFrame())->setText(""); + debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } - debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); - } + if (shouldQuit()) + return; + + _vm->_anims->drawScene(_vm->_screen->getSurface()); + _vm->_screen->copyToScreen(); + _vm->_system->delayMillis(20); - _vm->_anims->drawScene(_vm->_screen->getSurface()); - _vm->_screen->copyToScreen(); - _vm->_system->delayMillis(20); + } while (!shouldExitLoop()); } int Game::getObjectWithAnimation(int animID) { @@ -382,10 +386,10 @@ void Game::loadRoom(int roomNum) { // HACK: Gates' scripts shouldn't be run unconditionally // This is for testing - for (uint i = 0; i < _currentRoom._numGates; ++i) { - debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); - _vm->_script->run(_currentRoom._program, gates[i]); - } + //for (uint i = 0; i < _currentRoom._numGates; ++i) { + // debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); + // _vm->_script->run(_currentRoom._program, gates[i]); + //} // Set room palette f = _vm->_paletteArchive->getFile(_currentRoom._palette); diff --git a/engines/draci/game.h b/engines/draci/game.h index 5cfa5d894e..6393ea7573 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -215,6 +215,9 @@ public: bool shouldQuit() { return _shouldQuit; } void setQuit(bool quit) { _shouldQuit = quit; } + bool shouldExitLoop() { return _shouldExitLoop; } + void setExitLoop(bool exit) { _shouldExitLoop = exit; } + private: DraciEngine *_vm; @@ -230,6 +233,7 @@ private: LoopStatus _loopStatus; bool _shouldQuit; + bool _shouldExitLoop; int _objUnderCursor; int _markedAnimationIndex; //!< Used by the Mark GPL command -- cgit v1.2.3 From f42894c33cb744759a9cfd64fcc24599a8451572 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 19:39:10 +0000 Subject: Added support for animation callbacks and implemented a few callbacks (doNothing, exitGameLoop, stopAnimation). svn-id: r42901 --- engines/draci/animation.cpp | 13 +++++++++++-- engines/draci/animation.h | 14 +++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 6cde72a9d2..5ba12fb529 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -40,6 +40,7 @@ Animation::Animation(DraciEngine *vm, int index) : _vm(vm) { _looping = false; _tick = _vm->_system->getMillis(); _currentFrame = 0; + _callback = &Animation::doNothing; } Animation::~Animation() { @@ -95,8 +96,8 @@ void Animation::nextFrame(bool force) { // If we are at the last frame and not looping, stop the animation // The animation is also restarted to frame zero if ((_currentFrame == getFrameCount() - 1) && !_looping) { - // When the animation reaches its end, stop it - _vm->_anims->stop(_id); + // When the animation reaches its end, call the preset callback + (this->*_callback)(); // Reset the frame to 0 _currentFrame = 0; @@ -272,6 +273,14 @@ void Animation::deleteFrames() { } } +void Animation::stopAnimation() { + _vm->_anims->stop(_id); +} + +void Animation::exitGameLoop() { + _vm->_game->setExitLoop(true); +} + Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { // Increment animation index diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 6642107b25..3fd4b67114 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -51,7 +51,9 @@ enum { kIgnoreIndex = -2 }; class DraciEngine; class Animation { - + +typedef void (Animation::* AnimationCallback)(); + public: Animation(DraciEngine *v, int index); ~Animation(); @@ -90,6 +92,14 @@ public: void markDirtyRect(Surface *surface); + // Animation callbacks + + void registerCallback(AnimationCallback callback) { _callback = callback; } + + void doNothing() {} + void stopAnimation(); + void exitGameLoop(); + private: uint nextFrameNum(); @@ -118,6 +128,8 @@ private: bool _looping; Common::Array _frames; + AnimationCallback _callback; + DraciEngine *_vm; }; -- cgit v1.2.3 From 393cd99a6232112e7959aec3017e59ecabbbb8c4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 19:41:30 +0000 Subject: * Implemented the StartPlay and Play GPL commands properly * Changed Script::load() to use the new animation callbacks svn-id: r42902 --- engines/draci/script.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++-- engines/draci/script.h | 1 + 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 7669dc4c1b..84f2ee92af 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -46,7 +46,7 @@ void Script::setupCommandList() { { 3, 1, "if", 2, { 4, 3 }, &Script::c_If }, { 4, 1, "Start", 2, { 3, 2 }, &Script::start }, { 5, 1, "Load", 2, { 3, 2 }, &Script::load }, - { 5, 2, "StartPlay", 2, { 3, 2 }, &Script::start }, + { 5, 2, "StartPlay", 2, { 3, 2 }, &Script::startPlay }, { 5, 3, "JustTalk", 0, { 0 }, NULL }, { 5, 4, "JustStay", 0, { 0 }, NULL }, { 6, 1, "Talk", 2, { 3, 2 }, NULL }, @@ -289,7 +289,15 @@ int Script::funcActPhase(int objID) { /* GPL commands */ void Script::play(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + _vm->_game->setLoopStatus(kStatusStrange); + _vm->_game->setExitLoop(true); _vm->_game->loop(); + _vm->_game->setExitLoop(false); + _vm->_game->setLoopStatus(kStatusOrdinary); } void Script::load(Common::Queue ¶ms) { @@ -338,6 +346,50 @@ void Script::start(Common::Queue ¶ms) { GameObject *obj = _vm->_game->getObject(objID); + // Stop all animation that the object owns + + for (uint i = 0; i < obj->_anims.size(); ++i) { + _vm->_anims->stop(obj->_anims[i]); + } + + Animation *anim = _vm->_anims->getAnimation(animID); + anim->registerCallback(&Animation::stopAnimation); + + bool visible = (objID == kDragonObject || obj->_visible); + + if (visible && (obj->_location == _vm->_game->getRoomNum())) { + _vm->_anims->play(animID); + } +} + +void Script::startPlay(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int objID = params.pop() - 1; + int animID = params.pop() - 1; + + GameObject *obj = _vm->_game->getObject(objID); + + // Stop all animation that the object owns + + for (uint i = 0; i < obj->_anims.size(); ++i) { + _vm->_anims->stop(obj->_anims[i]); + } + + Animation *anim = _vm->_anims->getAnimation(animID); + anim->registerCallback(&Animation::exitGameLoop); + + _vm->_game->setLoopStatus(kStatusStrange); + _vm->_anims->play(animID); + _vm->_game->loop(); + _vm->_game->setExitLoop(false); + _vm->_anims->stop(animID); + _vm->_game->setLoopStatus(kStatusOrdinary); + + anim->registerCallback(&Animation::doNothing); + bool visible = (objID == kDragonObject || obj->_visible); if (visible && (obj->_location == _vm->_game->getRoomNum())) { @@ -567,7 +619,12 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { /** * @brief Find the current command in the internal table * - * @param num Command number + * @param G_LoopStatus=Inventory then Exit; + G_LoopSubStatus:= Strange; + G_QuitLoop:= True; + Loop; + G_QuitLoop:= False; + G_LoopSubStatus:= Ordinary; num Command number * @param subnum Command subnumer * * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command diff --git a/engines/draci/script.h b/engines/draci/script.h index 5c57ad7a1f..69effbedf0 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -113,6 +113,7 @@ private: void execUse(Common::Queue ¶ms); void walkOn(Common::Queue ¶ms); void play(Common::Queue ¶ms); + void startPlay(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From a2cc4a64793371cb6bdb027f9aa21ed06f847613 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 20:35:41 +0000 Subject: Explicitly set the kDragonObject enum constant value for clarity. svn-id: r42906 --- engines/draci/game.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/game.h b/engines/draci/game.h index 6393ea7573..de995a4300 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -36,7 +36,7 @@ namespace Draci { class DraciEngine; enum { - kDragonObject + kDragonObject = 0 }; enum StructSizes { -- cgit v1.2.3 From ad752b268b73c26b3a8a8b1f8f8ed9229a4abccc Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 20:41:53 +0000 Subject: * Removed some code I forgot to remove in Game::startPlay() (a call to AnimationManager::play()) * Fixed logic checking for object visibility in various GPL commands (I originally misinterpreted the original engine code). svn-id: r42908 --- engines/draci/script.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 84f2ee92af..d8539097d4 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -275,9 +275,9 @@ int Script::funcActPhase(int objID) { GameObject *obj = _vm->_game->getObject(objID); - bool visible = (objID == kDragonObject || obj->_visible); + bool visible = (obj->_location == _vm->_game->getRoomNum() && obj->_visible); - if (visible && (obj->_location == _vm->_game->getRoomNum())) { + if (objID == kDragonObject || visible) { int animID = obj->_anims[0]; Animation *anim = _vm->_anims->getAnimation(animID); ret = anim->currentFrameNum(); @@ -355,9 +355,9 @@ void Script::start(Common::Queue ¶ms) { Animation *anim = _vm->_anims->getAnimation(animID); anim->registerCallback(&Animation::stopAnimation); - bool visible = (objID == kDragonObject || obj->_visible); + bool visible = (obj->_location == _vm->_game->getRoomNum() && obj->_visible); - if (visible && (obj->_location == _vm->_game->getRoomNum())) { + if (objID == kDragonObject || visible) { _vm->_anims->play(animID); } } @@ -382,19 +382,19 @@ void Script::startPlay(Common::Queue ¶ms) { anim->registerCallback(&Animation::exitGameLoop); _vm->_game->setLoopStatus(kStatusStrange); - _vm->_anims->play(animID); + + bool visible = (obj->_location == _vm->_game->getRoomNum() && obj->_visible); + + if (objID == kDragonObject || visible) { + _vm->_anims->play(animID); + } + _vm->_game->loop(); _vm->_game->setExitLoop(false); _vm->_anims->stop(animID); _vm->_game->setLoopStatus(kStatusOrdinary); anim->registerCallback(&Animation::doNothing); - - bool visible = (objID == kDragonObject || obj->_visible); - - if (visible && (obj->_location == _vm->_game->getRoomNum())) { - _vm->_anims->play(animID); - } } void Script::c_If(Common::Queue ¶ms) { -- cgit v1.2.3 From 6ed99df75aadeb8c3844c7d4546735afbd1831de Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 29 Jul 2009 20:42:55 +0000 Subject: Removed some garbage I accidentally pasted into a comment. svn-id: r42909 --- engines/draci/script.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index d8539097d4..8ec9e5f582 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -619,12 +619,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { /** * @brief Find the current command in the internal table * - * @param G_LoopStatus=Inventory then Exit; - G_LoopSubStatus:= Strange; - G_QuitLoop:= True; - Loop; - G_QuitLoop:= False; - G_LoopSubStatus:= Ordinary; num Command number + * @param num Command number * @param subnum Command subnumer * * @return NULL if command is not found. Otherwise, a pointer to a GPL2Command -- cgit v1.2.3 From b124c8b1225627def357b284e43d9890e1fda79a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 30 Jul 2009 01:12:07 +0000 Subject: * Added Animation::setCurrentFrame() * Moved rewinding the animation to the beginning from Animation::nextFrame() to AnimationManager::stop() (fixes the owl animation) svn-id: r42913 --- engines/draci/animation.cpp | 17 ++++++++++++++--- engines/draci/animation.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 5ba12fb529..c5c33153ea 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -98,9 +98,6 @@ void Animation::nextFrame(bool force) { if ((_currentFrame == getFrameCount() - 1) && !_looping) { // When the animation reaches its end, call the preset callback (this->*_callback)(); - - // Reset the frame to 0 - _currentFrame = 0; } else { // Mark old frame dirty so it gets deleted markDirtyRect(surface); @@ -258,6 +255,16 @@ uint Animation::currentFrameNum() { return _currentFrame; } +void Animation::setCurrentFrame(uint frame) { + + // Check whether the value is sane + if (frame > _frames.size()) { + return; + } + + _currentFrame = frame; +} + void Animation::deleteFrames() { // If there are no frames to delete, return @@ -331,6 +338,10 @@ void AnimationManager::stop(int id) { anim->markDirtyRect(_vm->_screen->getSurface()); anim->setPlaying(false); + + // Reset the animation to the beginning + anim->setCurrentFrame(0); + debugC(3, kDraciAnimationDebugLevel, "Stopping animation %d...", id); } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 3fd4b67114..a6ab07a9a4 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -69,6 +69,7 @@ public: void addFrame(Drawable *frame); Drawable *getFrame(int frameNum = kCurrentFrame); + void setCurrentFrame(uint frame); uint currentFrameNum(); uint getFrameCount(); void deleteFrames(); -- cgit v1.2.3 From 7532845feea721b554fd38f59e5dc28321ea9bfa Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 30 Jul 2009 02:16:58 +0000 Subject: Fixed sanity check in Animation::setCurrentFrame(). svn-id: r42914 --- engines/draci/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index c5c33153ea..84ec6eceab 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -258,7 +258,7 @@ uint Animation::currentFrameNum() { void Animation::setCurrentFrame(uint frame) { // Check whether the value is sane - if (frame > _frames.size()) { + if (frame >= _frames.size()) { return; } -- cgit v1.2.3 From 181b155a2f50a05ec2982fa581d7ad5893746a35 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 30 Jul 2009 03:37:04 +0000 Subject: * Added support for keeping track of gates (exits from rooms) * Added getters and setters for current room and gate numbers svn-id: r42915 --- engines/draci/game.cpp | 19 ++++++++++++++++++- engines/draci/game.h | 8 ++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 0122ae1626..90cdf77434 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -175,6 +175,7 @@ void Game::init() { _vm->_script->run(dragon->_program, dragon->_init); _currentRoom._roomNum = _info._startRoom; + _currentGate = 0; changeRoom(_info._startRoom); } @@ -350,7 +351,7 @@ void Game::loadRoom(int roomNum) { Common::Array gates; for (uint i = 0; i < _currentRoom._numGates; ++i) { - gates.push_back(roomReader.readSint16LE()); + gates.push_back(roomReader.readSint16LE() - 1); } // Load the room's objects @@ -600,6 +601,22 @@ void Game::changeRoom(uint roomNum) { loadOverlays(); } +int Game::getRoomNum() { + return _currentRoom; +} + +void Game::setRoomNum(int room) { + _currentRoom = room; +} + +int Game::getGateNum() { + return _currentGate; +} + +void Game::setGateNum(int gate) { + _currentGate = gate; +} + void Game::setLoopStatus(LoopStatus status) { _loopStatus = status; } diff --git a/engines/draci/game.h b/engines/draci/game.h index de995a4300..ba69673642 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -204,6 +204,12 @@ public: int getVariable(int varNum); void setVariable(int varNum, int value); + int getRoomNum(); + void setRoomNum(int room); + + int getGateNum(); + void setGateNum(int gate); + int getIconStatus(int iconID); int getMarkedAnimationIndex(); @@ -230,6 +236,8 @@ private: GameObject *_objects; Room _currentRoom; + int _currentGate; + LoopStatus _loopStatus; bool _shouldQuit; -- cgit v1.2.3 From 167b6da23050a60ee0d56c6b435c3c1bbb159d8a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 30 Jul 2009 03:43:44 +0000 Subject: * Woops, Game::getRoomNum() was already implemented. Removed the superfluous implementation. * Set the first two game variables to the gate and room number in Game::init() * Fixed compilation svn-id: r42916 --- engines/draci/game.cpp | 12 ++++++------ engines/draci/game.h | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 90cdf77434..7b6e3608e7 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -176,6 +176,10 @@ void Game::init() { _currentRoom._roomNum = _info._startRoom; _currentGate = 0; + + _variables[0] = _currentRoom._roomNum; + _variables[1] = _currentGate; + changeRoom(_info._startRoom); } @@ -602,11 +606,11 @@ void Game::changeRoom(uint roomNum) { } int Game::getRoomNum() { - return _currentRoom; + return _currentRoom._roomNum; } void Game::setRoomNum(int room) { - _currentRoom = room; + _currentRoom._roomNum = room; } int Game::getGateNum() { @@ -625,10 +629,6 @@ LoopStatus Game::getLoopStatus() { return _loopStatus; } -int Game::getRoomNum() { - return _currentRoom._roomNum; -} - int Game::getVariable(int numVar) { return _variables[numVar]; } diff --git a/engines/draci/game.h b/engines/draci/game.h index ba69673642..c6168d6d49 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -164,7 +164,6 @@ public: void loop(); void changeRoom(uint roomNum); - int getRoomNum(); // HACK: this is only for testing int nextRoomNum() { -- cgit v1.2.3 From 18a8b5b3af96bc0d74167db27552956b646cd0d0 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 31 Jul 2009 04:32:33 +0000 Subject: * Added Game::runGateProgram() * Added a separate mechanism to Game to keep track both of the current room number and the next room/gate. Periodically, I check whether the new room differs from the old one and, if it does, I do the change. Doing it any other would is nearly impossible because of the way the original scripts were written. * Added GPL command Script::newRoom(). Rooms can now be traversed by clicking on their exits. Also, the intro animation partly works. Some parts go by far too soon. I assume this is because the engine still lacks a dialogue GPL command. * Fixed bug where the gates array of a room was not cleared between uses. * Save old jump value when we enter Script::run() and restore it in the end (mimicking the original engine). * Fixed small bug where the gate was supposed to be stored as the first in-game variable and not the room number. svn-id: r42957 --- engines/draci/game.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++------ engines/draci/game.h | 7 +++++ engines/draci/script.cpp | 24 +++++++++++++++- engines/draci/script.h | 1 + 4 files changed, 94 insertions(+), 10 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 7b6e3608e7..3665c09d71 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -153,13 +153,31 @@ Game::Game(DraciEngine *vm) : _vm(vm) { void Game::start() { while (!shouldQuit()) { - Game::loop(); + + if (_newRoom != _currentRoom._roomNum) { + + changeRoom(_newRoom); + + _currentRoom._roomNum = _newRoom; + _currentGate = _newGate; + + // HACK: Won't be needed once I've implemented the loop properly + _roomChange = false; + + runGateProgram(_newGate); + } + + loop(); } } void Game::init() { _shouldQuit = false; _shouldExitLoop = false; + + // HACK: Won't be needed once I've implemented the loop properly + _roomChange = false; + _loopStatus = kStatusOrdinary; _objUnderCursor = kOverlayImage; @@ -177,15 +195,20 @@ void Game::init() { _currentRoom._roomNum = _info._startRoom; _currentGate = 0; - _variables[0] = _currentRoom._roomNum; - _variables[1] = _currentGate; + _newRoom = _currentRoom._roomNum; + _newGate = _currentGate; - changeRoom(_info._startRoom); + _variables[0] = _currentGate; + _variables[1] = _currentRoom._roomNum; + + changeRoom(_currentRoom._roomNum); + runGateProgram(_currentGate); } void Game::loop() { - + do { + _vm->handleEvents(); if (_currentRoom._mouseOn) { @@ -235,6 +258,9 @@ void Game::loop() { _vm->_screen->copyToScreen(); _vm->_system->delayMillis(20); + // HACK: Won't be needed once the game loop is implemented properly + _shouldExitLoop = _shouldExitLoop || _roomChange; + } while (!shouldExitLoop()); } @@ -352,10 +378,11 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); // Read in the gates' numbers - Common::Array gates; + + _currentRoom._gates.clear(); for (uint i = 0; i < _currentRoom._numGates; ++i) { - gates.push_back(roomReader.readSint16LE() - 1); + _currentRoom._gates.push_back(roomReader.readSint16LE()); } // Load the room's objects @@ -605,12 +632,39 @@ void Game::changeRoom(uint roomNum) { loadOverlays(); } +void Game::runGateProgram(int gate) { + + // Mark last animation + int lastAnimIndex = _vm->_anims->getLastIndex(); + + // Run gate program + _vm->_script->run(_currentRoom._program, _currentRoom._gates[gate]); + + // Delete all animations loaded after the marked one + // (from objects and from the AnimationManager) + for (uint i = 0; i < getNumObjects(); ++i) { + GameObject *obj = &_objects[i]; + + for (uint j = 0; j < obj->_anims.size(); ++j) { + Animation *anim; + + anim = _vm->_anims->getAnimation(obj->_anims[j]); + if (anim != NULL && anim->getIndex() > lastAnimIndex) + obj->_anims.remove_at(j); + } + } + + _vm->_anims->deleteAfterIndex(lastAnimIndex); + + setExitLoop(false); +} + int Game::getRoomNum() { return _currentRoom._roomNum; } void Game::setRoomNum(int room) { - _currentRoom._roomNum = room; + _newRoom = room; } int Game::getGateNum() { @@ -618,7 +672,7 @@ int Game::getGateNum() { } void Game::setGateNum(int gate) { - _currentGate = gate; + _newGate = gate; } void Game::setLoopStatus(LoopStatus status) { diff --git a/engines/draci/game.h b/engines/draci/game.h index c6168d6d49..1e488ca083 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -131,6 +131,7 @@ struct Room { double _pers0, _persStep; byte _escRoom; byte _numGates; + Common::Array _gates; GPL2Program _program; }; @@ -223,6 +224,10 @@ public: bool shouldExitLoop() { return _shouldExitLoop; } void setExitLoop(bool exit) { _shouldExitLoop = exit; } + void runGateProgram(int gate); + + bool _roomChange; + private: DraciEngine *_vm; @@ -236,6 +241,8 @@ private: Room _currentRoom; int _currentGate; + int _newRoom; + int _newGate; LoopStatus _loopStatus; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 8ec9e5f582..78ea91b3f7 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -66,7 +66,7 @@ void Script::setupCommandList() { { 12, 2, "BlackPalette", 0, { 0 }, NULL }, { 13, 1, "FadePalette", 3, { 1, 1, 1 }, NULL }, { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 }, NULL }, - { 14, 1, "NewRoom", 2, { 3, 1 }, NULL }, + { 14, 1, "NewRoom", 2, { 3, 1 }, &Script::newRoom }, { 15, 1, "ExecInit", 1, { 3 }, &Script::execInit }, { 15, 2, "ExecLook", 1, { 3 }, &Script::execLook }, { 15, 3, "ExecUse", 1, { 3 }, &Script::execUse }, @@ -516,6 +516,23 @@ void Script::walkOn(Common::Queue ¶ms) { _vm->_game->walkHero(x, y); } + +void Script::newRoom(Common::Queue ¶ms) { + + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int room = params.pop() - 1; + int gate = params.pop() - 1; + + _vm->_game->setRoomNum(room); + _vm->_game->setGateNum(gate); + + // HACK: Won't be needed once I've implemented the loop properly + _vm->_game->_roomChange = true; +} + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression @@ -679,6 +696,8 @@ const GPL2Command *Script::findCommand(byte num, byte subnum) { int Script::run(GPL2Program program, uint16 offset) { + int oldJump = _jump; + // Mark the last animation index before we do anything so a Release command // doesn't unload too many animations if we forget to use a Mark command first _vm->_game->setMarkedAnimationIndex(_vm->_anims->getLastIndex()); @@ -748,6 +767,7 @@ int Script::run(GPL2Program program, uint16 offset) { else { debugC(1, kDraciBytecodeDebugLevel, "Unknown opcode %d, %d", num, subnum); + abort(); } GPLHandler handler = cmd->_handler; @@ -759,6 +779,8 @@ int Script::run(GPL2Program program, uint16 offset) { } while (cmd->_name != "gplend" && cmd->_name != "exit"); + _jump = oldJump; + return 0; } diff --git a/engines/draci/script.h b/engines/draci/script.h index 69effbedf0..d799dcaed5 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -114,6 +114,7 @@ private: void walkOn(Common::Queue ¶ms); void play(Common::Queue ¶ms); void startPlay(Common::Queue ¶ms); + void newRoom(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From 52a1c5df915fc5791b42c191c6d2c981d22117b5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 1 Aug 2009 02:49:40 +0000 Subject: Added archives for item descriptions and images. svn-id: r42970 --- engines/draci/draci.cpp | 6 ++++++ engines/draci/draci.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index ae4f154755..52b70dd727 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -53,6 +53,8 @@ const Common::String roomsPath("MIST.DFW"); const Common::String animationsPath("ANIM.DFW"); const Common::String iconsPath("HRA.DFW"); const Common::String walkingMapsPath("MAPY.DFW"); +const Common::String itemsPath("IKONY.DFW"); +const Common::String itemImagesPath("OBR_IK.DFW"); const Common::String initPath("INIT.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) @@ -91,6 +93,8 @@ int DraciEngine::init() { _animationsArchive = new BArchive(animationsPath); _iconsArchive = new BArchive(iconsPath); _walkingMapsArchive = new BArchive(walkingMapsPath); + _itemsArchive = new BArchive(itemsPath); + _itemImagesArchive = new BArchive(itemImagesPath); // Load the game's fonts _smallFont = new Font(kFontSmall); @@ -235,6 +239,8 @@ DraciEngine::~DraciEngine() { delete _animationsArchive; delete _iconsArchive; delete _walkingMapsArchive; + delete _itemsArchive; + delete _itemImagesArchive; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 1f43fc8f68..2b81ecb582 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -70,6 +70,8 @@ public: BArchive *_overlaysArchive; BArchive *_animationsArchive; BArchive *_walkingMapsArchive; + BArchive *_itemsArchive; + BArchive *_itemImagesArchive; BArchive *_initArchive; bool _showWalkingMap; -- cgit v1.2.3 From 240871aa2020c5bfc86b6d997465a12fc9a2e3b8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 1 Aug 2009 03:07:18 +0000 Subject: * Added support for loop substatus * Set loop substatus to Ordinary when changing rooms svn-id: r42971 --- engines/draci/game.cpp | 14 ++++++++++++++ engines/draci/game.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3665c09d71..995cd5d013 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -154,16 +154,22 @@ Game::Game(DraciEngine *vm) : _vm(vm) { void Game::start() { while (!shouldQuit()) { + // If the scheduled room differs from the current one, do a room change if (_newRoom != _currentRoom._roomNum) { + setLoopSubstatus(kStatusOrdinary); + + // Do the actual change changeRoom(_newRoom); + // Set the current room / gate to the new value _currentRoom._roomNum = _newRoom; _currentGate = _newGate; // HACK: Won't be needed once I've implemented the loop properly _roomChange = false; + // Run the program for the gate the dragon came through runGateProgram(_newGate); } @@ -679,10 +685,18 @@ void Game::setLoopStatus(LoopStatus status) { _loopStatus = status; } +void Game::setLoopSubstatus(LoopStatus status) { + _loopSubstatus = status; +} + LoopStatus Game::getLoopStatus() { return _loopStatus; } +LoopStatus Game::getLoopSubstatus() { + return _loopSubstatus; +} + int Game::getVariable(int numVar) { return _variables[numVar]; } diff --git a/engines/draci/game.h b/engines/draci/game.h index 1e488ca083..a38b71a256 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -216,7 +216,9 @@ public: void setMarkedAnimationIndex(int index); void setLoopStatus(LoopStatus status); + void setLoopSubstatus(LoopStatus status); LoopStatus getLoopStatus(); + LoopStatus getLoopSubstatus(); bool shouldQuit() { return _shouldQuit; } void setQuit(bool quit) { _shouldQuit = quit; } @@ -245,6 +247,7 @@ private: int _newGate; LoopStatus _loopStatus; + LoopStatus _loopSubstatus; bool _shouldQuit; bool _shouldExitLoop; -- cgit v1.2.3 From 5c6643f0f3e70c4465b5dcc8011d0fdbff0c5070 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 1 Aug 2009 03:26:39 +0000 Subject: When changing rooms, set the first two game variables to the new room and gate number. Also, if the new room is the map room, set the appropriate coordinates for the dragon in the persons array. svn-id: r42972 --- engines/draci/game.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 995cd5d013..c4f1161945 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -157,6 +157,17 @@ void Game::start() { // If the scheduled room differs from the current one, do a room change if (_newRoom != _currentRoom._roomNum) { + // Set the first two variables to the new room / gate + _variables[0] = _newGate; + _variables[1] = _newRoom; + + // If the new room is the map room, set the appropriate coordinates + // for the dragon in the persons array + if (_newRoom == _info._mapRoom) { + _persons[kDragonObject]._x = 160; + _persons[kDragonObject]._y = 0; + } + setLoopSubstatus(kStatusOrdinary); // Do the actual change -- cgit v1.2.3 From e0e06fc9e065466e4092e983056d67d1469e6752 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 1 Aug 2009 17:52:16 +0000 Subject: * Made the engine set the appropriate loop status before running a gate program or entering the main loop * Removed hack which ran programs for all gates when the room was changed svn-id: r42977 --- engines/draci/game.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index c4f1161945..4f83f135c6 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -184,6 +184,10 @@ void Game::start() { runGateProgram(_newGate); } + // Mimic the original engine by setting the loop status to Ordinary before + // entering the main loop + setLoopStatus(kStatusOrdinary); + loop(); } } @@ -433,13 +437,6 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "Running room init program..."); _vm->_script->run(_currentRoom._program, _currentRoom._init); - // HACK: Gates' scripts shouldn't be run unconditionally - // This is for testing - //for (uint i = 0; i < _currentRoom._numGates; ++i) { - // debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", i); - // _vm->_script->run(_currentRoom._program, gates[i]); - //} - // Set room palette f = _vm->_paletteArchive->getFile(_currentRoom._palette); _vm->_screen->setPalette(f->_data, 0, kNumColours); @@ -651,6 +648,11 @@ void Game::changeRoom(uint roomNum) { void Game::runGateProgram(int gate) { + debugC(6, kDraciLogicDebugLevel, "Running program for gate %d", gate); + + // Set the appropriate loop statu before executing the gate program + setLoopStatus(kStatusGate); + // Mark last animation int lastAnimIndex = _vm->_anims->getLastIndex(); -- cgit v1.2.3 From 014c33718f0569ca6a205595751531adc97dd6d5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 03:02:22 +0000 Subject: Added a dedicated animation for speech text. svn-id: r42988 --- engines/draci/animation.h | 6 +++++- engines/draci/game.cpp | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/engines/draci/animation.h b/engines/draci/animation.h index a6ab07a9a4..cc339084e3 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -34,7 +34,11 @@ namespace Draci { * Animation IDs for those animations that don't have their IDs * specified in the data files. */ -enum { kOverlayImage = -1, kWalkingMapOverlay = -2, kTitleText = -3, kUnused = -4 }; +enum { kOverlayImage = -1, + kWalkingMapOverlay = -2, + kTitleText = -3, + kSpeechText = -4, + kUnused = -5 }; /** * Default argument to Animation::getFrame() that makes it return diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 4f83f135c6..a0e0acbe85 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -204,9 +204,14 @@ void Game::init() { // Initialize animation for object / room titles Animation *titleAnim = _vm->_anims->addText(kTitleText, true); - Text *title = new Text ("", _vm->_bigFont, kFontColour3, 0, 0); + Text *title = new Text("", _vm->_bigFont, kFontColour3, 0, 0); titleAnim->addFrame(title); + // Initialize animation for speech text + Animation *speechAnim = _vm->_anims->addText(kSpeechText, true); + Text *speech = new Text("", _vm->_bigFont, kFontColour1, 0, 0); + speechAnim->addFrame(speech); + loadObject(kDragonObject); GameObject *dragon = getObject(kDragonObject); -- cgit v1.2.3 From 2d1df86f6910efe67b8f843448fa2f7c28578a62 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 03:16:44 +0000 Subject: Added the strings archive to DraciEngine. svn-id: r42989 --- engines/draci/draci.cpp | 3 +++ engines/draci/draci.h | 1 + 2 files changed, 4 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 52b70dd727..612f255fc6 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -56,6 +56,7 @@ const Common::String walkingMapsPath("MAPY.DFW"); const Common::String itemsPath("IKONY.DFW"); const Common::String itemImagesPath("OBR_IK.DFW"); const Common::String initPath("INIT.DFW"); +const Common::String stringsPath("RETEZCE.DFW"); DraciEngine::DraciEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) { @@ -95,6 +96,7 @@ int DraciEngine::init() { _walkingMapsArchive = new BArchive(walkingMapsPath); _itemsArchive = new BArchive(itemsPath); _itemImagesArchive = new BArchive(itemImagesPath); + _stringsArchive = new BArchive(stringsPath); // Load the game's fonts _smallFont = new Font(kFontSmall); @@ -241,6 +243,7 @@ DraciEngine::~DraciEngine() { delete _walkingMapsArchive; delete _itemsArchive; delete _itemImagesArchive; + delete _stringsArchive; // Remove all of our debug levels here Common::clearAllDebugChannels(); diff --git a/engines/draci/draci.h b/engines/draci/draci.h index 2b81ecb582..e2b5390c44 100644 --- a/engines/draci/draci.h +++ b/engines/draci/draci.h @@ -73,6 +73,7 @@ public: BArchive *_itemsArchive; BArchive *_itemImagesArchive; BArchive *_initArchive; + BArchive *_stringsArchive; bool _showWalkingMap; -- cgit v1.2.3 From 854c27ffacd40ab842a71dcbbf3fadfe007e1e1a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 05:09:55 +0000 Subject: Calculate the character length of Text objects (without the '|' separators) when setting a new string. Implemented Text::getLength(). svn-id: r42990 --- engines/draci/sprite.cpp | 19 +++++++++++++++++++ engines/draci/sprite.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 31a55bfddb..ecbfaf2767 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -307,6 +307,13 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, _delay = 0; _text = str; + + _length = 0; + for (uint i = 0; i < _text.size(); ++i) { + if (_text[i] != '|') { + ++_length; + } + } _spacing = spacing; _colour = fontColour; @@ -321,10 +328,18 @@ Text::Text(const Common::String &str, Font *font, byte fontColour, } void Text::setText(const Common::String &str) { + _width = _font->getStringWidth(str, _spacing); _height = _font->getStringHeight(str); _text = str; + + _length = 0; + for (uint i = 0; i < _text.size(); ++i) { + if (_text[i] != '|') { + ++_length; + } + } } void Text::setColour(byte fontColour) { @@ -335,6 +350,10 @@ void Text::setSpacing(uint spacing) { _spacing = spacing; } +uint Text::getLength() { + return _length; +} + void Text::draw(Surface *surface, bool markDirty) const { _font->setColour(_colour); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 77e45d6a7c..d2aa5ba3af 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -129,6 +129,8 @@ public: void setColour(byte fontColour); void setSpacing(uint spacing); + uint getLength(); + void draw(Surface *surface, bool markDirty = true) const; // TODO: drawScaled just calls draw so Text can be accessed through a Drawable pointer. -- cgit v1.2.3 From e6df651c084130baf2717a6b71aaba07502741a2 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 05:11:15 +0000 Subject: Changed some uint16s to uints (to blend more naturally with the rest of the engine). svn-id: r42991 --- engines/draci/barchive.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/draci/barchive.h b/engines/draci/barchive.h index 7d26b65884..6766c3c1fd 100644 --- a/engines/draci/barchive.h +++ b/engines/draci/barchive.h @@ -35,8 +35,8 @@ namespace Draci { */ struct BAFile { - uint16 _compLength; //!< Compressed length (the same as _length if the file is uncompressed) - uint16 _length; //!< Uncompressed length + uint _compLength; //!< Compressed length (the same as _length if the file is uncompressed) + uint _length; //!< Uncompressed length uint32 _offset; //!< Offset of file inside archive byte *_data; byte _crc; @@ -62,7 +62,7 @@ public: void openArchive(const Common::String &path); void closeArchive(void); - uint16 size() const { return _fileCount; } + uint size() const { return _fileCount; } /** * Checks whether there is an archive opened. Should be called before reading @@ -85,7 +85,7 @@ private: Common::String _path; //!< Path to file BAFile *_files; //!< Internal array of files - uint16 _fileCount; //!< Number of files in archive + uint _fileCount; //!< Number of files in archive bool _isDFW; //!< True if the archive is in DFW format, false otherwise bool _opened; //!< True if the archive is opened, false otherwise -- cgit v1.2.3 From 6bd1cfa1bdec266574d26b3bf0c3c45fa09d760a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 05:12:42 +0000 Subject: Implemented the Talk GPL command. svn-id: r42992 --- engines/draci/script.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++- engines/draci/script.h | 1 + 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 78ea91b3f7..690d7d45cd 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -49,7 +49,7 @@ void Script::setupCommandList() { { 5, 2, "StartPlay", 2, { 3, 2 }, &Script::startPlay }, { 5, 3, "JustTalk", 0, { 0 }, NULL }, { 5, 4, "JustStay", 0, { 0 }, NULL }, - { 6, 1, "Talk", 2, { 3, 2 }, NULL }, + { 6, 1, "Talk", 2, { 3, 2 }, &Script::talk }, { 7, 1, "ObjStat", 2, { 3, 3 }, &Script::objStat }, { 7, 2, "ObjStat_On", 2, { 3, 3 }, &Script::objStatOn }, { 8, 1, "IcoStat", 2, { 3, 3 }, NULL }, @@ -533,6 +533,73 @@ void Script::newRoom(Common::Queue ¶ms) { _vm->_game->_roomChange = true; } +void Script::talk(Common::Queue ¶ms) { + + int personID = params.pop() - 1; + int sentenceID = params.pop() - 1; + + // Fetch string + BAFile *f = _vm->_stringsArchive->getFile(sentenceID); + + // Fetch frame for the speech text + Animation *speechAnim = _vm->_anims->getAnimation(kSpeechText); + Text *speechFrame = reinterpret_cast(speechAnim->getFrame()); + + // Fetch person info + Person *person = _vm->_game->getPerson(personID); + + // Set the string and text colour + _vm->_screen->getSurface()->markDirtyRect(speechFrame->getRect(true)); + speechFrame->setText(Common::String((const char *)f->_data+1, f->_length-1)); + speechFrame->setColour(person->_fontColour); + + // Set the loop substatus to an appropriate value + _vm->_game->setLoopSubstatus(kStatusTalk); + + // Record time + _vm->_game->setSpeechTick(_vm->_system->getMillis()); + + // TODO: Implement inventory part + + // Set speech text coordinates + // TODO: Put this into a function + + int x = person->_x; + int y = person->_y; + + int difX = speechFrame->getWidth() / 2; + int difY = speechFrame->getHeight(); + int newX = x - difX; + int newY = y - difY; + + if (newX < 0) + newX = 0; + + if (newX + 2 * difX >= kScreenWidth - 1) + newX = (kScreenWidth - 1) - difX * 2; + + if (newY < 0) + newY = 0; + + if (newY + difY >= kScreenHeight - 1) + newY = (kScreenHeight - 1) - difY * 2; + + speechFrame->setX(newX); + speechFrame->setY(newY); + + // Call the game loop to enable interactivity until the text expires + _vm->_game->loop(); + + // Delete the text + _vm->_screen->getSurface()->markDirtyRect(speechFrame->getRect(true)); + speechFrame->setText(""); + + // Revert to "normal" loop status + _vm->_game->setLoopSubstatus(kStatusOrdinary); + _vm->_game->setExitLoop(false); +} + + /** * @brief Evaluates mathematical expressions * @param reader Stream reader set to the beginning of the expression diff --git a/engines/draci/script.h b/engines/draci/script.h index d799dcaed5..9e3345cd0b 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -115,6 +115,7 @@ private: void play(Common::Queue ¶ms); void startPlay(Common::Queue ¶ms); void newRoom(Common::Queue ¶ms); + void talk(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From 77033ca9a1a61e9de988849618ddd12ad28f7e7b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 05:16:36 +0000 Subject: * Fixed bug in Font::getStringWidth() which made it miscalculate string widths (a temporary variable used for storing the width of the current line was not being reset). * Temporarily disabled font transparency because the dragon's text is rendered hollow (transparency inside glyph bodies). svn-id: r42993 --- engines/draci/font.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index b867bf4877..dcd312a280 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -179,7 +179,12 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con } // Paint pixel (if not transparent) - if (colour != _transparent) + // HACK: Temporary turned off transparency because the dragon's colour of the + // font appears to be 255 (which should be transparent). + // This would not be a problem if the font background was also not colour + // 255 (apparently) so I don't know how to handle the background being + // transparent and at the same time a non-transparent font body. + //if (colour != _transparent) ptr[x] = colour; } @@ -279,7 +284,8 @@ int Font::getStringWidth(const Common::String &str, int spacing) const { if (tmp > width) { width = tmp; } - continue; + + tmp = 0; } } -- cgit v1.2.3 From f9bdd096595ceb924ffec95ea6f8225513e85670 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 2 Aug 2009 05:21:21 +0000 Subject: * Fixed bug when reading in persons data. I was reading in coordinates as bytes and font colour as int16; it should be the other way around. * Handled the kStatusTalk loop substatus properly inside Game::loop(). * Made Game::walkHero() set the person coordinates for the dragon after it warps him to a new location * Added Game::getPerson() method (used by Script::talk()) * Added Game::setSpeechTick() method (set by Script::talk() and used inside the loop to determine when to switch to new text). svn-id: r42994 --- engines/draci/game.cpp | 32 +++++++++++++++++++++++++++++--- engines/draci/game.h | 11 +++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index a0e0acbe85..58eb10a0ce 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -52,9 +52,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _persons = new Person[numPersons]; for (i = 0; i < numPersons; ++i) { - _persons[i]._x = personData.readByte(); - _persons[i]._y = personData.readByte(); - _persons[i]._fontColour = personData.readUint16LE(); + _persons[i]._x = personData.readUint16LE(); + _persons[i]._y = personData.readUint16LE(); + _persons[i]._fontColour = personData.readByte(); } // Close persons file @@ -277,6 +277,21 @@ void Game::loop() { debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } + if (_loopSubstatus == kStatusTalk) { + Animation *speechAnim = _vm->_anims->getAnimation(kSpeechText); + Text *speechFrame = reinterpret_cast(speechAnim->getFrame()); + + uint speechDuration = kBaseSpeechDuration + + speechFrame->getLength() * kSpeechTimeUnit / + (128 / 16 + 1); + + if ((_vm->_system->getMillis() - _speechTick) >= speechDuration) { + _shouldExitLoop = true; + } else { + _shouldExitLoop = false; + } + } + if (shouldQuit()) return; @@ -324,6 +339,9 @@ void Game::walkHero(int x, int y) { // Fetch base height of the frame uint height = frame->getHeight(); + _persons[kDragonObject]._x = x; + _persons[kDragonObject]._y = y - lround(scaleY) * height; + // We naturally want the dragon to position its feet to the location of the // click but sprites are drawn from their top-left corner so we subtract // the current height of the dragon's sprite @@ -727,6 +745,14 @@ int Game::getIconStatus(int iconID) { return _iconStatus[iconID]; } +Person *Game::getPerson(int personID) { + return &_persons[personID]; +} + +void Game::setSpeechTick(uint tick) { + _speechTick = tick; +} + /** * The GPL command Mark sets the animation index (which specifies the order in which * animations were loaded in) which is then used by the Release command to delete diff --git a/engines/draci/game.h b/engines/draci/game.h index a38b71a256..33b6e76894 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -47,6 +47,11 @@ enum { kNotFound = -1 }; +enum SpeechConstants { + kBaseSpeechDuration = 200, + kSpeechTimeUnit = 400 +}; + class WalkingMap { public: @@ -204,6 +209,8 @@ public: int getVariable(int varNum); void setVariable(int varNum, int value); + Person *getPerson(int personID); + int getRoomNum(); void setRoomNum(int room); @@ -228,6 +235,8 @@ public: void runGateProgram(int gate); + void setSpeechTick(uint tick); + bool _roomChange; private: @@ -252,6 +261,8 @@ private: bool _shouldQuit; bool _shouldExitLoop; + uint _speechTick; + int _objUnderCursor; int _markedAnimationIndex; //!< Used by the Mark GPL command }; -- cgit v1.2.3 From 96744e42c77bd00f69369d9b841500448b1d1ed3 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 3 Aug 2009 01:06:13 +0000 Subject: Fixed bug in the math expression evaluator; when evaluating operators, operands were being popped from the stack in the wrong order. svn-id: r43019 --- engines/draci/script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 690d7d45cd..68638ad15b 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -638,8 +638,8 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathOperator: value = reader.readSint16LE(); - arg1 = stk.pop(); arg2 = stk.pop(); + arg1 = stk.pop(); // Fetch operator oper = _operatorList[value-1]; -- cgit v1.2.3 From 5e2eefd4feeec43b532aef9a598b41adebfbfd5e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 3 Aug 2009 01:48:15 +0000 Subject: * Fixed bug which made characters talk with the wrong colour; the colour indexes are indexed from 1 in the data files so we need to subtract 1. * Turned on font transparency again. svn-id: r43022 --- engines/draci/font.cpp | 7 +------ engines/draci/game.cpp | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index dcd312a280..a3a261e293 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -179,12 +179,7 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con } // Paint pixel (if not transparent) - // HACK: Temporary turned off transparency because the dragon's colour of the - // font appears to be 255 (which should be transparent). - // This would not be a problem if the font background was also not colour - // 255 (apparently) so I don't know how to handle the background being - // transparent and at the same time a non-transparent font body. - //if (colour != _transparent) + if (colour != _transparent) ptr[x] = colour; } diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 58eb10a0ce..08207d4574 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -54,7 +54,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { for (i = 0; i < numPersons; ++i) { _persons[i]._x = personData.readUint16LE(); _persons[i]._y = personData.readUint16LE(); - _persons[i]._fontColour = personData.readByte(); + _persons[i]._fontColour = personData.readByte() - 1; } // Close persons file -- cgit v1.2.3 From 41d7590835cbee3c0befe41031e08f4ded969dc9 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 4 Aug 2009 15:41:27 +0000 Subject: * Reverted change that subtracts 1 from font colour indexes for various speaking characters; they are 0-based after all. * Fixed font blitting algorithm to allow for both white fonts and transparency. svn-id: r43044 --- engines/draci/font.cpp | 11 +++++++---- engines/draci/game.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index a3a261e293..4902965aa3 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -158,6 +158,10 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con int curr = y * _maxCharWidth + x; int colour = _charData[charOffset + curr]; + // If pixel is transparent, skip it + if (colour == _transparent) + continue; + // Replace colour with font colours switch (colour) { @@ -177,10 +181,9 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con colour = kFontColour4; break; } - - // Paint pixel (if not transparent) - if (colour != _transparent) - ptr[x] = colour; + + // Paint the pixel + ptr[x] = colour; } // Advance to next row diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 08207d4574..58eb10a0ce 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -54,7 +54,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { for (i = 0; i < numPersons; ++i) { _persons[i]._x = personData.readUint16LE(); _persons[i]._y = personData.readUint16LE(); - _persons[i]._fontColour = personData.readByte() - 1; + _persons[i]._fontColour = personData.readByte(); } // Close persons file -- cgit v1.2.3 From 561d55ff4d63d207895f127a2db5afb47007299a Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 4 Aug 2009 19:07:12 +0000 Subject: Added Surface methods centerOnX() and centerOnY(). svn-id: r43051 --- engines/draci/surface.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- engines/draci/surface.h | 2 ++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp index 636ec0c4ac..e5fb18dda0 100644 --- a/engines/draci/surface.cpp +++ b/engines/draci/surface.cpp @@ -118,7 +118,7 @@ void Surface::setTransparentColour(uint colour) { } /** - * @ brief Fills the surface with the specified colour + * @brief Fills the surface with the specified colour */ void Surface::fill(uint colour) { byte *ptr = (byte *)getBasePtr(0, 0); @@ -126,4 +126,46 @@ void Surface::fill(uint colour) { memset(ptr, colour, w * h); } +/** + * @brief Calculates horizontal center of an object + * + * @param x The x coordinate of the center + * @param width The width of the object to be centered (in pixels) + * + * @return The centered x coordinate + */ +uint Surface::centerOnX(uint x, uint width) { + + int newX = x - width / 2; + + if (newX < 0) + newX = 0; + + if (newX + width >= (uint)w - 1) + newX = (w - 1) - width; + + return newX; +} + +/** + * @brief Calculates vertical center of an object + * + * @param y The y coordinate of the center + * @param height The height of the object to be centered (in pixels) + * + * @return The centered y coordinate + */ +uint Surface::centerOnY(uint y, uint height) { + + int newY = y - height / 2; + + if (newY < 0) + newY = 0; + + if (newY + height >= (uint)h - 1) + newY = (h - 1) - height; + + return newY; +} + } // End of namespace Draci diff --git a/engines/draci/surface.h b/engines/draci/surface.h index db564ec2e5..1c7022ceff 100644 --- a/engines/draci/surface.h +++ b/engines/draci/surface.h @@ -45,6 +45,8 @@ public: uint getTransparentColour(); void setTransparentColour(uint colour); void fill(uint colour); + uint centerOnY(uint y, uint height); + uint centerOnX(uint x, uint width); private: /** The current transparent colour of the surface. See getTransparentColour() and -- cgit v1.2.3 From d3412ea3a433cee5dce9d520142110eea5713ea7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 4 Aug 2009 19:09:41 +0000 Subject: Refactored Script::talk() to use the new centering methods. svn-id: r43052 --- engines/draci/script.cpp | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 68638ad15b..cac8b0f7d4 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -538,6 +538,8 @@ void Script::talk(Common::Queue ¶ms) { int personID = params.pop() - 1; int sentenceID = params.pop() - 1; + Surface *surface = _vm->_screen->getSurface(); + // Fetch string BAFile *f = _vm->_stringsArchive->getFile(sentenceID); @@ -549,7 +551,7 @@ void Script::talk(Common::Queue ¶ms) { Person *person = _vm->_game->getPerson(personID); // Set the string and text colour - _vm->_screen->getSurface()->markDirtyRect(speechFrame->getRect(true)); + surface->markDirtyRect(speechFrame->getRect(true)); speechFrame->setText(Common::String((const char *)f->_data+1, f->_length-1)); speechFrame->setColour(person->_fontColour); @@ -562,30 +564,12 @@ void Script::talk(Common::Queue ¶ms) { // TODO: Implement inventory part // Set speech text coordinates - // TODO: Put this into a function - - int x = person->_x; - int y = person->_y; - - int difX = speechFrame->getWidth() / 2; - int difY = speechFrame->getHeight(); - int newX = x - difX; - int newY = y - difY; - - if (newX < 0) - newX = 0; - - if (newX + 2 * difX >= kScreenWidth - 1) - newX = (kScreenWidth - 1) - difX * 2; - - if (newY < 0) - newY = 0; - if (newY + difY >= kScreenHeight - 1) - newY = (kScreenHeight - 1) - difY * 2; + int x = surface->centerOnX(person->_x, speechFrame->getWidth()); + int y = surface->centerOnX(person->_y, speechFrame->getHeight() * 2); - speechFrame->setX(newX); - speechFrame->setY(newY); + speechFrame->setX(x); + speechFrame->setY(y); // Call the game loop to enable interactivity until the text expires _vm->_game->loop(); -- cgit v1.2.3 From 71dbb75031622432f94c38c4024c4253033d3747 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 4 Aug 2009 19:23:59 +0000 Subject: * Added Font::getLineWidth() * Changed Font::getStringWidth() and Font::getStringHeight() to return uint instead of int. * Made the Font::drawString() overload which accepts a Common::String the "default" one. The overload accepting a (byte *) now calls that one (it was the other way around before). * Added proper line centering to the Font::drawString() routine. svn-id: r43053 --- engines/draci/font.cpp | 71 ++++++++++++++++++++++++++++++++++---------------- engines/draci/font.h | 5 ++-- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 4902965aa3..2a9185e725 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -209,20 +209,37 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con void Font::drawString(Surface *dst, const byte *str, uint len, int x, int y, int spacing, bool markDirty) const { + drawString(dst, Common::String((const char *)str, len), x, y, spacing, markDirty); +} + +/** + * @brief Draw a string to a Draci::Surface + * + * @param dst Pointer to the destination surface + * @param str String to draw + * @param x Horizontal offset on the surface + * @param y Vertical offset on the surface + * @param spacing Space to leave between individual characters. Defaults to 0. + */ + +void Font::drawString(Surface *dst, const Common::String &str, + int x, int y, int spacing, bool markDirty) const { assert(dst != NULL); assert(x >= 0); assert(y >= 0); - int curx = x; - int cury = y; + uint widest = getStringWidth(str, spacing); - for (unsigned int i = 0; i < len; ++i) { + int curx = x + (widest - getLineWidth(str, 0, spacing)) / 2; + int cury = y; + + for (uint i = 0; i < str.size(); ++i) { // If we encounter the '|' char (newline and end of string marker), // skip it and go to the start of the next line if (str[i] == '|') { cury += getFontHeight(); - curx = x; + curx = x + (widest - getLineWidth(str, i+1, spacing) - 1) / 2; continue; } @@ -236,22 +253,6 @@ void Font::drawString(Surface *dst, const byte *str, uint len, } } -/** - * @brief Draw a string to a Draci::Surface - * - * @param dst Pointer to the destination surface - * @param str String to draw - * @param x Horizontal offset on the surface - * @param y Vertical offset on the surface - * @param spacing Space to leave between individual characters. Defaults to 0. - */ - -void Font::drawString(Surface *dst, const Common::String &str, - int x, int y, int spacing, bool markDirty) const { - - drawString(dst, (byte *) str.c_str(), str.size(), x, y, spacing, markDirty); -} - /** * @brief Calculate the width of a string when drawn in the current font * @@ -261,7 +262,7 @@ void Font::drawString(Surface *dst, const Common::String &str, * @return The calculated width of the string */ -int Font::getStringWidth(const Common::String &str, int spacing) const { +uint Font::getStringWidth(const Common::String &str, int spacing) const { unsigned int width = 0; // Real length, including '|' separators @@ -290,6 +291,30 @@ int Font::getStringWidth(const Common::String &str, int spacing) const { return width + 1; } +uint Font::getLineWidth(const Common::String &str, uint startIndex, int spacing) const { + + uint width = 0; + + // If the index is greater or equal to the string size, + // the width of the line is 0 + if (startIndex >= str.size()) + return 0; + + for (uint i = startIndex; i < str.size(); ++i) { + + // EOL encountered + if (str[i] == '|') + break; + + // Add width of the current char + uint8 charIndex = str[i] - kCharIndexOffset; + width += _charWidths[charIndex]; + width += spacing; + } + + return width; +} + /** * @brief Calculate the height of a string by counting the number of '|' chars (which * are used as newline characters and end-of-string markers) @@ -301,7 +326,7 @@ int Font::getStringWidth(const Common::String &str, int spacing) const { */ -int Font::getStringHeight(const Common::String &str) const { +uint Font::getStringHeight(const Common::String &str) const { uint len = str.size(); int separators = 0; @@ -314,6 +339,6 @@ int Font::getStringHeight(const Common::String &str) const { } return separators * getFontHeight(); -} +} } // End of namespace Draci diff --git a/engines/draci/font.h b/engines/draci/font.h index 67c32aa791..5ccf1f1cf8 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -67,8 +67,9 @@ public: void drawString(Surface *dst, const Common::String &str, int x, int y, int spacing, bool markDirty = true) const; - int getStringWidth(const Common::String &str, int spacing = 0) const; - int getStringHeight(const Common::String &str) const; + uint getStringWidth(const Common::String &str, int spacing = 0) const; + uint getStringHeight(const Common::String &str) const; + uint getLineWidth(const Common::String &str, uint startIndex, int spacing = 0) const; void setColour(uint8 colour); -- cgit v1.2.3 From 88276e91d97b5c1d7c55ff440ba945db27a80980 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 5 Aug 2009 00:05:36 +0000 Subject: Fixed second call to Surface::centerOnX() (should have been centerOnY()). svn-id: r43058 --- engines/draci/script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index cac8b0f7d4..17cdefe009 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -566,7 +566,7 @@ void Script::talk(Common::Queue ¶ms) { // Set speech text coordinates int x = surface->centerOnX(person->_x, speechFrame->getWidth()); - int y = surface->centerOnX(person->_y, speechFrame->getHeight() * 2); + int y = surface->centerOnY(person->_y, speechFrame->getHeight() * 2); speechFrame->setX(x); speechFrame->setY(y); -- cgit v1.2.3 From c9b24d2ff9f27a5926ea0dd992a85923dd1616f8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 5 Aug 2009 00:11:09 +0000 Subject: * Changed title text to use the small instead of the big font * Handled title positioning * Cleaned up the main loop a bit (comments, stylistic changes, shortened some lines, etc) * Fixed setting the dragon's feet position (the x coordinate should be at the midpoint of the animation) svn-id: r43059 --- engines/draci/game.cpp | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 58eb10a0ce..8fce400c9d 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -204,7 +204,7 @@ void Game::init() { // Initialize animation for object / room titles Animation *titleAnim = _vm->_anims->addText(kTitleText, true); - Text *title = new Text("", _vm->_bigFont, kFontColour3, 0, 0); + Text *title = new Text("", _vm->_smallFont, kFontColour3, 0, 0); titleAnim->addFrame(title); // Initialize animation for speech text @@ -233,31 +233,48 @@ void Game::init() { void Game::loop() { + Surface *surface = _vm->_screen->getSurface(); + + const int smallFontHeight = _vm->_smallFont->getFontHeight(); + do { _vm->handleEvents(); if (_currentRoom._mouseOn) { + + // Fetch mouse coordinates int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); + // If the player clicked on a walkable position, move the dragon there if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { walkHero(x, y); } + // Find the game object under the cursor + // (to be more precise, one that corresponds to the animation under the cursor) int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - //Animation *anim = _vm->_anims->getAnimation(animUnderCursor); - int curObject = getObjectWithAnimation(animUnderCursor); GameObject *obj = &_objects[curObject]; + // Fetch the dedicated objects' title animation / current frame Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); + Text *title = reinterpret_cast(titleAnim->getFrame()); - // TODO: Handle displaying title in the proper location - + // If there is an object under the cursor, display its title and enable + // executing its look and use scripts if (curObject != kNotFound) { - titleAnim->markDirtyRect(_vm->_screen->getSurface()); - reinterpret_cast(titleAnim->getFrame())->setText(obj->_title); + // Mark dirty rectangle to update the text + titleAnim->markDirtyRect(surface); + + // Set the title for the current object + title->setText(obj->_title); + + // Move the title to the correct place (just above the cursor) + int newX = surface->centerOnX(x, title->getWidth()); + int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); + titleAnim->setRelative(newX, newY); // HACK: Test running look and use scripts if (_vm->_mouse->lButtonPressed()) { @@ -270,13 +287,15 @@ void Game::loop() { _vm->_script->run(obj->_program, obj->_use); } } else { - titleAnim->markDirtyRect(_vm->_screen->getSurface()); - reinterpret_cast(titleAnim->getFrame())->setText(""); + // If there is no object under the cursor, just delete the previous title + titleAnim->markDirtyRect(surface); + title->setText(""); } debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } + // Handle character talking (if there is any) if (_loopSubstatus == kStatusTalk) { Animation *speechAnim = _vm->_anims->getAnimation(kSpeechText); Text *speechFrame = reinterpret_cast(speechAnim->getFrame()); @@ -292,9 +311,11 @@ void Game::loop() { } } + // This returns true if we got a signal to quit the game if (shouldQuit()) return; + // Advance animations and redraw screen _vm->_anims->drawScene(_vm->_screen->getSurface()); _vm->_screen->copyToScreen(); _vm->_system->delayMillis(20); @@ -336,10 +357,11 @@ void Game::walkHero(int x, int y) { // Fetch current frame Drawable *frame = anim->getFrame(); - // Fetch base height of the frame + // Fetch base dimensions of the frame uint height = frame->getHeight(); + uint width = frame->getWidth(); - _persons[kDragonObject]._x = x; + _persons[kDragonObject]._x = x + (lround(scaleX) * width) / 2; _persons[kDragonObject]._y = y - lround(scaleY) * height; // We naturally want the dragon to position its feet to the location of the -- cgit v1.2.3 From 6546c2ed8eb30201f0af68639cb5e37f65620741 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 5 Aug 2009 02:35:51 +0000 Subject: * Added kTitleColour = 255 enum constant used in the following item. * Added proper colouring of the title animation fonts * Added Game::getEscRoom(). svn-id: r43063 --- engines/draci/font.h | 2 +- engines/draci/game.cpp | 6 +++++- engines/draci/game.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/draci/font.h b/engines/draci/font.h index 5ccf1f1cf8..e566a5ad54 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -42,7 +42,7 @@ extern const Common::String kFontBig; enum { kFontColour1 = 2, kFontColour2 = 0, kFontColour3 = 3, kFontColour4 = 4, - kOverFontColour = 255 + kOverFontColour = 255, kTitleColour = 255 }; /** diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 8fce400c9d..e9714d6124 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -204,7 +204,7 @@ void Game::init() { // Initialize animation for object / room titles Animation *titleAnim = _vm->_anims->addText(kTitleText, true); - Text *title = new Text("", _vm->_smallFont, kFontColour3, 0, 0); + Text *title = new Text("", _vm->_smallFont, kTitleColour, 0, 0); titleAnim->addFrame(title); // Initialize animation for speech text @@ -775,6 +775,10 @@ void Game::setSpeechTick(uint tick) { _speechTick = tick; } +int Game::getEscRoom() { + return _currentRoom._escRoom; +} + /** * The GPL command Mark sets the animation index (which specifies the order in which * animations were loaded in) which is then used by the Release command to delete diff --git a/engines/draci/game.h b/engines/draci/game.h index 33b6e76894..8b8be1e9ea 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -219,6 +219,8 @@ public: int getIconStatus(int iconID); + int getEscRoom(); + int getMarkedAnimationIndex(); void setMarkedAnimationIndex(int index); -- cgit v1.2.3 From 1363a0680a564c356f497d0e90aefeef5f426f76 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 5 Aug 2009 02:42:23 +0000 Subject: * Implemented the "escape room" feature of the original engine which lets a user switch to another location (or skip the intro) by pressing ESC (the escRoom for every location is stored in the data files). * Reworked the left and right arrow key commands so they don't call changeRoom() themselves but instead schedule the room change via Game::setRoomNum(). In this way, changing rooms like that is still a hack but a bit more "natural", since the loop doesn't get skipped, the gate scripts get run, etc. svn-id: r43065 --- engines/draci/draci.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 612f255fc6..87408dbccf 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -191,12 +191,21 @@ bool DraciEngine::handleEvents() { _game->setQuit(true); break; case Common::EVENT_KEYDOWN: - if (event.kbd.keycode == Common::KEYCODE_RIGHT) - _game->changeRoom(_game->nextRoomNum()); - - else if (event.kbd.keycode == Common::KEYCODE_LEFT) - _game->changeRoom(_game->prevRoomNum()); - + if (event.kbd.keycode == Common::KEYCODE_RIGHT) { + _game->setRoomNum(_game->nextRoomNum()); + _game->setGateNum(0); + _game->_roomChange = true; + } + else if (event.kbd.keycode == Common::KEYCODE_LEFT) { + _game->setRoomNum(_game->prevRoomNum()); + _game->setGateNum(0); + _game->_roomChange = true; + } + else if (event.kbd.keycode == Common::KEYCODE_ESCAPE) { + _game->setRoomNum(_game->getEscRoom()); + _game->setGateNum(0); + _game->_roomChange = true; + } // Show walking map toggle else if (event.kbd.keycode == Common::KEYCODE_w) { _showWalkingMap = !_showWalkingMap; -- cgit v1.2.3 From e63210616972e59d6e9e98989c489cbf760bcb79 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 5 Aug 2009 17:58:14 +0000 Subject: * Made some type changes to struct/class members in game.cpp (uint -> int and uint16 -> uint) * Added enum constant kNoEscRoom for rooms that have no escape room defined * Fixed crash when ESC is pressed in rooms which have no escape room defined * Renamed kNotFound (used as a return value for Game::getObjectWithAnimation) to kObjectNotFound for clarity. svn-id: r43072 --- engines/draci/draci.cpp | 11 ++++++++--- engines/draci/game.cpp | 4 ++-- engines/draci/game.h | 37 +++++++++++++++++++++++-------------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 87408dbccf..aea3938f24 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -202,9 +202,14 @@ bool DraciEngine::handleEvents() { _game->_roomChange = true; } else if (event.kbd.keycode == Common::KEYCODE_ESCAPE) { - _game->setRoomNum(_game->getEscRoom()); - _game->setGateNum(0); - _game->_roomChange = true; + int escRoom = _game->getEscRoom(); + + // Check if there is an escape room defined for the current room + if (escRoom != kNoEscRoom) { + _game->setRoomNum(_game->getEscRoom()); + _game->setGateNum(0); + _game->_roomChange = true; + } } // Show walking map toggle else if (event.kbd.keycode == Common::KEYCODE_w) { diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index e9714d6124..d8152b0fcb 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -264,7 +264,7 @@ void Game::loop() { // If there is an object under the cursor, display its title and enable // executing its look and use scripts - if (curObject != kNotFound) { + if (curObject != kObjectNotFound) { // Mark dirty rectangle to update the text titleAnim->markDirtyRect(surface); @@ -337,7 +337,7 @@ int Game::getObjectWithAnimation(int animID) { } } - return kNotFound; + return kObjectNotFound; } void Game::walkHero(int x, int y) { diff --git a/engines/draci/game.h b/engines/draci/game.h index 8b8be1e9ea..c041490e04 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -43,8 +43,17 @@ enum StructSizes { personSize = sizeof(uint16) * 2 + sizeof(byte) }; + +// Used as a return value for Game::getObjectWithAnimation() if no object +// owns the animation in question +enum { + kObjectNotFound = -1 +}; + +// Used as the value of the _escRoom field of the current room if there is +// no escape room defined enum { - kNotFound = -1 + kNoEscRoom = -1 }; enum SpeechConstants { @@ -95,9 +104,9 @@ struct GameObject { bool _imInit, _imLook, _imUse; byte _walkDir; byte _z; - uint16 _lookX, _lookY, _useX, _useY; + uint _lookX, _lookY, _useX, _useY; byte _lookDir, _useDir; - uint16 _absNum; + uint _absNum; Common::Array _anims; GPL2Program _program; Common::String _title; @@ -106,26 +115,26 @@ struct GameObject { }; struct GameInfo { - byte _startRoom; - byte _mapRoom; - uint16 _numObjects; - uint16 _numIcons; + int _startRoom; + int _mapRoom; + uint _numObjects; + uint _numIcons; byte _numVariables; byte _numPersons; byte _numDialogs; - uint16 _maxIconWidth, _maxIconHeight; - uint16 _musicLength; - uint16 _crc[4]; - uint16 _numDialogBlocks; + uint _maxIconWidth, _maxIconHeight; + uint _musicLength; + uint _crc[4]; + uint _numDialogBlocks; }; struct Person { - uint16 _x, _y; + uint _x, _y; byte _fontColour; }; struct Room { - byte _roomNum; + int _roomNum; byte _music; WalkingMap _walkingMap; byte _palette; @@ -134,7 +143,7 @@ struct Room { bool _imInit, _imLook, _imUse; bool _mouseOn, _heroOn; double _pers0, _persStep; - byte _escRoom; + int _escRoom; byte _numGates; Common::Array _gates; GPL2Program _program; -- cgit v1.2.3 From da8bad0ef528ecb23dc82bcd3c1e30aef0a3b6ed Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 03:52:08 +0000 Subject: Made the game behave properly and safe when clicking on objects multiple times during talking or executing look/use scripts. Previously, the loop could be called nested arbitrarily many times. svn-id: r43081 --- engines/draci/game.cpp | 60 +++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d8152b0fcb..3e3162e543 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -262,37 +262,41 @@ void Game::loop() { Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); Text *title = reinterpret_cast(titleAnim->getFrame()); - // If there is an object under the cursor, display its title and enable - // executing its look and use scripts - if (curObject != kObjectNotFound) { - // Mark dirty rectangle to update the text - titleAnim->markDirtyRect(surface); - - // Set the title for the current object - title->setText(obj->_title); - - // Move the title to the correct place (just above the cursor) - int newX = surface->centerOnX(x, title->getWidth()); - int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); - titleAnim->setRelative(newX, newY); - - // HACK: Test running look and use scripts - if (_vm->_mouse->lButtonPressed()) { - _vm->_mouse->lButtonSet(false); - _vm->_script->run(obj->_program, obj->_look); + if (_loopStatus == kStatusOrdinary) { + // If there is an object under the cursor, display its title and enable + // executing its look and use scripts + if (curObject != kObjectNotFound) { + // Mark dirty rectangle to update the text + titleAnim->markDirtyRect(surface); + + // Set the title for the current object + title->setText(obj->_title); + + // Move the title to the correct place (just above the cursor) + int newX = surface->centerOnX(x, title->getWidth()); + int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); + titleAnim->setRelative(newX, newY); + + if (_loopSubstatus == kStatusOrdinary) { + // HACK: Test running look and use scripts + if (_vm->_mouse->lButtonPressed()) { + _vm->_mouse->lButtonSet(false); + _vm->_script->run(obj->_program, obj->_look); + } + + if (_vm->_mouse->rButtonPressed()) { + _vm->_mouse->rButtonSet(false); + _vm->_script->run(obj->_program, obj->_use); + } + } + } else { + // If there is no object under the cursor, just delete the previous title + titleAnim->markDirtyRect(surface); + title->setText(""); } - if (_vm->_mouse->rButtonPressed()) { - _vm->_mouse->rButtonSet(false); - _vm->_script->run(obj->_program, obj->_use); - } - } else { - // If there is no object under the cursor, just delete the previous title - titleAnim->markDirtyRect(surface); - title->setText(""); + debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } - - debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } // Handle character talking (if there is any) -- cgit v1.2.3 From c2dccaafcde526875999feb7802c13c482d6ce6d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 04:48:43 +0000 Subject: Added method Mouse::isCursorOn(). svn-id: r43082 --- engines/draci/mouse.cpp | 4 ++++ engines/draci/mouse.h | 1 + 2 files changed, 5 insertions(+) diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 352dbf4e80..9f34003840 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -80,6 +80,10 @@ void Mouse::cursorOff() { CursorMan.showMouse(false); } +bool Mouse::isCursorOn() { + return CursorMan.isVisible(); +} + void Mouse::setPosition(uint16 x, uint16 y) { _vm->_system->warpMouse(x, y); } diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h index 8135482929..07dc53311d 100644 --- a/engines/draci/mouse.h +++ b/engines/draci/mouse.h @@ -48,6 +48,7 @@ public: void handleEvent(Common::Event event); void cursorOn(); void cursorOff(); + bool isCursorOn(); void setPosition(uint16 x, uint16 y); void setCursorType(CursorType cur); CursorType getCursorType() { return _cursorType; } -- cgit v1.2.3 From 09e49a354fe40b500cf07e2ec97607b903aef70b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 04:50:37 +0000 Subject: Turn off mouse cursor and disable titles when running look / use scripts. svn-id: r43083 --- engines/draci/game.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3e3162e543..cef91528a7 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -266,27 +266,40 @@ void Game::loop() { // If there is an object under the cursor, display its title and enable // executing its look and use scripts if (curObject != kObjectNotFound) { - // Mark dirty rectangle to update the text - titleAnim->markDirtyRect(surface); - // Set the title for the current object - title->setText(obj->_title); + if(_vm->_mouse->isCursorOn()) { + // Mark dirty rectangle to delete the previous text + titleAnim->markDirtyRect(surface); - // Move the title to the correct place (just above the cursor) - int newX = surface->centerOnX(x, title->getWidth()); - int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); - titleAnim->setRelative(newX, newY); + // Set the title for the current object + title->setText(obj->_title); + + // Move the title to the correct place (just above the cursor) + int newX = surface->centerOnX(x, title->getWidth()); + int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); + titleAnim->setRelative(newX, newY); + } if (_loopSubstatus == kStatusOrdinary) { // HACK: Test running look and use scripts if (_vm->_mouse->lButtonPressed()) { + // Delete title text + title->setText(""); + + _vm->_mouse->cursorOff(); _vm->_mouse->lButtonSet(false); _vm->_script->run(obj->_program, obj->_look); + _vm->_mouse->cursorOn(); } if (_vm->_mouse->rButtonPressed()) { + // Delete title text + title->setText(""); + + _vm->_mouse->cursorOff(); _vm->_mouse->rButtonSet(false); _vm->_script->run(obj->_program, obj->_use); + _vm->_mouse->cursorOn(); } } } else { -- cgit v1.2.3 From 5ea44b9b5e52402369ab58fb3d978d9597b7830b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 05:04:21 +0000 Subject: Moved walkHero() (in the main loop) to the appropriate place (in anticipation of a smart finding a walkable point) and disabled walking during script execution / inventory. svn-id: r43084 --- engines/draci/game.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index cef91528a7..9965c9c4b1 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -247,11 +247,6 @@ void Game::loop() { int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); - // If the player clicked on a walkable position, move the dragon there - if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { - walkHero(x, y); - } - // Find the game object under the cursor // (to be more precise, one that corresponds to the animation under the cursor) int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); @@ -303,9 +298,24 @@ void Game::loop() { } } } else { - // If there is no object under the cursor, just delete the previous title + // We haven't found an object under the cursor + + // Delete the previous title titleAnim->markDirtyRect(surface); title->setText(""); + + // TODO: Implement "smart" walkability checking (so one can click + // anywhere on the screen and the engine finds the nearest walkable + // point) + + // If the player clicked on a walkable position and we are in the + // appropriate loop status, move the dragon there + if (_vm->_mouse->lButtonPressed() && + _currentRoom._walkingMap.isWalkable(x, y) && + _loopSubstatus == kStatusOrdinary) { + + walkHero(x, y); + } } debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); -- cgit v1.2.3 From 3ce16763c7d0f5ef22385dc482cc2c2e184b8f7c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 05:17:18 +0000 Subject: Enabled skipping the current line of text if a mouse click occurs. svn-id: r43085 --- engines/draci/game.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 9965c9c4b1..9e18eb5f3c 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -330,9 +330,16 @@ void Game::loop() { uint speechDuration = kBaseSpeechDuration + speechFrame->getLength() * kSpeechTimeUnit / (128 / 16 + 1); - - if ((_vm->_system->getMillis() - _speechTick) >= speechDuration) { + + // If the current speech text has expired or the user clicked a mouse button, + // advance to the next line of text + if (_vm->_mouse->lButtonPressed() || + _vm->_mouse->rButtonPressed() || + (_vm->_system->getMillis() - _speechTick) >= speechDuration) { + _shouldExitLoop = true; + _vm->_mouse->lButtonSet(false); + _vm->_mouse->rButtonSet(false); } else { _shouldExitLoop = false; } -- cgit v1.2.3 From 907a35c9297044b87f4e0c5c586873f669cee7da Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 07:40:14 +0000 Subject: Added ability to end the currently executing GPL program before it finishes via Script::endCurrentProgram(). svn-id: r43086 --- engines/draci/script.cpp | 10 +++++++++- engines/draci/script.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 17cdefe009..9d72c4ab34 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -583,6 +583,9 @@ void Script::talk(Common::Queue ¶ms) { _vm->_game->setExitLoop(false); } +void Script::endCurrentProgram() { + _endProgram = true; +} /** * @brief Evaluates mathematical expressions @@ -797,6 +800,10 @@ int Script::run(GPL2Program program, uint16 offset) { // extract low byte, i.e. the command subnumber byte subnum = cmdpair & 0xFF; + // This might get set by some GPL commands via Script::endCurrentProgram() + // if they need a program to stop midway + _endProgram = false; + if ((cmd = findCommand(num, subnum))) { int tmp; @@ -828,8 +835,9 @@ int Script::run(GPL2Program program, uint16 offset) { (this->*(cmd->_handler))(params); } - } while (cmd->_name != "gplend" && cmd->_name != "exit"); + } while (cmd->_name != "gplend" && cmd->_name != "exit" && !_endProgram); + _endProgram = false; _jump = oldJump; return 0; diff --git a/engines/draci/script.h b/engines/draci/script.h index 9e3345cd0b..78e813da40 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -89,10 +89,12 @@ public: Script(DraciEngine *vm) : _vm(vm), _jump(0) { setupCommandList(); }; int run(GPL2Program program, uint16 offset); + void endCurrentProgram(); private: int _jump; + bool _endProgram; /** List of all GPL commands. Initialised in the constructor. */ const GPL2Command *_commandList; -- cgit v1.2.3 From 58c56e28b973b4068a646326a2b5563cb2d9b63e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Thu, 6 Aug 2009 07:42:14 +0000 Subject: Fixed the 'ESC room' feature to work as intended. svn-id: r43087 --- engines/draci/draci.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index aea3938f24..4060b678ad 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -206,9 +206,14 @@ bool DraciEngine::handleEvents() { // Check if there is an escape room defined for the current room if (escRoom != kNoEscRoom) { + + // Schedule room change _game->setRoomNum(_game->getEscRoom()); _game->setGateNum(0); _game->_roomChange = true; + + // End any currently running GPL programs + _script->endCurrentProgram(); } } // Show walking map toggle -- cgit v1.2.3 From fc6ff00cbce11f4ffee62d964531f71c88590a11 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 8 Aug 2009 03:17:18 +0000 Subject: Implemented Surface::getRect(). svn-id: r43109 --- engines/draci/surface.cpp | 8 ++++++++ engines/draci/surface.h | 1 + 2 files changed, 9 insertions(+) diff --git a/engines/draci/surface.cpp b/engines/draci/surface.cpp index e5fb18dda0..a1e9b0f9ab 100644 --- a/engines/draci/surface.cpp +++ b/engines/draci/surface.cpp @@ -168,4 +168,12 @@ uint Surface::centerOnY(uint y, uint height) { return newY; } +/** + * @brief Returns a Common::Rect corresponding to the surface. + */ + +Common::Rect Surface::getRect() { + return Common::Rect(w, h); +} + } // End of namespace Draci diff --git a/engines/draci/surface.h b/engines/draci/surface.h index 1c7022ceff..ea3830a97f 100644 --- a/engines/draci/surface.h +++ b/engines/draci/surface.h @@ -47,6 +47,7 @@ public: void fill(uint colour); uint centerOnY(uint y, uint height); uint centerOnX(uint x, uint width); + Common::Rect getRect(); private: /** The current transparent colour of the surface. See getTransparentColour() and -- cgit v1.2.3 From 19d5d66fd7989f9028ee2ad54fd36d163fdb1b1c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 8 Aug 2009 12:31:49 +0000 Subject: * Implemented WalkingMap::findNearestWalkable() which mimics a heuristic from the original game that attempts to find walkable spots near the given point * Implemented moving to the right place when looking / using objects. svn-id: r43125 --- engines/draci/game.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++- engines/draci/game.h | 1 + 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 9e18eb5f3c..a83ba68901 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -38,6 +38,7 @@ namespace Draci { static double real_to_double(byte real[6]); Game::Game(DraciEngine *vm) : _vm(vm) { + unsigned int i; BArchive *initArchive = _vm->_initArchive; @@ -283,6 +284,15 @@ void Game::loop() { _vm->_mouse->cursorOff(); _vm->_mouse->lButtonSet(false); + + if (!obj->_imLook) { + if (obj->_lookDir == 0) { + walkHero(x, y); + } else { + walkHero(obj->_lookX, obj->_lookY); + } + } + _vm->_script->run(obj->_program, obj->_look); _vm->_mouse->cursorOn(); } @@ -293,6 +303,15 @@ void Game::loop() { _vm->_mouse->cursorOff(); _vm->_mouse->rButtonSet(false); + + if (!obj->_imUse) { + if (obj->_useDir == 0) { + walkHero(x, y); + } else { + walkHero(obj->_useX, obj->_useY); + } + } + _vm->_script->run(obj->_program, obj->_use); _vm->_mouse->cursorOn(); } @@ -311,7 +330,6 @@ void Game::loop() { // If the player clicked on a walkable position and we are in the // appropriate loop status, move the dragon there if (_vm->_mouse->lButtonPressed() && - _currentRoom._walkingMap.isWalkable(x, y) && _loopSubstatus == kStatusOrdinary) { walkHero(x, y); @@ -375,6 +393,13 @@ int Game::getObjectWithAnimation(int animID) { } void Game::walkHero(int x, int y) { + + Surface *surface = _vm->_screen->getSurface(); + Common::Point p = _currentRoom._walkingMap.findNearestWalkable(x, y, surface->getRect()); + + x = p.x; + y = p.y; + // Fetch dragon's animation ID // FIXME: Need to add proper walking (this only warps the dragon to position) int animID = getObject(kDragonObject)->_anims[0]; @@ -852,6 +877,103 @@ bool WalkingMap::isWalkable(int x, int y) { return mapByte & (1 << pixelIndex % 8); } +/** + * @brief For a given point, find a nearest walkable point on the walking map + * + * @param startX x coordinate of the point + * @param startY y coordinate of the point + * + * @return A Common::Point representing the nearest walkable point + * + * The algorithm was copied from the original engine for exactness. + * TODO: Study this algorithm in more detail so it can be documented properly and + * possibly improved / simplified. + */ +Common::Point WalkingMap::findNearestWalkable(int startX, int startY, Common::Rect searchRect) { + + int signs[] = { 1, -1 }; + const uint kSignsNum = 2; + + int radius = 0; + int x, y; + int dx, dy; + int prediction; + + // The place where, eventually, the result coordinates will be stored + int finalX, finalY; + + // The algorithm appears to start off with an ellipse with the minor radius equal to + // zero and the major radius equal to the walking map delta (the number of pixels + // one map pixel represents). It then uses a heuristic to gradually reshape it into + // a circle (by shortening the major radius and lengthening the minor one). At each + // such resizing step, it checks some select points on the ellipse for walkability. + // It also does the same check for the ellipse perpendicular to it (rotated by 90 degrees). + + while(1) { + + // The default major radius + radius += _deltaX; + + // The ellipse radii (minor, major) that get resized + x = 0; + y = radius; + + // Heuristic variables + prediction = 1 - radius; + dx = 3; + dy = 2 * radius - 2; + + do { + + // The following two loops serve the purpose of checking the points on the two + // ellipses for walkability. The signs[] array is there to obliterate the need + // of writing out all combinations manually. + + for (uint i = 0; i < kSignsNum; ++i) { + finalY = startY + y * signs[i]; + + for (uint j = 0; j < kSignsNum; ++j) { + finalX = startX + x * signs[j]; + + // If the current point is walkable, return it + if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { + return Common::Point(finalX, finalY); + } + } + } + + for (uint i = 0; i < kSignsNum; ++i) { + finalY = startY + x * signs[i]; + + for (uint j = 0; j < kSignsNum; ++j) { + finalX = startX + y * signs[j]; + + // If the current point is walkable, return it + if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { + return Common::Point(finalX, finalY); + } + } + } + + // If prediction is non-negative, we need to decrease the major radius of the + // ellipse + if (prediction >= 0) { + prediction -= dy; + dy -= 2 * _deltaX; + y -= _deltaX; + } + + // Increase the minor radius of the ellipse and update heuristic variables + prediction += dx; + dx += 2 * _deltaX; + x += _deltaX; + + // If the current ellipse has been reshaped into a circle, + // end this loop and enlarge the radius + } while (x <= y); + } +} + static double real_to_double(byte real[6]) { // Extract sign bit diff --git a/engines/draci/game.h b/engines/draci/game.h index c041490e04..7d0f8349f5 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -89,6 +89,7 @@ public: } bool isWalkable(int x, int y); + Common::Point findNearestWalkable(int x, int y, Common::Rect searchRect); private: int _realWidth, _realHeight; -- cgit v1.2.3 From d2f7268171b1ef3756a5de10aafc5f93761484f1 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 8 Aug 2009 15:53:47 +0000 Subject: Removed TODO concerning the nearest walkable point feature and reworded some obsolete documentation. svn-id: r43128 --- engines/draci/game.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index a83ba68901..2ba3103f19 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -323,12 +323,8 @@ void Game::loop() { titleAnim->markDirtyRect(surface); title->setText(""); - // TODO: Implement "smart" walkability checking (so one can click - // anywhere on the screen and the engine finds the nearest walkable - // point) - - // If the player clicked on a walkable position and we are in the - // appropriate loop status, move the dragon there + // If we are in the appropriate loop status and the player clicked + // on the room, move the dragon to the nearest walkable point if (_vm->_mouse->lButtonPressed() && _loopSubstatus == kStatusOrdinary) { -- cgit v1.2.3 From 18b5d7ce33ffc3631f38b041cb3a48bcb64a3bc7 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 8 Aug 2009 15:55:19 +0000 Subject: Implemented Script::testExpression(). svn-id: r43129 --- engines/draci/script.cpp | 35 ++++++++++++++++++++++++++++++++++- engines/draci/script.h | 1 + 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 9d72c4ab34..a997fa4e55 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -598,6 +598,8 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { GPL2Operator oper; GPL2Function func; + debugC(3, kDraciBytecodeDebugLevel, "\t"); + // Read in initial math object obj = (mathExpressionObject)reader.readSint16LE(); @@ -687,6 +689,36 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { return stk.pop(); } +/** + * @brief Evaluates a GPL mathematical expression on a given offset and returns + * the result (which is normally a boolean-like value) + * + * @param program A GPL2Program instance of the program containing the expression + * @param offset Offset of the expression inside the program (in multiples of 2 bytes) + * + * @return The result of the expression converted to a bool. + * + * Reference: the function equivalent to this one is called "Can()" in the original engine. + */ +bool Script::testExpression(GPL2Program program, uint16 offset) { + + // Initialize program reader + Common::MemoryReadStream reader(program._bytecode, program._length); + + // Offset is given as number of 16-bit integers so we need to convert + // it to a number of bytes + offset -= 1; + offset *= 2; + + // Seek to the expression + reader.seek(offset); + + debugC(2, kDraciBytecodeDebugLevel, + "Evaluating (standalone) GPL expression at offset %d:", offset); + + return (bool)handleMathExpression(reader); +} + /** * @brief Find the current command in the internal table * @@ -812,7 +844,8 @@ int Script::run(GPL2Program program, uint16 offset) { for (int i = 0; i < cmd->_numParams; ++i) { if (cmd->_paramTypes[i] == 4) { - debugC(2, kDraciBytecodeDebugLevel, "\t"); + debugC(2, kDraciBytecodeDebugLevel, + "Evaluating (in-script) GPL expression at offset %d: ", offset); params.push(handleMathExpression(reader)); } else { diff --git a/engines/draci/script.h b/engines/draci/script.h index 78e813da40..38871a05f9 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -89,6 +89,7 @@ public: Script(DraciEngine *vm) : _vm(vm), _jump(0) { setupCommandList(); }; int run(GPL2Program program, uint16 offset); + bool testExpression(GPL2Program, uint16 offset); void endCurrentProgram(); private: -- cgit v1.2.3 From c193c80e67fa9d172f9f57edae927e1c3ed11c0e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 8 Aug 2009 16:17:21 +0000 Subject: * Test whether an object can be used by evaluating its canUse script (warning: this will break many things currently working until I implement IsIcoAct in my next few commits). * Removed old HACK note because look / use scripts are now more properly implemented. svn-id: r43130 --- engines/draci/game.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 2ba3103f19..3441ba7860 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -277,7 +277,7 @@ void Game::loop() { } if (_loopSubstatus == kStatusOrdinary) { - // HACK: Test running look and use scripts + if (_vm->_mouse->lButtonPressed()) { // Delete title text title->setText(""); @@ -297,23 +297,30 @@ void Game::loop() { _vm->_mouse->cursorOn(); } + // TODO: Handle global use scripts (the use script for the room itself) + if (_vm->_mouse->rButtonPressed()) { // Delete title text title->setText(""); - _vm->_mouse->cursorOff(); _vm->_mouse->rButtonSet(false); - if (!obj->_imUse) { - if (obj->_useDir == 0) { - walkHero(x, y); - } else { - walkHero(obj->_useX, obj->_useY); + if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { + _vm->_mouse->cursorOff(); + + if (!obj->_imUse) { + if (obj->_useDir == 0) { + walkHero(x, y); + } else { + walkHero(obj->_useX, obj->_useY); + } } - } - _vm->_script->run(obj->_program, obj->_use); - _vm->_mouse->cursorOn(); + _vm->_script->run(obj->_program, obj->_use); + _vm->_mouse->cursorOn(); + } else { + walkHero(x, y); + } } } } else { -- cgit v1.2.3 From 295ab7e6ff022ea1f460740dd75d107b3f2fe64c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 03:58:03 +0000 Subject: Added Mouse::loadItemCursor(). Removed hotspot FIXME as all cursors seem to use the same hotspot (the center of the sprite). svn-id: r43158 --- engines/draci/mouse.cpp | 14 ++++++++++++-- engines/draci/mouse.h | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 9f34003840..02510e15c5 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -88,12 +88,22 @@ void Mouse::setPosition(uint16 x, uint16 y) { _vm->_system->warpMouse(x, y); } -// FIXME: Handle hotspots properly void Mouse::setCursorType(CursorType cur) { _cursorType = cur; + + BAFile *f; + f = _vm->_iconsArchive->getFile(_cursorType); + + Sprite sp(f->_data, f->_length, 0, 0, true); + CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); + CursorMan.replaceCursor(sp.getBuffer(), sp.getWidth(), sp.getHeight(), + sp.getWidth() / 2, sp.getHeight() / 2); +} + +void Mouse::loadItemCursor(int itemID, bool highlighted) { BAFile *f; - f = _vm->_iconsArchive->getFile(_cursorType); + f = _vm->_itemImagesArchive->getFile(itemID + highlighted); Sprite sp(f->_data, f->_length, 0, 0, true); CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h index 07dc53311d..f3e0123f59 100644 --- a/engines/draci/mouse.h +++ b/engines/draci/mouse.h @@ -50,8 +50,9 @@ public: void cursorOff(); bool isCursorOn(); void setPosition(uint16 x, uint16 y); - void setCursorType(CursorType cur); CursorType getCursorType() { return _cursorType; } + void setCursorType(CursorType cur); + void loadItemCursor(int itemID, bool highlighted = false); bool lButtonPressed() { return _lButton; } bool rButtonPressed() { return _rButton; } void lButtonSet(bool state) { _lButton = state; } -- cgit v1.2.3 From e46abf16435031aaa7c717e9ca8de9cf50b141ca Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 03:59:39 +0000 Subject: Added Text::setFont(). svn-id: r43159 --- engines/draci/sprite.cpp | 7 +++++++ engines/draci/sprite.h | 1 + 2 files changed, 8 insertions(+) diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index ecbfaf2767..e37d40dd46 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -364,6 +364,13 @@ void Text::draw(Surface *surface, bool markDirty) const { Common::Rect Text::getRect(bool scaled) const { return Common::Rect(_x, _y, _x + _width, _y + _height); } + +void Text::setFont(Font *font) { + _font = font; + + _width = _font->getStringWidth(_text, _spacing); + _height = _font->getStringHeight(_text); +} } // End of namespace Draci diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index d2aa5ba3af..2fb668ba65 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -128,6 +128,7 @@ public: void setText(const Common::String &str); void setColour(byte fontColour); void setSpacing(uint spacing); + void setFont(Font *font); uint getLength(); -- cgit v1.2.3 From eeb72e3d0db18043d6ce050ebb1103ca907d640c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 04:09:24 +0000 Subject: * Implemented Game::loadWalkingMap(). * Extracted title updating from the main loop to a new method, Game::updateTitle(). * Added Game::updateCursor(). * Restructured the main loop to fix many subtle bugs and enable some new functionality concerning object scripts (like support for room-global use scripts). * Added support for tracking currently selected icons (items, probably should be renamed). * Changed walkDir, lookDir and useDir members of GameObject to int and adjusted them for zero-based indexing. * Added Game::getCurrentIcon(). * Return from WalkingMap::findNearestWalkable immediately if the starting point is walkable. svn-id: r43160 --- engines/draci/game.cpp | 222 ++++++++++++++++++++++++++++++++++--------------- engines/draci/game.h | 25 +++++- 2 files changed, 178 insertions(+), 69 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3441ba7860..8020e29fdb 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -197,6 +197,10 @@ void Game::init() { _shouldQuit = false; _shouldExitLoop = false; + _currentIcon = kNoIcon; + + _vm->_mouse->setCursorType(kNormalCursor); + // HACK: Won't be needed once I've implemented the loop properly _roomChange = false; @@ -236,8 +240,6 @@ void Game::loop() { Surface *surface = _vm->_screen->getSurface(); - const int smallFontHeight = _vm->_smallFont->getFontHeight(); - do { _vm->handleEvents(); @@ -248,45 +250,37 @@ void Game::loop() { int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); - // Find the game object under the cursor - // (to be more precise, one that corresponds to the animation under the cursor) - int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - int curObject = getObjectWithAnimation(animUnderCursor); - GameObject *obj = &_objects[curObject]; - // Fetch the dedicated objects' title animation / current frame Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); Text *title = reinterpret_cast(titleAnim->getFrame()); - if (_loopStatus == kStatusOrdinary) { - // If there is an object under the cursor, display its title and enable - // executing its look and use scripts - if (curObject != kObjectNotFound) { + if (_loopStatus == kStatusOrdinary && _loopSubstatus == kStatusOrdinary) { + if(_vm->_mouse->isCursorOn()) { + // Find the game object under the cursor + // (to be more precise, one that corresponds to the animation under the cursor) + int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + int curObject = getObjectWithAnimation(animUnderCursor); - if(_vm->_mouse->isCursorOn()) { - // Mark dirty rectangle to delete the previous text - titleAnim->markDirtyRect(surface); + updateTitle(); - // Set the title for the current object - title->setText(obj->_title); - - // Move the title to the correct place (just above the cursor) - int newX = surface->centerOnX(x, title->getWidth()); - int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); - titleAnim->setRelative(newX, newY); + _objUnderCursor = curObject; + if (_objUnderCursor != _oldObjUnderCursor) { + _oldObjUnderCursor = _objUnderCursor; + updateCursor(); } - if (_loopSubstatus == kStatusOrdinary) { + if (_vm->_mouse->lButtonPressed()) { + _vm->_mouse->lButtonSet(false); - if (_vm->_mouse->lButtonPressed()) { - // Delete title text + if (_objUnderCursor != kObjectNotFound) { + GameObject *obj = &_objects[_objUnderCursor]; + + _vm->_mouse->cursorOff(); + titleAnim->markDirtyRect(surface); title->setText(""); - _vm->_mouse->cursorOff(); - _vm->_mouse->lButtonSet(false); - if (!obj->_imLook) { - if (obj->_lookDir == 0) { + if (obj->_lookDir == -1) { walkHero(x, y); } else { walkHero(obj->_lookX, obj->_lookY); @@ -295,21 +289,24 @@ void Game::loop() { _vm->_script->run(obj->_program, obj->_look); _vm->_mouse->cursorOn(); + } else { + walkHero(x, y); } + } - // TODO: Handle global use scripts (the use script for the room itself) - - if (_vm->_mouse->rButtonPressed()) { - // Delete title text - title->setText(""); + if (_vm->_mouse->rButtonPressed()) { + _vm->_mouse->rButtonSet(false); - _vm->_mouse->rButtonSet(false); + if (_objUnderCursor != kObjectNotFound) { + GameObject *obj = &_objects[_objUnderCursor]; if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { _vm->_mouse->cursorOff(); + titleAnim->markDirtyRect(surface); + title->setText(""); if (!obj->_imUse) { - if (obj->_useDir == 0) { + if (obj->_useDir == -1) { walkHero(x, y); } else { walkHero(obj->_useX, obj->_useY); @@ -320,26 +317,23 @@ void Game::loop() { _vm->_mouse->cursorOn(); } else { walkHero(x, y); - } - } - } - } else { - // We haven't found an object under the cursor - - // Delete the previous title - titleAnim->markDirtyRect(surface); - title->setText(""); + } + } else { + if (_vm->_script->testExpression(_currentRoom._program, _currentRoom._canUse)) { + _vm->_mouse->cursorOff(); + titleAnim->markDirtyRect(surface); + title->setText(""); - // If we are in the appropriate loop status and the player clicked - // on the room, move the dragon to the nearest walkable point - if (_vm->_mouse->lButtonPressed() && - _loopSubstatus == kStatusOrdinary) { - walkHero(x, y); + _vm->_script->run(_currentRoom._program, _currentRoom._use); + _vm->_mouse->cursorOn(); + } else { + walkHero(x, y); + } + } } + debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } - - debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } } @@ -371,7 +365,9 @@ void Game::loop() { return; // Advance animations and redraw screen - _vm->_anims->drawScene(_vm->_screen->getSurface()); + if (_loopStatus != kStatusInventory) { + _vm->_anims->drawScene(surface); + } _vm->_screen->copyToScreen(); _vm->_system->delayMillis(20); @@ -381,6 +377,75 @@ void Game::loop() { } while (!shouldExitLoop()); } +void Game::updateCursor() { + + _vm->_mouse->setCursorType(kNormalCursor); + + if (_currentIcon != kNoIcon) { + _vm->_mouse->loadItemCursor(_currentIcon); + } + + if (_objUnderCursor == kObjectNotFound) { + + if (_vm->_script->testExpression(_currentRoom._program, _currentRoom._canUse)) { + if (_currentIcon == kNoIcon) { + _vm->_mouse->setCursorType(kHighlightedCursor); + } else { + _vm->_mouse->loadItemCursor(_currentIcon, true); + } + } + } else { + GameObject *obj = &_objects[_objUnderCursor]; + + _vm->_mouse->setCursorType((CursorType)obj->_walkDir); + + if (!(obj->_walkDir > 0)) { + if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { + if (_currentIcon == kNoIcon) { + _vm->_mouse->setCursorType(kHighlightedCursor); + } else { + _vm->_mouse->loadItemCursor(_currentIcon, true); + } + } + } + } +} + +void Game::updateTitle() { + + Surface *surface = _vm->_screen->getSurface(); + const int smallFontHeight = _vm->_smallFont->getFontHeight(); + + // Fetch mouse coordinates + int x = _vm->_mouse->getPosX(); + int y = _vm->_mouse->getPosY(); + + // Fetch the dedicated objects' title animation / current frame + Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); + Text *title = reinterpret_cast(titleAnim->getFrame()); + + // Mark dirty rectangle to delete the previous text + titleAnim->markDirtyRect(surface); + + if (_objUnderCursor == kObjectNotFound) { + title->setText(""); + } else { + GameObject *obj = &_objects[_objUnderCursor]; + title->setText(obj->_title); + } + + // Move the title to the correct place (just above the cursor) + int newX = surface->centerOnX(x, title->getWidth()); + int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); + titleAnim->setRelative(newX, newY); + + if (titleAnim->isPlaying()) { + titleAnim->markDirtyRect(surface); + } else { + _vm->_anims->play(titleAnim->getID()); + } +} + int Game::getObjectWithAnimation(int animID) { for (uint i = 0; i < _info._numObjects; ++i) { GameObject *obj = &_objects[i]; @@ -398,11 +463,14 @@ int Game::getObjectWithAnimation(int animID) { void Game::walkHero(int x, int y) { Surface *surface = _vm->_screen->getSurface(); + Common::Point p = _currentRoom._walkingMap.findNearestWalkable(x, y, surface->getRect()); x = p.x; y = p.y; + debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); + // Fetch dragon's animation ID // FIXME: Need to add proper walking (this only warps the dragon to position) int animID = getObject(kDragonObject)->_anims[0]; @@ -426,19 +494,18 @@ void Game::walkHero(int x, int y) { _persons[kDragonObject]._x = x + (lround(scaleX) * width) / 2; _persons[kDragonObject]._y = y - lround(scaleY) * height; + // Set the per-animation scaling factor + anim->setScaleFactors(scaleX, scaleY); + // We naturally want the dragon to position its feet to the location of the // click but sprites are drawn from their top-left corner so we subtract // the current height of the dragon's sprite y -= (int)(scaleY * height); + //x -= (int)(scaleX * width) / 2; anim->setRelative(x, y); - // Set the per-animation scaling factor - anim->setScaleFactors(scaleX, scaleY); - // Play the animation _vm->_anims->play(animID); - - debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); } void Game::loadRoom(int roomNum) { @@ -453,9 +520,8 @@ void Game::loadRoom(int roomNum) { _currentRoom._music = roomReader.readByte(); - int mapIdx = roomReader.readByte() - 1; - f = _vm->_walkingMapsArchive->getFile(mapIdx); - _currentRoom._walkingMap.load(f->_data, f->_length); + int mapID = roomReader.readByte() - 1; + loadWalkingMap(mapID); _currentRoom._palette = roomReader.readByte() - 1; _currentRoom._numOverlays = roomReader.readSint16LE(); @@ -488,7 +554,7 @@ void Game::loadRoom(int roomNum) { _currentRoom._numGates = roomReader.readByte(); debugC(4, kDraciLogicDebugLevel, "Music: %d", _currentRoom._music); - debugC(4, kDraciLogicDebugLevel, "Map: %d", mapIdx); + debugC(4, kDraciLogicDebugLevel, "Map: %d", mapID); debugC(4, kDraciLogicDebugLevel, "Palette: %d", _currentRoom._palette); debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _currentRoom._numOverlays); debugC(4, kDraciLogicDebugLevel, "Init: %d", _currentRoom._init); @@ -558,8 +624,6 @@ void Game::loadRoom(int roomNum) { _vm->_mouse->cursorOff(); } - _vm->_mouse->setCursorType(kNormalCursor); - // HACK: Create a visible overlay from the walking map so we can test it byte *wlk = new byte[kScreenWidth * kScreenHeight]; memset(wlk, 255, kScreenWidth * kScreenHeight); @@ -651,7 +715,7 @@ void Game::loadObject(uint objNum) { obj->_imInit = objReader.readByte(); obj->_imLook = objReader.readByte(); obj->_imUse = objReader.readByte(); - obj->_walkDir = objReader.readByte(); + obj->_walkDir = objReader.readByte() - 1; obj->_z = objReader.readByte(); objReader.readUint16LE(); // idxSeq field, not used objReader.readUint16LE(); // numSeq field, not used @@ -659,8 +723,8 @@ void Game::loadObject(uint objNum) { obj->_lookY = objReader.readUint16LE(); obj->_useX = objReader.readUint16LE(); obj->_useY = objReader.readUint16LE(); - obj->_lookDir = objReader.readByte(); - obj->_useDir = objReader.readByte(); + obj->_lookDir = objReader.readByte() - 1; + obj->_useDir = objReader.readByte() - 1; obj->_absNum = objNum; @@ -676,6 +740,13 @@ void Game::loadObject(uint objNum) { obj->_program._length = file->_length; } +void Game::loadWalkingMap(int mapID) { + + BAFile *f; + f = _vm->_walkingMapsArchive->getFile(mapID); + _currentRoom._walkingMap.load(f->_data, f->_length); +} + GameObject *Game::getObject(uint objNum) { return _objects + objNum; } @@ -829,6 +900,10 @@ int Game::getIconStatus(int iconID) { return _iconStatus[iconID]; } +int Game::getCurrentIcon() { + return _currentIcon; +} + Person *Game::getPerson(int personID) { return &_persons[personID]; } @@ -894,6 +969,12 @@ bool WalkingMap::isWalkable(int x, int y) { */ Common::Point WalkingMap::findNearestWalkable(int startX, int startY, Common::Rect searchRect) { + // If the starting point is walkable, just return that + if (searchRect.contains(startX, startY) && isWalkable(startX, startY)) { + return Common::Point(startX, startY); + } + + int signs[] = { 1, -1 }; const uint kSignsNum = 2; @@ -945,6 +1026,13 @@ Common::Point WalkingMap::findNearestWalkable(int startX, int startY, Common::Re } } + if (x == y) { + // If the starting point is walkable, just return that + if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { + return Common::Point(finalX, finalY); + } + } + for (uint i = 0; i < kSignsNum; ++i) { finalY = startY + x * signs[i]; diff --git a/engines/draci/game.h b/engines/draci/game.h index 7d0f8349f5..47b940ce7e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -56,6 +56,18 @@ enum { kNoEscRoom = -1 }; +// Used as a value to Game::_currentIcon and means there is no icon (game item) selected +// and a "real" cursor image is used +enum { + kNoIcon = -1 +}; + +// Used as a default parameter in Game::loadWalkingMap() to specify that the default +// walking map to the room is to be loaded. +enum { + kDefaultRoomMap = -1 +}; + enum SpeechConstants { kBaseSpeechDuration = 200, kSpeechTimeUnit = 400 @@ -103,10 +115,10 @@ struct GameObject { uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; - byte _walkDir; + int _walkDir; byte _z; uint _lookX, _lookY, _useX, _useY; - byte _lookDir, _useDir; + int _lookDir, _useDir; uint _absNum; Common::Array _anims; GPL2Program _program; @@ -211,6 +223,7 @@ public: int loadAnimation(uint animNum, uint z); void loadOverlays(); void loadObject(uint numObj); + void loadWalkingMap(int mapID = kDefaultRoomMap); uint getNumObjects(); GameObject *getObject(uint objNum); @@ -228,6 +241,7 @@ public: void setGateNum(int gate); int getIconStatus(int iconID); + int getCurrentIcon(); int getEscRoom(); @@ -249,6 +263,9 @@ public: void setSpeechTick(uint tick); + void updateTitle(); + void updateCursor(); + bool _roomChange; private: @@ -267,6 +284,8 @@ private: int _newRoom; int _newGate; + int _currentIcon; + LoopStatus _loopStatus; LoopStatus _loopSubstatus; @@ -276,6 +295,8 @@ private: uint _speechTick; int _objUnderCursor; + int _oldObjUnderCursor; + int _markedAnimationIndex; //!< Used by the Mark GPL command }; -- cgit v1.2.3 From f68ceeb88cb839f7205a0ba401b8ee329a439122 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 04:12:36 +0000 Subject: * Implemented GPL functions Script::funcActIco() and Script::funcIsIcoAct(). * Implemented GPL commands Script::loadMap() and Script::roomMap(). * Added temporary HACK to change some speech texts to use the small font because some strings overflow the screen (as stored in the data files). svn-id: r43161 --- engines/draci/script.cpp | 44 ++++++++++++++++++++++++++++++++++++++++---- engines/draci/script.h | 4 ++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index a997fa4e55..872b10a3cb 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -81,8 +81,8 @@ void Script::setupCommandList() { { 19, 1, "Mark", 0, { 0 }, &Script::mark }, { 19, 2, "Release", 0, { 0 }, &Script::release }, { 20, 1, "Play", 0, { 0 }, &Script::play }, - { 21, 1, "LoadMap", 1, { 2 }, NULL }, - { 21, 2, "RoomMap", 0, { 0 }, NULL }, + { 21, 1, "LoadMap", 1, { 2 }, &Script::loadMap }, + { 21, 2, "RoomMap", 0, { 0 }, &Script::roomMap }, { 22, 1, "DisableQuickHero", 0, { 0 }, NULL }, { 22, 2, "EnableQuickHero", 0, { 0 }, NULL }, { 23, 1, "DisableSpeedText", 0, { 0 }, NULL }, @@ -119,9 +119,9 @@ void Script::setupCommandList() { { "Not", &Script::funcNot }, { "Random", &Script::funcRandom }, { "IsIcoOn", &Script::funcIsIcoOn }, - { "IsIcoAct", NULL }, + { "IsIcoAct", &Script::funcIsIcoAct }, { "IcoStat", &Script::funcIcoStat }, - { "ActIco", NULL }, + { "ActIco", &Script::funcActIco }, { "IsObjOn", &Script::funcIsObjOn }, { "IsObjOff", &Script::funcIsObjOff }, { "IsObjAway", &Script::funcIsObjAway }, @@ -235,6 +235,22 @@ int Script::funcIcoStat(int iconID) { return (status == 1) ? 1 : 2; } +int Script::funcIsIcoAct(int iconID) { + iconID -= 1; + + return _vm->_game->getCurrentIcon() == iconID; +} + +int Script::funcActIco(int iconID) { + + // The parameter seems to be an omission in the original player since it's not + // used in the implementation of the function. It's possible that the functions were + // implemented in such a way that they had to have a single parameter so this is only + // passed as a dummy. + + return _vm->_game->getCurrentIcon(); +} + int Script::funcIsObjOn(int objID) { objID -= 1; @@ -555,6 +571,14 @@ void Script::talk(Common::Queue ¶ms) { speechFrame->setText(Common::String((const char *)f->_data+1, f->_length-1)); speechFrame->setColour(person->_fontColour); + // HACK: Some strings in the English data files are too long to fit the screen + // This is a temporary resolution. + if (speechFrame->getWidth() >= kScreenWidth) { + speechFrame->setFont(_vm->_smallFont); + } else { + speechFrame->setFont(_vm->_bigFont); + } + // Set the loop substatus to an appropriate value _vm->_game->setLoopSubstatus(kStatusTalk); @@ -583,6 +607,18 @@ void Script::talk(Common::Queue ¶ms) { _vm->_game->setExitLoop(false); } +void Script::loadMap(Common::Queue ¶ms) { + int mapID = params.pop() - 1; + + _vm->_game->loadWalkingMap(mapID); +} + +void Script::roomMap(Common::Queue ¶ms) { + + // Load the default walking map for the room + _vm->_game->loadWalkingMap(); +} + void Script::endCurrentProgram() { _endProgram = true; } diff --git a/engines/draci/script.h b/engines/draci/script.h index 38871a05f9..f6df7ecee5 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -119,6 +119,8 @@ private: void startPlay(Common::Queue ¶ms); void newRoom(Common::Queue ¶ms); void talk(Common::Queue ¶ms); + void loadMap(Common::Queue ¶ms); + void roomMap(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); @@ -139,6 +141,8 @@ private: int funcNot(int n); int funcIsIcoOn(int iconID); int funcIcoStat(int iconID); + int funcActIco(int iconID); + int funcIsIcoAct(int iconID); int funcIsObjOn(int objID); int funcIsObjOff(int objID); int funcIsObjAway(int objID); -- cgit v1.2.3 From abedc7e9bb44a13ebf62e0cb37d8e317afc27e28 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 04:24:52 +0000 Subject: Moved cursor state setting (when entering a new room) from Game::loadRoom() to Game::start() (just after running the gate program). This fixes a black cursor bug when the game starts (the cursor should not be even displayed then). svn-id: r43162 --- engines/draci/game.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 8020e29fdb..6c3ee96e98 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -183,6 +183,16 @@ void Game::start() { // Run the program for the gate the dragon came through runGateProgram(_newGate); + + // Set cursor state + // Need to do this after we set the palette since the cursors use it + if (_currentRoom._mouseOn) { + debugC(6, kDraciLogicDebugLevel, "Mouse: ON"); + _vm->_mouse->cursorOn(); + } else { + debugC(6, kDraciLogicDebugLevel, "Mouse: OFF"); + _vm->_mouse->cursorOff(); + } } // Mimic the original engine by setting the loop status to Ordinary before @@ -614,16 +624,6 @@ void Game::loadRoom(int roomNum) { f = _vm->_paletteArchive->getFile(_currentRoom._palette); _vm->_screen->setPalette(f->_data, 0, kNumColours); - // Set cursor state - // Need to do this after we set the palette since the cursors use it - if (_currentRoom._mouseOn) { - debugC(6, kDraciLogicDebugLevel, "Mouse: ON"); - _vm->_mouse->cursorOn(); - } else { - debugC(6, kDraciLogicDebugLevel, "Mouse: OFF"); - _vm->_mouse->cursorOff(); - } - // HACK: Create a visible overlay from the walking map so we can test it byte *wlk = new byte[kScreenWidth * kScreenHeight]; memset(wlk, 255, kScreenWidth * kScreenHeight); -- cgit v1.2.3 From b9a9a5ef8801f83886a6249f4ad24122cfe0569d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 16:58:04 +0000 Subject: Implemented GPL function Script::funcObjStat(). svn-id: r43176 --- engines/draci/script.cpp | 18 +++++++++++++++++- engines/draci/script.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 872b10a3cb..af64204f42 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -125,7 +125,7 @@ void Script::setupCommandList() { { "IsObjOn", &Script::funcIsObjOn }, { "IsObjOff", &Script::funcIsObjOff }, { "IsObjAway", &Script::funcIsObjAway }, - { "ObjStat", NULL }, + { "ObjStat", &Script::funcObjStat }, { "LastBlock", NULL }, { "AtBegin", NULL }, { "BlockVar", NULL }, @@ -269,6 +269,22 @@ int Script::funcIsObjOff(int objID) { return !obj->_visible && obj->_location != -1; } +int Script::funcObjStat(int objID) { + objID -= 1; + + GameObject *obj = _vm->_game->getObject(objID); + + if (obj->_location == _vm->_game->getRoomNum()) { + if (obj->_visible) { + return 1; // object is ON (in the room and visible) + } else { + return 2; // object is OFF (in the room, not visible) + } + } else { + return 3; // object is AWAY (not in the room) + } +} + int Script::funcIsObjAway(int objID) { objID -= 1; diff --git a/engines/draci/script.h b/engines/draci/script.h index f6df7ecee5..6c85a7cc5b 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -147,6 +147,7 @@ private: int funcIsObjOff(int objID); int funcIsObjAway(int objID); int funcActPhase(int objID); + int funcObjStat(int objID); void setupCommandList(); -- cgit v1.2.3 From d59d03e52f7a75d8af55f7e0af09c0200321e52e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 9 Aug 2009 20:33:58 +0000 Subject: Multiply itemID by two before using it as an index into the item image archive because every item has a highlighted and a non-highlighted version. svn-id: r43185 --- engines/draci/mouse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index 02510e15c5..dc10efbab8 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -103,7 +103,7 @@ void Mouse::setCursorType(CursorType cur) { void Mouse::loadItemCursor(int itemID, bool highlighted) { BAFile *f; - f = _vm->_itemImagesArchive->getFile(itemID + highlighted); + f = _vm->_itemImagesArchive->getFile(2 * itemID + highlighted); Sprite sp(f->_data, f->_length, 0, 0, true); CursorMan.replaceCursorPalette(_vm->_screen->getPalette(), 0, kNumColours); -- cgit v1.2.3 From 51cc821619bda77881f7514757aedb94bfb9070b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 11 Aug 2009 04:03:22 +0000 Subject: Added dialogue support. svn-id: r43253 --- engines/draci/draci.cpp | 1 + engines/draci/font.h | 3 +- engines/draci/game.cpp | 258 +++++++++++++++++++++++++++++++++++++++++++---- engines/draci/game.h | 41 +++++++- engines/draci/mouse.h | 2 +- engines/draci/script.cpp | 78 +++++++++++--- engines/draci/script.h | 11 +- 7 files changed, 356 insertions(+), 38 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index 4060b678ad..a09f5488a9 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -211,6 +211,7 @@ bool DraciEngine::handleEvents() { _game->setRoomNum(_game->getEscRoom()); _game->setGateNum(0); _game->_roomChange = true; + _game->setExitLoop(true); // End any currently running GPL programs _script->endCurrentProgram(); diff --git a/engines/draci/font.h b/engines/draci/font.h index e566a5ad54..e81b344af1 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -42,7 +42,8 @@ extern const Common::String kFontBig; enum { kFontColour1 = 2, kFontColour2 = 0, kFontColour3 = 3, kFontColour4 = 4, - kOverFontColour = 255, kTitleColour = 255 + kOverFontColour = 255, kTitleColour = 255, + kLineActiveColour = 254, kLineInactiveColour = 255 }; /** diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 6c3ee96e98..2b861c46f8 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -35,6 +35,8 @@ namespace Draci { +const Common::String dialoguePath("ROZH"); + static double real_to_double(byte real[6]); Game::Game(DraciEngine *vm) : _vm(vm) { @@ -61,21 +63,24 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Close persons file file->close(); - // Read in dialog offsets + // Read in dialogue offsets file = initArchive->getFile(4); - Common::MemoryReadStream dialogData(file->_data, file->_length); + Common::MemoryReadStream dialogueData(file->_data, file->_length); - unsigned int numDialogs = file->_length / sizeof(uint16); - _dialogOffsets = new uint[numDialogs]; + unsigned int numDialogues = file->_length / sizeof(uint16); + _dialogueOffsets = new uint[numDialogues]; unsigned int curOffset; - for (i = 0, curOffset = 0; i < numDialogs; ++i) { - _dialogOffsets[i] = curOffset; - curOffset += dialogData.readUint16LE(); + for (i = 0, curOffset = 0; i < numDialogues; ++i) { + _dialogueOffsets[i] = curOffset; + curOffset += dialogueData.readUint16LE(); } - // Close dialogs file + _dialogueVars = new int[curOffset]; + memset(_dialogueVars, 0, sizeof (int) * curOffset); + + // Close dialogues file file->close(); // Read in game info @@ -89,7 +94,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info._numIcons = gameData.readUint16LE(); _info._numVariables = gameData.readByte(); _info._numPersons = gameData.readByte(); - _info._numDialogs = gameData.readByte(); + _info._numDialogues = gameData.readByte(); _info._maxIconWidth = gameData.readUint16LE(); _info._maxIconHeight = gameData.readUint16LE(); _info._musicLength = gameData.readUint16LE(); @@ -98,7 +103,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info._crc[2] = gameData.readUint16LE(); _info._crc[3] = gameData.readUint16LE(); - _info._numDialogBlocks = curOffset; + _info._numDialogueBlocks = curOffset; // Close game info file file->close(); @@ -145,7 +150,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Close object status file file->close(); - assert(numDialogs == _info._numDialogs); + assert(numDialogues == _info._numDialogues); assert(numPersons == _info._numPersons); assert(numVariables == _info._numVariables); assert(numObjects == _info._numObjects); @@ -227,6 +232,19 @@ void Game::init() { Text *speech = new Text("", _vm->_bigFont, kFontColour1, 0, 0); speechAnim->addFrame(speech); + for (uint i = 0; i < kDialogueLines; ++i) { + _dialogueAnims[i] = _vm->_anims->addText(-10 - i, true); + Text *dialogueLine0 = new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0); + _dialogueAnims[i]->addFrame(dialogueLine0); + + _dialogueAnims[i]->setZ(254); + _dialogueAnims[i]->setRelative(1, + kScreenHeight - (i + 1) * _vm->_smallFont->getFontHeight()); + + Text *text = reinterpret_cast(_dialogueAnims[i]->getFrame()); + text->setText(""); + } + loadObject(kDragonObject); GameObject *dragon = getObject(kDragonObject); @@ -254,11 +272,23 @@ void Game::loop() { _vm->handleEvents(); - if (_currentRoom._mouseOn) { + // Fetch mouse coordinates + int x = _vm->_mouse->getPosX(); + int y = _vm->_mouse->getPosY(); - // Fetch mouse coordinates - int x = _vm->_mouse->getPosX(); - int y = _vm->_mouse->getPosY(); + if (_loopStatus == kStatusDialogue && _loopSubstatus == kStatusOrdinary) { + + // Find animation under cursor + _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + + if (_vm->_mouse->lButtonPressed() || _vm->_mouse->rButtonPressed()) { + _shouldExitLoop = true; + _vm->_mouse->lButtonSet(false); + _vm->_mouse->rButtonSet(false); + } + } + + if (_currentRoom._mouseOn) { // Fetch the dedicated objects' title animation / current frame Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); @@ -268,8 +298,8 @@ void Game::loop() { if(_vm->_mouse->isCursorOn()) { // Find the game object under the cursor // (to be more precise, one that corresponds to the animation under the cursor) - int animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - int curObject = getObjectWithAnimation(animUnderCursor); + _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + int curObject = getObjectWithAnimation(_animUnderCursor); updateTitle(); @@ -342,11 +372,12 @@ void Game::loop() { } } } - debugC(2, kDraciAnimationDebugLevel, "Anim under cursor: %d", animUnderCursor); } } } + debug(8, "Anim under cursor: %d", _animUnderCursor); + // Handle character talking (if there is any) if (_loopSubstatus == kStatusTalk) { Animation *speechAnim = _vm->_anims->getAnimation(kSpeechText); @@ -382,7 +413,8 @@ void Game::loop() { _vm->_system->delayMillis(20); // HACK: Won't be needed once the game loop is implemented properly - _shouldExitLoop = _shouldExitLoop || _roomChange; + _shouldExitLoop = _shouldExitLoop || (_roomChange && + (_loopStatus == kStatusOrdinary || _loopStatus == kStatusGate)); } while (!shouldExitLoop()); } @@ -469,7 +501,193 @@ int Game::getObjectWithAnimation(int animID) { return kObjectNotFound; } + +void Game::dialogueMenu(int dialogueID) { + + int oldLines, hit; + + char tmp[5]; + sprintf(tmp, "%d", dialogueID+1); + Common::String ext(tmp); + _dialogueArchive = new BArchive(dialoguePath + ext + ".dfw"); + + debugC(4, kDraciLogicDebugLevel, "Starting dialogue (ID: %d, Archive: %s)", + dialogueID, (dialoguePath + ext + ".dfw").c_str()); + + _currentDialogue = dialogueID; + oldLines = 255; + dialogueInit(dialogueID); + + do { + _dialogueExit = false; + hit = dialogueDraw(); + + debug(2, "Hit: %d, _lines[hit]: %d", hit, _lines[hit]); + + if ((!_dialogueExit) && (hit != -1) && (_lines[hit] != -1)) { + if ((oldLines == 1) && (_dialogueLines == 1) && (_lines[hit] == _lastBlock)) { + break; + } + _currentBlock = _lines[hit]; + runDialogueProg(_dialogueBlocks[_lines[hit]]._program, 1); + } else { + break; + } + _lastBlock = _lines[hit]; + _dialogueVars[_dialogueOffsets[dialogueID] + _lastBlock + 1] += 1; + _dialogueBegin = false; + oldLines = _dialogueLines; + + } while(!_dialogueExit); + + dialogueDone(); + _currentDialogue = kNoDialogue; +} + +int Game::dialogueDraw() { + _dialogueLines = 0; + int i = 0; + int ret = 0; + Animation *anim; + Text *dialogueLine; + + while ((_dialogueLines < 4) && (i < _blockNum)) { + + GPL2Program blockTest; + blockTest._bytecode = _dialogueBlocks[i]._canBlock; + blockTest._length = _dialogueBlocks[i]._canLen; + + debugC(3, kDraciLogicDebugLevel, "Testing dialogue block %d", i); + if (_vm->_script->testExpression(blockTest, 1)) { + anim = _dialogueAnims[_dialogueLines]; + dialogueLine = reinterpret_cast(anim->getFrame()); + dialogueLine->setText(_dialogueBlocks[i]._title); + + dialogueLine->setColour(kLineInactiveColour); + _lines[_dialogueLines] = i; + _dialogueLines++; + } + ++i; + } + + for (i = _dialogueLines; i < kDialogueLines; ++i) { + _lines[i] = 0; + anim = _dialogueAnims[i]; + dialogueLine = reinterpret_cast(anim->getFrame()); + dialogueLine->setText(""); + } + + _oldObjUnderCursor = kObjectNotFound; + + if (_dialogueLines > 1) { + _vm->_mouse->cursorOn(); + _shouldExitLoop = false; + loop(); + _vm->_mouse->cursorOff(); + + bool notDialogueAnim = true; + for (uint j = 0; j < kDialogueLines; ++j) { + if (_dialogueAnims[j]->getID() == _animUnderCursor) { + notDialogueAnim = false; + break; + } + } + + if (notDialogueAnim) { + ret = -1; + } else { + ret = _dialogueAnims[0]->getID() - _animUnderCursor; + } + } else { + ret = _dialogueLines - 1; + } + + for (i = 0; i < kDialogueLines; ++i) { + dialogueLine = reinterpret_cast(_dialogueAnims[i]->getFrame()); + _dialogueAnims[i]->markDirtyRect(_vm->_screen->getSurface()); + dialogueLine->setText(""); + } + + return ret; +} + +void Game::dialogueInit(int dialogID) { + _vm->_mouse->setCursorType(kDialogueCursor); + + _blockNum = _dialogueArchive->size() / 3; + _dialogueBlocks = new Dialogue[_blockNum]; + + BAFile *f; + + for (uint i = 0; i < kDialogueLines; ++i) { + _lines[i] = 0; + } + + for (int i = 0; i < _blockNum; ++i) { + f = _dialogueArchive->getFile(i * 3); + _dialogueBlocks[i]._canLen = f->_length; + _dialogueBlocks[i]._canBlock = f->_data; + + f = _dialogueArchive->getFile(i * 3 + 1); + + // The first byte of the file is the length of the string (without the length) + assert(f->_length - 1 == f->_data[0]); + + _dialogueBlocks[i]._title = Common::String((char *)(f->_data+1), f->_length-1); + + f = _dialogueArchive->getFile(i * 3 + 2); + _dialogueBlocks[i]._program._bytecode = f->_data; + _dialogueBlocks[i]._program._length = f->_length; + } + + for (uint i = 0; i < kDialogueLines; ++i) { + _vm->_anims->play(_dialogueAnims[i]->getID()); + } + + _loopStatus = kStatusDialogue; + _lastBlock = 0; + _dialogueBegin = true; +} + +void Game::dialogueDone() { + for (uint i = 0; i < kDialogueLines; ++i) { + _vm->_anims->stop(_dialogueAnims[i]->getID()); + } + + _dialogueArchive->closeArchive(); + + delete[] _dialogueBlocks; + + _loopStatus = kStatusOrdinary; + _vm->_mouse->setCursorType(kNormalCursor); +} + +void Game::runDialogueProg(GPL2Program prog, int offset) { + + // Mark last animation + int lastAnimIndex = _vm->_anims->getLastIndex(); + + // Run gate program + _vm->_script->run(prog, offset); + + // Delete all animations loaded after the marked one + // (from objects and from the AnimationManager) + for (uint i = 0; i < getNumObjects(); ++i) { + GameObject *obj = &_objects[i]; + + for (uint j = 0; j < obj->_anims.size(); ++j) { + Animation *anim; + + anim = _vm->_anims->getAnimation(obj->_anims[j]); + if (anim != NULL && anim->getIndex() > lastAnimIndex) + obj->_anims.remove_at(j); + } + } + + _vm->_anims->deleteAfterIndex(lastAnimIndex); +} + void Game::walkHero(int x, int y) { Surface *surface = _vm->_screen->getSurface(); @@ -937,7 +1155,7 @@ void Game::setMarkedAnimationIndex(int index) { Game::~Game() { delete[] _persons; delete[] _variables; - delete[] _dialogOffsets; + delete[] _dialogueOffsets; delete[] _objects; } diff --git a/engines/draci/game.h b/engines/draci/game.h index 47b940ce7e..a712542e9e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -27,6 +27,7 @@ #define DRACI_GAME_H #include "common/str.h" +#include "draci/barchive.h" #include "draci/script.h" #include "draci/animation.h" #include "draci/sprite.h" @@ -68,6 +69,10 @@ enum { kDefaultRoomMap = -1 }; +enum { + kNoDialogue = -1, kDialogueLines = 4 +}; + enum SpeechConstants { kBaseSpeechDuration = 200, kSpeechTimeUnit = 400 @@ -134,11 +139,11 @@ struct GameInfo { uint _numIcons; byte _numVariables; byte _numPersons; - byte _numDialogs; + byte _numDialogues; uint _maxIconWidth, _maxIconHeight; uint _musicLength; uint _crc[4]; - uint _numDialogBlocks; + uint _numDialogueBlocks; }; struct Person { @@ -146,6 +151,14 @@ struct Person { byte _fontColour; }; +struct Dialogue { + int _canLen; + byte *_canBlock; + Common::String _title; + GPL2Program _program; +}; + + struct Room { int _roomNum; byte _music; @@ -266,13 +279,18 @@ public: void updateTitle(); void updateCursor(); + void dialogueMenu(int dialogueID); + int dialogueDraw(); + void dialogueInit(int dialogID); + void dialogueDone(); + void runDialogueProg(GPL2Program, int offset); + bool _roomChange; private: DraciEngine *_vm; GameInfo _info; - uint *_dialogOffsets; int *_variables; byte *_iconStatus; @@ -286,6 +304,22 @@ private: int _currentIcon; +// HACK: remove public when tested and add getters instead +public: + uint *_dialogueOffsets; + int _currentDialogue; + int *_dialogueVars; + BArchive *_dialogueArchive; + Dialogue *_dialogueBlocks; + bool _dialogueBegin; + bool _dialogueExit; + int _currentBlock; + int _lastBlock; + int _dialogueLines; + int _blockNum; + int _lines[4]; + Animation *_dialogueAnims[4]; + LoopStatus _loopStatus; LoopStatus _loopSubstatus; @@ -296,6 +330,7 @@ private: int _objUnderCursor; int _oldObjUnderCursor; + int _animUnderCursor; int _markedAnimationIndex; //!< Used by the Mark GPL command }; diff --git a/engines/draci/mouse.h b/engines/draci/mouse.h index f3e0123f59..d6df7f312d 100644 --- a/engines/draci/mouse.h +++ b/engines/draci/mouse.h @@ -34,7 +34,7 @@ namespace Draci { enum CursorType { kNormalCursor, kArrowCursor1, kArrowCursor2, kArrowCursor3, - kArrowCursor4, kDialogCursor, + kArrowCursor4, kDialogueCursor, kHighlightedCursor, kMainMenuCursor }; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index af64204f42..e7e4861e62 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -53,11 +53,11 @@ void Script::setupCommandList() { { 7, 1, "ObjStat", 2, { 3, 3 }, &Script::objStat }, { 7, 2, "ObjStat_On", 2, { 3, 3 }, &Script::objStatOn }, { 8, 1, "IcoStat", 2, { 3, 3 }, NULL }, - { 9, 1, "Dialogue", 1, { 2 }, NULL }, - { 9, 2, "ExitDialogue", 0, { 0 }, NULL }, - { 9, 3, "ResetDialogue", 0, { 0 }, NULL }, - { 9, 4, "ResetDialogueFrom", 0, { 0 }, NULL }, - { 9, 5, "ResetBlock", 1, { 3 }, NULL }, + { 9, 1, "Dialogue", 1, { 2 }, &Script::dialogue }, + { 9, 2, "ExitDialogue", 0, { 0 }, &Script::exitDialogue }, + { 9, 3, "ResetDialogue", 0, { 0 }, &Script::resetDialogue }, + { 9, 4, "ResetDialogueFrom", 0, { 0 }, &Script::resetDialogueFrom }, + { 9, 5, "ResetBlock", 1, { 3 }, &Script::resetBlock }, { 10, 1, "WalkOn", 3, { 1, 1, 3 }, &Script::walkOn }, { 10, 2, "StayOn", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation @@ -126,11 +126,11 @@ void Script::setupCommandList() { { "IsObjOff", &Script::funcIsObjOff }, { "IsObjAway", &Script::funcIsObjAway }, { "ObjStat", &Script::funcObjStat }, - { "LastBlock", NULL }, - { "AtBegin", NULL }, - { "BlockVar", NULL }, - { "HasBeen", NULL }, - { "MaxLine", NULL }, + { "LastBlock", &Script::funcLastBlock }, + { "AtBegin", &Script::funcAtBegin }, + { "BlockVar", &Script::funcBlockVar }, + { "HasBeen", &Script::funcHasBeen }, + { "MaxLine", &Script::funcMaxLine }, { "ActPhase", &Script::funcActPhase }, { "Cheat", NULL }, }; @@ -218,6 +218,27 @@ int Script::funcRandom(int n) { return _vm->_rnd.getRandomNumber(n); } +int Script::funcAtBegin(int yesno) { + return _vm->_game->_dialogueBegin == yesno; +} + +int Script::funcLastBlock(int blockID) { + + return _vm->_game->_lastBlock == blockID; +} + +int Script::funcBlockVar(int blockID) { + return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID]; +} + +int Script::funcHasBeen(int blockID) { + return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID] > 0; +} + +int Script::funcMaxLine(int lines) { + return _vm->_game->_dialogueLines < lines; +} + int Script::funcNot(int n) { return !n; } @@ -373,8 +394,11 @@ void Script::start(Common::Queue ¶ms) { return; } - int objID = params.pop() - 1; - int animID = params.pop() - 1; + int objID = params.pop(); + int animID = params.pop(); + + objID -= 1; + animID -= 1; GameObject *obj = _vm->_game->getObject(objID); @@ -623,12 +647,42 @@ void Script::talk(Common::Queue ¶ms) { _vm->_game->setExitLoop(false); } +void Script::dialogue(Common::Queue ¶ms) { + int dialogueID = params.pop() - 1; + + _vm->_game->dialogueMenu(dialogueID); +} + void Script::loadMap(Common::Queue ¶ms) { int mapID = params.pop() - 1; _vm->_game->loadWalkingMap(mapID); } +void Script::resetDialogue(Common::Queue ¶ms) { + + for (int i = 0; i < _vm->_game->_blockNum; ++i) { + _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+i] = 0; + } +} + +void Script::resetDialogueFrom(Common::Queue ¶ms) { + + for (int i = _vm->_game->_currentBlock; i < _vm->_game->_blockNum; ++i) { + _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+i] = 0; + } +} + +void Script::resetBlock(Common::Queue ¶ms) { + int blockID = params.pop(); + + _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+blockID] = 0; +} + +void Script::exitDialogue(Common::Queue ¶ms) { + _vm->_game->_dialogueExit = true; +} + void Script::roomMap(Common::Queue ¶ms) { // Load the default walking map for the room diff --git a/engines/draci/script.h b/engines/draci/script.h index 6c85a7cc5b..b1f9ed9bbd 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -121,6 +121,11 @@ private: void talk(Common::Queue ¶ms); void loadMap(Common::Queue ¶ms); void roomMap(Common::Queue ¶ms); + void dialogue(Common::Queue ¶ms); + void exitDialogue(Common::Queue ¶ms); + void resetDialogue(Common::Queue ¶ms); + void resetDialogueFrom(Common::Queue ¶ms); + void resetBlock(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); @@ -148,7 +153,11 @@ private: int funcIsObjAway(int objID); int funcActPhase(int objID); int funcObjStat(int objID); - + int funcLastBlock(int blockID); + int funcAtBegin(int yesno); + int funcBlockVar(int blockID); + int funcHasBeen(int blockID); + int funcMaxLine(int lines); void setupCommandList(); const GPL2Command *findCommand(byte num, byte subnum); -- cgit v1.2.3 From 0daad906859b29da86dfd5160a0a179da2487149 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 11 Aug 2009 04:14:38 +0000 Subject: Fix intro crash because of bug in the data files. svn-id: r43254 --- engines/draci/script.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index e7e4861e62..eefc90d9c0 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -397,6 +397,15 @@ void Script::start(Common::Queue ¶ms) { int objID = params.pop(); int animID = params.pop(); + // Fixes bug in the data files which makes the game crash in the intro + // TODO: This is possibly exclusive to the English version, so check for that + if (animID == 657) { + Common::Queue tmp; + tmp.push(objID); + tmp.push(animID); + this->load(tmp); + } + objID -= 1; animID -= 1; -- cgit v1.2.3 From ee7b9271a2ca245a8b18e44a7379fc70b2362e27 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 11 Aug 2009 04:18:14 +0000 Subject: Implemented GPL command WalkOnPlay. svn-id: r43255 --- engines/draci/script.cpp | 23 ++++++++++++++++++++++- engines/draci/script.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index eefc90d9c0..19b59dff48 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -60,7 +60,7 @@ void Script::setupCommandList() { { 9, 5, "ResetBlock", 1, { 3 }, &Script::resetBlock }, { 10, 1, "WalkOn", 3, { 1, 1, 3 }, &Script::walkOn }, { 10, 2, "StayOn", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation - { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation + { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, &Script::walkOnPlay }, { 11, 1, "LoadPalette", 1, { 2 }, NULL }, { 12, 1, "SetPalette", 0, { 0 }, NULL }, { 12, 2, "BlackPalette", 0, { 0 }, NULL }, @@ -582,6 +582,27 @@ void Script::walkOn(Common::Queue ¶ms) { _vm->_game->walkHero(x, y); } +void Script::walkOnPlay(Common::Queue ¶ms) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + return; + } + + int x = params.pop(); + int y = params.pop(); + params.pop(); // facing direction, not used yet + + // HACK: This should be an onDest action when hero walking is properly implemented + _vm->_game->setExitLoop(true); + + _vm->_game->walkHero(x, y); + + _vm->_game->setLoopStatus(kStatusStrange); + _vm->_game->loop(); + _vm->_game->setLoopStatus(kStatusOrdinary); + + _vm->_game->setExitLoop(false); +} + void Script::newRoom(Common::Queue ¶ms) { if (_vm->_game->getLoopStatus() == kStatusInventory) { diff --git a/engines/draci/script.h b/engines/draci/script.h index b1f9ed9bbd..5483bf4e6a 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -115,6 +115,7 @@ private: void execLook(Common::Queue ¶ms); void execUse(Common::Queue ¶ms); void walkOn(Common::Queue ¶ms); + void walkOnPlay(Common::Queue ¶ms); void play(Common::Queue ¶ms); void startPlay(Common::Queue ¶ms); void newRoom(Common::Queue ¶ms); -- cgit v1.2.3 From 9093e179cc3eab632de003321a3d0f14b28a6cdd Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Tue, 11 Aug 2009 04:53:30 +0000 Subject: Added dialogue selection colouring. svn-id: r43256 --- engines/draci/game.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 2b861c46f8..ef262ae7e8 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -212,6 +212,8 @@ void Game::init() { _shouldQuit = false; _shouldExitLoop = false; + _animUnderCursor = kOverlayImage; + _currentIcon = kNoIcon; _vm->_mouse->setCursorType(kNormalCursor); @@ -234,8 +236,8 @@ void Game::init() { for (uint i = 0; i < kDialogueLines; ++i) { _dialogueAnims[i] = _vm->_anims->addText(-10 - i, true); - Text *dialogueLine0 = new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0); - _dialogueAnims[i]->addFrame(dialogueLine0); + Text *dialogueLine = new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0); + _dialogueAnims[i]->addFrame(dialogueLine); _dialogueAnims[i]->setZ(254); _dialogueAnims[i]->setRelative(1, @@ -281,6 +283,16 @@ void Game::loop() { // Find animation under cursor _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + Text *text; + for (int i = 0; i < kDialogueLines; ++i) { + text = reinterpret_cast(_dialogueAnims[i]->getFrame()); + text->setColour(kLineInactiveColour); + + if (_animUnderCursor == _dialogueAnims[i]->getID()) { + text->setColour(kLineActiveColour); + } + } + if (_vm->_mouse->lButtonPressed() || _vm->_mouse->rButtonPressed()) { _shouldExitLoop = true; _vm->_mouse->lButtonSet(false); -- cgit v1.2.3 From 3b0895dd2fdfd9dcadfeac021f0b58546fc72c26 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 00:56:44 +0000 Subject: Added some debug info for loop statuses and dialogues. svn-id: r43295 --- engines/draci/game.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index ef262ae7e8..a1652ab732 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -270,6 +270,9 @@ void Game::loop() { Surface *surface = _vm->_screen->getSurface(); + debugC(6, kDraciLogicDebugLevel, "loopstatus: %d, loopsubstatus: %d", + _loopStatus, _loopSubstatus); + do { _vm->handleEvents(); @@ -534,7 +537,9 @@ void Game::dialogueMenu(int dialogueID) { _dialogueExit = false; hit = dialogueDraw(); - debug(2, "Hit: %d, _lines[hit]: %d", hit, _lines[hit]); + debug(7, kDraciLogicDebugLevel, + "hit: %d, _lines[hit]: %d, lastblock: %d, dialogueLines: %d, dialogueExit: %d", + hit, _lines[hit], _lastBlock, _dialogueLines, _dialogueExit); if ((!_dialogueExit) && (hit != -1) && (_lines[hit] != -1)) { if ((oldLines == 1) && (_dialogueLines == 1) && (_lines[hit] == _lastBlock)) { -- cgit v1.2.3 From 100603e683b51cf89545756b5ef81775dc57337f Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 01:03:54 +0000 Subject: Fixed Script::walkOnPlay() (was setting loop status whereas it was substatus that needed to be set). svn-id: r43297 --- engines/draci/script.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 19b59dff48..4dd5a826d7 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -596,9 +596,9 @@ void Script::walkOnPlay(Common::Queue ¶ms) { _vm->_game->walkHero(x, y); - _vm->_game->setLoopStatus(kStatusStrange); + _vm->_game->setLoopSubstatus(kStatusStrange); _vm->_game->loop(); - _vm->_game->setLoopStatus(kStatusOrdinary); + _vm->_game->setLoopSubstatus(kStatusOrdinary); _vm->_game->setExitLoop(false); } -- cgit v1.2.3 From 6693b22851dc7030922360e4275b73e2f9804cf0 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 04:18:45 +0000 Subject: * Split loop status and substatus into two different enums since they are two separate concepts * Fixed slight glitch where object titles (which normally disappear when objects are used/looked at) reappeared for a moment after the script has finished svn-id: r43305 --- engines/draci/game.cpp | 16 +++++++++------- engines/draci/game.h | 22 +++++++++++++++------- engines/draci/script.cpp | 16 ++++++++-------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index a1652ab732..7c55489677 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -174,7 +174,7 @@ void Game::start() { _persons[kDragonObject]._y = 0; } - setLoopSubstatus(kStatusOrdinary); + setLoopSubstatus(kSubstatusOrdinary); // Do the actual change changeRoom(_newRoom); @@ -281,7 +281,7 @@ void Game::loop() { int x = _vm->_mouse->getPosX(); int y = _vm->_mouse->getPosY(); - if (_loopStatus == kStatusDialogue && _loopSubstatus == kStatusOrdinary) { + if (_loopStatus == kStatusDialogue && _loopSubstatus == kSubstatusOrdinary) { // Find animation under cursor _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); @@ -309,7 +309,7 @@ void Game::loop() { Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); Text *title = reinterpret_cast(titleAnim->getFrame()); - if (_loopStatus == kStatusOrdinary && _loopSubstatus == kStatusOrdinary) { + if (_loopStatus == kStatusOrdinary && _loopSubstatus == kSubstatusOrdinary) { if(_vm->_mouse->isCursorOn()) { // Find the game object under the cursor // (to be more precise, one that corresponds to the animation under the cursor) @@ -333,6 +333,7 @@ void Game::loop() { _vm->_mouse->cursorOff(); titleAnim->markDirtyRect(surface); title->setText(""); + _objUnderCursor = kObjectNotFound; if (!obj->_imLook) { if (obj->_lookDir == -1) { @@ -359,6 +360,7 @@ void Game::loop() { _vm->_mouse->cursorOff(); titleAnim->markDirtyRect(surface); title->setText(""); + _objUnderCursor = kObjectNotFound; if (!obj->_imUse) { if (obj->_useDir == -1) { @@ -394,7 +396,7 @@ void Game::loop() { debug(8, "Anim under cursor: %d", _animUnderCursor); // Handle character talking (if there is any) - if (_loopSubstatus == kStatusTalk) { + if (_loopSubstatus == kSubstatusTalk) { Animation *speechAnim = _vm->_anims->getAnimation(kSpeechText); Text *speechFrame = reinterpret_cast(speechAnim->getFrame()); @@ -537,7 +539,7 @@ void Game::dialogueMenu(int dialogueID) { _dialogueExit = false; hit = dialogueDraw(); - debug(7, kDraciLogicDebugLevel, + debugC(7, kDraciLogicDebugLevel, "hit: %d, _lines[hit]: %d, lastblock: %d, dialogueLines: %d, dialogueExit: %d", hit, _lines[hit], _lastBlock, _dialogueLines, _dialogueExit); @@ -1111,7 +1113,7 @@ void Game::setLoopStatus(LoopStatus status) { _loopStatus = status; } -void Game::setLoopSubstatus(LoopStatus status) { +void Game::setLoopSubstatus(LoopSubstatus status) { _loopSubstatus = status; } @@ -1119,7 +1121,7 @@ LoopStatus Game::getLoopStatus() { return _loopStatus; } -LoopStatus Game::getLoopSubstatus() { +LoopSubstatus Game::getLoopSubstatus() { return _loopSubstatus; } diff --git a/engines/draci/game.h b/engines/draci/game.h index a712542e9e..31e27f9708 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -175,10 +175,18 @@ struct Room { GPL2Program _program; }; -enum LoopStatus { - kStatusGate, kStatusOrdinary, kStatusInventory, - kStatusDialogue, kStatusTalk, kStatusStrange, - kStatusFade +enum LoopStatus { + kStatusOrdinary, + kStatusGate, + kStatusInventory, + kStatusDialogue +}; + +enum LoopSubstatus { + kSubstatusOrdinary, + kSubstatusTalk, + kSubstatusFade, + kSubstatusStrange }; /** @@ -262,9 +270,9 @@ public: void setMarkedAnimationIndex(int index); void setLoopStatus(LoopStatus status); - void setLoopSubstatus(LoopStatus status); + void setLoopSubstatus(LoopSubstatus status); LoopStatus getLoopStatus(); - LoopStatus getLoopSubstatus(); + LoopSubstatus getLoopSubstatus(); bool shouldQuit() { return _shouldQuit; } void setQuit(bool quit) { _shouldQuit = quit; } @@ -321,7 +329,7 @@ public: Animation *_dialogueAnims[4]; LoopStatus _loopStatus; - LoopStatus _loopSubstatus; + LoopSubstatus _loopSubstatus; bool _shouldQuit; bool _shouldExitLoop; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 4dd5a826d7..b30a081027 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -346,11 +346,11 @@ void Script::play(Common::Queue ¶ms) { return; } - _vm->_game->setLoopStatus(kStatusStrange); + _vm->_game->setLoopSubstatus(kSubstatusStrange); _vm->_game->setExitLoop(true); _vm->_game->loop(); _vm->_game->setExitLoop(false); - _vm->_game->setLoopStatus(kStatusOrdinary); + _vm->_game->setLoopSubstatus(kSubstatusOrdinary); } void Script::load(Common::Queue ¶ms) { @@ -446,7 +446,7 @@ void Script::startPlay(Common::Queue ¶ms) { Animation *anim = _vm->_anims->getAnimation(animID); anim->registerCallback(&Animation::exitGameLoop); - _vm->_game->setLoopStatus(kStatusStrange); + _vm->_game->setLoopSubstatus(kSubstatusStrange); bool visible = (obj->_location == _vm->_game->getRoomNum() && obj->_visible); @@ -457,7 +457,7 @@ void Script::startPlay(Common::Queue ¶ms) { _vm->_game->loop(); _vm->_game->setExitLoop(false); _vm->_anims->stop(animID); - _vm->_game->setLoopStatus(kStatusOrdinary); + _vm->_game->setLoopSubstatus(kSubstatusOrdinary); anim->registerCallback(&Animation::doNothing); } @@ -596,9 +596,9 @@ void Script::walkOnPlay(Common::Queue ¶ms) { _vm->_game->walkHero(x, y); - _vm->_game->setLoopSubstatus(kStatusStrange); + _vm->_game->setLoopSubstatus(kSubstatusStrange); _vm->_game->loop(); - _vm->_game->setLoopSubstatus(kStatusOrdinary); + _vm->_game->setLoopSubstatus(kSubstatusOrdinary); _vm->_game->setExitLoop(false); } @@ -650,7 +650,7 @@ void Script::talk(Common::Queue ¶ms) { } // Set the loop substatus to an appropriate value - _vm->_game->setLoopSubstatus(kStatusTalk); + _vm->_game->setLoopSubstatus(kSubstatusTalk); // Record time _vm->_game->setSpeechTick(_vm->_system->getMillis()); @@ -673,7 +673,7 @@ void Script::talk(Common::Queue ¶ms) { speechFrame->setText(""); // Revert to "normal" loop status - _vm->_game->setLoopSubstatus(kStatusOrdinary); + _vm->_game->setLoopSubstatus(kSubstatusOrdinary); _vm->_game->setExitLoop(false); } -- cgit v1.2.3 From 303085c66b7288c9bdb375a7091de611dd1c187d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 04:22:47 +0000 Subject: Whenever we enter the top-level loop, disable exiting by default (fixes the high-five scene between Bert and Eveline which ended too fast). svn-id: r43306 --- engines/draci/game.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 7c55489677..6051e0d651 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -160,6 +160,10 @@ Game::Game(DraciEngine *vm) : _vm(vm) { void Game::start() { while (!shouldQuit()) { + // Whenever the top-level loop is entered, it should not finish unless + // the exit is triggered by a script + _shouldExitLoop = false; + // If the scheduled room differs from the current one, do a room change if (_newRoom != _currentRoom._roomNum) { -- cgit v1.2.3 From 534158af87985a8ca74b99928a74d99681aca79d Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 05:20:25 +0000 Subject: * When setting the first two game variables (room and gate), first convert them back to 1-based indexing so they play well with the rest of the scripts. This fixes a number of bugs, e.g. the dragon now appears automatically when the game starts and the question mark animation in the intro is played / stopped at an appropriate time. * Removed hack from Script::start() which loaded animation 657 before playing it to stop a crash. The fix above seems to fix this bug as well. svn-id: r43308 --- engines/draci/game.cpp | 12 ++++++++---- engines/draci/script.cpp | 22 +++++----------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 6051e0d651..419e2e9c29 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -168,8 +168,10 @@ void Game::start() { if (_newRoom != _currentRoom._roomNum) { // Set the first two variables to the new room / gate - _variables[0] = _newGate; - _variables[1] = _newRoom; + // Before setting these variables we have to convert the values to + // 1-based indexing because this is how everything is stored in the data files + _variables[0] = _newGate + 1; + _variables[1] = _newRoom + 1; // If the new room is the map room, set the appropriate coordinates // for the dragon in the persons array @@ -263,8 +265,10 @@ void Game::init() { _newRoom = _currentRoom._roomNum; _newGate = _currentGate; - _variables[0] = _currentGate; - _variables[1] = _currentRoom._roomNum; + // Before setting these variables we have to convert the values to 1-based indexing + // because this is how everything is stored in the data files + _variables[0] = _currentGate + 1; + _variables[1] = _currentRoom._roomNum + 1; changeRoom(_currentRoom._roomNum); runGateProgram(_currentGate); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index b30a081027..f526bdc874 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -394,20 +394,8 @@ void Script::start(Common::Queue ¶ms) { return; } - int objID = params.pop(); - int animID = params.pop(); - - // Fixes bug in the data files which makes the game crash in the intro - // TODO: This is possibly exclusive to the English version, so check for that - if (animID == 657) { - Common::Queue tmp; - tmp.push(objID); - tmp.push(animID); - this->load(tmp); - } - - objID -= 1; - animID -= 1; + int objID = params.pop() - 1; + int animID = params.pop() - 1; GameObject *obj = _vm->_game->getObject(objID); @@ -780,12 +768,12 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { break; case kMathVariable: - value = reader.readSint16LE(); + value = reader.readSint16LE() - 1; - stk.push(_vm->_game->getVariable(value-1)); + stk.push(_vm->_game->getVariable(value)); debugC(3, kDraciBytecodeDebugLevel, "\t\tvariable: %d (%d)", value, - _vm->_game->getVariable(value-1)); + _vm->_game->getVariable(value)); break; case kMathFunctionCall: -- cgit v1.2.3 From e526983dbed44de0499de2bc7cc640ae8b6d43ab Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 05:22:50 +0000 Subject: Fixed erroneous comment mentioning gates in Game::runDialogueProg(). svn-id: r43309 --- engines/draci/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 419e2e9c29..3f63967316 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -695,7 +695,7 @@ void Game::runDialogueProg(GPL2Program prog, int offset) { // Mark last animation int lastAnimIndex = _vm->_anims->getLastIndex(); - // Run gate program + // Run the dialogue program _vm->_script->run(prog, offset); // Delete all animations loaded after the marked one -- cgit v1.2.3 From 45e4f88e4e2928f5066a6448f4262a3062662df0 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 05:35:08 +0000 Subject: Removed unnecessary else branch in the part of the loop handling substatus Talk. svn-id: r43310 --- engines/draci/game.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 3f63967316..03842a3d7f 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -421,8 +421,6 @@ void Game::loop() { _shouldExitLoop = true; _vm->_mouse->lButtonSet(false); _vm->_mouse->rButtonSet(false); - } else { - _shouldExitLoop = false; } } -- cgit v1.2.3 From c57515b5f868d5c79d4ec9176c9f0c92cac9b454 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 05:38:15 +0000 Subject: Moved setting inactive dialogue option colour to an else branch. svn-id: r43311 --- engines/draci/game.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 03842a3d7f..860344c693 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -297,10 +297,11 @@ void Game::loop() { Text *text; for (int i = 0; i < kDialogueLines; ++i) { text = reinterpret_cast(_dialogueAnims[i]->getFrame()); - text->setColour(kLineInactiveColour); if (_animUnderCursor == _dialogueAnims[i]->getID()) { text->setColour(kLineActiveColour); + } else { + text->setColour(kLineInactiveColour); } } -- cgit v1.2.3 From 8ca10ac3b0527e51a0f72a60e5249525a2746e1c Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 07:34:31 +0000 Subject: Fixed dialogues logic (some indexes were calculated erroneously +/- 1). svn-id: r43312 --- engines/draci/game.cpp | 6 +++--- engines/draci/script.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 860344c693..715b233ab2 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -560,7 +560,7 @@ void Game::dialogueMenu(int dialogueID) { break; } _lastBlock = _lines[hit]; - _dialogueVars[_dialogueOffsets[dialogueID] + _lastBlock + 1] += 1; + _dialogueVars[_dialogueOffsets[dialogueID] + _lastBlock] += 1; _dialogueBegin = false; oldLines = _dialogueLines; @@ -598,7 +598,7 @@ int Game::dialogueDraw() { } for (i = _dialogueLines; i < kDialogueLines; ++i) { - _lines[i] = 0; + _lines[i] = -1; anim = _dialogueAnims[i]; dialogueLine = reinterpret_cast(anim->getFrame()); dialogueLine->setText(""); @@ -672,7 +672,7 @@ void Game::dialogueInit(int dialogID) { } _loopStatus = kStatusDialogue; - _lastBlock = 0; + _lastBlock = -1; _dialogueBegin = true; } diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index f526bdc874..26d0a666ba 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -223,15 +223,20 @@ int Script::funcAtBegin(int yesno) { } int Script::funcLastBlock(int blockID) { + blockID -= 1; return _vm->_game->_lastBlock == blockID; } int Script::funcBlockVar(int blockID) { + blockID -= 1; + return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID]; } int Script::funcHasBeen(int blockID) { + blockID -= 1; + return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID] > 0; } @@ -692,7 +697,7 @@ void Script::resetDialogueFrom(Common::Queue ¶ms) { } void Script::resetBlock(Common::Queue ¶ms) { - int blockID = params.pop(); + int blockID = params.pop() - 1; _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+blockID] = 0; } -- cgit v1.2.3 From 3022c623d6eebdb7827f8f60b3e05dfd3bf677be Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 12 Aug 2009 07:37:08 +0000 Subject: Stopped returning from Animation::nextFrame() early even if the animation has only one frame because such animations may need to have callbacks called too. Fixes intro freeze during mother's lecture. svn-id: r43313 --- engines/draci/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 84ec6eceab..2865a1daf6 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -85,8 +85,8 @@ void Animation::markDirtyRect(Surface *surface) { void Animation::nextFrame(bool force) { - // If there's only one or no frames, or if the animation is not playing, return - if (getFrameCount() < 2 || !_playing) + // If there are no frames or if the animation is not playing, return + if (getFrameCount() == 0 || !_playing) return; Drawable *frame = _frames[_currentFrame]; -- cgit v1.2.3 From 87e64d27f7f1ef3d1f5a635198f006ff89df1f26 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 14 Aug 2009 13:17:53 +0000 Subject: Fixed bug which made the dragon's spoken line in a dialogue end too quickly. svn-id: r43365 --- engines/draci/script.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 26d0a666ba..5e0354dffe 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -658,6 +658,10 @@ void Script::talk(Common::Queue ¶ms) { speechFrame->setX(x); speechFrame->setY(y); + // Prevent the loop from exiting early if other things left the loop in the + // "exit immediately" state + _vm->_game->setExitLoop(false); + // Call the game loop to enable interactivity until the text expires _vm->_game->loop(); -- cgit v1.2.3 From fad77de23486d806f5cc94ae65e0df5953511a73 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 14 Aug 2009 16:12:17 +0000 Subject: Sped up the game during dialogues by not updating every drawn char separately but the whole string at once. Also removed the markDirty parameter from Font::drawChar() since it's not needed anymore. svn-id: r43368 --- engines/draci/font.cpp | 14 +++++++------- engines/draci/font.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engines/draci/font.cpp b/engines/draci/font.cpp index 2a9185e725..093b8d9d17 100644 --- a/engines/draci/font.cpp +++ b/engines/draci/font.cpp @@ -132,7 +132,7 @@ uint8 Font::getCharWidth(uint8 chr) const { * @param ty Vertical offset on the surface */ -void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) const { +void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty) const { assert(dst != NULL); assert(tx >= 0); assert(ty >= 0); @@ -189,11 +189,6 @@ void Font::drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty) con // Advance to next row ptr += dst->pitch; } - - if (markDirty) { - Common::Rect r(tx, ty, tx + xPixelsToDraw + 1, ty + yPixelsToDraw); - dst->markDirtyRect(r); - } } /** @@ -248,9 +243,14 @@ void Font::drawString(Surface *dst, const Common::String &str, break; } - drawChar(dst, str[i], curx, cury, markDirty); + drawChar(dst, str[i], curx, cury); curx += getCharWidth(str[i]) + spacing; } + + if (markDirty) { + Common::Rect r(x, y, x + widest, y + getStringHeight(str)); + dst->markDirtyRect(r); + } } /** diff --git a/engines/draci/font.h b/engines/draci/font.h index e81b344af1..5258108add 100644 --- a/engines/draci/font.h +++ b/engines/draci/font.h @@ -61,7 +61,7 @@ public: uint8 getFontHeight() const { return _fontHeight; }; uint8 getMaxCharWidth() const { return _maxCharWidth; }; uint8 getCharWidth(byte chr) const; - void drawChar(Surface *dst, uint8 chr, int tx, int ty, bool markDirty = true) const; + void drawChar(Surface *dst, uint8 chr, int tx, int ty) const; void drawString(Surface *dst, const byte *str, uint len, int x, int y, int spacing, bool markDirty = true) const; -- cgit v1.2.3 From abf10049bb50d55020ee0f791646a6ca0c0baea8 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 15 Aug 2009 02:42:34 +0000 Subject: * Implemented LoadPalette, SetPalette and BlackPalette GPL commands. * Used a more natural condition (whether the scheduled room number is different from the current room number) instead of the _roomChange hack. svn-id: r43391 --- engines/draci/game.cpp | 11 ++++++++++- engines/draci/game.h | 9 +++++++++ engines/draci/script.cpp | 28 +++++++++++++++++++++++++--- engines/draci/script.h | 3 +++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 715b233ab2..cfd06201b6 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -217,6 +217,7 @@ void Game::start() { void Game::init() { _shouldQuit = false; _shouldExitLoop = false; + _scheduledPalette = 0; _animUnderCursor = kOverlayImage; @@ -437,7 +438,7 @@ void Game::loop() { _vm->_system->delayMillis(20); // HACK: Won't be needed once the game loop is implemented properly - _shouldExitLoop = _shouldExitLoop || (_roomChange && + _shouldExitLoop = _shouldExitLoop || (_newRoom != _currentRoom._roomNum && (_loopStatus == kStatusOrdinary || _loopStatus == kStatusGate)); } while (!shouldExitLoop()); @@ -1160,6 +1161,14 @@ int Game::getEscRoom() { return _currentRoom._escRoom; } +void Game::schedulePalette(int paletteID) { + _scheduledPalette = paletteID; +} + +int Game::getScheduledPalette() { + return _scheduledPalette; +} + /** * The GPL command Mark sets the animation index (which specifies the order in which * animations were loaded in) which is then used by the Release command to delete diff --git a/engines/draci/game.h b/engines/draci/game.h index 31e27f9708..8445bf7a72 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -73,6 +73,10 @@ enum { kNoDialogue = -1, kDialogueLines = 4 }; +enum { + kBlackPalette = -1 +}; + enum SpeechConstants { kBaseSpeechDuration = 200, kSpeechTimeUnit = 400 @@ -293,6 +297,9 @@ public: void dialogueDone(); void runDialogueProg(GPL2Program, int offset); + void schedulePalette(int paletteID); + int getScheduledPalette(); + bool _roomChange; private: @@ -341,6 +348,8 @@ public: int _animUnderCursor; int _markedAnimationIndex; //!< Used by the Mark GPL command + + int _scheduledPalette; }; } // End of namespace Draci diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 5e0354dffe..e30af8f00c 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -61,9 +61,9 @@ void Script::setupCommandList() { { 10, 1, "WalkOn", 3, { 1, 1, 3 }, &Script::walkOn }, { 10, 2, "StayOn", 3, { 1, 1, 3 }, &Script::walkOn }, // HACK: not a proper implementation { 10, 3, "WalkOnPlay", 3, { 1, 1, 3 }, &Script::walkOnPlay }, - { 11, 1, "LoadPalette", 1, { 2 }, NULL }, - { 12, 1, "SetPalette", 0, { 0 }, NULL }, - { 12, 2, "BlackPalette", 0, { 0 }, NULL }, + { 11, 1, "LoadPalette", 1, { 2 }, &Script::loadPalette }, + { 12, 1, "SetPalette", 0, { 0 }, &Script::setPalette }, + { 12, 2, "BlackPalette", 0, { 0 }, &Script::blackPalette }, { 13, 1, "FadePalette", 3, { 1, 1, 1 }, NULL }, { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 }, NULL }, { 14, 1, "NewRoom", 2, { 3, 1 }, &Script::newRoom }, @@ -716,6 +716,28 @@ void Script::roomMap(Common::Queue ¶ms) { _vm->_game->loadWalkingMap(); } +void Script::loadPalette(Common::Queue ¶ms) { + int palette = params.pop() - 1; + + _vm->_game->schedulePalette(palette); +} + +void Script::blackPalette(Common::Queue ¶ms) { + + _vm->_game->schedulePalette(kBlackPalette); +} + +void Script::setPalette(Common::Queue ¶ms) { + + if (_vm->_game->getScheduledPalette() == -1) { + _vm->_screen->setPaletteEmpty(); + } else { + BAFile *f; + f = _vm->_paletteArchive->getFile(_vm->_game->getScheduledPalette()); + _vm->_screen->setPalette(f->_data, 0, kNumColours); + } +} + void Script::endCurrentProgram() { _endProgram = true; } diff --git a/engines/draci/script.h b/engines/draci/script.h index 5483bf4e6a..7fe917eaf3 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -127,6 +127,9 @@ private: void resetDialogue(Common::Queue ¶ms); void resetDialogueFrom(Common::Queue ¶ms); void resetBlock(Common::Queue ¶ms); + void setPalette(Common::Queue ¶ms); + void blackPalette(Common::Queue ¶ms); + void loadPalette(Common::Queue ¶ms); int operAnd(int op1, int op2); int operOr(int op1, int op2); -- cgit v1.2.3 From 1c0df34b4dd47fb686b4af67abdcc13a50d24f7e Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sat, 15 Aug 2009 02:53:14 +0000 Subject: Removed _roomChange hack since it's no longer needed. svn-id: r43392 --- engines/draci/draci.cpp | 3 --- engines/draci/game.cpp | 6 ------ engines/draci/game.h | 2 -- engines/draci/script.cpp | 3 --- 4 files changed, 14 deletions(-) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index a09f5488a9..e14c9343c2 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -194,12 +194,10 @@ bool DraciEngine::handleEvents() { if (event.kbd.keycode == Common::KEYCODE_RIGHT) { _game->setRoomNum(_game->nextRoomNum()); _game->setGateNum(0); - _game->_roomChange = true; } else if (event.kbd.keycode == Common::KEYCODE_LEFT) { _game->setRoomNum(_game->prevRoomNum()); _game->setGateNum(0); - _game->_roomChange = true; } else if (event.kbd.keycode == Common::KEYCODE_ESCAPE) { int escRoom = _game->getEscRoom(); @@ -210,7 +208,6 @@ bool DraciEngine::handleEvents() { // Schedule room change _game->setRoomNum(_game->getEscRoom()); _game->setGateNum(0); - _game->_roomChange = true; _game->setExitLoop(true); // End any currently running GPL programs diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index cfd06201b6..5d78011e8d 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -189,9 +189,6 @@ void Game::start() { _currentRoom._roomNum = _newRoom; _currentGate = _newGate; - // HACK: Won't be needed once I've implemented the loop properly - _roomChange = false; - // Run the program for the gate the dragon came through runGateProgram(_newGate); @@ -225,9 +222,6 @@ void Game::init() { _vm->_mouse->setCursorType(kNormalCursor); - // HACK: Won't be needed once I've implemented the loop properly - _roomChange = false; - _loopStatus = kStatusOrdinary; _objUnderCursor = kOverlayImage; diff --git a/engines/draci/game.h b/engines/draci/game.h index 8445bf7a72..0dcd68cd68 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -300,8 +300,6 @@ public: void schedulePalette(int paletteID); int getScheduledPalette(); - bool _roomChange; - private: DraciEngine *_vm; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index e30af8f00c..fdc2624b73 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -607,9 +607,6 @@ void Script::newRoom(Common::Queue ¶ms) { _vm->_game->setRoomNum(room); _vm->_game->setGateNum(gate); - - // HACK: Won't be needed once I've implemented the loop properly - _vm->_game->_roomChange = true; } void Script::talk(Common::Queue ¶ms) { -- cgit v1.2.3 From 74d4392a78889ee162c6626c7c5c3f331f23e5a4 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 16 Aug 2009 04:21:17 +0000 Subject: Added struct GameItem. svn-id: r43424 --- engines/draci/game.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/engines/draci/game.h b/engines/draci/game.h index 0dcd68cd68..a95dbe7b52 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -150,6 +150,13 @@ struct GameInfo { uint _numDialogueBlocks; }; +struct GameItem { + uint _init, _look, _use, _canUse; + bool _imInit, _imLook, _imUse; + GPL2Program _program; + Common::String _title; +}; + struct Person { uint _x, _y; byte _fontColour; @@ -161,7 +168,6 @@ struct Dialogue { Common::String _title; GPL2Program _program; }; - struct Room { int _roomNum; -- cgit v1.2.3 From 680bed134bd96cb4437b8265aee1a8bcfd8bb7ad Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 17 Aug 2009 18:23:05 +0000 Subject: * Set the _x and _y position for the mouse only when an EVENT_MOUSEMOVE happens. * Stop calling Mouse::setPosition() on EVENT_MOUSEMOVE since it's not needed (the engine warps the mouse automatically; I still left the method for situations when we want to warp the mouse explicitly). svn-id: r43484 --- engines/draci/mouse.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/draci/mouse.cpp b/engines/draci/mouse.cpp index dc10efbab8..53c227d626 100644 --- a/engines/draci/mouse.cpp +++ b/engines/draci/mouse.cpp @@ -39,8 +39,6 @@ Mouse::Mouse(DraciEngine *vm) { } void Mouse::handleEvent(Common::Event event) { - _x = (uint16) event.mouse.x; - _y = (uint16) event.mouse.y; switch (event.type) { case Common::EVENT_LBUTTONDOWN: @@ -64,7 +62,9 @@ void Mouse::handleEvent(Common::Event event) { break; case Common::EVENT_MOUSEMOVE: - setPosition(_x, _y); + debugC(6, kDraciGeneralDebugLevel, "Mouse move (x: %u y: %u)", _x, _y); + _x = (uint16) event.mouse.x; + _y = (uint16) event.mouse.y; break; default: -- cgit v1.2.3 From e5774d2881fe769e31ead57870b1315c56a4ba21 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 17 Aug 2009 18:47:17 +0000 Subject: * Added pause support for animations. * Added AnimationManager::addItem() for adding inventory items animations. svn-id: r43486 --- engines/draci/animation.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++--- engines/draci/animation.h | 12 +++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 2865a1daf6..248cc09197 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -38,6 +38,7 @@ Animation::Animation(DraciEngine *vm, int index) : _vm(vm) { _scaleY = 1.0; _playing = false; _looping = false; + _paused = false; _tick = _vm->_system->getMillis(); _currentFrame = 0; _callback = &Animation::doNothing; @@ -118,6 +119,9 @@ void Animation::nextFrame(bool force) { uint Animation::nextFrameNum() { + if (_paused) + return _currentFrame; + if ((_currentFrame == getFrameCount() - 1) && _looping) return 0; else @@ -200,6 +204,14 @@ void Animation::setPlaying(bool playing) { _playing = playing; } +bool Animation::isPaused() { + return _paused; +} + +void Animation::setPaused(bool paused) { + _paused = paused; +} + void Animation::setScaleFactors(double scaleX, double scaleY) { debugC(5, kDraciAnimationDebugLevel, @@ -304,7 +316,7 @@ Animation *AnimationManager::addAnimation(int id, uint z, bool playing) { return anim; } -Animation *AnimationManager::addText(int id, bool playing) { +Animation *AnimationManager::addItem(int id, bool playing) { Animation *anim = new Animation(_vm, kIgnoreIndex); @@ -317,6 +329,19 @@ Animation *AnimationManager::addText(int id, bool playing) { return anim; } +Animation *AnimationManager::addText(int id, bool playing) { + + Animation *anim = new Animation(_vm, kIgnoreIndex); + + anim->setID(id); + anim->setZ(257); + anim->setPlaying(playing); + + insertAnimation(anim); + + return anim; +} + void AnimationManager::play(int id) { Animation *anim = getAnimation(id); @@ -341,12 +366,39 @@ void AnimationManager::stop(int id) { // Reset the animation to the beginning anim->setCurrentFrame(0); - debugC(3, kDraciAnimationDebugLevel, "Stopping animation %d...", id); } } +void AnimationManager::pauseAnimations() { + + Common::List::iterator it; + + for (it = _animations.begin(); it != _animations.end(); ++it) { + if ((*it)->getID() > 0 || (*it)->getID() == kTitleText) { + // Clean up the last frame that was drawn before stopping + (*it)->markDirtyRect(_vm->_screen->getSurface()); + + (*it)->setPaused(true); + } + } +} + +void AnimationManager::unpauseAnimations() { + + Common::List::iterator it; + + for (it = _animations.begin(); it != _animations.end(); ++it) { + if ((*it)->isPaused()) { + // Clean up the last frame that was drawn before stopping + (*it)->markDirtyRect(_vm->_screen->getSurface()); + + (*it)->setPaused(false); + } + } +} + Animation *AnimationManager::getAnimation(int id) { Common::List::iterator it; @@ -535,7 +587,7 @@ int AnimationManager::getTopAnimationID(int x, int y) { Animation *anim = *it; // If the animation is not playing, ignore it - if (!anim->isPlaying()) { + if (!anim->isPlaying() || anim->isPaused()) { continue; } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index cc339084e3..5d7c0bf7b6 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -38,7 +38,10 @@ enum { kOverlayImage = -1, kWalkingMapOverlay = -2, kTitleText = -3, kSpeechText = -4, - kUnused = -5 }; + kInventorySprite = -5, + kDialogueLinesID = -6, + kUnused = -10, + kInventoryItemsID = -11}; /** * Default argument to Animation::getFrame() that makes it return @@ -81,6 +84,9 @@ public: bool isPlaying(); void setPlaying(bool playing); + bool isPaused(); + void setPaused(bool paused); + bool isLooping(); void setLooping(bool looping); @@ -131,6 +137,7 @@ private: uint _tick; bool _playing; bool _looping; + bool _paused; Common::Array _frames; AnimationCallback _callback; @@ -147,10 +154,13 @@ public: Animation *addAnimation(int id, uint z, bool playing = false); Animation *addText(int id, bool playing = false); + Animation *addItem(int id, bool playing = false); void addOverlay(Drawable *overlay, uint z); void play(int id); void stop(int id); + void pauseAnimations(); + void unpauseAnimations(); void deleteAnimation(int id); void deleteOverlays(); -- cgit v1.2.3 From b0fea939f49c3b0c6287d5a165c5f8ad27b9d794 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 17 Aug 2009 18:50:38 +0000 Subject: Added inventory and item handling support (monster patch, sorry). Items were previously called "icons" as in the original player. This commit also renamed every such instance to the proper "item". svn-id: r43487 --- engines/draci/game.cpp | 461 ++++++++++++++++++++++++++++++++++++++--------- engines/draci/game.h | 49 +++-- engines/draci/script.cpp | 89 ++++++--- engines/draci/script.h | 1 + 4 files changed, 486 insertions(+), 114 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 5d78011e8d..d641809dc2 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -40,7 +40,6 @@ const Common::String dialoguePath("ROZH"); static double real_to_double(byte real[6]); Game::Game(DraciEngine *vm) : _vm(vm) { - unsigned int i; BArchive *initArchive = _vm->_initArchive; @@ -91,12 +90,12 @@ Game::Game(DraciEngine *vm) : _vm(vm) { _info._startRoom = gameData.readByte() - 1; _info._mapRoom = gameData.readByte() - 1; _info._numObjects = gameData.readUint16LE(); - _info._numIcons = gameData.readUint16LE(); + _info._numItems = gameData.readUint16LE(); _info._numVariables = gameData.readByte(); _info._numPersons = gameData.readByte(); _info._numDialogues = gameData.readByte(); - _info._maxIconWidth = gameData.readUint16LE(); - _info._maxIconHeight = gameData.readUint16LE(); + _info._maxItemWidth = gameData.readUint16LE(); + _info._maxItemHeight = gameData.readUint16LE(); _info._musicLength = gameData.readUint16LE(); _info._crc[0] = gameData.readUint16LE(); _info._crc[1] = gameData.readUint16LE(); @@ -126,8 +125,9 @@ Game::Game(DraciEngine *vm) : _vm(vm) { // Read in item icon status file = initArchive->getFile(1); - _iconStatus = file->_data; - uint numIcons = file->_length; + _itemStatus = file->_data; + uint numItems = file->_length; + _items = new GameItem[numItems]; // Read in object status @@ -154,7 +154,7 @@ Game::Game(DraciEngine *vm) : _vm(vm) { assert(numPersons == _info._numPersons); assert(numVariables == _info._numVariables); assert(numObjects == _info._numObjects); - assert(numIcons == _info._numIcons); + assert(numItems == _info._numItems); } void Game::start() { @@ -218,13 +218,17 @@ void Game::init() { _animUnderCursor = kOverlayImage; - _currentIcon = kNoIcon; + _currentItem = kNoItem; + _itemUnderCursor = kNoItem; _vm->_mouse->setCursorType(kNormalCursor); _loopStatus = kStatusOrdinary; _objUnderCursor = kOverlayImage; + // Set the inventory to empty initially + memset(_inventory, kNoItem, kInventorySlots * sizeof (int)); + // Initialize animation for object / room titles Animation *titleAnim = _vm->_anims->addText(kTitleText, true); Text *title = new Text("", _vm->_smallFont, kTitleColour, 0, 0); @@ -235,8 +239,16 @@ void Game::init() { Text *speech = new Text("", _vm->_bigFont, kFontColour1, 0, 0); speechAnim->addFrame(speech); + // Initialize inventory animation + BAFile *f = _vm->_iconsArchive->getFile(13); + Animation *inventoryAnim = _vm->_anims->addAnimation(kInventorySprite, 255, false); + Sprite *inventorySprite = new Sprite(f->_data, f->_length, 0, 0, true); + inventoryAnim->addFrame(inventorySprite); + inventoryAnim->setRelative((kScreenWidth - inventorySprite->getWidth()) / 2, + (kScreenHeight - inventorySprite->getHeight()) / 2); + for (uint i = 0; i < kDialogueLines; ++i) { - _dialogueAnims[i] = _vm->_anims->addText(-10 - i, true); + _dialogueAnims[i] = _vm->_anims->addText(kDialogueLinesID - i, true); Text *dialogueLine = new Text("", _vm->_smallFont, kLineInactiveColour, 0, 0); _dialogueAnims[i]->addFrame(dialogueLine); @@ -248,6 +260,10 @@ void Game::init() { text->setText(""); } + for (uint i = 0; i < _info._numItems; ++i) { + loadItem(i); + } + loadObject(kDragonObject); GameObject *dragon = getObject(kDragonObject); @@ -273,11 +289,11 @@ void Game::loop() { Surface *surface = _vm->_screen->getSurface(); - debugC(6, kDraciLogicDebugLevel, "loopstatus: %d, loopsubstatus: %d", - _loopStatus, _loopSubstatus); - do { + debugC(4, kDraciLogicDebugLevel, "loopstatus: %d, loopsubstatus: %d", + _loopStatus, _loopSubstatus); + _vm->handleEvents(); // Fetch mouse coordinates @@ -286,9 +302,6 @@ void Game::loop() { if (_loopStatus == kStatusDialogue && _loopSubstatus == kSubstatusOrdinary) { - // Find animation under cursor - _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - Text *text; for (int i = 0; i < kDialogueLines; ++i) { text = reinterpret_cast(_dialogueAnims[i]->getFrame()); @@ -307,33 +320,28 @@ void Game::loop() { } } - if (_currentRoom._mouseOn) { + if(_vm->_mouse->isCursorOn()) { // Fetch the dedicated objects' title animation / current frame Animation *titleAnim = _vm->_anims->getAnimation(kTitleText); Text *title = reinterpret_cast(titleAnim->getFrame()); - if (_loopStatus == kStatusOrdinary && _loopSubstatus == kSubstatusOrdinary) { - if(_vm->_mouse->isCursorOn()) { - // Find the game object under the cursor - // (to be more precise, one that corresponds to the animation under the cursor) - _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); - int curObject = getObjectWithAnimation(_animUnderCursor); + updateCursor(); + updateTitle(); - updateTitle(); + if (_loopStatus == kStatusOrdinary && _loopSubstatus == kSubstatusOrdinary) { - _objUnderCursor = curObject; - if (_objUnderCursor != _oldObjUnderCursor) { - _oldObjUnderCursor = _objUnderCursor; + if (_vm->_mouse->lButtonPressed()) { + _vm->_mouse->lButtonSet(false); + + if (_currentItem != kNoItem) { + putItem(_currentItem, 0); + _currentItem = kNoItem; updateCursor(); - } - - if (_vm->_mouse->lButtonPressed()) { - _vm->_mouse->lButtonSet(false); - + } else { if (_objUnderCursor != kObjectNotFound) { GameObject *obj = &_objects[_objUnderCursor]; - + _vm->_mouse->cursorOff(); titleAnim->markDirtyRect(surface); title->setText(""); @@ -353,51 +361,128 @@ void Game::loop() { walkHero(x, y); } } + } - if (_vm->_mouse->rButtonPressed()) { - _vm->_mouse->rButtonSet(false); + if (_vm->_mouse->rButtonPressed()) { + _vm->_mouse->rButtonSet(false); - if (_objUnderCursor != kObjectNotFound) { - GameObject *obj = &_objects[_objUnderCursor]; + if (_objUnderCursor != kObjectNotFound) { + GameObject *obj = &_objects[_objUnderCursor]; - if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { - _vm->_mouse->cursorOff(); - titleAnim->markDirtyRect(surface); - title->setText(""); - _objUnderCursor = kObjectNotFound; - - if (!obj->_imUse) { - if (obj->_useDir == -1) { - walkHero(x, y); - } else { - walkHero(obj->_useX, obj->_useY); - } - } + if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { + _vm->_mouse->cursorOff(); + titleAnim->markDirtyRect(surface); + title->setText(""); + _objUnderCursor = kObjectNotFound; - _vm->_script->run(obj->_program, obj->_use); - _vm->_mouse->cursorOn(); - } else { - walkHero(x, y); + if (!obj->_imUse) { + if (obj->_useDir == -1) { + walkHero(x, y); + } else { + walkHero(obj->_useX, obj->_useY); + } } + + _vm->_script->run(obj->_program, obj->_use); + _vm->_mouse->cursorOn(); } else { - if (_vm->_script->testExpression(_currentRoom._program, _currentRoom._canUse)) { - _vm->_mouse->cursorOff(); - titleAnim->markDirtyRect(surface); - title->setText(""); + walkHero(x, y); + } + } else { + if (_vm->_script->testExpression(_currentRoom._program, _currentRoom._canUse)) { + _vm->_mouse->cursorOff(); + titleAnim->markDirtyRect(surface); + title->setText(""); - _vm->_script->run(_currentRoom._program, _currentRoom._use); - _vm->_mouse->cursorOn(); - } else { - walkHero(x, y); - } + _vm->_script->run(_currentRoom._program, _currentRoom._use); + _vm->_mouse->cursorOn(); + } else { + walkHero(x, y); } } } } - } - debug(8, "Anim under cursor: %d", _animUnderCursor); + if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) { + if (_inventoryExit) { + inventoryDone(); + } + + // If we are in inventory mode, all the animations except game items' + // images will necessarily be paused so we can safely assume that any + // animation under the cursor (a value returned by + // AnimationManager::getTopAnimationID()) will be an item animation or. + // an overlay, for which we check. Item animations have their IDs + // calculated by offseting their itemID from the ID of the last "special" + // animation ID. In this way, we obtain its itemID. + if (_animUnderCursor != kOverlayImage && _animUnderCursor != kInventorySprite) { + _itemUnderCursor = kInventoryItemsID - _animUnderCursor; + } else { + _itemUnderCursor = kNoItem; + } + + // If the user pressed the left mouse button + if (_vm->_mouse->lButtonPressed()) { + _vm->_mouse->lButtonSet(false); + + // If there is an inventory item under the cursor and we aren't + // holding any item, run its look GPL program + if (_itemUnderCursor != kNoItem && _currentItem == kNoItem) { + const GPL2Program &program = _items[_itemUnderCursor]._program; + const int lookOffset = _items[_itemUnderCursor]._look; + + _vm->_script->run(program, lookOffset); + // Otherwise, if we are holding an item, try to place it inside the + // inventory + } else if (_currentItem != kNoItem) { + // FIXME: This should place the item in the nearest inventory slot, + // not the first one available + putItem(_currentItem, 0); + + // Remove it from our hands + _currentItem = kNoItem; + } + } else if (_vm->_mouse->rButtonPressed()) { + _vm->_mouse->rButtonSet(false); + + Animation *inventoryAnim = _vm->_anims->getAnimation(kInventorySprite); + + // If we right-clicked outside the inventory, close it + if (!inventoryAnim->getFrame()->getRect().contains(x, y)) { + inventoryDone(); + + // If there is an inventory item under our cursor + } else if (_itemUnderCursor != kNoItem) { + + // Again, we have two possibilities: + + // The first is that there is no item in our hands. + // In that case, just take the inventory item from the inventory. + if (_currentItem == kNoItem) { + _currentItem = _itemUnderCursor; + removeItem(_itemUnderCursor); + + // The second is that there *is* an item in our hands. + // In that case, run the canUse script for the inventory item + // which will check if the two items are combinable and, finally, + // run the use script for the item. + } else { + const GPL2Program &program = _items[_itemUnderCursor]._program; + const int canUseOffset = _items[_itemUnderCursor]._canUse; + const int useOffset = _items[_itemUnderCursor]._use; + + if (_vm->_script->testExpression(program, canUseOffset)) { + _vm->_script->run(program, useOffset); + } + } + updateCursor(); + } + } + } + } + + debugC(5, kDraciLogicDebugLevel, "Anim under cursor: %d", _animUnderCursor); // Handle character talking (if there is any) if (_loopSubstatus == kSubstatusTalk) { @@ -425,9 +510,7 @@ void Game::loop() { return; // Advance animations and redraw screen - if (_loopStatus != kStatusInventory) { - _vm->_anims->drawScene(surface); - } + _vm->_anims->drawScene(surface); _vm->_screen->copyToScreen(); _vm->_system->delayMillis(20); @@ -440,40 +523,106 @@ void Game::loop() { void Game::updateCursor() { - _vm->_mouse->setCursorType(kNormalCursor); + // Fetch mouse coordinates + int x = _vm->_mouse->getPosX(); + int y = _vm->_mouse->getPosY(); + + // Find animation under cursor + _animUnderCursor = _vm->_anims->getTopAnimationID(x, y); + + // If we are inside a dialogue, all we need is to update the ID of the current + // animation under the cursor. This enables us to update the currently selected + // dialogue line (by recolouring it) but still leave the cursor unupdated when + // over background objects. + if (_loopStatus == kStatusDialogue) + return; + + // If we are in inventory mode, we do a different kind of updating that handles + // inventory items and return early + if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) { + + if (_currentItem == kNoItem) { + _vm->_mouse->setCursorType(kNormalCursor); + } else { + _vm->_mouse->loadItemCursor(_currentItem); + } + + if (_itemUnderCursor != kNoItem) { + const GPL2Program &program = _items[_itemUnderCursor]._program; + const int canUseOffset = _items[_itemUnderCursor]._canUse; + + if (_vm->_script->testExpression(program, canUseOffset)) { + if (_currentItem == kNoItem) { + _vm->_mouse->setCursorType(kHighlightedCursor); + } else { + _vm->_mouse->loadItemCursor(_currentItem, true); + } + } + } - if (_currentIcon != kNoIcon) { - _vm->_mouse->loadItemCursor(_currentIcon); + return; } + // Find the game object under the cursor + // (to be more precise, one that corresponds to the animation under the cursor) + int curObject = getObjectWithAnimation(_animUnderCursor); + + // Update the game object under the cursor + _objUnderCursor = curObject; + if (_objUnderCursor != _oldObjUnderCursor) { + _oldObjUnderCursor = _objUnderCursor; + } + + // Load the appropriate cursor (item image if an item is held or ordinary cursor + // if not) + if (_currentItem == kNoItem) { + _vm->_mouse->setCursorType(kNormalCursor); + } else { + _vm->_mouse->loadItemCursor(_currentItem); + } + + // TODO: Handle main menu + + // If there is no game object under the cursor, try using the room itself if (_objUnderCursor == kObjectNotFound) { if (_vm->_script->testExpression(_currentRoom._program, _currentRoom._canUse)) { - if (_currentIcon == kNoIcon) { + if (_currentItem == kNoItem) { _vm->_mouse->setCursorType(kHighlightedCursor); } else { - _vm->_mouse->loadItemCursor(_currentIcon, true); + _vm->_mouse->loadItemCursor(_currentItem, true); } } + // If there *is* a game object under the cursor, update the cursor image } else { GameObject *obj = &_objects[_objUnderCursor]; - - _vm->_mouse->setCursorType((CursorType)obj->_walkDir); - if (!(obj->_walkDir > 0)) { + // If there is no walking direction set on the object (i.e. the object + // is not a gate / exit), test whether it can be used and, if so, + // update the cursor image (highlight it). + if (obj->_walkDir == 0) { if (_vm->_script->testExpression(obj->_program, obj->_canUse)) { - if (_currentIcon == kNoIcon) { + if (_currentItem == kNoItem) { _vm->_mouse->setCursorType(kHighlightedCursor); } else { - _vm->_mouse->loadItemCursor(_currentIcon, true); + _vm->_mouse->loadItemCursor(_currentItem, true); } } + // If the walking direction *is* set, the game object is a gate, so update + // the cursor image to the appropriate arrow. + } else { + _vm->_mouse->setCursorType((CursorType)obj->_walkDir); } } } void Game::updateTitle() { + // If we are inside a dialogue, don't update titles + if (_loopStatus == kStatusDialogue) + return; + + // Fetch current surface and height of the small font (used for titles) Surface *surface = _vm->_screen->getSurface(); const int smallFontHeight = _vm->_smallFont->getFontHeight(); @@ -488,6 +637,8 @@ void Game::updateTitle() { // Mark dirty rectangle to delete the previous text titleAnim->markDirtyRect(surface); + // If there is no object under the cursor, delete the title. + // Otherwise, show the object's title. if (_objUnderCursor == kObjectNotFound) { title->setText(""); } else { @@ -500,6 +651,8 @@ void Game::updateTitle() { int newY = surface->centerOnY(y - smallFontHeight / 2, title->getHeight() * 2); titleAnim->setRelative(newX, newY); + // If we are currently playing the title, mark it dirty so it gets updated. + // Otherwise, start playing the title animation. if (titleAnim->isPlaying()) { titleAnim->markDirtyRect(surface); } else { @@ -521,6 +674,115 @@ int Game::getObjectWithAnimation(int animID) { return kObjectNotFound; } +void Game::removeItem(int itemID) { + + for (uint i = 0; i < kInventorySlots; ++i) { + if (_inventory[i] == itemID) { + _inventory[i] = kNoItem; + _vm->_anims->stop(kInventoryItemsID - itemID); + break; + } + } +} + +void Game::putItem(int itemID, int position) { + + if (itemID == kNoItem) + return; + + uint i = position; + + if (position >= 0 && + position < kInventoryLines * kInventoryColumns && + _inventory[position] == kNoItem) { + _inventory[position] = itemID; + } else { + for (i = 0; i < kInventorySlots; ++i) { + if (_inventory[i] == kNoItem) { + _inventory[i] = itemID; + break; + } + } + } + + const int line = i / kInventoryColumns + 1; + const int column = i % kInventoryColumns + 1; + + Animation *anim = _vm->_anims->getAnimation(kInventoryItemsID - itemID); + Drawable *frame = anim->getFrame(); + + const int x = kInventoryX + + (column * kInventoryItemWidth) - + (kInventoryItemWidth / 2) - + (frame->getWidth() / 2); + + const int y = kInventoryY + + (line * kInventoryItemHeight) - + (kInventoryItemHeight / 2) - + (frame->getHeight() / 2); + + debug(2, "itemID: %d position: %d line: %d column: %d x: %d y: %d", itemID, position, line, column, x, y); + + anim->setRelative(x, y); + + // If we are in inventory mode, we need to play the item animation, immediately + // upon returning it to its slot but *not* in other modes because it should be + // invisible then (along with the inventory) + if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) { + _vm->_anims->play(kInventoryItemsID - itemID); + } +} + +void Game::inventoryInit() { + + // Pause all "background" animations + _vm->_anims->pauseAnimations(); + + // Draw the inventory and the current items + inventoryDraw(); + + // Turn cursor on if it is off + _vm->_mouse->cursorOn(); + + // Set the appropriate loop status + _loopStatus = kStatusInventory; + + // TODO: This will be used for exiting the inventory automatically when the mouse + // is outside it for some time + _inventoryExit = false; +} + +void Game::inventoryDone() { + _vm->_mouse->cursorOn(); + _loopStatus = kStatusOrdinary; + + _vm->_anims->unpauseAnimations(); + + _vm->_anims->stop(kInventorySprite); + + for (uint i = 0; i < kInventorySlots; ++i) { + if (_inventory[i] != kNoItem) { + _vm->_anims->stop(kInventoryItemsID - _inventory[i]); + } + } + + // Reset item under cursor + _itemUnderCursor = kNoItem; + + // TODO: Handle main menu +} + +void Game::inventoryDraw() { + + _vm->_anims->play(kInventorySprite); + + for (uint i = 0; i < kInventorySlots; ++i) { + if (_inventory[i] != kNoItem) { + _vm->_anims->play(kInventoryItemsID - _inventory[i]); + } + } +} + void Game::dialogueMenu(int dialogueID) { int oldLines, hit; @@ -578,7 +840,6 @@ int Game::dialogueDraw() { GPL2Program blockTest; blockTest._bytecode = _dialogueBlocks[i]._canBlock; blockTest._length = _dialogueBlocks[i]._canLen; - debugC(3, kDraciLogicDebugLevel, "Testing dialogue block %d", i); if (_vm->_script->testExpression(blockTest, 1)) { anim = _dialogueAnims[_dialogueLines]; @@ -757,6 +1018,33 @@ void Game::walkHero(int x, int y) { _vm->_anims->play(animID); } +void Game::loadItem(int itemID) { + + BAFile *f = _vm->_itemsArchive->getFile(itemID * 3); + Common::MemoryReadStream itemReader(f->_data, f->_length); + + GameItem *item = _items + itemID; + + item->_init = itemReader.readSint16LE(); + item->_look = itemReader.readSint16LE(); + item->_use = itemReader.readSint16LE(); + item->_canUse = itemReader.readSint16LE(); + item->_imInit = itemReader.readByte(); + item->_imLook = itemReader.readByte(); + item->_imUse = itemReader.readByte(); + + f = _vm->_itemsArchive->getFile(itemID * 3 + 1); + + // The first byte is the length of the string + item->_title = Common::String((const char *)f->_data + 1, f->_length - 1); + assert(f->_data[0] == item->_title.size()); + + f = _vm->_itemsArchive->getFile(itemID * 3 + 2); + + item->_program._bytecode = f->_data; + item->_program._length = f->_length; +} + void Game::loadRoom(int roomNum) { BAFile *f; @@ -1135,12 +1423,20 @@ void Game::setVariable(int numVar, int value) { _variables[numVar] = value; } -int Game::getIconStatus(int iconID) { - return _iconStatus[iconID]; +int Game::getItemStatus(int itemID) { + return _itemStatus[itemID]; +} + +void Game::setItemStatus(int itemID, int status) { + _itemStatus[itemID] = status; +} + +int Game::getCurrentItem() { + return _currentItem; } -int Game::getCurrentIcon() { - return _currentIcon; +void Game::setCurrentItem(int itemID) { + _currentItem = itemID; } Person *Game::getPerson(int personID) { @@ -1186,6 +1482,7 @@ Game::~Game() { delete[] _variables; delete[] _dialogueOffsets; delete[] _objects; + delete[] _items; } diff --git a/engines/draci/game.h b/engines/draci/game.h index a95dbe7b52..5cefa5dec1 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -57,10 +57,10 @@ enum { kNoEscRoom = -1 }; -// Used as a value to Game::_currentIcon and means there is no icon (game item) selected +// Used as a value to Game::_currentIcon and means there is no item selected // and a "real" cursor image is used enum { - kNoIcon = -1 + kNoItem = -1 }; // Used as a default parameter in Game::loadWalkingMap() to specify that the default @@ -82,6 +82,17 @@ enum SpeechConstants { kSpeechTimeUnit = 400 }; +/** Inventory related magical constants */ +enum InventoryConstants { + kInventoryItemWidth = 25, + kInventoryItemHeight = 25, + kInventoryColumns = 7, + kInventoryLines = 5, + kInventoryX = 70, //!< Used for positioning of the inventory sprite on the X axis + kInventoryY = 30, //!< Used for positioning of the inventory sprite on the Y axis + kInventorySlots = kInventoryLines * kInventoryColumns +}; + class WalkingMap { public: @@ -140,11 +151,11 @@ struct GameInfo { int _startRoom; int _mapRoom; uint _numObjects; - uint _numIcons; + uint _numItems; byte _numVariables; byte _numPersons; byte _numDialogues; - uint _maxIconWidth, _maxIconHeight; + uint _maxItemWidth, _maxItemHeight; uint _musicLength; uint _crc[4]; uint _numDialogueBlocks; @@ -255,6 +266,7 @@ public: void loadOverlays(); void loadObject(uint numObj); void loadWalkingMap(int mapID = kDefaultRoomMap); + void loadItem(int itemID); uint getNumObjects(); GameObject *getObject(uint objNum); @@ -271,8 +283,13 @@ public: int getGateNum(); void setGateNum(int gate); - int getIconStatus(int iconID); - int getCurrentIcon(); + int getItemStatus(int itemID); + void setItemStatus(int itemID, int status); + int getCurrentItem(); + void setCurrentItem(int itemID); + void removeItem(int itemID); + void putItem(int itemID, int position); + void addItem(int itemID); int getEscRoom(); @@ -297,6 +314,10 @@ public: void updateTitle(); void updateCursor(); + void inventoryInit(); + void inventoryDraw(); + void inventoryDone(); + void dialogueMenu(int dialogueID); int dialogueDraw(); void dialogueInit(int dialogID); @@ -312,17 +333,23 @@ private: GameInfo _info; int *_variables; - byte *_iconStatus; Person *_persons; GameObject *_objects; + byte *_itemStatus; + GameItem *_items; + int _currentItem; + int _itemUnderCursor; + + int _inventory[kInventorySlots]; + bool _inventoryExit; + + Room _currentRoom; int _currentGate; int _newRoom; int _newGate; - int _currentIcon; - // HACK: remove public when tested and add getters instead public: uint *_dialogueOffsets; @@ -336,8 +363,8 @@ public: int _lastBlock; int _dialogueLines; int _blockNum; - int _lines[4]; - Animation *_dialogueAnims[4]; + int _lines[kDialogueLines]; + Animation *_dialogueAnims[kDialogueLines]; LoopStatus _loopStatus; LoopSubstatus _loopSubstatus; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index fdc2624b73..70b982b6d6 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -52,7 +52,7 @@ void Script::setupCommandList() { { 6, 1, "Talk", 2, { 3, 2 }, &Script::talk }, { 7, 1, "ObjStat", 2, { 3, 3 }, &Script::objStat }, { 7, 2, "ObjStat_On", 2, { 3, 3 }, &Script::objStatOn }, - { 8, 1, "IcoStat", 2, { 3, 3 }, NULL }, + { 8, 1, "IcoStat", 2, { 3, 3 }, &Script::icoStat }, { 9, 1, "Dialogue", 1, { 2 }, &Script::dialogue }, { 9, 2, "ExitDialogue", 0, { 0 }, &Script::exitDialogue }, { 9, 3, "ResetDialogue", 0, { 0 }, &Script::resetDialogue }, @@ -248,33 +248,33 @@ int Script::funcNot(int n) { return !n; } -int Script::funcIsIcoOn(int iconID) { - iconID -= 1; +int Script::funcIsIcoOn(int itemID) { + itemID -= 1; - return _vm->_game->getIconStatus(iconID) == 1; + return _vm->_game->getItemStatus(itemID) == 1; } -int Script::funcIcoStat(int iconID) { - iconID -= 1; +int Script::funcIcoStat(int itemID) { + itemID -= 1; - int status = _vm->_game->getIconStatus(iconID); + int status = _vm->_game->getItemStatus(itemID); return (status == 1) ? 1 : 2; } -int Script::funcIsIcoAct(int iconID) { - iconID -= 1; +int Script::funcIsIcoAct(int itemID) { + itemID -= 1; - return _vm->_game->getCurrentIcon() == iconID; + return _vm->_game->getCurrentItem() == itemID; } -int Script::funcActIco(int iconID) { +int Script::funcActIco(int itemID) { // The parameter seems to be an omission in the original player since it's not // used in the implementation of the function. It's possible that the functions were // implemented in such a way that they had to have a single parameter so this is only // passed as a dummy. - return _vm->_game->getCurrentIcon(); + return _vm->_game->getCurrentItem(); } int Script::funcIsObjOn(int objID) { @@ -500,6 +500,53 @@ void Script::release(Common::Queue ¶ms) { _vm->_anims->deleteAfterIndex(markedIndex); } +void Script::icoStat(Common::Queue ¶ms) { + int status = params.pop(); + int itemID = params.pop() - 1; + + _vm->_game->setItemStatus(itemID, status == 1); + + if (_vm->_game->getItemStatus(itemID) == 0) { + + if (itemID != kNoItem) { + _vm->_anims->deleteAnimation(kInventoryItemsID - itemID); + } + + _vm->_game->removeItem(itemID); + + if (_vm->_game->getCurrentItem() == itemID) { + _vm->_game->setCurrentItem(kNoItem); + } + + if (_vm->_mouse->getCursorType() == kNormalCursor) { + if (_vm->_game->getLoopStatus() == kStatusInventory) { + _vm->_mouse->cursorOff(); + } + } + } + + if (_vm->_game->getItemStatus(itemID) == 1) { + + if (itemID != kNoItem) { + Animation *itemAnim = _vm->_anims->addItem(kInventoryItemsID - itemID); + BAFile *f = _vm->_itemImagesArchive->getFile(2 * itemID); + Sprite *sp = new Sprite(f->_data, f->_length, 0, 0, true); + itemAnim->addFrame(sp); + } + + _vm->_game->setCurrentItem(itemID); + + _vm->_mouse->loadItemCursor(itemID); + + // TODO: This is probably not needed but I'm leaving it to be sure for now + // The original engine needed to turn off the mouse temporarily when changing + // the cursor image. I'm just setting it to the final state of that transition. + if (_vm->_game->getLoopStatus() == kStatusInventory) { + _vm->_mouse->cursorOn(); + } + } +} + void Script::objStatOn(Common::Queue ¶ms) { int objID = params.pop() - 1; int roomID = params.pop() - 1; @@ -750,7 +797,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { GPL2Operator oper; GPL2Function func; - debugC(3, kDraciBytecodeDebugLevel, "\t"); + debugC(4, kDraciBytecodeDebugLevel, "\t"); // Read in initial math object obj = (mathExpressionObject)reader.readSint16LE(); @@ -774,7 +821,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { case kMathNumber: value = reader.readSint16LE(); stk.push(value); - debugC(3, kDraciBytecodeDebugLevel, "\t\tnumber: %d", value); + debugC(4, kDraciBytecodeDebugLevel, "\t\tnumber: %d", value); break; case kMathOperator: @@ -791,7 +838,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { // Push result stk.push(res); - debugC(3, kDraciBytecodeDebugLevel, "\t\t%d %s %d (res: %d)", + debugC(4, kDraciBytecodeDebugLevel, "\t\t%d %s %d (res: %d)", arg1, oper._name.c_str(), arg2, res); break; @@ -800,7 +847,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { stk.push(_vm->_game->getVariable(value)); - debugC(3, kDraciBytecodeDebugLevel, "\t\tvariable: %d (%d)", value, + debugC(4, kDraciBytecodeDebugLevel, "\t\tvariable: %d (%d)", value, _vm->_game->getVariable(value)); break; @@ -817,7 +864,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { // FIXME: Pushing dummy value for now, but should push return value stk.push(0); - debugC(3, kDraciBytecodeDebugLevel, "\t\tcall: %s (not implemented)", + debugC(4, kDraciBytecodeDebugLevel, "\t\tcall: %s (not implemented)", func._name.c_str()); } else { arg1 = stk.pop(); @@ -828,7 +875,7 @@ int Script::handleMathExpression(Common::MemoryReadStream &reader) { // Push the result on the evaluation stack stk.push(res); - debugC(3, kDraciBytecodeDebugLevel, "\t\tcall: %s(%d) (res: %d)", + debugC(4, kDraciBytecodeDebugLevel, "\t\tcall: %s(%d) (res: %d)", func._name.c_str(), arg1, res); } @@ -865,7 +912,7 @@ bool Script::testExpression(GPL2Program program, uint16 offset) { // Seek to the expression reader.seek(offset); - debugC(2, kDraciBytecodeDebugLevel, + debugC(4, kDraciBytecodeDebugLevel, "Evaluating (standalone) GPL expression at offset %d:", offset); return (bool)handleMathExpression(reader); @@ -962,7 +1009,7 @@ int Script::run(GPL2Program program, uint16 offset) { // Account for GPL jump that some commands set if (_jump != 0) { - debugC(6, kDraciBytecodeDebugLevel, + debugC(3, kDraciBytecodeDebugLevel, "Jumping from offset %d to %d (%d bytes)", reader.pos(), reader.pos() + _jump, _jump); reader.seek(_jump, SEEK_CUR); @@ -996,7 +1043,7 @@ int Script::run(GPL2Program program, uint16 offset) { for (int i = 0; i < cmd->_numParams; ++i) { if (cmd->_paramTypes[i] == 4) { - debugC(2, kDraciBytecodeDebugLevel, + debugC(3, kDraciBytecodeDebugLevel, "Evaluating (in-script) GPL expression at offset %d: ", offset); params.push(handleMathExpression(reader)); } diff --git a/engines/draci/script.h b/engines/draci/script.h index 7fe917eaf3..86abb5ee9b 100644 --- a/engines/draci/script.h +++ b/engines/draci/script.h @@ -109,6 +109,7 @@ private: void start(Common::Queue ¶ms); void mark(Common::Queue ¶ms); void release(Common::Queue ¶ms); + void icoStat(Common::Queue ¶ms); void objStat(Common::Queue ¶ms); void objStatOn(Common::Queue ¶ms); void execInit(Common::Queue ¶ms); -- cgit v1.2.3 From 85bf130a50acd6445042889f5c67a9489d894d51 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 17 Aug 2009 18:51:45 +0000 Subject: Enabled hotkey 'i' for accessing or exiting the inventory. svn-id: r43488 --- engines/draci/draci.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index e14c9343c2..134b2a3cfa 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -218,6 +218,15 @@ bool DraciEngine::handleEvents() { else if (event.kbd.keycode == Common::KEYCODE_w) { _showWalkingMap = !_showWalkingMap; } + else if (event.kbd.keycode == Common::KEYCODE_i) { + if(_game->getLoopStatus() == kStatusInventory && + _game->getLoopSubstatus() == kSubstatusOrdinary) { + _game->inventoryDone(); + } else if (_game->getLoopStatus() == kStatusOrdinary && + _game->getLoopSubstatus() == kSubstatusOrdinary) { + _game->inventoryInit(); + } + } break; default: _mouse->handleEvent(event); -- cgit v1.2.3 From be0cfa50f29ae1bb5ddd2461c1e4d865d1b30899 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 17 Aug 2009 19:37:55 +0000 Subject: Removed public data variables of Game concerning dialogues and added getters/setters. svn-id: r43492 --- engines/draci/game.cpp | 66 ++++++++++++++++++++++++++++++++++++++++-------- engines/draci/game.h | 17 ++++++++++--- engines/draci/script.cpp | 32 ++++++++++++++--------- 3 files changed, 88 insertions(+), 27 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d641809dc2..9c68d00907 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -805,10 +805,10 @@ void Game::dialogueMenu(int dialogueID) { debugC(7, kDraciLogicDebugLevel, "hit: %d, _lines[hit]: %d, lastblock: %d, dialogueLines: %d, dialogueExit: %d", - hit, _lines[hit], _lastBlock, _dialogueLines, _dialogueExit); + hit, _lines[hit], _lastBlock, _dialogueLinesNum, _dialogueExit); if ((!_dialogueExit) && (hit != -1) && (_lines[hit] != -1)) { - if ((oldLines == 1) && (_dialogueLines == 1) && (_lines[hit] == _lastBlock)) { + if ((oldLines == 1) && (_dialogueLinesNum == 1) && (_lines[hit] == _lastBlock)) { break; } _currentBlock = _lines[hit]; @@ -819,7 +819,7 @@ void Game::dialogueMenu(int dialogueID) { _lastBlock = _lines[hit]; _dialogueVars[_dialogueOffsets[dialogueID] + _lastBlock] += 1; _dialogueBegin = false; - oldLines = _dialogueLines; + oldLines = _dialogueLinesNum; } while(!_dialogueExit); @@ -828,32 +828,32 @@ void Game::dialogueMenu(int dialogueID) { } int Game::dialogueDraw() { - _dialogueLines = 0; + _dialogueLinesNum = 0; int i = 0; int ret = 0; Animation *anim; Text *dialogueLine; - while ((_dialogueLines < 4) && (i < _blockNum)) { + while ((_dialogueLinesNum < 4) && (i < _blockNum)) { GPL2Program blockTest; blockTest._bytecode = _dialogueBlocks[i]._canBlock; blockTest._length = _dialogueBlocks[i]._canLen; debugC(3, kDraciLogicDebugLevel, "Testing dialogue block %d", i); if (_vm->_script->testExpression(blockTest, 1)) { - anim = _dialogueAnims[_dialogueLines]; + anim = _dialogueAnims[_dialogueLinesNum]; dialogueLine = reinterpret_cast(anim->getFrame()); dialogueLine->setText(_dialogueBlocks[i]._title); dialogueLine->setColour(kLineInactiveColour); - _lines[_dialogueLines] = i; - _dialogueLines++; + _lines[_dialogueLinesNum] = i; + _dialogueLinesNum++; } ++i; } - for (i = _dialogueLines; i < kDialogueLines; ++i) { + for (i = _dialogueLinesNum; i < kDialogueLines; ++i) { _lines[i] = -1; anim = _dialogueAnims[i]; dialogueLine = reinterpret_cast(anim->getFrame()); @@ -862,7 +862,7 @@ int Game::dialogueDraw() { _oldObjUnderCursor = kObjectNotFound; - if (_dialogueLines > 1) { + if (_dialogueLinesNum > 1) { _vm->_mouse->cursorOn(); _shouldExitLoop = false; loop(); @@ -882,7 +882,7 @@ int Game::dialogueDraw() { ret = _dialogueAnims[0]->getID() - _animUnderCursor; } } else { - ret = _dialogueLines - 1; + ret = _dialogueLinesNum - 1; } for (i = 0; i < kDialogueLines; ++i) { @@ -970,6 +970,50 @@ void Game::runDialogueProg(GPL2Program prog, int offset) { _vm->_anims->deleteAfterIndex(lastAnimIndex); } +bool Game::isDialogueBegin() { + return _dialogueBegin; +} + +bool Game::shouldExitDialogue() { + return _dialogueExit; +} + +void Game::setDialogueExit(bool exit) { + _dialogueExit = exit; +} + +int Game::getDialogueBlockNum() { + return _blockNum; +} + +int Game::getDialogueVar(int dialogueID) { + return _dialogueVars[dialogueID]; +} + +void Game::setDialogueVar(int dialogueID, int value) { + _dialogueVars[dialogueID] = value; +} + +int Game::getCurrentDialogue() { + return _currentDialogue; +} + +int Game::getDialogueLastBlock() { + return _lastBlock; +} + +int Game::getDialogueLinesNum() { + return _dialogueLinesNum; +} + +int Game::getDialogueCurrentBlock() { + return _currentBlock; +} + +int Game::getCurrentDialogueOffset() { + return _dialogueOffsets[_currentDialogue]; +} + void Game::walkHero(int x, int y) { Surface *surface = _vm->_screen->getSurface(); diff --git a/engines/draci/game.h b/engines/draci/game.h index 5cefa5dec1..0197b167b6 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -324,6 +324,18 @@ public: void dialogueDone(); void runDialogueProg(GPL2Program, int offset); + bool isDialogueBegin(); + bool shouldExitDialogue(); + void setDialogueExit(bool exit); + int getDialogueBlockNum(); + int getDialogueVar(int dialogueID); + void setDialogueVar(int dialogueID, int value); + int getCurrentDialogue(); + int getDialogueCurrentBlock(); + int getDialogueLastBlock(); + int getDialogueLinesNum(); + int getCurrentDialogueOffset(); + void schedulePalette(int paletteID); int getScheduledPalette(); @@ -344,14 +356,11 @@ private: int _inventory[kInventorySlots]; bool _inventoryExit; - Room _currentRoom; int _currentGate; int _newRoom; int _newGate; -// HACK: remove public when tested and add getters instead -public: uint *_dialogueOffsets; int _currentDialogue; int *_dialogueVars; @@ -361,7 +370,7 @@ public: bool _dialogueExit; int _currentBlock; int _lastBlock; - int _dialogueLines; + int _dialogueLinesNum; int _blockNum; int _lines[kDialogueLines]; Animation *_dialogueAnims[kDialogueLines]; diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 70b982b6d6..db5cb80a20 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -219,29 +219,31 @@ int Script::funcRandom(int n) { } int Script::funcAtBegin(int yesno) { - return _vm->_game->_dialogueBegin == yesno; + return _vm->_game->isDialogueBegin() == yesno; } int Script::funcLastBlock(int blockID) { blockID -= 1; - return _vm->_game->_lastBlock == blockID; + return _vm->_game->getDialogueLastBlock() == blockID; } int Script::funcBlockVar(int blockID) { blockID -= 1; - - return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID]; + + const int currentOffset = _vm->_game->getCurrentDialogueOffset(); + return _vm->_game->getDialogueVar(currentOffset + blockID); } int Script::funcHasBeen(int blockID) { blockID -= 1; - return _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue] + blockID] > 0; + const int currentOffset = _vm->_game->getCurrentDialogueOffset(); + return _vm->_game->getDialogueVar(currentOffset + blockID) > 0; } int Script::funcMaxLine(int lines) { - return _vm->_game->_dialogueLines < lines; + return _vm->_game->getDialogueLinesNum() < lines; } int Script::funcNot(int n) { @@ -731,27 +733,33 @@ void Script::loadMap(Common::Queue ¶ms) { } void Script::resetDialogue(Common::Queue ¶ms) { + + const int currentOffset = _vm->_game->getCurrentDialogueOffset(); - for (int i = 0; i < _vm->_game->_blockNum; ++i) { - _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+i] = 0; + for (int i = 0; i < _vm->_game->getDialogueBlockNum(); ++i) { + _vm->_game->setDialogueVar(currentOffset + i, 0); } } void Script::resetDialogueFrom(Common::Queue ¶ms) { - for (int i = _vm->_game->_currentBlock; i < _vm->_game->_blockNum; ++i) { - _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+i] = 0; + const int currentOffset = _vm->_game->getCurrentDialogueOffset(); + + for (int i = _vm->_game->getDialogueCurrentBlock(); i < _vm->_game->getDialogueBlockNum(); ++i) { + _vm->_game->setDialogueVar(currentOffset + i, 0); } } void Script::resetBlock(Common::Queue ¶ms) { int blockID = params.pop() - 1; - _vm->_game->_dialogueVars[_vm->_game->_dialogueOffsets[_vm->_game->_currentDialogue]+blockID] = 0; + const int currentOffset = _vm->_game->getCurrentDialogueOffset(); + + _vm->_game->setDialogueVar(currentOffset + blockID, 0); } void Script::exitDialogue(Common::Queue ¶ms) { - _vm->_game->_dialogueExit = true; + _vm->_game->setDialogueExit(true); } void Script::roomMap(Common::Queue ¶ms) { -- cgit v1.2.3 From e4fb567319c5b1d9584b36eea58ffdab33ddac0e Mon Sep 17 00:00:00 2001 From: Robert Špalek Date: Fri, 25 Sep 2009 06:06:01 +0000 Subject: Disable compilation of Draci Historie svn-id: r44325 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index fd9f325109..d1b668f8db 100755 --- a/configure +++ b/configure @@ -74,6 +74,7 @@ add_engine agos "AGOS" yes "pn" add_engine pn "Personal Nightmare" no add_engine cine "Cinematique evo 1" yes add_engine cruise "Cinematique evo 2" no +add_engine draci "Dragon History" no add_engine drascula "Drascula: The Vampire Strikes Back" yes add_engine gob "Gobli*ns" yes add_engine groovie "Groovie" yes @@ -96,7 +97,6 @@ add_engine sword2 "Broken Sword 2" yes add_engine tinsel "Tinsel" no add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes add_engine tucker "Bud Tucker in Double Trouble" yes -add_engine draci "Dragon History" yes # -- cgit v1.2.3