diff options
Diffstat (limited to 'engines/prince')
40 files changed, 6811 insertions, 0 deletions
diff --git a/engines/prince/animation.cpp b/engines/prince/animation.cpp new file mode 100644 index 0000000000..8edf9d04ee --- /dev/null +++ b/engines/prince/animation.cpp @@ -0,0 +1,155 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/animation.h" +#include "prince/decompress.h" + +#include "common/debug.h" +#include "common/endian.h" + +namespace Prince { + +bool Animation::loadFromStream(Common::SeekableReadStream &stream) { + _dataSize = stream.size(); + _data = (byte*) malloc(_dataSize); + + if (stream.read(_data, _dataSize) != _dataSize) { + free(_data); + return false; + } + return true; +} +/* +const Graphics::Surface * Animation::getSurface(uint16 frameIndex) { + // bida kaszing + if (frameIndex >= _frameList.size()) { + _frameList.resize(frameIndex); + _frameList.push_back(_helper->getFrame(frameIndex)); + + } + return _frameList[frameIndex]; +} +*/ +Animation::Animation(): _data(NULL) { + +} + +Animation::Animation(byte *data, uint32 dataSize) + : _data(data), _dataSize(dataSize) { +} + +Animation::~Animation() { + free(_data); +} + +void Animation::clear() { + if (_data != NULL) { + free(_data); + } +} + +// TEMP +/* +int8 Animation::getZoom(uint16 offset) const { + return *(uint8*)(_data+offset); +} +*/ +int16 Animation::getZoom(uint16 offset) const { + return READ_LE_UINT16(_data + offset); +} + +int16 Animation::getLoopCount() const { + return READ_LE_UINT16(_data + 2); +} + +int16 Animation::getBaseX() const { + return READ_LE_UINT16(_data + 8); +} + +int16 Animation::getBaseY() const { + return READ_LE_UINT16(_data + 10); +} + +uint Animation::getPhaseCount() const { + return READ_LE_UINT16(_data + 4); +} + +uint Animation::getFrameCount() const { + return READ_LE_UINT16(_data + 6); +} + +int16 Animation::getPhaseOffsetX(uint phaseIndex) const { + return READ_LE_UINT16(getPhaseEntry(phaseIndex) + 0); +} + +int16 Animation::getPhaseOffsetY(uint phaseIndex) const { + return READ_LE_UINT16(getPhaseEntry(phaseIndex) + 2); +} + +int16 Animation::getPhaseFrameIndex(uint phaseIndex) const { + return READ_LE_UINT16(getPhaseEntry(phaseIndex) + 4); +} + +int16 Animation::getFrameWidth(uint frameIndex) const { + byte *frameData = _data + READ_LE_UINT32(_data + 16 + frameIndex * 4); + return READ_LE_UINT16(frameData + 0); +} + +int16 Animation::getFrameHeight(uint frameIndex) const { + byte *frameData = _data + READ_LE_UINT32(_data + 16 + frameIndex * 4); + return READ_LE_UINT16(frameData + 2); +} + +Graphics::Surface *Animation::getFrame(uint frameIndex) { + byte *frameData = _data + READ_LE_UINT32(_data + 16 + frameIndex * 4); + int16 width = READ_LE_UINT16(frameData + 0); + int16 height = READ_LE_UINT16(frameData + 2); + debug("width = %d; height = %d", width, height); + Graphics::Surface *surf = new Graphics::Surface(); + surf->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + debug("frameData %p", frameData); + if (READ_BE_UINT32(frameData + 4) == 0x6D61736D) { + // Compressed + Decompressor dec; + uint32 ddataSize = READ_LE_UINT32(frameData + 8); + byte *ddata = new byte[ddataSize]; + dec.decompress(frameData + 12, ddata, ddataSize); + for (uint16 i = 0; i < height; ++i) { + memcpy(surf->getBasePtr(0, i), ddata + width * i, width); + } + delete[] ddata; + } else { + // Uncompressed + for (uint16 i = 0; i < height; ++i) { + memcpy(surf->getBasePtr(0, i), frameData + 4 + width * i, width); + } + } + return surf; +} + +byte *Animation::getPhaseEntry(uint phaseIndex) const { + return _data + READ_LE_UINT32(_data + 12) + phaseIndex * 8; +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/animation.h b/engines/prince/animation.h new file mode 100644 index 0000000000..710f8730cc --- /dev/null +++ b/engines/prince/animation.h @@ -0,0 +1,66 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_ANIMATION_H +#define PRINCE_ANIMATION_H + +#include "common/array.h" +#include "common/stream.h" + +#include "graphics/surface.h" + +namespace Prince { + +class Animation { +public: + bool loadFromStream(Common::SeekableReadStream &stream); + //const Graphics::Surface *getSurface(uint16 frameIndex); + + Animation(); + Animation(byte *data, uint32 dataSize); + ~Animation(); + int16 getLoopCount() const; + int16 getBaseX() const; + int16 getBaseY() const; + uint getPhaseCount() const; + uint getFrameCount() const; + int16 getPhaseOffsetX(uint phaseIndex) const; + int16 getPhaseOffsetY(uint phaseIndex) const; + int16 getPhaseFrameIndex(uint phaseIndex) const; + Graphics::Surface *getFrame(uint frameIndex); + int16 getFrameWidth(uint frameIndex) const; + int16 getFrameHeight(uint frameIndex) const; + int16 getZoom(uint16 offset) const; + void clear(); + +private: + Common::Array<Graphics::Surface *> _frameList; + byte *_data; + uint32 _dataSize; + byte *getPhaseEntry(uint phaseIndex) const; +}; + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/archive.cpp b/engines/prince/archive.cpp new file mode 100644 index 0000000000..d1b680c204 --- /dev/null +++ b/engines/prince/archive.cpp @@ -0,0 +1,146 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/archive.h" +#include "prince/decompress.h" + +#include "common/stream.h" +#include "common/debug.h" +#include "common/memstream.h" + +namespace Prince { + +PtcArchive::PtcArchive() : _stream(NULL) { +} + +PtcArchive::~PtcArchive() { + close(); +} + +static void decrypt(byte *buffer, uint32 size) { + uint32 key = 0xDEADF00D; + while (size--) { + *buffer++ += key & 0xFF; + key ^= 0x2E84299A; + key += 0x424C4148; + key = ((key & 1) << 31) | (key >> 1); + } +} + +bool PtcArchive::open(const Common::String &filename) { + _stream = SearchMan.createReadStreamForMember(filename); + if (!_stream) + return false; + + uint32 magic = _stream->readUint32LE(); + uint32 fileTableOffset = _stream->readUint32LE() ^ 0x4D4F4B2D; // MOK- + uint32 fileTableSize = _stream->readUint32LE() ^ 0x534F4654; // SOFT + + //debug("fileTableOffset : %08X", fileTableOffset); + //debug("fileTableSize: %08X", fileTableSize); + + _stream->seek(fileTableOffset); + + byte *fileTable = new byte[fileTableSize]; + byte *fileTableEnd = fileTable + fileTableSize; + _stream->read(fileTable, fileTableSize); + decrypt(fileTable, fileTableSize); + + for (byte *fileItem = fileTable; fileItem < fileTableEnd; fileItem += 32) { + FileEntry item; + Common::String name = (const char*)fileItem; + item._offset = READ_LE_UINT32(fileItem + 24); + item._size = READ_LE_UINT32(fileItem + 28); + //debug("%12s %8X %d", name.c_str(), item._offset, item._size); + _items[name] = item; + } + + delete[] fileTable; + + return true; +} + +void PtcArchive::close() { + delete _stream; + _stream = NULL; + _items.clear(); +} + +bool PtcArchive::hasFile(const Common::String &name) const { + // TODO: check if path matching should be added + return _items.contains(name); +} + +int PtcArchive::listMembers(Common::ArchiveMemberList &list) const { + int matches = 0; + + for (FileMap::const_iterator it = _items.begin(); it != _items.end(); ++it) { + list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(it->_key, this))); + matches++; + } + + return matches; +} + +const Common::ArchiveMemberPtr PtcArchive::getMember(const Common::String &name) const { + if (!_items.contains(name)) { + Common::ArchiveMemberPtr(); + } + return Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *PtcArchive::createReadStreamForMember(const Common::String &name) const { + if (!_items.contains(name)) { + return 0; + } + + const FileEntry &entryHeader = _items[name]; + + if (entryHeader._size < 4) + return 0; + + uint32 size = entryHeader._size; + + _stream->seek(entryHeader._offset); + + // This *HAS* to be malloc (not new[]) because MemoryReadStream uses free() to free the memory + byte* buffer = (byte *)malloc(size); + _stream->read(buffer, size); + + if (READ_BE_UINT32(buffer) == 0x4D41534D) { + Decompressor dec; + uint32 decompLen = READ_BE_UINT32(buffer + 14); + byte *decompData = (byte*)malloc(decompLen); + dec.decompress(buffer + 18, decompData, decompLen); + free(buffer); + size = decompLen; + buffer = decompData; + } + + //debug("PtcArchive::createReadStreamForMember name %s", name.c_str()); + + return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES); +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/archive.h b/engines/prince/archive.h new file mode 100644 index 0000000000..29d3d58560 --- /dev/null +++ b/engines/prince/archive.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_ARCHIVE_H +#define PRINCE_ARCHIVE_H + +#include "common/archive.h" +#include "common/hashmap.h" +#include "common/hash-str.h" + +namespace Prince { + +class PtcArchive : public Common::Archive { +public: + PtcArchive(); + ~PtcArchive(); + + bool open(const Common::String &filename); + void close(); + bool isOpen() const { return _stream != 0; } + + // Common::Archive API implementation + bool hasFile(const Common::String &name) const; + int listMembers(Common::ArchiveMemberList &list) const; + const Common::ArchiveMemberPtr getMember(const Common::String &name) const; + Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; + +private: + struct FileEntry { + uint32 _offset; + uint32 _size; + }; + + Common::SeekableReadStream *_stream; + + typedef Common::HashMap<Common::String, FileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap; + FileMap _items; +}; + +} // End of namespace Prince + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/common.h b/engines/prince/common.h new file mode 100644 index 0000000000..6dc1bad6a8 --- /dev/null +++ b/engines/prince/common.h @@ -0,0 +1,47 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_COMMON_H +#define PRINCE_COMMON_H + +namespace Prince { + +enum Direction { + LD = 0, + L = 1, + LG = 2, + PD = 3, + P = 4, + PG = 5, + GL = 6, + G = 7, + GP = 8, + DL = 9, + D = 10, + DP = 11 +}; + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/configure.engine b/engines/prince/configure.engine new file mode 100644 index 0000000000..50740d9f41 --- /dev/null +++ b/engines/prince/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine prince "The Prince and The Coward" no diff --git a/engines/prince/cursor.cpp b/engines/prince/cursor.cpp new file mode 100644 index 0000000000..865ae99cad --- /dev/null +++ b/engines/prince/cursor.cpp @@ -0,0 +1,54 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/cursor.h" + +#include "common/debug.h" +#include "common/stream.h" + +namespace Prince { + +Cursor::Cursor() : _surface(NULL) { +} + +Cursor::~Cursor() { + _surface->free(); + delete _surface; + _surface = NULL; +} + +bool Cursor::loadFromStream(Common::SeekableReadStream &stream) { + stream.skip(4); + uint16 w = stream.readUint16LE(); + uint16 h = stream.readUint16LE(); + + _surface = new Graphics::Surface(); + _surface->create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + + for (int ih = 0; ih < h; ++ih) + stream.read(_surface->getBasePtr(0, ih), w); + return true; +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/cursor.h b/engines/prince/cursor.h new file mode 100644 index 0000000000..70516519e6 --- /dev/null +++ b/engines/prince/cursor.h @@ -0,0 +1,50 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef CURSOR_PRINCE_H +#define CURSOR_PRINCE_H + +#include "graphics/surface.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Prince { + +class Cursor { +public: + Cursor(); + ~Cursor(); + + bool loadFromStream(Common::SeekableReadStream &stream); + const Graphics::Surface *getSurface() const { return _surface; } + +private: + Graphics::Surface *_surface; +}; + +} + +#endif + +/* vim: set tabstop=4 expandtab!: */ diff --git a/engines/prince/debugger.cpp b/engines/prince/debugger.cpp new file mode 100644 index 0000000000..d9264cb02d --- /dev/null +++ b/engines/prince/debugger.cpp @@ -0,0 +1,156 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/debugger.h" +#include "prince/prince.h" + +namespace Prince { + +Debugger::Debugger(PrinceEngine *vm) : GUI::Debugger(), _vm(vm), _locationNr(0) { + DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); + DCmd_Register("level", WRAP_METHOD(Debugger, Cmd_DebugLevel)); + DCmd_Register("setflag", WRAP_METHOD(Debugger, Cmd_SetFlag)); + DCmd_Register("getflag", WRAP_METHOD(Debugger, Cmd_GetFlag)); + DCmd_Register("clearflag", WRAP_METHOD(Debugger, Cmd_ClearFlag)); + DCmd_Register("viewflc", WRAP_METHOD(Debugger, Cmd_ViewFlc)); + DCmd_Register("initroom", WRAP_METHOD(Debugger, Cmd_InitRoom)); + DCmd_Register("changecursor", WRAP_METHOD(Debugger, Cmd_ChangeCursor)); +} + +static int strToInt(const char *s) { + if (!*s) + // No string at all + return 0; + else if (toupper(s[strlen(s) - 1]) != 'H') + // Standard decimal string + return atoi(s); + + // Hexadecimal string + uint tmp = 0; + int read = sscanf(s, "%xh", &tmp); + if (read < 1) + error("strToInt failed on string \"%s\"", s); + return (int)tmp; +} + +bool Debugger::Cmd_DebugLevel(int argc, const char **argv) { + if (argc == 1) { + DebugPrintf("Debugging is currently set at level %d\n", gDebugLevel); + } else { // set level + gDebugLevel = atoi(argv[1]); + if (0 <= gDebugLevel && gDebugLevel < 11) { + DebugPrintf("Debug level set to level %d\n", gDebugLevel); + } else if (gDebugLevel < 0) { + DebugPrintf("Debugging is now disabled\n"); + } else + DebugPrintf("Not a valid debug level (0 - 10)\n"); + } + + return true; +} + +/* + * This command sets a flag + */ +bool Debugger::Cmd_SetFlag(int argc, const char **argv) { + // Check for a flag to set + if (argc != 2) { + DebugPrintf("Usage: %s <flag number>\n", argv[0]); + return true; + } + + int flagNum = strToInt(argv[1]); + //g_globals->setFlag(flagNum); + return true; +} + +/* + * This command gets the value of a flag + */ +bool Debugger::Cmd_GetFlag(int argc, const char **argv) { + // Check for an flag to display + if (argc != 2) { + DebugPrintf("Usage: %s <flag number>\n", argv[0]); + return true; + } + + int flagNum = strToInt(argv[1]); + //DebugPrintf("Value: %d\n", g_globals->getFlag(flagNum)); + return true; +} + +/* + * This command clears a flag + */ +bool Debugger::Cmd_ClearFlag(int argc, const char **argv) { + // Check for a flag to clear + if (argc != 2) { + DebugPrintf("Usage: %s <flag number>\n", argv[0]); + return true; + } + + int flagNum = strToInt(argv[1]); + //g_globals->clearFlag(flagNum); + return true; +} + +/* + * This command starts new flc anim + */ +bool Debugger::Cmd_ViewFlc(int argc, const char **argv) { + // Check for a flag to clear + if (argc != 2) { + DebugPrintf("Usage: %s <anim number>\n", argv[0]); + return true; + } + + int flagNum = strToInt(argv[1]); + _vm->loadAnim(flagNum, false); + return true; +} + +bool Debugger::Cmd_InitRoom(int argc, const char **argv) { + // Check for a flag to clear + if (argc != 2) { + DebugPrintf("Usage: %s <anim number>\n", argv[0]); + return true; + } + + _locationNr = strToInt(argv[1]); + return true; +} + +bool Debugger::Cmd_ChangeCursor(int argc, const char **argv) { + // Check for a flag to clear + if (argc != 2) { + DebugPrintf("Usage: %s <curId>\n", argv[0]); + return true; + } + + _cursorNr = strToInt(argv[1]); + + return true; +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/debugger.h b/engines/prince/debugger.h new file mode 100644 index 0000000000..f3608af81d --- /dev/null +++ b/engines/prince/debugger.h @@ -0,0 +1,57 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_DEBUGGER_H +#define PRINCE_DEBUGGER_H + +#include "common/scummsys.h" +#include "gui/debugger.h" + +namespace Prince { + +class PrinceEngine; + +class Debugger : public GUI::Debugger { +public: + Debugger(PrinceEngine *vm); + virtual ~Debugger() {} // we need this for __SYMBIAN32__ archaic gcc/UIQ + + uint8 _locationNr; + uint8 _cursorNr; + +private: + bool Cmd_DebugLevel(int argc, const char **argv); + bool Cmd_SetFlag(int argc, const char **argv); + bool Cmd_GetFlag(int argc, const char **argv); + bool Cmd_ClearFlag(int argc, const char **argv); + bool Cmd_ViewFlc(int argc, const char **argv); + bool Cmd_InitRoom(int argc, const char **argv); + bool Cmd_ChangeCursor(int argc, const char **argv); + + PrinceEngine *_vm; +}; + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/decompress.cpp b/engines/prince/decompress.cpp new file mode 100644 index 0000000000..7fba179541 --- /dev/null +++ b/engines/prince/decompress.cpp @@ -0,0 +1,171 @@ +/* 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. + * + */ + +// John_Doe's implementation + +#include "prince/decompress.h" + +namespace Prince { + +static const uint16 table1[] = { + 0x8000, 0x0002, + 0x4000, 0x0004, + 0x2000, 0x0008, + 0x1000, 0x0010, + 0x0800, 0x0020, + 0x0400, 0x0040, + 0x0200, 0x0080, + 0x0100, 0x0100, + 0x0080, 0x0200, + 0x0040, 0x0400 +}; + +static const uint32 table2[] = { + 0x0000F000, + 0x0020FC00, + 0x00A0FF00, + 0x02A0FF80, + 0x06A0FFC0, + 0x0EA0FFE0, + 0x1EA0FFF0, + 0x3EA0FFF8 +}; + +static const uint16 table3[] = { + 0x8000, 0x0000, + 0x4000, 0x0002, + 0x2000, 0x0006, + 0x1000, 0x000E, + 0x0800, 0x001E, + 0x0400, 0x003E, + 0x0200, 0x007E, + 0x0100, 0x00FE, + 0x0080, 0x01FE, + 0x0040, 0x03FE, + 0x0020, 0x07FE, + 0x0010, 0x0FFE, + 0x0008, 0x1FFE, + 0x0004, 0x3FFE, + 0x0002, 0x7FFE, + 0x0001, 0xFFFE +}; + +void Decompressor::decompress(byte *source, byte *dest, uint32 destSize) { + byte *destEnd = dest + destSize; + int more; + _src = source; + _dst = dest; + _bitBuffer = 0x80; + while (_dst < destEnd) { + uint32 ebp; + uint16 offset, length; + if (getBit()) { + if (getBit()) { + if (getBit()) { + if (getBit()) { + if (getBit()) { + if (getBit()) { + uint32 tableIndex = 0; + while (getBit()) + tableIndex++; + length = table3[tableIndex * 2 + 0]; + do { + more = !(length & 0x8000); + length = (length << 1) | getBit(); + } while (more); + length += table3[tableIndex * 2 + 1]; + length++; + memcpy(_dst, _src, length); + _src += length; + _dst += length; + } + *_dst++ = *_src++; + } + *_dst++ = *_src++; + } + *_dst++ = *_src++; + } + *_dst++ = *_src++; + } + *_dst++ = *_src++; + } + if (!getBit()) { + if (getBit()) { + uint32 tableIndex = getBit(); + tableIndex = (tableIndex << 1) | getBit(); + tableIndex = (tableIndex << 1) | getBit(); + ebp = table2[tableIndex]; + length = 1; + } else { + ebp = 0x0000FF00; + length = 0; + } + } else { + uint32 tableIndex = 0; + while (getBit()) + tableIndex++; + length = table1[tableIndex * 2 + 0]; + do { + more = !(length & 0x8000); + length = (length << 1) | getBit(); + } while (more); + length += table1[tableIndex * 2 + 1]; + tableIndex = getBit(); + tableIndex = (tableIndex << 1) | getBit(); + tableIndex = (tableIndex << 1) | getBit(); + ebp = table2[tableIndex]; + } + offset = ebp & 0xFFFF; + do { + if (_bitBuffer == 0x80) { + if (offset >= 0xFF00) { + offset = (offset << 8) | *_src++; + } + } + more = offset & 0x8000; + offset = (offset << 1) | getBit(); + } while (more); + offset += (ebp >> 16); + length += 2; + while (length--) { + if (_dst >= destEnd) { + return; + } + *_dst = *(_dst - offset); + _dst++; + } + } +} + +int Decompressor::getBit() { + int bit = (_bitBuffer & 0x80) >> 7; + _bitBuffer <<= 1; + if (_bitBuffer == 0) { + _bitBuffer = *_src++; + bit = (_bitBuffer & 0x80) >> 7; + _bitBuffer <<= 1; + _bitBuffer |= 1; + } + return bit; +} + +} // End of namespace Prince diff --git a/engines/prince/decompress.h b/engines/prince/decompress.h new file mode 100644 index 0000000000..ef495db65e --- /dev/null +++ b/engines/prince/decompress.h @@ -0,0 +1,44 @@ +/* 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. + * + */ + +// John_Doe's implementation + +#ifndef PRINCE_DECOMPRESS_H +#define PRINCE_DECOMPRESS_H + +#include "engines/util.h" + +namespace Prince { + +class Decompressor { +public: + void decompress(byte *source, byte *dest, uint32 destSize); +protected: + byte *_src, *_dst; + byte _bitBuffer; + int _bitsLeft; + int getBit(); +}; + +} // End of namespace Prince + +#endif diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp new file mode 100644 index 0000000000..fa9df38c90 --- /dev/null +++ b/engines/prince/detection.cpp @@ -0,0 +1,147 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" +#include "engines/advancedDetector.h" + +#include "prince/prince.h" + +namespace Prince { + +struct PrinceGameDescription { + ADGameDescription desc; + + int gameType; +}; + +int PrinceEngine::getGameType() const { + return _gameDescription->gameType; +} + +const char *PrinceEngine::getGameId() const { + return _gameDescription->desc.gameid; +} + +uint32 PrinceEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +Common::Language PrinceEngine::getLanguage() const { + return _gameDescription->desc.language; +} + +} + +static const PlainGameDescriptor princeGames[] = { + {"prince", "Prince Game"}, + {0, 0} +}; + +namespace Prince { + +static const PrinceGameDescription gameDescriptions[] = { + + // German + { + { + "prince", + "Galador", + AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031), + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + 0 + }, + // Polish + { + { + "prince", + "Ksiaze i Tchorz", + AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298), + Common::PL_POL, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + 1 + }, + + + { AD_TABLE_END_MARKER, 0 } +}; + +} // End of namespace Prince + +using namespace Prince; + +// we match from data too, to stop detection from a non-top-level directory +const static char *directoryGlobs[] = { + "all", + 0 +}; + +class PrinceMetaEngine : public AdvancedMetaEngine { +public: + PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) { + _singleid = "prince"; + _maxScanDepth = 2; + _directoryGlobs = directoryGlobs; + } + + virtual const char *getName() const { + return "Prince Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Copyright (C)"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual bool hasFeature(MetaEngineFeature f) const; +}; + +bool PrinceMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + using namespace Prince; + const PrinceGameDescription *gd = (const PrinceGameDescription *)desc; + if (gd) { + *engine = new PrinceEngine(syst, gd); + } + return gd != 0; +} + +bool PrinceMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool Prince::PrinceEngine::hasFeature(EngineFeature f) const { + return false;//(f == kSupportsRTL); +} + +#if PLUGIN_ENABLED_DYNAMIC(PRINCE) +REGISTER_PLUGIN_DYNAMIC(PRINCE, PLUGIN_TYPE_ENGINE, PrinceMetaEngine); +#else +REGISTER_PLUGIN_STATIC(PRINCE, PLUGIN_TYPE_ENGINE, PrinceMetaEngine); +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/flags.cpp b/engines/prince/flags.cpp new file mode 100644 index 0000000000..d6d577a575 --- /dev/null +++ b/engines/prince/flags.cpp @@ -0,0 +1,406 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/flags.h" + +namespace Prince { + +const char * Flags::getFlagName(uint16 flagId) +{ + switch (flagId) { + default: return "unknown_flag"; + case FLAGA1: return "FLAGA1"; + case FLAGA2: return "FLAGA2"; + case FLAGA3: return "FLAGA3"; + case DESTX: return "DESTX"; + case DESTY: return "DESTY"; + case DESTD: return "DESTD"; + case DwarfDone: return "DwarfDone"; + case GRABARZCOUNTER: return "GRABARZCOUNTER"; + case KIERUNEK: return "KIERUNEK"; + case BACKFLAG1: return "BACKFLAG1"; + case BACKFLAG2: return "BACKFLAG2"; + case BACKFLAG3: return "BACKFLAG3"; + case BACKFLAG4: return "BACKFLAG4"; + case MACROFLAG1: return "MACROFLAG1"; + case MACROFLAG2: return "MACROFLAG2"; + case MACROFLAG3: return "MACROFLAG3"; + case HEROLDDONE: return "HEROLDDONE"; + case BRIDGESET: return "BRIDGESET"; + case U_BT_1: return "U_BT_1"; + case U_BT_2: return "U_BT_2"; + case U_BT_3: return "U_BT_3"; + case U_BT_4: return "U_BT_4"; + case U_BT_5: return "U_BT_5"; + case U_BT_6: return "U_BT_6"; + case U_BT_7: return "U_BT_7"; + case U_BT_8: return "U_BT_8"; + case U_BT_9: return "U_BT_9"; + case U_BT_COUNTER: return "U_BT_COUNTER"; + case ARIVALDALIVE: return "ARIVALDALIVE"; + case TALKCHAR1: return "TALKCHAR1"; + case TalkType1: return "TalkType1"; + case TALKROUT1: return "TALKROUT1"; + case TALKROUT2: return "TALKROUT2"; + case TALKROUT3: return "TALKROUT3"; + case TALKROUT4: return "TALKROUT4"; + case TALKANIM1: return "TALKANIM1"; + case TALKANIM2: return "TALKANIM2"; + case TALKCOLOR1: return "TALKCOLOR1"; + case TALKCOLOR2: return "TALKCOLOR2"; + case KapciuchTaken: return "KapciuchTaken"; + case CurrentBeggarA: return "CurrentBeggarA"; + case TempKapc: return "TempKapc"; + case HomTaken: return "HomTaken"; + case WizardTalk: return "WizardTalk"; + case SunlordTalk: return "SunlordTalk"; + case HermitTalk: return "HermitTalk"; + case RunyMode: return "RunyMode"; + case FatMerchantTalk: return "FatMerchantTalk"; + case HotDogTalk: return "HotDogTalk"; + case ThiefTalk: return "ThiefTalk"; + case BeggarTalk: return "BeggarTalk"; + case MonkTalk: return "MonkTalk"; + case BardTalk: return "BardTalk"; + case BarmanTalk: return "BarmanTalk"; + case LeftPlayerTalk: return "LeftPlayerTalk"; + case OczySowy: return "OczySowy"; + case CzachySpeed1: return "CzachySpeed1"; + case CzachySpeed2: return "CzachySpeed2"; + case CzachySpeed3: return "CzachySpeed3"; + case CzachySlowDown1: return "CzachySlowDown1"; + case CzachySlowDown2: return "CzachySlowDown2"; + case CzachySlowDown3: return "CzachySlowDown3"; + case FjordDane: return "FjordDane"; + case GKopany1: return "GKopany1"; + case GKopany2: return "GKopany2"; + case GKopany3: return "GKopany3"; + case GKopany4: return "GKopany4"; + case KnowGodWord: return "KnowGodWord"; + case TALKROUT21: return "TALKROUT21"; + case TALKROUT22: return "TALKROUT22"; + case TALKROUT23: return "TALKROUT23"; + case TALKROUT24: return "TALKROUT24"; + case TalkType2: return "TalkType2"; + case GrabarzTalk: return "GrabarzTalk"; + case LastTalker: return "LastTalker"; + case MapaPustelniaEnabled: return "MapaPustelniaEnabled"; + case MapaTempleEnabled: return "MapaTempleEnabled"; + case MapaFjordEnabled: return "MapaFjordEnabled"; + case MapaSilmanionaEnabled: return "MapaSilmanionaEnabled"; + case MapaKurhanEnabled: return "MapaKurhanEnabled"; + case MapaDragonEnabled: return "MapaDragonEnabled"; + case MapaMillEnabled: return "MapaMillEnabled"; + case DwarfRunning: return "DwarfRunning"; + case DwarfTalk: return "DwarfTalk"; + case CurseLift: return "CurseLift"; + case KosciSwapped: return "KosciSwapped"; + case BookStolen: return "BookStolen"; + case MapaUsable: return "MapaUsable"; + case FjordBoss: return "FjordBoss"; + case FjordHotDog: return "FjordHotDog"; + case FjordLewy: return "FjordLewy"; + case FjordPrawy: return "FjordPrawy"; + case TalkArivald: return "TalkArivald"; + case ShootDone: return "ShootDone"; + case ShootRunning: return "ShootRunning"; + case ShootKnow: return "ShootKnow"; + case MirrorKnow: return "MirrorKnow"; + case Gar1stTime: return "Gar1stTime"; + case KosciTaken: return "KosciTaken"; + case ArivGotSpell: return "ArivGotSpell"; + case BookGiven: return "BookGiven"; + case Wywieszka: return "Wywieszka"; + case TalkSheila: return "TalkSheila"; + case TalkSheila2: return "TalkSheila2"; + case BackHuman: return "BackHuman"; + case SkarbiecOpen: return "SkarbiecOpen"; + case LustroTaken: return "LustroTaken"; + case GargoyleHom: return "GargoyleHom"; + case GargoyleBroken: return "GargoyleBroken"; + case FjordDzien: return "FjordDzien"; + case GargoyleHom2: return "GargoyleHom2"; + case RunMonstersRunning: return "RunMonstersRunning"; + case FoundPaperInCoffin: return "FoundPaperInCoffin"; + case KnowSunlord: return "KnowSunlord"; + case KnowSunlordTalk: return "KnowSunlordTalk"; + case ArivaldCzyta: return "ArivaldCzyta"; + case TelepX: return "TelepX"; + case TelepY: return "TelepY"; + case TelepDir: return "TelepDir"; + case TelepRoom: return "TelepRoom"; + case ListStolen: return "ListStolen"; + case WifeInDoor: return "WifeInDoor"; + case TalkWifeFlag: return "TalkWifeFlag"; + case LetterGiven: return "LetterGiven"; + case LutniaTaken: return "LutniaTaken"; + case BardHomeOpen: return "BardHomeOpen"; + case FjordNoMonsters: return "FjordNoMonsters"; + case ShandriaWallTalking: return "ShandriaWallTalking"; + case ShandriaWallCounter: return "ShandriaWallCounter"; + case ShandriaWallDone: return "ShandriaWallDone"; + case FutureDone: return "FutureDone"; + case TalkButch: return "TalkButch"; + case GotSzalik: return "GotSzalik"; + case GotCzosnek: return "GotCzosnek"; + case BearDone: return "BearDone"; + case NekrVisited: return "NekrVisited"; + case SunRiddle: return "SunRiddle"; + case PtaszekAway: return "PtaszekAway"; + case KotGadanie: return "KotGadanie"; + case SzlafmycaTaken: return "SzlafmycaTaken"; + case BabkaTalk: return "BabkaTalk"; + case SellerTalk: return "SellerTalk"; + case CzosnekDone: return "CzosnekDone"; + case PriestCounter: return "PriestCounter"; + case PriestGest1: return "PriestGest1"; + case PriestGest2: return "PriestGest2"; + case PriestGest3: return "PriestGest3"; + case PriestGest4: return "PriestGest4"; + case PriestAnim: return "PriestAnim"; + case HolyWaterTaken: return "HolyWaterTaken"; + case AxeTaken: return "AxeTaken"; + case BadylTaken1: return "BadylTaken1"; + case BadylTaken2: return "BadylTaken2"; + case BadylSharpened: return "BadylSharpened"; + case PorwanieSmoka: return "PorwanieSmoka"; + case ShopReOpen: return "ShopReOpen"; + case LuskaShown: return "LuskaShown"; + case CudKnow: return "CudKnow"; + case VampireDead: return "VampireDead"; + case MapaVisible1: return "MapaVisible1"; + case MapaVisible2: return "MapaVisible2"; + case MapaVisible3: return "MapaVisible3"; + case MapaVisible4: return "MapaVisible4"; + case MapaVisible5: return "MapaVisible5"; + case MapaVisible6: return "MapaVisible6"; + case MapaVisible7: return "MapaVisible7"; + case MapaVisible8: return "MapaVisible8"; + case MapaVisible9: return "MapaVisible9"; + case MapaX: return "MapaX"; + case MapaY: return "MapaY"; + case MapaD: return "MapaD"; + case OldMapaX: return "OldMapaX"; + case OldMapaY: return "OldMapaY"; + case OldMapaD: return "OldMapaD"; + case MovingBack: return "MovingBack"; + case MapaCount: return "MapaCount"; + case Pustelnia1st: return "Pustelnia1st"; + case CzarnePole1st: return "CzarnePole1st"; + case TalkArivNum: return "TalkArivNum"; + case Pfui: return "Pfui"; + case MapaSunlordEnabled:return "MapaSunlordEnabled"; + case WebDone: return "WebDone"; + case DragonDone: return "DragonDone"; + case KanPlay: return "KanPlay"; + case OldKanPlay: return "OldKanPlay"; + case LapkiWait: return "LapkiWait"; + case WebNoCheck: return "WebNoCheck"; + case Perfumeria: return "Perfumeria"; + case SmokNoCheck: return "SmokNoCheck"; + case IluzjaBroken: return "IluzjaBroken"; + case IluzjaWorking: return "IluzjaWorking"; + case IluzjaCounter: return "IluzjaCounter"; + case KurhanOpen1: return "KurhanOpen1"; + case KastetTaken: return "KastetTaken"; + case KastetDown: return "KastetDown"; + case KurhanDone: return "KurhanDone"; + case SkelCounter: return "SkelCounter"; + case SkelDial1: return "SkelDial1"; + case SkelDial2: return "SkelDial2"; + case SkelDial3: return "SkelDial3"; + case SkelDial4: return "SkelDial4"; + case SameTalker: return "SameTalker"; + case RunMonstersText: return "RunMonstersText"; + case PiwnicaChecked: return "PiwnicaChecked"; + case DragonTalked: return "DragonTalked"; + case ToldAboutBook: return "ToldAboutBook"; + case SilmanionaDone: return "SilmanionaDone"; + case ToldBookCount: return "ToldBookCount"; + case SmrodNoCheck: return "SmrodNoCheck"; + case RopeTaken: return "RopeTaken"; + case RopeTime: return "RopeTime"; + case LaskaFree: return "LaskaFree"; + case ShanSmokTalked: return "ShanSmokTalked"; + case SwordTaken: return "SwordTaken"; + case Mill1st: return "Mill1st"; + case SawRat: return "SawRat"; + case KnowRat: return "KnowRat"; + case DziuraTimer: return "DziuraTimer"; + case LaskaInside: return "LaskaInside"; + case HoleBig: return "HoleBig"; + case EnableWiedzmin: return "EnableWiedzmin"; + case EnableTrucizna: return "EnableTrucizna"; + case KnowPoison: return "KnowPoison"; + case KufelTaken: return "KufelTaken"; + case BojkaEnabled: return "BojkaEnabled"; + case BitwaNot1st: return "BitwaNot1st"; + case BojkaTimer: return "BojkaTimer"; + case BojkaGirl: return "BojkaGirl"; + case Look1st: return "Look1st"; + case RatTaken: return "RatTaken"; + case LaskaTalkedGr: return "LaskaTalkedGr"; + case RatusGivus: return "RatusGivus"; + case MamObole: return "MamObole"; + case Speed1st: return "Speed1st"; + case SpeedTimer: return "SpeedTimer"; + case ProveIt: return "ProveIt"; + case Proven: return "Proven"; + case ShowWoalka: return "ShowWoalka"; + case PoisonTaken: return "PoisonTaken"; + case HellOpened: return "HellOpened"; + case HellNoCheck: return "HellNoCheck"; + case TalAn1: return "TalAn1"; + case TalAn2: return "TalAn2"; + case TalAn3: return "TalAn3"; + case TalkDevilGuard: return "TalkDevilGuard"; + case Sword1st: return "Sword1st"; + case IluzjaNoCheck: return "IluzjaNoCheck"; + case RozdzielniaNumber: return "RozdzielniaNumber"; + case JailChecked: return "JailChecked"; + case JailTalked: return "JailTalked"; + case TrickFailed: return "TrickFailed"; + case WegielVisible: return "WegielVisible"; + case WegielTimer1: return "WegielTimer1"; + case RandomSample: return "RandomSample"; + case RandomSampleTimer: return "RandomSampleTimer"; + case SampleTimer: return "SampleTimer"; + case ZonaSample: return "ZonaSample"; + case HoleTryAgain: return "HoleTryAgain"; + case TeleportTimer: return "TeleportTimer"; + case RozLezy: return "RozLezy"; + case UdkoTimer: return "UdkoTimer"; + case ZaworZatkany: return "ZaworZatkany"; + case ZaworOpened: return "ZaworOpened"; + case DoorExploded: return "DoorExploded"; + case SkoraTaken: return "SkoraTaken"; + case CiezkieByl: return "CiezkieByl"; + case MamWegiel: return "MamWegiel"; + case SwiecaAway: return "SwiecaAway"; + case ITSAVE: return "ITSAVE"; + case RozpadlSie: return "RozpadlSie"; + case WegielFullTimer: return "WegielFullTimer"; + case WegielDown: return "WegielDown"; + case WegielDownTimer: return "WegielDownTimer"; + case PaliSie: return "PaliSie"; + case DiabGuardTalked: return "DiabGuardTalked"; + case GuardsNoCheck: return "GuardsNoCheck"; + case TalkedPowloka: return "TalkedPowloka"; + case JailOpen: return "JailOpen"; + case PrzytulTimer: return "PrzytulTimer"; + case JailDone: return "JailDone"; + case MamMonety: return "MamMonety"; + case LotTimer: return "LotTimer"; + case LotObj: return "LotObj"; + case PtakTimer: return "PtakTimer"; + case BookTimer: return "BookTimer"; + case BookGiba: return "BookGiba"; + case PtakLata: return "PtakLata"; + case Podej: return "Podej"; + case GotHint: return "GotHint"; + case LawaLeci: return "LawaLeci"; + case PowerKlik: return "PowerKlik"; + case LucekBad: return "LucekBad"; + case LucekBad1st: return "LucekBad1st"; + case IntroDial1: return "IntroDial1"; + case IntroDial2: return "IntroDial2"; + case ItsOutro: return "ItsOutro"; + case KamienComment: return "KamienComment"; + case KamienSkip: return "KamienSkip"; + case TesterFlag: return "TesterFlag"; + case RememberLine: return "RememberLine"; + case OpisLapek: return "OpisLapek"; + case TalWait: return "TalWait"; + case OpisKamienia: return "OpisKamienia"; + case JumpBox: return "JumpBox"; + case JumpBox1: return "JumpBox1"; + case JumpBox2: return "JumpBox2"; + case JumpBox3: return "JumpBox3"; + case SpecPiesek: return "SpecPiesek"; + case SpecPiesekCount: return "SpecPiesekCount"; + case SpecPiesekGadanie: return "SpecPiesekGadanie"; + case ZnikaFlag: return "ZnikaFlag"; + case ZnikaTimer: return "ZnikaTimer"; + case SowaTimer: return "SowaTimer"; + case MamrotanieOff: return "MamrotanieOff"; + + case CURRMOB: return "CURRMOB"; + case KOLOR: return "KOLOR"; + case MBFLAG: return "MBFLAG"; + case MXFLAG: return "MXFLAG"; + case MYFLAG: return "MYFLAG"; + case SCROLLTYPE: return "SCROLLTYPE"; + case SCROLLVALUE: return "SCROLLVALUE"; + case SCROLLVALUE2: return "SCROLLVALUE2"; + case TALKEXITCODE: return "TALKEXITCODE"; + case SPECROUTFLAG1: return "SPECROUTFLAG1"; + case SPECROUTFLAG2: return "SPECROUTFLAG2"; + case SPECROUTFLAG3: return "SPECROUTFLAG3"; + case TALKFLAGCODE: return "TALKFLAGCODE"; + case CURRROOM: return "CURRROOM"; + case Talker1Init: return "Talker1Init"; + case Talker2Init: return "Talker2Init"; + case RESTOREROOM: return "RESTOREROOM"; + case INVALLOWED: return "INVALLOWED"; + case BOXSEL: return "BOXSEL"; + case CURSEBLINK: return "CURSEBLINK"; + case EXACTMOVE: return "EXACTMOVE"; + case MOVEDESTX: return "MOVEDESTX"; + case MOVEDESTY: return "MOVEDESTY"; + case NOANTIALIAS: return "NOANTIALIAS"; + case ESCAPED: return "ESCAPED"; + case ALLOW1OPTION: return "ALLOW1OPTION"; + case VOICE_H_LINE: return "VOICE_H_LINE"; + case VOICE_A_LINE: return "VOICE_A_LINE"; + case VOICE_B_LINE: return "VOICE_B_LINE"; + case VOICE_C_LINE: return "VOICE_C_LINE"; + case NOHEROATALL: return "NOHEROATALL"; + case MOUSEENABLED: return "MOUSEENABLED"; + case DIALINES: return "DIALINES"; + + case SHANWALK: return "SHANWALK"; + case SHANDOG: return "SHANDOG"; + case GETACTIONBACK: return "GETACTIONBACK"; + case GETACTIONDATA: return "GETACTIONDATA"; + case GETACTION: return "GETACTION"; + case HEROFAST: return "HEROFAST"; + case SELITEM: return "SELITEM"; + case LMOUSE: return "LMOUSE"; + case MINMX: return "MINMX"; + case MAXMX: return "MAXMX"; + case MINMY: return "MINMY"; + case MAXMY: return "MAXMY"; + case TORX1: return "TORX1"; + case TORY1: return "TORY1"; + case TORX2: return "TORX2"; + case TORY2: return "TORY2"; + case POWER: return "POWER"; + case POWERENABLED: return "POWERENABLED"; + case FLCRESTORE: return "FLCRESTORE"; + case NOCLSTEXT: return "NOCLSTEXT"; + case ESCAPED2: return "ESCAPED2"; + } +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/flags.h b/engines/prince/flags.h new file mode 100644 index 0000000000..aa607a01fe --- /dev/null +++ b/engines/prince/flags.h @@ -0,0 +1,416 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_FLAGS_H +#define PRINCE_FLAGS_H + +#include "common/scummsys.h" + +namespace Prince { + +struct Flags { + + // TODO: Remove from release build + // useful just for debugging + static const char * getFlagName(uint16 flagId); + + enum Id { + FLAGA1 = 0x8000, + FLAGA2 = 0x8002, + FLAGA3 = 0x8004, + DESTX = 0x8006, + DESTY = 0x8008, + DESTD = 0x800A, + DwarfDone = 0x800C, + GRABARZCOUNTER = 0x800E, + KIERUNEK = 0x8010, + BACKFLAG1 = 0x8012, + BACKFLAG2 = 0x8014, + BACKFLAG3 = 0x8016, + BACKFLAG4 = 0x8018, + MACROFLAG1 = 0x801A, + MACROFLAG2 = 0x801C, + MACROFLAG3 = 0x801E, + HEROLDDONE = 0x8020, + BRIDGESET = 0x8022, + U_BT_1 = 0x8024, + U_BT_2 = 0x8026, + U_BT_3 = 0x8028, + U_BT_4 = 0x802A, + U_BT_5 = 0x802C, + U_BT_6 = 0x802E, + U_BT_7 = 0x8030, + U_BT_8 = 0x8032, + U_BT_9 = 0x8034, + U_BT_COUNTER = 0x8036, + ARIVALDALIVE = 0x8038, + TALKCHAR1 = 0x803A, + TalkType1 = 0x803C, + TALKROUT1 = 0x803E, + TALKROUT2 = 0x8042, + TALKROUT3 = 0x8046, + TALKROUT4 = 0x804A, + TALKANIM1 = 0x804E, + TALKANIM2 = 0x8050, + TALKCOLOR1 = 0x8052, + TALKCOLOR2 = 0x8054, + KapciuchTaken = 0x8056, + CurrentBeggarA = 0x8058, + TempKapc = 0x805A, + HomTaken = 0x805C, + WizardTalk = 0x805E, + SunlordTalk = 0x8060, + HermitTalk = 0x8062, + RunyMode = 0x8064, + FatMerchantTalk = 0x8066, + HotDogTalk = 0x8068, + ThiefTalk = 0x806A, + BeggarTalk = 0x806C, + // DwarfTalk = 0x806E, // Redefinition + MonkTalk = 0x8070, + BardTalk = 0x8072, + BarmanTalk = 0x8074, + LeftPlayerTalk = 0x8076, + OczySowy = 0x8078, + CzachySpeed1 = 0x807A, + CzachySpeed2 = 0x807C, + CzachySpeed3 = 0x807E, + CzachySlowDown1 = 0x8080, + CzachySlowDown2 = 0x8082, + CzachySlowDown3 = 0x8084, + FjordDane = 0x8086, + GKopany1 = 0x8088, + GKopany2 = 0x808A, + GKopany3 = 0x808C, + GKopany4 = 0x808E, + KnowGodWord = 0x8090, + TALKROUT21 = 0x8092, + TALKROUT22 = 0x8096, + TALKROUT23 = 0x809A, + TALKROUT24 = 0x809E, + TalkType2 = 0x80A2, + GrabarzTalk = 0x80A4, + LastTalker = 0x80A6, + MapaPustelniaEnabled = 0x80A8, + MapaTempleEnabled = 0x80AA, + MapaFjordEnabled = 0x80AC, + MapaSilmanionaEnabled = 0x80AE, + MapaKurhanEnabled = 0x80B0, + MapaDragonEnabled = 0x80B2, + MapaMillEnabled = 0x80B4, + DwarfRunning = 0x80B6, + DwarfTalk = 0x80B8, + CurseLift = 0x80BA, + KosciSwapped = 0x80BC, + BookStolen = 0x80BE, + MapaUsable = 0x80C0, + FjordBoss = 0x80C2, + FjordHotDog = 0x80C4, + FjordLewy = 0x80C6, + FjordPrawy = 0x80C8, + TalkArivald = 0x80CA, + ShootDone = 0x80CC, + ShootRunning = 0x80CE, + ShootKnow = 0x80D0, + MirrorKnow = 0x80D2, + Gar1stTime = 0x80D4, + KosciTaken = 0x80D6, + ArivGotSpell = 0x80D8, + BookGiven = 0x80DA, + Wywieszka = 0x80DC, + TalkSheila = 0x80DE, + TalkSheila2 = 0x80E0, + BackHuman = 0x80E2, + SkarbiecOpen = 0x80E4, + LustroTaken = 0x80E6, + GargoyleHom = 0x80E8, + GargoyleBroken = 0x80EA, + FjordDzien = 0x80EC, + GargoyleHom2 = 0x80EE, + RunMonstersRunning = 0x80F0, + FoundPaperInCoffin = 0x80F2, + KnowSunlord = 0x80F4, + KnowSunlordTalk = 0x80F6, + ArivaldCzyta = 0x80F8, + TelepX = 0x80FA, + TelepY = 0x80FC, + TelepDir = 0x80FE, + TelepRoom = 0x8100, + ListStolen = 0x8102, + WifeInDoor = 0x8104, + TalkWifeFlag = 0x8106, + LetterGiven = 0x8108, + LutniaTaken = 0x810A, + BardHomeOpen = 0x810C, + FjordNoMonsters = 0x810E, + ShandriaWallTalking = 0x8110, + ShandriaWallCounter = 0x8112, + ShandriaWallDone = 0x8114, + FutureDone = 0x8116, + TalkButch = 0x8118, + GotSzalik = 0x811A, + GotCzosnek = 0x811C, + BearDone = 0x811E, + NekrVisited = 0x8120, + SunRiddle = 0x8122, + PtaszekAway = 0x8124, + KotGadanie = 0x8126, + SzlafmycaTaken = 0x8128, + BabkaTalk = 0x812A, + SellerTalk = 0x812C, + CzosnekDone = 0x812E, + PriestCounter = 0x8130, + PriestGest1 = 0x8132, + PriestGest2 = 0x8134, + PriestGest3 = 0x8136, + PriestGest4 = 0x8138, + PriestAnim = 0x813A, + HolyWaterTaken = 0x813C, + AxeTaken = 0x813E, + BadylTaken1 = 0x8140, + BadylTaken2 = 0x8142, + BadylSharpened = 0x8144, + PorwanieSmoka = 0x8146, + ShopReOpen = 0x8148, + LuskaShown = 0x814A, + CudKnow = 0x814C, + VampireDead = 0x814E, + MapaVisible1 = 0x8150, + MapaVisible2 = 0x8152, + MapaVisible3 = 0x8154, + MapaVisible4 = 0x8156, + MapaVisible5 = 0x8158, + MapaVisible6 = 0x815A, + MapaVisible7 = 0x815C, + MapaVisible8 = 0x815E, + MapaVisible9 = 0x8160, + MapaX = 0x8162, + MapaY = 0x8164, + MapaD = 0x8166, + OldMapaX = 0x8168, + OldMapaY = 0x816A, + OldMapaD = 0x816C, + MovingBack = 0x816E, + MapaCount = 0x8170, + Pustelnia1st = 0x8172, + CzarnePole1st = 0x8174, + TalkArivNum = 0x8176, + Pfui = 0x8178, + MapaSunlordEnabled = 0x817A, + WebDone = 0x817C, + DragonDone = 0x817E, + KanPlay = 0x8180, + OldKanPlay = 0x8182, + LapkiWait = 0x8184, + WebNoCheck = 0x8186, + Perfumeria = 0x8188, + SmokNoCheck = 0x818A, + IluzjaBroken = 0x818C, + IluzjaWorking = 0x818E, + IluzjaCounter = 0x8190, + KurhanOpen1 = 0x8192, + KastetTaken = 0x8194, + KastetDown = 0x8196, + KurhanDone = 0x8198, + SkelCounter = 0x819A, + SkelDial1 = 0x819C, + SkelDial2 = 0x819E, + SkelDial3 = 0x81A0, + SkelDial4 = 0x81A2, + SameTalker = 0x81A4, + RunMonstersText = 0x81A6, + PiwnicaChecked = 0x81A8, + DragonTalked = 0x81AA, + ToldAboutBook = 0x81AC, + SilmanionaDone = 0x81AE, + ToldBookCount = 0x81B0, + SmrodNoCheck = 0x81B2, + RopeTaken = 0x81B4, + RopeTime = 0x81B6, + LaskaFree = 0x81B8, + ShanSmokTalked = 0x81BA, + SwordTaken = 0x81BC, + Mill1st = 0x81BE, + SawRat = 0x81C0, + KnowRat = 0x81C2, + DziuraTimer = 0x81C4, + LaskaInside = 0x81C6, + HoleBig = 0x81C8, + EnableWiedzmin = 0x81CA, + EnableTrucizna = 0x81CC, + KnowPoison = 0x81CE, + KufelTaken = 0x81D0, + BojkaEnabled = 0x81D2, + BitwaNot1st = 0x81D4, + BojkaTimer = 0x81D6, + BojkaGirl = 0x81D8, + Look1st = 0x81DA, + RatTaken = 0x81DC, + LaskaTalkedGr = 0x81DE, + RatusGivus = 0x81E0, + MamObole = 0x81E2, + Speed1st = 0x81E4, + SpeedTimer = 0x81E6, + ProveIt = 0x81E8, + Proven = 0x81EA, + ShowWoalka = 0x81EC, + PoisonTaken = 0x81EE, + HellOpened = 0x81F0, + HellNoCheck = 0x81F2, + TalAn1 = 0x81F4, + TalAn2 = 0x81F6, + TalAn3 = 0x81F8, + TalkDevilGuard = 0x81fA, + Sword1st = 0x81FC, + IluzjaNoCheck = 0x81FE, + RozdzielniaNumber = 0x8200, + JailChecked = 0x8202, + JailTalked = 0x8204, + TrickFailed = 0x8206, + WegielVisible = 0x8208, + WegielTimer1 = 0x820A, + RandomSample = 0x820C, + RandomSampleTimer = 0x820E, + SampleTimer = 0x8210, + ZonaSample = 0x8212, + HoleTryAgain = 0x8214, + TeleportTimer = 0x8216, + RozLezy = 0x8218, + UdkoTimer = 0x821A, + ZaworZatkany = 0x821C, + ZaworOpened = 0x821E, + DoorExploded = 0x8220, + SkoraTaken = 0x8222, + CiezkieByl = 0x8224, + MamWegiel = 0x8226, + SwiecaAway = 0x8228, + ITSAVE = 0x822A, + RozpadlSie = 0x822C, + WegielFullTimer = 0x822E, + WegielDown = 0x8230, + WegielDownTimer = 0x8232, + PaliSie = 0x8234, + DiabGuardTalked = 0x8236, + GuardsNoCheck = 0x8238, + TalkedPowloka = 0x823A, + JailOpen = 0x823C, + PrzytulTimer = 0x823E, + JailDone = 0x8240, + MamMonety = 0x8242, + LotTimer = 0x8244, + LotObj = 0x8246, + PtakTimer = 0x8248, + BookTimer = 0x824A, + BookGiba = 0x824C, + PtakLata = 0x824E, + Podej = 0x8250, + GotHint = 0x8252, + LawaLeci = 0x8254, + PowerKlik = 0x8258, + LucekBad = 0x825A, + LucekBad1st = 0x825C, + IntroDial1 = 0x825E, + IntroDial2 = 0x8260, + ItsOutro = 0x8262, + KamienComment = 0x8264, + KamienSkip = 0x8266, + TesterFlag = 0x8268, + RememberLine = 0x826A, + OpisLapek = 0x826C, + //OpisKamienia = 0x826E, // Redefinition + TalWait = 0x8270, + OpisKamienia = 0x8272, + JumpBox = 0x8274, + JumpBox1 = 0x8276, + JumpBox2 = 0x8278, + JumpBox3 = 0x827A, + SpecPiesek = 0x827C, + SpecPiesekCount = 0x827E, + SpecPiesekGadanie = 0x8282, + ZnikaFlag = 0x8284, + ZnikaTimer = 0x8286, + SowaTimer = 0x8288, + MamrotanieOff = 0x828A, + // Flagi systemowe do kontroli przez skrypt + // System flags controlled by script + CURRMOB = 0x8400, + KOLOR = 0x8402, + MBFLAG = 0x8404, + MXFLAG = 0x8406, + MYFLAG = 0x8408, + SCROLLTYPE = 0x840A, + SCROLLVALUE = 0x840C, + SCROLLVALUE2 = 0x840E, + TALKEXITCODE = 0x8410, + SPECROUTFLAG1 = 0x8412, + SPECROUTFLAG2 = 0x8414, + SPECROUTFLAG3 = 0x8416, + TALKFLAGCODE = 0x8418, + CURRROOM = 0x841A, + Talker1Init = 0x841C, + Talker2Init = 0x841E, + RESTOREROOM = 0x8420, + INVALLOWED = 0x8422, + BOXSEL = 0x8424, + CURSEBLINK = 0x8426, + EXACTMOVE = 0x8428, + MOVEDESTX = 0x842A, + MOVEDESTY = 0x842C, + NOANTIALIAS = 0x842E, + ESCAPED = 0x8430, + ALLOW1OPTION = 0x8432, + VOICE_H_LINE = 0x8434, + VOICE_A_LINE = 0x8436, + VOICE_B_LINE = 0x8438, + VOICE_C_LINE = 0x843A, + NOHEROATALL = 0x843C, + MOUSEENABLED = 0x843E, + DIALINES = 0x8440, + //SELITEM = 0x8442, // Redefinition + SHANWALK = 0x8444, + SHANDOG = 0x8446, + GETACTIONBACK = 0x8448, + GETACTIONDATA = 0x844C, + GETACTION = 0x8450, + HEROFAST = 0x8452, + SELITEM = 0x8454, + LMOUSE = 0x8456, + MINMX = 0x8458, + MAXMX = 0x845A, + MINMY = 0x845C, + MAXMY = 0x845E, + TORX1 = 0x8460, + TORY1 = 0x8462, + TORX2 = 0x8464, + TORY2 = 0x8466, + POWER = 0x8468, + POWERENABLED = 0x846A, + FLCRESTORE = 0x846C, + NOCLSTEXT = 0x846E, + ESCAPED2 = 0x8470 + }; +}; + +} +#endif +/* vim: set tabstop=4 noexpandtab: */ + diff --git a/engines/prince/font.cpp b/engines/prince/font.cpp new file mode 100644 index 0000000000..40b6d014e6 --- /dev/null +++ b/engines/prince/font.cpp @@ -0,0 +1,91 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/archive.h" +#include "common/debug.h" +#include "common/stream.h" +#include "common/str.h" + +#include "graphics/surface.h" + +#include "prince/font.h" + +namespace Prince { + +Font::Font() { +} + +Font::~Font() { + delete [] _fontData; +} + +bool Font::loadFromStream(Common::SeekableReadStream &stream) { + stream.seek(0); + _fontData = new byte[stream.size()]; + stream.read(_fontData, stream.size()); + return true; +} + +int Font::getFontHeight() const { + return _fontData[5]; +} + +int Font::getMaxCharWidth() const { + return 0; +} + +Font::ChrData Font::getChrData(byte chr) const { + chr -= 32; + uint16 chrOffset = 4*chr+6; + + ChrData chrData; + chrData._width = _fontData[chrOffset+2]; + chrData._height = _fontData[chrOffset+3]; + chrData._pixels = _fontData + READ_LE_UINT16(_fontData + chrOffset); + + return chrData; +} + +int Font::getCharWidth(uint32 chr) const { + return getChrData(chr)._width; +} + +void Font::drawChar(Graphics::Surface *dst, uint32 chr, int posX, int posY, uint32 color) const { + const ChrData chrData = getChrData(chr); + + for (int y = 0; y < chrData._height; ++y) { + for (int x = 0; x < chrData._width; ++x) { + byte d = chrData._pixels[x + (chrData._width * y)]; + if (d == 0) d = 255; + else if (d == 1) d = 0; + else if (d == 2) d = color; + else if (d == 3) d = 0; + if (d != 255) { + *(byte*)dst->getBasePtr(posX + x, posY + y) = d; + } + } + } +} + +} + +/* vim: set tabstop=4 expandtab!: */ diff --git a/engines/prince/font.h b/engines/prince/font.h new file mode 100644 index 0000000000..bf9c09d0e9 --- /dev/null +++ b/engines/prince/font.h @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PRINCE_FONT_H +#define PRINCE_FONT_H + +#include "graphics/font.h" + +namespace Graphics { + struct Surface; +} + +namespace Common { + class String; +} + +namespace Prince { + +class Font : public Graphics::Font { +public: + Font(); + virtual ~Font(); + + bool loadFromStream(Common::SeekableReadStream &stream); + + virtual int getFontHeight() const override; + + virtual int getMaxCharWidth() const override; + + virtual int getCharWidth(uint32 chr) const override; + + virtual void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override; + + virtual int getKerningOffset(uint32 left, uint32 right) const override { return -2; } + +private: + struct ChrData { + byte *_pixels; + byte _width; + byte _height; + }; + + ChrData getChrData(byte chr) const; + + byte *_fontData; +}; + +} + +#endif + +/* vim: set tabstop=4 expandtab!: */ diff --git a/engines/prince/graphics.cpp b/engines/prince/graphics.cpp new file mode 100644 index 0000000000..3f9517a6e9 --- /dev/null +++ b/engines/prince/graphics.cpp @@ -0,0 +1,87 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/graphics.h" + +#include "prince/prince.h" + +#include "graphics/palette.h" + +namespace Prince { + +GraphicsMan::GraphicsMan(PrinceEngine *vm) + : _vm(vm), _changed(false) { + initGraphics(640, 480, true); + _frontScreen = new Graphics::Surface(); + _frontScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8()); +} + +GraphicsMan::~GraphicsMan() { + _frontScreen->free(); + delete _frontScreen; +} + +void GraphicsMan::update() { + if (_changed) { + _vm->_system->copyRectToScreen((byte*)_frontScreen->getBasePtr(0,0), 640, 0, 0, 640, 480); + + _vm->_system->updateScreen(); + _changed = false; + } +} + +void GraphicsMan::setPalette(const byte *palette) { + _vm->_system->getPaletteManager()->setPalette(palette, 0, 256); +} + +void GraphicsMan::change() { + _changed = true; +} + +void GraphicsMan::draw(uint16 posX, uint16 posY, const Graphics::Surface *s) +{ + uint16 w = MIN(_frontScreen->w, s->w); + for (uint y = 0; y < s->h; y++) { + if (y < _frontScreen->h) { + memcpy((byte*)_frontScreen->getBasePtr(0, y), (byte*)s->getBasePtr(0, y), w); + } + } + change(); +} + +void GraphicsMan::drawTransparent(uint16 posX, uint16 posY, const Graphics::Surface *s) +{ + for (uint y = 0; y < s->h; ++y) { + for (uint x = 0; x < s->w; ++x) { + byte pixel = *((byte*)s->getBasePtr(x, y)); + if (pixel != 255) { + //*((byte*)_frontScreen->getBasePtr(x, y)) = pixel; + *((byte*)_frontScreen->getBasePtr(x + posX, y + posY)) = pixel; + } + } + } + change(); +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/graphics.h b/engines/prince/graphics.h new file mode 100644 index 0000000000..1766e2a04e --- /dev/null +++ b/engines/prince/graphics.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_GRAPHICS_H +#define PRINCE_GRAPHICS_H + +#include "graphics/surface.h" + + +namespace Prince { + +class PrinceEngine; + +class GraphicsMan +{ +public: + GraphicsMan(PrinceEngine *vm); + ~GraphicsMan(); + + void update(); + + void change(); + + void setPalette(const byte *palette); + + void draw(uint16 x, uint16 y, const Graphics::Surface *s); + void drawTransparent(uint16 x, uint16 y, const Graphics::Surface *s); + + Graphics::Surface *_frontScreen; + Graphics::Surface *_backScreen; + const Graphics::Surface *_roomBackground; + +private: + + PrinceEngine *_vm; + + bool _changed; +}; + +} + +#endif diff --git a/engines/prince/hero.cpp b/engines/prince/hero.cpp new file mode 100644 index 0000000000..81e686c740 --- /dev/null +++ b/engines/prince/hero.cpp @@ -0,0 +1,333 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "common/debug.h" +#include "common/random.h" + +#include "prince/hero.h" +#include "prince/hero_set.h" +#include "prince/animation.h" +#include "prince/resource.h" + + +namespace Prince { + +Hero::Hero() : _number(0), _visible(false), _state(MOVE), _middleX(0), _middleY(0) + , _boreNum(1), _currHeight(0), _moveDelay(0), _shadMinus(1), _moveSetType(0) + , _lastDirection(DOWN), _destDirection(DOWN), _talkTime(0), _boredomTime(0), _phase(0) + , _specAnim(0), _drawX(0), _drawY(0), _randomSource("prince"), _zoomFactor(0), _scaleValue(0) +{ + _zoomBitmap = new Animation(); +} + +Hero::~Hero() { + delete _zoomBitmap; +} + +bool Hero::loadAnimSet(uint32 animSetNr) { + if (animSetNr > sizeof(heroSetTable)) { + return false; + } + + for (uint32 i = 0; i < _moveSet.size(); ++i) { + delete _moveSet[i]; + } + + const HeroSetAnimNames &animSet = *heroSetTable[animSetNr]; + + _moveSet.resize(kMoveSetSize); + for (uint32 i = 0; i < kMoveSetSize; ++i) { + debug("Anim set item %d %s", i, animSet[i]); + Animation *anim = NULL; + if (animSet[i] != NULL) { + anim = new Animation(); + Resource::loadResource(anim, animSet[i]); + } + _moveSet[i] = anim; + } + + return true; +} + +const Graphics::Surface * Hero::getSurface() { + if (_moveSet[_moveSetType]) { + //debug("BaseX: %d", _moveSet[_moveSetType]->getBaseX()); + //debug("BaseY: %d", _moveSet[_moveSetType]->getBaseY()); + //debug("FrameCount: %d", _moveSet[_moveSetType]->getFrameCount()); + //debug("LoopCount: %d", _moveSet[_moveSetType]->getLoopCount()); + //debug("PhaseCount: %d", _moveSet[_moveSetType]->getPhaseCount()); + //debug("PhaseFrameIndex(%d): %d", _frame, _moveSet[_moveSetType]->getPhaseFrameIndex(_frame)); + //debug("PhaseOffsetX(%d): %d", _frame, _moveSet[_moveSetType]->getPhaseOffsetX(_frame)); + //debug("PhaseOffsetY(%d) %d", _frame, _moveSet[_moveSetType]->getPhaseOffsetY(_frame)); + //debug("FrameSizeX(%d) %d", _frame, _moveSet[_moveSetType]->getFrameWidth(_frame)); + //debug("FrameSizeY(%d) %d", _frame, _moveSet[_moveSetType]->getFrameHeight(_frame)); + //getState(); + int16 phaseFrameIndex = _moveSet[_moveSetType]->getPhaseFrameIndex(_phase); + return _moveSet[_moveSetType]->getFrame(phaseFrameIndex); + } + return NULL; +} + +//TEMP +void Hero::getState() { + switch (_state) { + case STAY: + debug("STAY"); + break; + case TURN: + debug("TURN"); + break; + case MOVE: + debug("MOVE"); + break; + case BORE: + debug("BORE"); + break; + case SPEC: + debug("SPEC"); + break; + case TALK: + debug("TALK"); + break; + case MVAN: + debug("MVAN"); + break; + case TRAN: + debug("TRAN"); + break; + case RUN: + debug("RUN"); + break; + case DMOVE: + debug("DMOVE"); + break; + } +} + +//TODO +void Hero::countDrawPosition() { + int16 frameXSize = _moveSet[_moveSetType]->getFrameWidth(_phase); + int16 frameYSize = _moveSet[_moveSetType]->getFrameHeight(_phase); + _drawX = _middleX - frameXSize/2; + _drawY = _middleY - frameYSize; +} + +void Hero::showHeroAnimFrame() { + if (_phase < _moveSet[_moveSetType]->getFrameCount() - 1) { + _phase++; + } else { + _phase = 0; + } + countDrawPosition(); + //debug("_drawX: %d", _drawX); + //debug("_drawY: %d", _drawY); + //debug("_middleX: %d", _middleX); + //debug("_middleY: %d", _middleY); +} + +void Hero::setScale(int8 zoomBitmapValue) { + if (zoomBitmapValue == 0) { + _zoomFactor = 1; + } else { + _zoomFactor = zoomBitmapValue; + } + _scaleValue = 10000 / _zoomFactor; + debug("_scaleValue: %d", _scaleValue); +} + +void Hero::selectZoom() { + int8 zoomBitmapValue = _zoomBitmap->getZoom(_middleY / 4 * kZoomBitmapWidth + _middleX / 4); + debug("offset: %d", _middleY / 4 * kZoomBitmapWidth + _middleX / 4); + debug("zoomBitmapValue: %d", _zoomFactor); + setScale(zoomBitmapValue); +} + +void Hero::specialAnim() { +} + +void Hero::rotateHero() { + switch (_lastDirection) { + case LEFT: + switch (_destDirection) { + case RIGHT: + _moveSetType = Move_MLR; + break; + case UP: + _moveSetType = Move_MLU; + break; + case DOWN: + _moveSetType = Move_MLD; + break; + } + break; + case RIGHT: + switch (_destDirection) { + case LEFT: + _moveSetType = Move_MRL; + break; + case UP: + _moveSetType = Move_MRU; + break; + case DOWN: + _moveSetType = Move_MRD; + break; + } + break; + case UP: + switch (_destDirection) { + case LEFT: + _moveSetType = Move_MUL; + break; + case RIGHT: + _moveSetType = Move_MUR; + break; + case DOWN: + _moveSetType = Move_MUD; + break; + } + break; + case DOWN: + switch (_destDirection) { + case LEFT: + _moveSetType = Move_MDL; + break; + case RIGHT: + _moveSetType = Move_MDR; + break; + case UP: + _moveSetType = Move_MDU; + break; + } + break; + } +} + +void Hero::showHero() { + if (_visible) { + // Is he talking? + if (_talkTime == 0) { //? + // Scale of hero + selectZoom(); + switch (_state) { + case STAY: + //if(OptionsFlag == false) { + //if(OpcodePC == null) { + _boredomTime++; + if (_boredomTime == 200) { // 140 for second hero + _boredomTime = 0; + _state = BORE; + } + switch (_lastDirection) { + case LEFT: + _moveSetType = Move_SL; + break; + case RIGHT: + _moveSetType = Move_SR; + break; + case UP: + _moveSetType = Move_SU; + break; + case DOWN: + _moveSetType = Move_SD; + break; + } + break; + case TURN: + /* + if(_lastDirection == _destDirection) { + _state = STAY; + } else { + _frame = 0; + rotateHero(); + _lastDirection = _destDirection; + } + */ + break; + case MOVE: + switch (_lastDirection) { + case LEFT: + _moveSetType = Move_ML; + break; + case RIGHT: + _moveSetType = Move_MR; + break; + case UP: + _moveSetType = Move_MU; + break; + case DOWN: + _moveSetType = Move_MD; + break; + } + break; + case BORE: + //if (_direction == UP) { + switch (_boreNum) { + case 0: + _moveSetType = Move_BORED1; + break; + case 1: + _moveSetType = Move_BORED2; + break; + } + if (_phase == _moveSet[_moveSetType]->getFrameCount() - 1) { + _boreNum = _randomSource.getRandomNumber(1); // rand one of two 'bored' animation + _lastDirection = DOWN; + _state = STAY; + } + break; + case SPEC: + //specialAnim(); + break; + case TALK: + switch (_lastDirection) { + case LEFT: + _moveSetType = Move_TL; + break; + case RIGHT: + _moveSetType = Move_TR; + break; + case UP: + _moveSetType = Move_TU; + break; + case DOWN: + _moveSetType = Move_TD; + break; + } + break; + case TRAN: + break; + case RUN: + break; + case DMOVE: + break; + } + } else { + _talkTime--; // o ile? + } + showHeroAnimFrame(); + } else { + // no hero visible + return; + } +} +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/hero.h b/engines/prince/hero.h new file mode 100644 index 0000000000..e01a5c071f --- /dev/null +++ b/engines/prince/hero.h @@ -0,0 +1,160 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_HERO_H +#define PRINCE_HERO_H + +#include "common/scummsys.h" +#include "common/array.h" + +#include "graphics/surface.h" + +namespace Prince { + +class Animation; + +class Hero { +public: + static const uint32 kMoveSetSize = 26; + static const int16 kZoomStep = 4; + static const int16 kMaxPicWidth = 1280; + static const int16 kZoomBitmapWidth = kMaxPicWidth / kZoomStep; + + enum State { + STAY = 0, + TURN = 1, + MOVE = 2, + BORE = 3, + SPEC = 4, + TALK = 5, + MVAN = 6, + TRAN = 7, + RUN = 8, + DMOVE = 9 + }; + + enum Direction { + LEFT = 1, + RIGHT = 2, + UP = 3, + DOWN = 4 + }; + + enum MoveSet { + Move_SL, + Move_SR, + Move_SU, + Move_SD, + Move_ML, + Move_MR, + Move_MU, + Move_MD, + Move_TL, + Move_TR, + Move_TU, + Move_TD, + Move_MLU, + Move_MLD, + Move_MLR, + Move_MRU, + Move_MRD, + Move_MRL, + Move_MUL, + Move_MUR, + Move_MUD, + Move_MDL, + Move_MDR, + Move_MDU, + Move_BORED1, + Move_BORED2 + }; + + Hero(); + ~Hero(); + Common::RandomSource _randomSource; + bool loadAnimSet(uint32 heroAnimNumber); + + const Graphics::Surface * getSurface(); + + void setPos(int16 x, int16 y) { _middleX = x; _middleY = y; } + void setVisible(bool flag) { _visible = flag; } + + void showHero(); + void moveHero(); + void rotateHero(); + void setScale(int8 zoomBitmapValue); + void selectZoom(); + void countDrawPosition(); + void showHeroAnimFrame(); + void specialAnim(); + void getState(); + +//private: + uint16 _number; + uint16 _visible; + int16 _state; + int16 _middleX; // middle of X + int16 _middleY; // lower part of hero + int16 _drawX; + int16 _drawY; + int16 _lastDirection; + int16 _destDirection; + int16 _moveSetType; + int8 _zoomFactor; + int16 _scaleValue; + + // Coords array of coordinates + // DirTab array of directions + // CurrCoords current coordinations + // CurrDirTab current direction + // LastDir previous move direction + // DestDir + // LeftRight previous left/right direction + // UpDown previous up/down direction + uint _phase; // Phase animation phase + // Step x/y step size depends on direction + // MaxBoredom stand still timeout + int16 _boredomTime;// Boredom current boredom time in frames + uint16 _boreNum; // Bore anim frame + int16 _talkTime; // TalkTime time of talk anim + int32 _specAnim; // SpecAnim additional anim + + uint16 _currHeight; // height of current anim phase + + // Inventory array of items + // Inventory2 array of items + // Font subtitiles font + // Color subtitiles color + // AnimSet number of animation set + Common::Array<Animation *> _moveSet; // MoveAnims MoveSet + // TurnAnim ?? + Animation *_zoomBitmap; // change to sth else, not Animation ?? + + uint32 _moveDelay; + uint32 _shadMinus; //?? +}; + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/hero_set.cpp b/engines/prince/hero_set.cpp new file mode 100644 index 0000000000..a8c05de724 --- /dev/null +++ b/engines/prince/hero_set.cpp @@ -0,0 +1,243 @@ + +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/hero_set.h" +#include "common/scummsys.h" + +namespace Prince { + +static HeroSetAnimNames heroSet5= { + "SL_DIAB.ANI", + "SR_DIAB.ANI", + "SU_DIAB.ANI", + "SD_DIAB.ANI", + NULL, + NULL, + "MU_DIAB.ANI", + "MD_DIAB.ANI", + "TL_DIAB.ANI", + "TR_DIAB.ANI", + "TU_DIAB.ANI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static HeroSetAnimNames heroSet1= { + "SL_HERO1.ANI", + "SR_HERO1.ANI", + "SU_HERO1.ANI", + "SD_HERO1.ANI", + "ML_HERO1.ANI", + "MR_HERO1.ANI", + "MU_HERO1.ANI", + "MD_HERO1.ANI", + "TL_HERO1.ANI", + "TR_HERO1.ANI", + "TU_HERO1.ANI", + "TD_HERO1.ANI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "KSI_KURZ.ANI", + "KS_WLOSY.ANI" +}; + +static HeroSetAnimNames heroSet2= { + "SL_HERO2.ANI", + "SR_HERO2.ANI", + "SU_HERO2.ANI", + "SD_HERO2.ANI", + "ML_HERO2.ANI", + "MR_HERO2.ANI", + "MU_HERO2.ANI", + "MD_HERO2.ANI", + "TL_HERO2.ANI", + "TR_HERO2.ANI", + "TU_HERO2.ANI", + "TD_HERO2.ANI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "KSI_KU_S.ANI", + "KS_WLO_S.ANI" +}; + +static HeroSetAnimNames heroSet3= { + "SL_BEAR.ANI", + "SR_BEAR.ANI", + "SU_BEAR.ANI", + "SD_BEAR.ANI", + "NIED-LEW.ANI", + "NIED-PRW.ANI", + "NIED-TYL.ANI", + "NIED-PRZ.ANI", + "SL_BEAR.ANI", + "SR_BEAR.ANI", + "SU_BEAR.ANI", + "SD_BEAR.ANI", + "N_LW-TYL.ANI", + "N_LW-PRZ.ANI", + "N_LW-PR.ANI", + "N_PR-TYL.ANI", + "N_PR-PRZ.ANI", + "N_PR-LW.ANI", + "N_TYL-LW.ANI", + "N_TYL-PR.ANI", + "N_TL-PRZ.ANI", + "N_PRZ-LW.ANI", + "N_PRZ-PR.ANI", + "N_PRZ-TL.ANI", + NULL, + NULL, +}; + +static HeroSetAnimNames shanSet1= { + "SL_SHAN.ANI", + "SR_SHAN.ANI", + "SU_SHAN.ANI", + "SD_SHAN.ANI", + "ML_SHAN.ANI", + "MR_SHAN.ANI", + "MU_SHAN.ANI", + "MD_SHAN.ANI", + "TL_SHAN.ANI", + "TR_SHAN.ANI", + "TU_SHAN.ANI", + "TD_SHAN.ANI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "B1_SHAN.ANI", + "B2_SHAN.ANI", +}; + +static HeroSetAnimNames shanSet2= { + "SL_SHAN2.ANI", + "SR_SHAN2.ANI", + "SU_SHAN.ANI", + "SD_SHAN2.ANI", + "ML_SHAN2.ANI", + "MR_SHAN2.ANI", + "MU_SHAN.ANI", + "MD_SHAN2.ANI", + "TL_SHAN2.ANI", + "TR_SHAN2.ANI", + "TU_SHAN.ANI", + "TD_SHAN2.ANI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "B1_SHAN2.ANI", + "B2_SHAN2.ANI" +}; + +static HeroSetAnimNames arivSet1= { + "SL_ARIV.ANI", + "SR_ARIV.ANI", + "SU_ARIV.ANI", + "SD_ARIV.ANI", + "ML_ARIV.ANI", + "MR_ARIV.ANI", + "MU_ARIV.ANI", + "MD_ARIV.ANI", + "TL_ARIV.ANI", + "TR_ARIV.ANI", + "TU_ARIV.ANI", + "TD_ARIV.ANI", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +const HeroSetAnimNames *heroSetTable[7] = { + &heroSet1, + &heroSet2, + &heroSet3, + &shanSet1, + &arivSet1, + &heroSet5, + &shanSet2, +}; + +} +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/hero_set.h b/engines/prince/hero_set.h new file mode 100644 index 0000000000..335f70a6ab --- /dev/null +++ b/engines/prince/hero_set.h @@ -0,0 +1,30 @@ +/* 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. + * + */ + +namespace Prince { + +typedef const char *HeroSetAnimNames[26]; + +extern const HeroSetAnimNames *heroSetTable[7]; + +} +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/mhwanh.cpp b/engines/prince/mhwanh.cpp new file mode 100644 index 0000000000..3bd034e4a7 --- /dev/null +++ b/engines/prince/mhwanh.cpp @@ -0,0 +1,74 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/stream.h" + +#include "graphics/surface.h" + +#include "prince/mhwanh.h" + +namespace Prince { + +MhwanhDecoder::MhwanhDecoder() + : _surface(NULL), _palette(0), _paletteColorCount(0) { +} + +MhwanhDecoder::~MhwanhDecoder() { + destroy(); +} + +void MhwanhDecoder::destroy() { + if (_surface) { + _surface->free(); + delete _surface; + _surface = 0; + } + + delete [] _palette; _palette = 0; + _paletteColorCount = 0; +} + +bool MhwanhDecoder::loadStream(Common::SeekableReadStream &stream) { + destroy(); + _paletteColorCount = 256; + stream.seek(0); + stream.skip(0x20); + // Read the palette + _palette = new byte[_paletteColorCount * 3]; + for (uint16 i = 0; i < _paletteColorCount; i++) { + _palette[i * 3 + 0] = stream.readByte(); + _palette[i * 3 + 1] = stream.readByte(); + _palette[i * 3 + 2] = stream.readByte(); + } + + _surface = new Graphics::Surface(); + _surface->create(640, 480, Graphics::PixelFormat::createFormatCLUT8()); + for (int h = 0; h < 480; ++h) { + stream.read(_surface->getBasePtr(0, h), 640); + } + + return true; +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/mhwanh.h b/engines/prince/mhwanh.h new file mode 100644 index 0000000000..5364c5d20a --- /dev/null +++ b/engines/prince/mhwanh.h @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_MHWANH_H +#define PRINCE_MHWANH_H + +#include "image/image_decoder.h" +#include "image/bmp.h" +#include "graphics/surface.h" +#include "resource.h" + +namespace Prince { + +class MhwanhDecoder : public Image::ImageDecoder { +public: + MhwanhDecoder(); + virtual ~MhwanhDecoder(); + + // ImageDecoder API + void destroy(); + virtual bool loadStream(Common::SeekableReadStream &stream); + virtual const Graphics::Surface *getSurface() const { return _surface; } + virtual const byte *getPalette() const { return _palette; } + uint16 getPaletteCount() const { return _paletteColorCount; } + +private: + Graphics::Surface *_surface; + byte *_palette; + uint16 _paletteColorCount; +}; + +namespace Resource { + template <> inline + bool loadFromStream<MhwanhDecoder>(MhwanhDecoder &image, Common::SeekableReadStream &stream) { + return image.loadStream(stream); + } + + template <> inline + bool loadFromStream<Image::BitmapDecoder>(Image::BitmapDecoder &image, Common::SeekableReadStream &stream) { + return image.loadStream(stream); + } +} + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/mob.cpp b/engines/prince/mob.cpp new file mode 100644 index 0000000000..c4bb607347 --- /dev/null +++ b/engines/prince/mob.cpp @@ -0,0 +1,101 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/mob.h" + +#include "common/stream.h" + +namespace Prince { + +bool Mob::loadFromStream(Common::SeekableReadStream &stream) { + int32 pos = stream.pos(); + + uint16 visible = stream.readUint16LE(); + + if (visible == 0xFFFF) + return false; + + _visible = visible; + _type = stream.readUint16LE(); + _rect.left = stream.readUint16LE(); + _rect.top = stream.readUint16LE(); + _rect.right = stream.readUint16LE(); + _rect.bottom = stream.readUint16LE(); + + _mask = stream.readUint16LE(); + + _examPosition.x = stream.readUint16LE(); + _examPosition.y = stream.readUint16LE(); + _examDirection = (Direction)stream.readUint16LE(); + + _usePosition.x = stream.readByte(); + _usePosition.y = stream.readByte(); + _useDirection = (Direction)stream.readUint16LE(); + + uint32 nameOffset = stream.readUint32LE(); + uint32 examTextOffset = stream.readUint32LE(); + + byte c; + stream.seek(nameOffset); + _name.clear(); + while ((c = stream.readByte())) + _name += c; + + stream.seek(examTextOffset); + _examText.clear(); + while ((c = stream.readByte())) + _examText += c; + stream.seek(pos + 32); + + return true; +} + +void Mob::setData(AttrId dataId, uint16 value) { + switch (dataId) { + case ExamDir: + _examDirection = (Direction)value; + break; + case ExamX: + _examPosition.x = value; + break; + case ExamY: + _examPosition.y = value; + break; + default: + assert(false); + } +} + +uint16 Mob::getData(AttrId dataId) { + switch (dataId) { + case Visible: return _visible; + case ExamDir: return _examDirection; + case ExamX: return _examPosition.x; + case ExamY: return _examPosition.y; + default: + assert(false); + } +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/mob.h b/engines/prince/mob.h new file mode 100644 index 0000000000..36630eb6eb --- /dev/null +++ b/engines/prince/mob.h @@ -0,0 +1,86 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_MOB_H +#define PRINCE_MOB_H + +#include "common/scummsys.h" +#include "common/rect.h" +#include "common/str.h" + +#include "prince/common.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Prince { + +class Mob { +public: + + Mob() : _name(""), _examText("") {} + + bool loadFromStream(Common::SeekableReadStream &stream); + + // Used instead of offset in setData and getData + enum AttrId { + Visible = 0, + Type = 2, + X1 = 4, + Y1 = 6, + X2 = 8, + Y2 = 10, + Mask = 12, + ExamX = 14, + ExamY = 16, + ExamDir = 18, + UseX = 20, + UseY = 21, + UseDir = 22, + Name = 24, + ExamText = 28 + }; + + void setData(AttrId dataId, uint16 value); + uint16 getData(AttrId dataId); + + bool _visible; + uint16 _type; + uint16 _mask; + Common::Rect _rect; + + Common::Point _examPosition; + Direction _examDirection; + + Common::Point _usePosition; + Direction _useDirection; + + Common::String _name; + Common::String _examText; +}; + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/module.mk b/engines/prince/module.mk new file mode 100644 index 0000000000..228e5990e2 --- /dev/null +++ b/engines/prince/module.mk @@ -0,0 +1,29 @@ +MODULE := engines/prince + +MODULE_OBJS = \ + animation.o \ + debugger.o \ + script.o \ + graphics.o \ + mhwanh.o \ + detection.o \ + font.o \ + mob.o \ + object.o \ + sound.o \ + flags.o \ + variatxt.o \ + prince.o \ + archive.o \ + decompress.o \ + hero.o \ + hero_set.o \ + cursor.o + +# This module can be built as a plugin +ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/prince/musNum.h b/engines/prince/musNum.h new file mode 100644 index 0000000000..65b31f8175 --- /dev/null +++ b/engines/prince/musNum.h @@ -0,0 +1,87 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +namespace Prince { + +enum RoomMus { + ROOM01MUS = 3, + ROOM02MUS = 9, + ROOM03MUS = 9, + ROOM04MUS = 9, + ROOM05MUS = 13, + ROOM06MUS = 9, + ROOM07MUS = 9, + ROOM08MUS = 9, + ROOM09MUS = 14, + ROOM10MUS = 9, + ROOM11MUS = 9, + ROOM12MUS = 9, + ROOM13MUS = 9, + ROOM14MUS = 9, + ROOM15MUS = 5, + ROOM16MUS = 5, + ROOM17MUS = 5, + ROOM18MUS = 5, + ROOM19MUS = 5, + ROOM20MUS = 12, + ROOM21MUS = 9, + ROOM22MUS = 9, + ROOM23MUS = 1, + ROOM24MUS = 1, + ROOM25MUS = 2, + ROOM26MUS = 10, + ROOM27MUS = 7, + ROOM28MUS = 10, + ROOM29MUS = 10, + ROOM30MUS = 11, + ROOM31MUS = 14, + ROOM32MUS = 11, + ROOM33MUS = 7, + ROOM34MUS = 7, + ROOM35MUS = 7, + ROOM36MUS = 7, + ROOM37MUS = 7, + ROOM38MUS = 7, + ROOM39MUS = 7, + ROOM40MUS = 7, + ROOM41MUS = 7, + ROOM42MUS = 7, + ROOM43MUS = 15, + ROOM46MUS = 100, + ROOM47MUS = 100, + ROOM48MUS = 100, + ROOM49MUS = 100, + ROOM50MUS = 100, + ROOM51MUS = 12, + ROOM52MUS = 9, + ROOM53MUS = 5, + ROOM54MUS = 11, + ROOM55MUS = 11, + ROOM56MUS = 11, + ROOM57MUS = 7, + ROOM58MUS = 13, + ROOM59MUS = 16, + ROOM60MUS = 4, + ROOM61MUS = 0 +}; + +} diff --git a/engines/prince/object.cpp b/engines/prince/object.cpp new file mode 100644 index 0000000000..4148cdf854 --- /dev/null +++ b/engines/prince/object.cpp @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/archive.h" +#include "common/debug-channels.h" +#include "common/debug.h" +#include "common/stream.h" + + +#include "graphics/surface.h" + +#include "prince/object.h" + +namespace Prince { + +Object::Object() : _surface(NULL), _x(0), _y(0), _z(0) { +} + +Object::~Object() { + if (_surface) { + _surface->free(); + delete _surface; + _surface = NULL; + } +} + +void Object::loadSurface(Common::SeekableReadStream &stream) { + stream.skip(4); + + _surface = new Graphics::Surface(); + _surface->create(stream.readUint16LE(), stream.readUint16LE(), Graphics::PixelFormat::createFormatCLUT8()); + for (int h = 0; h < _surface->h; ++h) { + stream.read(_surface->getBasePtr(0, h), _surface->w); + } +} + +bool Object::loadFromStream(Common::SeekableReadStream &stream) { + int32 pos = stream.pos(); + uint16 x = stream.readUint16LE(); + if (x == 0xFFFF) + return false; + _x = x; + _y = stream.readUint16LE(); + + const Common::String obStreamName = Common::String::format("OB%02d", stream.readUint16LE()); + Common::SeekableReadStream *obStream = SearchMan.createReadStreamForMember(obStreamName); + if (!obStream) { + error("Can't load %s", obStreamName.c_str()); + return false; + } + + loadSurface(*obStream); + delete obStream; + + _z = stream.readUint16LE(); + + stream.seek(pos + 16); + + debug("Object x %d, y %d, z %d", _x, _y, _z); + + return true; +} + +} +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/object.h b/engines/prince/object.h new file mode 100644 index 0000000000..7a3d19e906 --- /dev/null +++ b/engines/prince/object.h @@ -0,0 +1,49 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_OBJECT_H +#define PRINCE_OBJECT_H + +#include "image/image_decoder.h" +#include "graphics/surface.h" + +namespace Prince { + +class Object { +public: + Object(); + ~Object(); + + bool loadFromStream(Common::SeekableReadStream &stream); + const Graphics::Surface *getSurface() const { return _surface; } + +private: + void loadSurface(Common::SeekableReadStream &stream); + + Graphics::Surface *_surface; + uint16 _x, _y, _z; +}; + +} + +#endif +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp new file mode 100644 index 0000000000..324c4592ae --- /dev/null +++ b/engines/prince/prince.cpp @@ -0,0 +1,707 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "common/config-manager.h" +#include "common/debug-channels.h" +#include "common/debug.h" +#include "common/events.h" +#include "common/file.h" +#include "common/random.h" +#include "common/fs.h" +#include "common/keyboard.h" +#include "common/substream.h" +#include "common/str.h" + +#include "graphics/cursorman.h" +#include "graphics/surface.h" +#include "graphics/palette.h" +#include "graphics/pixelformat.h" + +#include "engines/util.h" +#include "engines/advancedDetector.h" + +#include "audio/audiostream.h" + +#include "prince/prince.h" +#include "prince/font.h" +#include "prince/graphics.h" +#include "prince/script.h" +#include "prince/debugger.h" +#include "prince/object.h" +#include "prince/mob.h" +#include "prince/sound.h" +#include "prince/variatxt.h" +#include "prince/flags.h" +#include "prince/font.h" +#include "prince/mhwanh.h" +#include "prince/cursor.h" +#include "prince/archive.h" +#include "prince/hero.h" +#include "prince/resource.h" +#include "prince/animation.h" + +namespace Prince { + +void PrinceEngine::debugEngine(const char *s, ...) { + char buf[STRINGBUFLEN]; + va_list va; + + va_start(va, s); + vsnprintf(buf, STRINGBUFLEN, s, va); + va_end(va); + + debug("Prince::Engine frame %08ld %s", _frameNr, buf); +} + +PrinceEngine::PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc) : + Engine(syst), _gameDescription(gameDesc), _graph(nullptr), _script(nullptr), _interpreter(nullptr), _flags(nullptr), + _locationNr(0), _debugger(nullptr), _midiPlayer(nullptr), + _cameraX(0), _newCameraX(0), _frameNr(0), _cursor1(nullptr), _cursor2(nullptr), _font(nullptr), + _walizkaBmp(nullptr), _roomBmp(nullptr), _cursorNr(0) { + + // Debug/console setup + DebugMan.addDebugChannel(DebugChannel::kScript, "script", "Prince Script debug channel"); + DebugMan.addDebugChannel(DebugChannel::kEngine, "engine", "Prince Engine debug channel"); + + DebugMan.enableDebugChannel("script"); + + memset(_voiceStream, 0, sizeof(_voiceStream)); + + gDebugLevel = 10; +} + +PrinceEngine::~PrinceEngine() { + DebugMan.clearAllDebugChannels(); + + delete _rnd; + delete _debugger; + delete _cursor1; + delete _cursor2; + delete _midiPlayer; + delete _script; + delete _flags; + delete _interpreter; + delete _font; + delete _roomBmp; + delete _walizkaBmp; + delete _variaTxt; + delete[] _talkTxt; + delete _graph; + delete _mainHero; + delete _secondHero; + + for (uint32 i = 0; i < _objList.size(); ++i) { + delete _objList[i]; + } + _objList.clear(); +} + +GUI::Debugger *PrinceEngine::getDebugger() { + return _debugger; +} + +void PrinceEngine::init() { + + const Common::FSNode gameDataDir(ConfMan.get("path")); + + debugEngine("Adding all path: %s", gameDataDir.getPath().c_str()); + + PtcArchive *all = new PtcArchive(); + if (!all->open("all/databank.ptc")) + error("Can't open all/databank.ptc"); + + PtcArchive *voices = new PtcArchive(); + if (!voices->open("data/voices/databank.ptc")) + error("Can't open data/voices/databank.ptc"); + + PtcArchive *sound = new PtcArchive(); + if (!sound->open("sound/databank.ptc")) + error("Can't open sound/databank.ptc"); + + SearchMan.addSubDirectoryMatching(gameDataDir, "all"); + + SearchMan.add("all", all); + SearchMan.add("voices", voices); + SearchMan.add("sound", sound); + + _graph = new GraphicsMan(this); + + _rnd = new Common::RandomSource("prince"); + _debugger = new Debugger(this); + + _midiPlayer = new MusicPlayer(this); + + _font = new Font(); + Resource::loadResource(_font, "font1.raw"); + + _walizkaBmp = new MhwanhDecoder(); + Resource::loadResource(_walizkaBmp, "walizka"); + + _script = new Script(); + Resource::loadResource(_script, "skrypt.dat"); + + _flags = new InterpreterFlags(); + _interpreter = new Interpreter(this, _script, _flags); + + _variaTxt = new VariaTxt(); + Resource::loadResource(_variaTxt, "variatxt.dat"); + + _cursor1 = new Cursor(); + Resource::loadResource(_cursor1, "mouse1.cur"); + + _cursor2 = new Cursor(); + Resource::loadResource(_cursor2, "mouse2.cur"); + + Common::SeekableReadStream *talkTxtStream = SearchMan.createReadStreamForMember("talktxt.dat"); + if (!talkTxtStream) { + error("Can't load talkTxtStream"); + return; + } + _talkTxtSize = talkTxtStream->size(); + _talkTxt = new byte[_talkTxtSize]; + talkTxtStream->read(_talkTxt, _talkTxtSize); + + delete talkTxtStream; + + _roomBmp = new Image::BitmapDecoder(); + + _mainHero = new Hero(); + _secondHero = new Hero(); + + _mainHero->loadAnimSet(0); +} + +void PrinceEngine::showLogo() { + MhwanhDecoder logo; + if (Resource::loadResource(&logo, "logo.raw")) { + _graph->setPalette(logo.getPalette()); + _graph->draw(0, 0, logo.getSurface()); + _graph->update(); + _system->delayMillis(700); + } +} + +Common::Error PrinceEngine::run() { + + init(); + + showLogo(); + + mainLoop(); + + return Common::kNoError; +} + +bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) { + int32 pos = stream.pos(); + + uint16 type = stream.readUint16LE(); + if (type == 0xFFFF) { + return false; + } + _type = type; + _fileNumber = stream.readUint16LE(); + _startPhase = stream.readUint16LE(); + _endPhase = stream.readUint16LE(); + _loopPhase = stream.readUint16LE(); + _x = stream.readSint16LE(); + _y = stream.readSint16LE(); + _loopType = stream.readUint16LE(); + _nextAnim = stream.readUint16LE(); + _flags = stream.readUint16LE(); + + debug("AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags); + + + // 32 byte aligment + stream.seek(pos + 32); + + return true; +} + +bool PrinceEngine::loadLocation(uint16 locationNr) { + _flicPlayer.close(); + + memset(_textSlots, 0, sizeof(_textSlots)); + for(uint32 sampleId = 0; sampleId < MAX_SAMPLES; ++sampleId) { + stopSample(sampleId); + } + + debugEngine("PrinceEngine::loadLocation %d", locationNr); + const Common::FSNode gameDataDir(ConfMan.get("path")); + SearchMan.remove(Common::String::format("%02d", _locationNr)); + + _locationNr = locationNr; + _debugger->_locationNr = locationNr; + _cameraX = 0; + _newCameraX = 0; + + _flags->setFlagValue(Flags::CURRROOM, _locationNr); + _interpreter->stopBg(); + + changeCursor(0); + + const Common::String locationNrStr = Common::String::format("%02d", _locationNr); + debugEngine("loadLocation %s", locationNrStr.c_str()); + + PtcArchive *locationArchive = new PtcArchive(); + if (!locationArchive->open(locationNrStr + "/databank.ptc")) + error("Can't open location %s", locationNrStr.c_str()); + + SearchMan.add(locationNrStr, locationArchive); + + const char *musName = MusicPlayer::_musTable[MusicPlayer::_musRoomTable[locationNr]]; + _midiPlayer->loadMidi(musName); + + // load location background, replace old one + Resource::loadResource(_roomBmp, "room"); + if (_roomBmp->getSurface()) { + _sceneWidth = _roomBmp->getSurface()->w; + } + + _mainHero->_zoomBitmap->clear(); + Resource::loadResource(_mainHero->_zoomBitmap, "zoom", false); + + _mobList.clear(); + Resource::loadResource(_mobList, "mob.lst", false); + + for (uint32 i = 0; i < _objList.size(); ++i) { + delete _objList[i]; + } + _objList.clear(); + Resource::loadResource(_objList, "obj.lst", false); + + _animList.clear(); + Resource::loadResource(_animList, "anim.lst", false); + + return true; +} + +void PrinceEngine::changeCursor(uint16 curId) { + _debugger->_cursorNr = curId; + + const Graphics::Surface *curSurface = nullptr; + + uint16 hotspotX = 0; + uint16 hotspotY = 0; + + switch(curId) { + case 0: + CursorMan.showMouse(false); + return; + case 1: + curSurface = _cursor1->getSurface(); + break; + case 2: + curSurface = _cursor2->getSurface(); + hotspotX = curSurface->w >> 1; + hotspotY = curSurface->h >> 1; + break; + } + + CursorMan.replaceCursorPalette(_roomBmp->getPalette(), 0, 255); + CursorMan.replaceCursor( + curSurface->getBasePtr(0, 0), + curSurface->w, curSurface->h, + hotspotX, hotspotY, + 255, false, + &curSurface->format + ); + CursorMan.showMouse(true); +} + +bool PrinceEngine::playNextFrame() { + if (!_flicPlayer.isVideoLoaded()) + return false; + + const Graphics::Surface *s = _flicPlayer.decodeNextFrame(); + if (s) { + _graph->drawTransparent(0, 0, s); + _graph->change(); + } else if (_flicLooped) { + _flicPlayer.rewind(); + playNextFrame(); + } + + return true; +} + +void PrinceEngine::playSample(uint16 sampleId, uint16 loopType) { + if (_voiceStream[sampleId]) { + + if (_mixer->isSoundIDActive(sampleId)) { + return; + } + + Audio::AudioStream *audioStream = Audio::makeWAVStream(_voiceStream[sampleId], DisposeAfterUse::YES); + if (loopType) { + audioStream = new Audio::LoopingAudioStream((Audio::RewindableAudioStream*)audioStream, 0, DisposeAfterUse::NO); + } + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[sampleId], audioStream, sampleId); + } +} + +void PrinceEngine::stopSample(uint16 sampleId) { + _mixer->stopID(sampleId); + _voiceStream[sampleId] = nullptr; +} + +bool PrinceEngine::loadSample(uint32 sampleSlot, const Common::String &streamName) { + // FIXME: This is just a workaround streamName is a path + // SOUND\\SCIERKA1.WAV for now only last path component is used + Common::String normalizedPath = lastPathComponent(streamName, '\\'); + + debugEngine("loadSample slot %d, name %s", sampleSlot, normalizedPath.c_str()); + + _mixer->stopID(sampleSlot); + _voiceStream[sampleSlot] = nullptr; + _voiceStream[sampleSlot] = SearchMan.createReadStreamForMember(normalizedPath); + if (_voiceStream[sampleSlot] == nullptr) { + error("Can't load sample %s to slot %d", normalizedPath.c_str(), sampleSlot); + } + return _voiceStream[sampleSlot] == nullptr; +} + +bool PrinceEngine::loadVoice(uint32 slot, uint32 sampleSlot, const Common::String &streamName) { + debugEngine("Loading wav %s slot %d", streamName.c_str(), slot); + + if (slot > MAXTEXTS) { + error("Text slot bigger than MAXTEXTS %d", MAXTEXTS); + return false; + } + + _voiceStream[sampleSlot] = SearchMan.createReadStreamForMember(streamName); + if (!_voiceStream[sampleSlot]) { + error("Can't open %s", streamName.c_str()); + return false; + } + + uint32 id = _voiceStream[sampleSlot]->readUint32LE(); + if (id != 0x46464952) { + error("It's not RIFF file %s", streamName.c_str()); + return false; + } + + _voiceStream[sampleSlot]->skip(0x20); + id = _voiceStream[sampleSlot]->readUint32LE(); + if (id != 0x61746164) { + error("No data section in %s id %04x", streamName.c_str(), id); + return false; + } + + id = _voiceStream[sampleSlot]->readUint32LE(); + debugEngine("SetVoice slot %d time %04x", slot, id); + id <<= 3; + id /= 22050; + id += 2; + + _textSlots[slot]._time = id; + + debugEngine("SetVoice slot %d time %04x", slot, id); + _voiceStream[sampleSlot]->seek(0); + + return true; +} + +bool PrinceEngine::loadAnim(uint16 animNr, bool loop) { + Common::String streamName = Common::String::format("AN%02d", animNr); + Common::SeekableReadStream * flicStream = SearchMan.createReadStreamForMember(streamName); + + if (!flicStream) { + error("Can't open %s", streamName.c_str()); + return false; + } + + if (!_flicPlayer.loadStream(flicStream)) { + error("Can't load flic stream %s", streamName.c_str()); + } + + debugEngine("%s loaded", streamName.c_str()); + _flicLooped = loop; + _flicPlayer.start(); + playNextFrame(); + return true; +} + +void PrinceEngine::scrollCameraLeft(int16 delta) { + if (_newCameraX > 0) { + if (_newCameraX < delta) + _newCameraX = 0; + else + _newCameraX -= delta; + } +} + +void PrinceEngine::scrollCameraRight(int16 delta) { + if (_newCameraX != _sceneWidth - 640) { + if (_sceneWidth - 640 < delta + _newCameraX) + delta += (_sceneWidth - 640) - (delta + _newCameraX); + _newCameraX += delta; + debugEngine("PrinceEngine::scrollCameraRight() _newCameraX = %d; delta = %d", _newCameraX, delta); + } +} + +void PrinceEngine::keyHandler(Common::Event event) { + uint16 nChar = event.kbd.keycode; + switch (nChar) { + case Common::KEYCODE_d: + if (event.kbd.hasFlags(Common::KBD_CTRL)) { + getDebugger()->attach(); + } + break; + case Common::KEYCODE_LEFT: + scrollCameraLeft(32); + break; + case Common::KEYCODE_RIGHT: + scrollCameraRight(32); + break; + case Common::KEYCODE_ESCAPE: + _flags->setFlagValue(Flags::ESCAPED2, 1); + break; + case Common::KEYCODE_UP: + _mainHero->_phase++; + debugEngine("%d", _mainHero->_phase); + break; + case Common::KEYCODE_DOWN: + if(_mainHero->_phase > 0) { + _mainHero->_phase--; + } + debugEngine("%d", _mainHero->_phase); + break; + case Common::KEYCODE_w: + _mainHero->_lastDirection = _mainHero->UP; + debugEngine("UP"); + break; + case Common::KEYCODE_s: + _mainHero->_lastDirection = _mainHero->DOWN; + debugEngine("DOWN"); + break; + case Common::KEYCODE_a: + _mainHero->_lastDirection = _mainHero->LEFT; + debugEngine("LEFT"); + break; + case Common::KEYCODE_f: + _mainHero->_lastDirection = _mainHero->RIGHT; + debugEngine("RIGHT"); + break; + case Common::KEYCODE_1: + if(_mainHero->_state > 0) { + _mainHero->_state--; + } + debugEngine("%d", _mainHero->_state); + break; + case Common::KEYCODE_2: + _mainHero->_state++; + debugEngine("%d", _mainHero->_state); + break; + case Common::KEYCODE_i: + _mainHero->_middleY -= 10; + break; + case Common::KEYCODE_k: + _mainHero->_middleY += 10; + break; + case Common::KEYCODE_j: + _mainHero->_middleX -= 10; + break; + case Common::KEYCODE_l: + _mainHero->_middleX += 10; + break; + } +} + +void PrinceEngine::hotspot() { + Common::Point mousepos = _system->getEventManager()->getMousePos(); + Common::Point mousePosCamera(mousepos.x + _cameraX, mousepos.y); + + for (Common::Array<Mob>::const_iterator it = _mobList.begin() + ; it != _mobList.end() ; ++it) { + const Mob& mob = *it; + if (mob._visible) + continue; + if (mob._rect.contains(mousePosCamera)) { + uint16 textW = 0; + for (uint16 i = 0; i < mob._name.size(); ++i) + textW += _font->getCharWidth(mob._name[i]); + + uint16 x = mousepos.x - textW/2; + if (x > _graph->_frontScreen->w) + x = 0; + + if (x + textW > _graph->_frontScreen->w) + x = _graph->_frontScreen->w - textW; + + uint16 y = mousepos.y - _font->getFontHeight(); + if (y > _graph->_frontScreen->h) + y = _font->getFontHeight() - 2; + + _font->drawString( + _graph->_frontScreen, + mob._name, + x, + y, + _graph->_frontScreen->w, + 216 + ); + break; + } + } +} + +void PrinceEngine::printAt(uint32 slot, uint8 color, const char *s, uint16 x, uint16 y) { + + debugC(1, DebugChannel::kEngine, "PrinceEngine::printAt slot %d, color %d, x %02d, y %02d, str %s", slot, color, x, y, s); + + Text &text = _textSlots[slot]; + text._str = s; + text._x = x; + text._y = y; + text._color = color; +} + +uint32 PrinceEngine::getTextWidth(const char *s) { + uint16 textW = 0; + while (*s) { + textW += _font->getCharWidth(*s) + _font->getKerningOffset(0, 0); + ++s; + } + return textW; +} + +void PrinceEngine::showTexts() { + for (uint32 slot = 0; slot < MAXTEXTS; ++slot) { + Text& text = _textSlots[slot]; + if (!text._str && !text._time) + continue; + + Common::Array<Common::String> lines; + _font->wordWrapText(text._str, _graph->_frontScreen->w, lines); + + for (uint8 i = 0; i < lines.size(); ++i) { + _font->drawString( + _graph->_frontScreen, + lines[i], + text._x - getTextWidth(lines[i].c_str())/2, + text._y - (lines.size() - i) * (_font->getFontHeight()), + _graph->_frontScreen->w, + text._color + ); + } + + --text._time; + if (text._time == 0) { + text._str = nullptr; + } + } +} + +void PrinceEngine::drawScreen() { + const Graphics::Surface *roomSurface = _roomBmp->getSurface(); + if (roomSurface) { + _graph->setPalette(_roomBmp->getPalette()); + const Graphics::Surface visiblePart = roomSurface->getSubArea(Common::Rect(_cameraX, 0, roomSurface->w, roomSurface->h)); + _graph->draw(0, 0, &visiblePart); + } + + if (_mainHero->_visible) { + const Graphics::Surface *mainHeroSurface = _mainHero->getSurface(); + + if (mainHeroSurface) + //_graph->drawTransparent(_mainHero->_middleX, _mainHero->_middleY, mainHeroSurface); + _graph->drawTransparent(_mainHero->_drawX, _mainHero->_drawY, mainHeroSurface); + } + + playNextFrame(); + + //if (_objectList) + // _graph->drawTransparent(_objectList->getSurface()); + + hotspot(); + + showTexts(); + + getDebugger()->onFrame(); + + _graph->update(); +} + +void PrinceEngine::mainLoop() { + + changeCursor(0); + + while (!shouldQuit()) { + uint32 currentTime = _system->getMillis(); + + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + keyHandler(event); + break; + case Common::EVENT_KEYUP: + break; + case Common::EVENT_MOUSEMOVE: + break; + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_RBUTTONDOWN: + break; + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: + break; + case Common::EVENT_QUIT: + break; + default: + break; + } + } + + if (shouldQuit()) + return; + + // TODO: Update all structures, animations, naks, heros etc. + _mainHero -> showHero(); + + _interpreter->step(); + + drawScreen(); + + // Calculate the frame delay based off a desired frame time + int delay = 1000/15 - int32(_system->getMillis() - currentTime); + // Ensure non-negative + delay = delay < 0 ? 0 : delay; + _system->delayMillis(delay); + + _cameraX = _newCameraX; + ++_frameNr; + + if (_debugger->_locationNr != _locationNr) + loadLocation(_debugger->_locationNr); + if (_debugger->_cursorNr != _cursorNr) + changeCursor(_debugger->_cursorNr); + } +} + +} // End of namespace Prince + +/* vim: set tabstop=4 expandtab!: */ diff --git a/engines/prince/prince.h b/engines/prince/prince.h new file mode 100644 index 0000000000..a48f056d4d --- /dev/null +++ b/engines/prince/prince.h @@ -0,0 +1,197 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_H +#define PRINCE_H + +#include "common/random.h" +#include "common/system.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/textconsole.h" +#include "common/rect.h" +#include "common/events.h" + +#include "image/bmp.h" + +#include "gui/debugger.h" + +#include "engines/engine.h" +#include "engines/util.h" + +#include "audio/mixer.h" + +#include "video/flic_decoder.h" + +#include "prince/mob.h" +#include "prince/object.h" + + +namespace Prince { + +struct PrinceGameDescription; + +class PrinceEngine; +class GraphicsMan; +class Script; +class Interpreter; +class InterpreterFlags; +class Debugger; +class MusicPlayer; +class VariaTxt; +class Cursor; +class MhwanhDecoder; +class Font; +class Hero; +class Animation; + +struct Text { + const char *_str; + uint16 _x, _y; + uint16 _time; + uint32 _color; + + Text() : _str(NULL), _x(0), _y(0), _time(0), _color(255){ + } +}; + +struct AnimListItem { + uint16 _type; + uint16 _fileNumber; + uint16 _startPhase; + uint16 _endPhase; + uint16 _loopPhase; + int16 _x; + int16 _y; + uint16 _loopType; + uint16 _nextAnim; + uint16 _flags; + + bool loadFromStream(Common::SeekableReadStream &stream); +}; + +struct DebugChannel { + +enum Type { + kScript, + kEngine +}; + +}; + +class PrinceEngine : public Engine { +protected: + Common::Error run(); + +public: + PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc); + virtual ~PrinceEngine(); + + virtual bool hasFeature(EngineFeature f) const; + + int getGameType() const; + const char *getGameId() const; + uint32 getFeatures() const; + Common::Language getLanguage() const; + + const PrinceGameDescription *_gameDescription; + Video::FlicDecoder _flicPlayer; + VariaTxt *_variaTxt; + + uint32 _talkTxtSize; + byte *_talkTxt; + + bool loadLocation(uint16 locationNr); + bool loadAnim(uint16 animNr, bool loop); + bool loadVoice(uint32 textSlot, uint32 sampleSlot, const Common::String &name); + bool loadSample(uint32 sampleSlot, const Common::String &name); + + void playSample(uint16 sampleId, uint16 loopType); + void stopSample(uint16 sampleId); + + virtual GUI::Debugger *getDebugger(); + + void changeCursor(uint16 curId); + void printAt(uint32 slot, uint8 color, const char *s, uint16 x, uint16 y); + + static const uint8 MAXTEXTS = 32; + Text _textSlots[MAXTEXTS]; + + uint64 _frameNr; + Hero* _mainHero; + Hero* _secondHero; + +private: + bool playNextFrame(); + void keyHandler(Common::Event event); + void hotspot(); + void scrollCameraRight(int16 delta); + void scrollCameraLeft(int16 delta); + void drawScreen(); + void showTexts(); + void init(); + void showLogo(); + + uint32 getTextWidth(const char *s); + void debugEngine(const char *s, ...); + + uint16 _locationNr; + uint8 _cursorNr; + + Common::RandomSource *_rnd; + Image::BitmapDecoder *_roomBmp; + Cursor *_cursor1; + Cursor *_cursor2; + MhwanhDecoder *_walizkaBmp; + Debugger *_debugger; + GraphicsMan *_graph; + Script *_script; + InterpreterFlags *_flags; + Interpreter *_interpreter; + Font *_font; + MusicPlayer *_midiPlayer; + + + static const uint32 MAX_SAMPLES = 60; + Common::SeekableReadStream *_voiceStream[MAX_SAMPLES]; + Audio::SoundHandle _soundHandle[MAX_SAMPLES]; + + Animation *_zoom; + Common::Array<Mob> _mobList; + Common::Array<Object *> _objList; + Common::Array<AnimListItem> _animList; + + uint16 _cameraX; + uint16 _newCameraX; + uint16 _sceneWidth; + + bool _flicLooped; + + void mainLoop(); + +}; + +} // End of namespace Prince + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/resource.h b/engines/prince/resource.h new file mode 100644 index 0000000000..2f7e6ba3a8 --- /dev/null +++ b/engines/prince/resource.h @@ -0,0 +1,102 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_RESOURCE_H +#define PRINCE_RESOURCE_H + +#include "common/stream.h" +#include "common/archive.h" +#include "common/debug-channels.h" +#include "common/ptr.h" + +namespace Prince { + +namespace Resource { + + template <typename T> + bool loadFromStream(T &resource, Common::SeekableReadStream &stream) { + return resource.loadFromStream(stream); + } + + template<typename T> + bool loadResource(T *resource, const char *resourceName, bool required = true) { + Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName)); + if (!stream) { + if (required) + error("Can't load %s", resourceName); + return false; + } + + return loadFromStream(*resource, *stream); + } + + template <typename T> + bool loadResource(Common::Array<T> &array, Common::SeekableReadStream &stream, bool required = true) { + T t; + while (t.loadFromStream(stream)) + array.push_back(t); + + return true; + } + + + template <typename T> + bool loadResource(Common::Array<T> &array, const char *resourceName, bool required = true) { + Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName)); + if (!stream) { + if (required) + error("Can't load %s", resourceName); + return false; + } + + return loadResource(array, *stream, required); + } + + template <typename T> + bool loadResource(Common::Array<T *> &array, const char *resourceName, bool required = true) { + + Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName)); + if (!stream) { + if (required) + error("Can't load %s", resourceName); + return false; + } + + // FIXME: This is stupid. Maybe loadFromStream should be helper method that returns initiailzed object + while (true) { + T* t = new T(); + if (!t->loadFromStream(*stream)) { + delete t; + break; + } + array.push_back(t); + } + return true; + } + +} + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp new file mode 100644 index 0000000000..84ae64791e --- /dev/null +++ b/engines/prince/script.cpp @@ -0,0 +1,1452 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/script.h" +#include "prince/prince.h" +#include "prince/flags.h" +#include "prince/variatxt.h" +#include "prince/font.h" +#include "prince/hero.h" +#include "prince/resource.h" + +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/stream.h" +#include "common/archive.h" +#include "common/memstream.h" + +namespace Prince { + +static const uint16 NUM_OPCODES = 144; + +Room::Room() {} + +void Room::loadMobs(Common::SeekableReadStream &stream) { + debug("loadMobs %d", stream.pos()); + static const uint8 MAX_MOBS = 64; + uint8 mobs[MAX_MOBS]; + stream.read(&mobs, sizeof(mobs)); + for(uint8 i = 0; i < sizeof(mobs); ++i) { + debug("mob %d flag %d", i, mobs[i]); + } +} + +void Room::loadBackAnim(Common::SeekableReadStream &stream) { + debug("loadBackAnim %d", stream.pos()); + static const uint8 MAX_BACK_ANIMS = 64; + uint32 backAnim[MAX_BACK_ANIMS]; + debug("loadBackAnim sizeof %lu", sizeof(backAnim)); + stream.read(backAnim, sizeof(backAnim)); + for(uint8 i = 0; i < MAX_BACK_ANIMS; ++i) { + debug("back anim offset %d", backAnim[i]); + } +} + +void Room::loadObj(Common::SeekableReadStream &stream) {} +void Room::loadNak(Common::SeekableReadStream &stream) {} +void Room::loadItemUse(Common::SeekableReadStream &stream) {} +void Room::loadItemGive(Common::SeekableReadStream &stream) {} +void Room::loadWalkTo(Common::SeekableReadStream &stream) {} +void Room::loadExamine(Common::SeekableReadStream &stream) {} +void Room::loadPickup(Common::SeekableReadStream &stream) {} +void Room::loadUse(Common::SeekableReadStream &stream) {} +void Room::loadPushOpen(Common::SeekableReadStream &stream) {} +void Room::loadPullClose(Common::SeekableReadStream &stream) {} +void Room::loadTalk(Common::SeekableReadStream &stream) {} +void Room::loadGive(Common::SeekableReadStream &stream) {} + +void Room::nextLoadStep(Common::SeekableReadStream &stream, LoadingStep step) { + uint32 offset = stream.readUint32LE(); + uint32 pos = stream.pos(); + stream.seek(offset); + + debug("nextLoadStep offset %d, pos %d", offset, pos); + + (this->*step)(stream); + + stream.seek(pos); +} + +bool Room::loadFromStream(Common::SeekableReadStream &stream) { + + uint32 pos = stream.pos(); + + nextLoadStep(stream, &Room::loadMobs); + nextLoadStep(stream, &Room::loadBackAnim); + nextLoadStep(stream, &Room::loadObj); + nextLoadStep(stream, &Room::loadNak); + nextLoadStep(stream, &Room::loadItemUse); + nextLoadStep(stream, &Room::loadItemGive); + nextLoadStep(stream, &Room::loadWalkTo); + nextLoadStep(stream, &Room::loadExamine); + nextLoadStep(stream, &Room::loadPickup); + nextLoadStep(stream, &Room::loadUse); + nextLoadStep(stream, &Room::loadPushOpen); + nextLoadStep(stream, &Room::loadPullClose); + nextLoadStep(stream, &Room::loadTalk); + nextLoadStep(stream, &Room::loadGive); + + // skip some data for now + static const uint8 ROOM_ENTRY_SIZE = 64; + stream.seek(pos + ROOM_ENTRY_SIZE); + + return true;; +} + +Script::Script() : _data(nullptr), _dataSize(0) { +} + +Script::~Script() { + delete[] _data; + _dataSize = 0; + _data = nullptr; +} + +bool Script::loadFromStream(Common::SeekableReadStream &stream) { + _dataSize = stream.size(); + if (!_dataSize) + return false; + + _data = new byte[_dataSize]; + + if (!_data) + return false; + + stream.read(_data, _dataSize); + + Common::MemoryReadStream scriptDataStream(_data, _dataSize); + scriptDataStream.seek(getRoomTableOffset()+64); + debug("room table offset %d", scriptDataStream.pos()); + Room room; + room.loadFromStream(scriptDataStream); + + return true; +} + +InterpreterFlags::InterpreterFlags() { + resetAllFlags(); +} + +void InterpreterFlags::resetAllFlags() { + memset(_flags, 0, sizeof(_flags)); +} + +void InterpreterFlags::setFlagValue(Flags::Id flagId, uint16 value) { + _flags[(uint16)flagId - FLAG_MASK] = value; +} + +uint16 InterpreterFlags::getFlagValue(Flags::Id flagId) { + return _flags[(uint16)flagId - FLAG_MASK]; +} + +Interpreter::Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags) : + _vm(vm), _script(script), _flags(flags), + _stacktop(0), _opcodeNF(false), + _waitFlag(0), _result(true) { + + // Initialize the script + _mode = "fg"; + _fgOpcodePC = _script->getStartGameOffset(); + _bgOpcodePC = 0; +} + +void Interpreter::debugInterpreter(const char *s, ...) { + char buf[STRINGBUFLEN]; + va_list va; + + va_start(va, s); + vsnprintf(buf, STRINGBUFLEN, s, va); + va_end(va); + + Common::String str = Common::String::format("@0x%08X: ", _lastInstruction); + str += Common::String::format("op %04d: ", _lastOpcode); + //debugC(10, DebugChannel::kScript, "PrinceEngine::Script %s %s", str.c_str(), buf); + + //debug("Prince::Script frame %08ld mode %s %s %s", _vm->_frameNr, _mode, str.c_str(), buf); +} + +void Interpreter::step() { + if (_bgOpcodePC) { + _mode = "bg"; + _bgOpcodePC = step(_bgOpcodePC); + } + if (_fgOpcodePC) { + _mode = "fg"; + _fgOpcodePC = step(_fgOpcodePC); + } +} + +uint32 Interpreter::step(uint32 opcodePC) { + _currentInstruction = opcodePC; + + while (!_opcodeNF) { + _lastInstruction = _currentInstruction; + + // Get the current opcode + _lastOpcode = readScript<uint16>(); + + if (_lastOpcode > NUM_OPCODES) + error( + "Trying to execute unknown opcode @0x%04X: %02d", + _currentInstruction, + _lastOpcode); + + // Execute the current opcode + OpcodeFunc op = _opcodes[_lastOpcode]; + (this->*op)(); + if (_opcodeNF) { + _opcodeNF = 0; + break; + } + } + + return _currentInstruction; +} + +template <typename T> +T Interpreter::readScript() { + T data = _script->read<T>(_currentInstruction); + _currentInstruction += sizeof(data); + return data; +} + +uint16 Interpreter::readScriptFlagValue() { + uint16 value = readScript<uint16>(); + if (value & InterpreterFlags::FLAG_MASK) { + return _flags->getFlagValue((Flags::Id)value); + } + return value; +} + +Flags::Id Interpreter::readScriptFlagId() { + return (Flags::Id)readScript<uint16>(); +} + +void Interpreter::O_WAITFOREVER() { + debugInterpreter("O_WAITFOREVER"); + _opcodeNF = 1; + _currentInstruction -= 2; +} + +void Interpreter::O_BLACKPALETTE() { + debugInterpreter("O_BLACKPALETTE"); +} + +void Interpreter::O_SETUPPALETTE() { + debugInterpreter("O_SETUPPALETTE"); +} + +void Interpreter::O_INITROOM() { + uint16 roomId = readScriptFlagValue(); + debugInterpreter("O_INITROOM %d", roomId); + _vm->loadLocation(roomId); + _opcodeNF = 1; +} + +void Interpreter::O_SETSAMPLE() { + uint16 sampleId = readScriptFlagValue(); + int32 sampleNameOffset = readScript<uint32>(); + const char * sampleName = _script->getString(_currentInstruction + sampleNameOffset - 4); + debugInterpreter("O_SETSAMPLE %d %s", sampleId, sampleName); + _vm->loadSample(sampleId, sampleName); +} + +void Interpreter::O_FREESAMPLE() { + uint16 sample = readScriptFlagValue(); + debugInterpreter("O_FREESAMPLE %d", sample); +} + +void Interpreter::O_PLAYSAMPLE() { + uint16 sampleId = readScriptFlagValue(); + uint16 loopType = readScript<uint16>(); + debugInterpreter("O_PLAYSAMPLE sampleId %d loopType %d", sampleId, loopType); + _vm->playSample(sampleId, loopType); +} + +void Interpreter::O_PUTOBJECT() { + uint16 roomId = readScriptFlagValue(); + uint16 slot = readScriptFlagValue(); + uint16 objectId = readScriptFlagValue(); + debugInterpreter("O_PUTOBJECT roomId %d, slot %d, objectId %d", roomId, slot, objectId); +} + +void Interpreter::O_REMOBJECT() { + uint16 roomId = readScriptFlagValue(); + uint16 objectId = readScriptFlagValue(); + + debugInterpreter("O_REMOBJECT roomId %d objectId %d", roomId, objectId); +} + +void Interpreter::O_SHOWANIM() { + uint16 slot = readScriptFlagValue(); + uint16 animId = readScriptFlagValue(); + + debugInterpreter("O_SHOWANIM slot %d, animId %d", slot, animId); +} + +void Interpreter::O_CHECKANIMEND() { + uint16 slot = readScriptFlagValue(); + uint16 frameId = readScriptFlagValue(); + + debugInterpreter("O_CHECKANIMEND slot %d, frameId %d", slot, frameId); + _opcodeNF = 1; +} + +void Interpreter::O_FREEANIM() { + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_FREEANIM slot %d", slot); +} + +void Interpreter::O_CHECKANIMFRAME() { + uint16 slot = readScriptFlagValue(); + uint16 frameId = readScriptFlagValue(); + + debugInterpreter("O_CHECKANIMFRAME slot %d, frameId %d", slot, frameId); + _opcodeNF = 1; +} + +void Interpreter::O_PUTBACKANIM() { + uint16 roomId = readScriptFlagValue(); + uint16 slot = readScriptFlagValue(); + int32 animId = readScript<uint32>(); + debugInterpreter("O_PUTBACKANIM roomId %d, slot %d, animId %d", roomId, slot, animId); +} + +void Interpreter::O_REMBACKANIM() { + uint16 roomId = readScriptFlagValue(); + uint16 slot = readScriptFlagValue(); + + debugInterpreter("O_REMBACKANIM roomId %d, slot %d", roomId, slot); +} + +void Interpreter::O_CHECKBACKANIMFRAME() { + uint16 slotId = readScriptFlagValue(); + uint16 frameId = readScriptFlagValue(); + + debugInterpreter("O_CHECKBACKANIMFRAME slotId %d, frameId %d", slotId, frameId); + _opcodeNF = 1; +} + +void Interpreter::O_FREEALLSAMPLES() { + debugInterpreter("O_FREEALLSAMPLES"); +} + +void Interpreter::O_SETMUSIC() { + uint16 musicId = readScript<uint16>(); + + debugInterpreter("O_SETMUSIC musicId %d", musicId); +} + +void Interpreter::O_STOPMUSIC() { + debugInterpreter("O_STOPMUSIC"); +} + +void Interpreter::O__WAIT() { + uint16 pause = readScriptFlagValue(); + + debugInterpreter("O__WAIT pause %d", pause); + + if (_waitFlag == 0) { + // set new wait flag value and continue + _waitFlag = pause; + _opcodeNF = 1; + _currentInstruction -= 4; + return; + } + + --_waitFlag; + + if (_waitFlag > 0) { + _opcodeNF = 1; + _currentInstruction -= 4; + return; + } +} + +void Interpreter::O_UPDATEOFF() { + debugInterpreter("O_UPDATEOFF"); + //_updateEnable = false; +} + +void Interpreter::O_UPDATEON() { + debugInterpreter("O_UPDATEON"); + //_updateEnable = true; +} + +void Interpreter::O_UPDATE () { + debugInterpreter("O_UPDATE"); + // Refresh screen +} + +void Interpreter::O_CLS() { + debugInterpreter("O_CLS"); + // do nothing +} + +void Interpreter::O__CALL() { + int32 address = readScript<uint32>(); + _stack[_stacktop] = _currentInstruction; + _stacktop++; + _currentInstruction += address - 4; + debugInterpreter("O__CALL 0x%04X", _currentInstruction); +} + +void Interpreter::O_RETURN() { + // Get the return address + if (_stacktop > 0) { + _stacktop--; + _currentInstruction = _stack[_stacktop]; + debugInterpreter("O_RETURN 0x%04X", _currentInstruction); + } else { + error("Return: Stack is empty"); + } +} + +void Interpreter::O_GO() { + int32 opPC = readScript<uint32>(); + debugInterpreter("O_GO 0x%04X", opPC); + _currentInstruction += opPC - 4; +} + +void Interpreter::O_BACKANIMUPDATEOFF() { + uint16 slotId = readScriptFlagValue(); + debugInterpreter("O_BACKANIMUPDATEOFF slotId %d", slotId); +} + +void Interpreter::O_BACKANIMUPDATEON() { + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_BACKANIMUPDATEON %d", slot); +} + +void Interpreter::O_CHANGECURSOR() { + uint16 cursorId = readScriptFlagValue(); + debugInterpreter("O_CHANGECURSOR %x", cursorId); + _vm->changeCursor(cursorId); +} + +void Interpreter::O_CHANGEANIMTYPE() { + // NOT IMPLEMENTED +} + +void Interpreter::O__SETFLAG() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O__SETFLAG 0x%04X (%s) = %d", flagId, Flags::getFlagName(flagId), value); + + _flags->setFlagValue((Flags::Id)(flagId), value); +} + +void Interpreter::O_COMPARE() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + _result = _flags->getFlagValue(flagId) != value; + debugInterpreter("O_COMPARE flagId 0x%04X (%s), value %d == %d (%d)", flagId, Flags::getFlagName(flagId), value, _flags->getFlagValue(flagId), _result); +} + +void Interpreter::O_JUMPZ() { + int32 offset = readScript<uint32>(); + if (! _result) { + _currentInstruction += offset - 4; + } + + debugInterpreter("O_JUMPZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset); +} + +void Interpreter::O_JUMPNZ() { + int32 offset = readScript<uint32>(); + if (_result) { + _currentInstruction += offset - 4; + } + + debugInterpreter("O_JUMPNZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset); +} + +void Interpreter::O_EXIT() { + uint16 exitCode = readScriptFlagValue(); + debugInterpreter("O_EXIT exitCode %d", exitCode); + // Set exit code and shows credits + // if exit code == 0x02EAD +} + +void Interpreter::O_ADDFLAG() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) + value); + if (_flags->getFlagValue(flagId)) + _result = 1; + else + _result = 0; + + debugInterpreter("O_ADDFLAG flagId %04x (%s), value %d", flagId, Flags::getFlagName(flagId), value); +} + +void Interpreter::O_TALKANIM() { + uint16 animSlot = readScriptFlagValue(); + uint16 slot = readScriptFlagValue(); + + debugInterpreter("O_TALKANIM animSlot %d, slot %d", animSlot, slot); +} + +void Interpreter::O_SUBFLAG() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) - value); + if (_flags->getFlagValue(flagId)) + _result = 1; + else + _result = 0; + + debugInterpreter("O_SUBFLAG flagId %d, value %d", flagId, value); +} + +void Interpreter::O_SETSTRING() { + int32 offset = readScript<uint32>(); + _currentString = offset; + + // FIXME: Make it better ;) + if (offset >= 80000) { + debugInterpreter("GetVaria %s", _vm->_variaTxt->getString(offset - 80000)); + } + else if (offset < 2000) { + uint32 of = READ_LE_UINT32(_vm->_talkTxt+offset*4); + const char * txt = (const char *)&_vm->_talkTxt[of]; + _string = &_vm->_talkTxt[of]; + debugInterpreter("TalkTxt %d %s", of, txt); + } + + debugInterpreter("O_SETSTRING %04d", offset); +} + +void Interpreter::O_ANDFLAG() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_ANDFLAG flagId %d, value %d", flagId, value); + + _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) & value); + + if (_flags->getFlagValue(flagId)) { + _result = 1; + } else { + _result = 0; + } +} + +void Interpreter::O_GETMOBDATA() { + Flags::Id flagId = readScriptFlagId(); + uint16 mobId = readScript<uint16>(); + uint16 mobOffset = readScript<uint16>(); + + debugInterpreter("O_GETMOBDATA flagId %d, modId %d, mobOffset %d", flagId, mobId, mobOffset); +} + +void Interpreter::O_ORFLAG() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_ORFLAG flagId %d, value %d", flagId, value); + + _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) | value); + + if (_flags->getFlagValue(flagId)) { + _result = 1; + } else { + _result = 0; + } +} + +void Interpreter::O_SETMOBDATA() { + uint16 mobId = readScriptFlagValue(); + uint16 mobOffset = readScriptFlagValue(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_SETMOBDATA mobId %d, mobOffset %d, value %d", mobId, mobOffset, value); +} + +void Interpreter::O_XORFLAG() { + Flags::Id flagId = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_XORFLAG flagId %d, value %d", flagId, value); + + _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) ^ value); + + if (_flags->getFlagValue(flagId)) { + _result = 1; + } else { + _result = 0; + } +} + +void Interpreter::O_GETMOBTEXT() { + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_GETMOBTEXT value %d", value); + // Use Mob::ExamText as current string +} + +void Interpreter::O_MOVEHERO() { + uint16 heroId = readScriptFlagValue(); + uint16 x = readScriptFlagValue(); + uint16 y = readScriptFlagValue(); + uint16 dir = readScriptFlagValue(); + + debugInterpreter("O_MOVEHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir); +} + +void Interpreter::O_WALKHERO() { + uint16 heroId = readScriptFlagValue(); + + debugInterpreter("O_WALKHERO %d", heroId); + _opcodeNF = 1; +} + +void Interpreter::O_SETHERO() { + uint16 hero = readScriptFlagValue(); + int16 x = readScriptFlagValue(); + int16 y = readScriptFlagValue(); + uint16 dir = readScriptFlagValue(); + debugInterpreter("O_SETHERO hero %d, x %d, y %d, dir %d", hero, x, y, dir); + _vm->_mainHero->setPos(x, y); + _vm->_mainHero->_lastDirection = dir; + _vm->_mainHero->_state = _vm->_mainHero->STAY; + _vm->_mainHero->_moveSetType = _vm->_mainHero->_lastDirection - 1; // for countDrawPosition + _vm->_mainHero->countDrawPosition(); //setting drawX, drawY +} + +void Interpreter::O_HEROOFF() { + uint16 heroId = readScriptFlagValue(); + debugInterpreter("O_HEROOFF %d", heroId); + _vm->_mainHero->setVisible(false); +} + +void Interpreter::O_HEROON() { + uint16 heroId = readScriptFlagValue(); + debugInterpreter("O_HEROON %d", heroId); + _vm->_mainHero->setVisible(true); +} + +void Interpreter::O_CLSTEXT() { + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_CLSTEXT slot %d", slot); + // Sets text line to null + // Sets text timeout to zero +} + +void Interpreter::O_CALLTABLE() { + uint16 flag = readScript<uint16>(); + int32 table = readScript<uint32>(); + + debugInterpreter("O_CALLTABLE flag %d, table %d", flag, table); + // makes a call from script function table + // must read table pointer from _code and + // use table entry as next opcode +} + +void Interpreter::O_CHANGEMOB() { + uint16 mob = readScriptFlagValue(); + uint16 value = readScriptFlagValue(); + debugInterpreter("O_CHANGEMOB mob %d, value %d", mob, value); + // Probably sets mobs visible flag to value +} + +void Interpreter::O_ADDINV() { + uint16 hero = readScriptFlagValue(); + uint16 item = readScriptFlagValue(); + debugInterpreter("O_ADDINV hero %d, item %d", hero, item); +} + +void Interpreter::O_REMINV() { + uint16 hero = readScriptFlagValue(); + uint16 item = readScriptFlagValue(); + debugInterpreter("O_REMINV hero %d, item %d", hero, item); +} + +void Interpreter::O_REPINV() { + uint16 hero = readScript<uint16>(); + uint16 item1 = readScript<uint16>(); + uint16 item2 = readScript<uint16>(); + // shouldn't be uses + error("O_REPINV hero %d, item1 %d, item2 %d", hero, item1, item2); +} + +void Interpreter::O_OBSOLETE_GETACTION() { + // shouldn't be uses + error("O_OBSOLETE_GETACTION"); +} + +void Interpreter::O_ADDWALKAREA() { + uint16 x1 = readScript<uint16>(); + uint16 y1 = readScript<uint16>(); + uint16 x2 = readScript<uint16>(); + uint16 y2 = readScript<uint16>(); + // shouldn't be uses + error("O_ADDWALKAREA x1 %d, y1 %d, x2 %d, y2 %d", x1, y1, x2, y2); +} + +void Interpreter::O_REMWALKAREA() { + uint16 x1 = readScript<uint16>(); + uint16 y1 = readScript<uint16>(); + uint16 x2 = readScript<uint16>(); + uint16 y2 = readScript<uint16>(); + + // shouldn't be uses + error("O_REMWALKAREA x1 %d, y1 %d, x2 %d, y2 %d", x1, y1, x2, y2); +} + +void Interpreter::O_RESTOREWALKAREA() { + debugInterpreter("O_RESTOREWALKAREA"); +} + +void Interpreter::O_WAITFRAME() { + debugInterpreter("O_WAITFRAME"); + _opcodeNF = true; +} + +void Interpreter::O_SETFRAME() { + uint16 anim = readScriptFlagValue(); + uint16 frame = readScriptFlagValue(); + debugInterpreter("O_SETFRAME anim %d, frame %d", anim, frame); +} + +void Interpreter::O_RUNACTION() { + // It's empty in original and never used in script + // it's better to report error + error("O_RUNACTION"); +} + +void Interpreter::O_COMPAREHI() { + Flags::Id flag = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_COMPAREHI flag %d, value %d", flag, value); + _result = value < _flags->getFlagValue(flag); +} + +void Interpreter::O_COMPARELO() { + Flags::Id flag = readScriptFlagId(); + uint16 value = readScriptFlagValue(); + + debugInterpreter("O_COMPARELO flag %d, value %d", flag, value); + _result = value > _flags->getFlagValue(flag); +} + +void Interpreter::O_PRELOADSET() { + // not used in script + int32 offset = readScript<uint32>(); + debugInterpreter("O_PRELOADSET offset %04x", offset); +} + +void Interpreter::O_FREEPRELOAD() { + // not used in script + debugInterpreter("O_FREEPRELOAD"); +} + +void Interpreter::O_CHECKINV() { + uint16 hero = readScriptFlagValue(); + uint16 item = readScriptFlagValue(); + debugInterpreter("O_CHECKINV hero %d, item %d", hero, item); + // checks if item is in heros inventory +} + +void Interpreter::O_TALKHERO() { + uint16 hero = readScriptFlagValue(); + debugInterpreter("O_TALKHERO hero %d", hero); +} + +void Interpreter::O_WAITTEXT() { + uint16 slot = readScriptFlagValue(); + Text &text = _vm->_textSlots[slot]; + if (text._time) { + _opcodeNF = 1; + _currentInstruction -= 4; + } +} + +void Interpreter::O_SETHEROANIM() { + uint16 hero = readScriptFlagValue(); + int32 offset = readScript<uint32>(); + debugInterpreter("O_SETHEROANIM hero %d, offset %d", hero, offset); +} + +void Interpreter::O_WAITHEROANIM() { + uint16 hero = readScriptFlagValue(); + + debugInterpreter("O_WAITHEROANIM hero %d", hero); +} + +void Interpreter::O_GETHERODATA() { + uint16 flag = readScript<uint16>(); + uint16 hero = readScriptFlagValue(); + uint16 heroOffset = readScriptFlagValue(); + debugInterpreter("O_GETHERODATA flag %d, hero %d, heroOffset %d", flag, hero, heroOffset); +} + +void Interpreter::O_GETMOUSEBUTTON() { + debugInterpreter("O_GETMOUSEBUTTON"); +} + +void Interpreter::O_CHANGEFRAMES() { + uint16 anim = readScriptFlagValue(); + uint16 frame = readScriptFlagValue(); + uint16 lastFrame = readScriptFlagValue(); + uint16 loopFrame = readScriptFlagValue(); + + debugInterpreter( + "O_CHANGFRAMES anim %d, fr1 %d, fr2 %d, fr3 %d", + anim, + frame, + lastFrame, + loopFrame); + +} + +void Interpreter::O_CHANGEBACKFRAMES() { + uint16 anim = readScriptFlagValue(); + uint16 frame = readScriptFlagValue(); + uint16 lastFrame = readScriptFlagValue(); + uint16 loopFrame = readScriptFlagValue(); + + debugInterpreter( + "O_CHANGEBACKFRAMES anim %d, fr1 %d, fr2 %d, fr3 %d", + anim, + frame, + lastFrame, + loopFrame); +} + +void Interpreter::O_GETBACKANIMDATA() { + uint16 flag = readScript<uint16>(); + uint16 anim = readScript<uint16>(); + uint16 animOffset = readScript<uint16>(); + debugInterpreter("O_GETBACKANIMDATA flag %d, anim %d, animOffset %d", flag, anim, animOffset); +} + +void Interpreter::O_GETANIMDATA() { + uint16 flag = readScript<uint16>(); + uint16 anim = readScriptFlagValue(); + uint16 animOffset = readScriptFlagValue(); + debugInterpreter("O_GETANIMDATA flag %d, anim %d, animOffset %d", flag, anim, animOffset); + // Gets value of anim data + // use anim offset as attribute id not an offset +} + +void Interpreter::O_SETBGCODE() { + int32 offset = readScript<uint32>(); + _bgOpcodePC = _currentInstruction + offset - 4; + debugInterpreter("O_SETBGCODE next %08x, offset %08x", _bgOpcodePC, offset); +} + +void Interpreter::O_SETBACKFRAME() { + uint16 anim = readScriptFlagValue(); + uint16 frame = readScriptFlagValue(); + + debugInterpreter("O_SETBACKFRAME anim %d, frame %d", anim, frame); +} + +void Interpreter::O_GETRND() { + Flags::Id flag = readScriptFlagId(); + uint16 rndSeed = readScript<uint16>(); + debugInterpreter("O_GETRND flag %d, rndSeed %d", flag, rndSeed); + // puts and random value as flag value + // fairly random value ;) + // _flags->setFlagValue(flag, 4); +} + +void Interpreter::O_TALKBACKANIM() { + uint16 animSlot = readScriptFlagValue(); + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_TALKBACKANIM animSlot %d, slot %d", animSlot, slot); +} + +void Interpreter::O_LOADPATH() { + int32 offset = readScript<uint32>(); + debugInterpreter("O_LOADPATH offset %d", offset); + // _currentInstruction + offset path file name ptr + // free path bitmap + // load packet path bitmap and puts in Sala +} + +void Interpreter::O_GETCHAR() { + Flags::Id flagId = readScriptFlagId(); + + _flags->setFlagValue(flagId, *_string); + + debugInterpreter( + "O_GETCHAR %04X (%s) %02x", + flagId, + Flags::getFlagName(flagId), + _flags->getFlagValue(flagId)); + + ++_string; +} + +void Interpreter::O_SETDFLAG() { + uint16 flag = readScript<uint16>(); + int32 offset = readScript<uint32>(); + debugInterpreter("O_SETDFLAG flag %d, offset %04x", flag, offset); + // run this through debugger looks strange + // it looks like this one store two 16 bit value in one go +} + +void Interpreter::O_CALLDFLAG() { + uint16 flag = readScript<uint16>(); + debugInterpreter("O_CALLDFLAG flag %d", flag); + // it seems that some flags are 32 bit long +} + +void Interpreter::O_PRINTAT() { + uint16 slot = readScriptFlagValue(); + uint16 fr1 = readScriptFlagValue(); + uint16 fr2 = readScriptFlagValue(); + + debugInterpreter("O_PRINTAT slot %d, fr1 %d, fr2 %d", slot, fr1, fr2); + + uint8 color = _flags->getFlagValue(Flags::KOLOR); + + _vm->printAt(slot, color, (const char *)_string, fr1, fr2); + + while (*_string) { + ++_string; + } + ++_string; +} + +void Interpreter::O_ZOOMIN() { + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_ZOOMIN slot %04d", slot); +} + +void Interpreter::O_ZOOMOUT() { + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_ZOOMOUT slot %d", slot); +} + +void Interpreter::O_SETSTRINGOFFSET() { + int32 offset = readScript<uint32>(); + debugInterpreter("O_SETSTRINGOFFSET offset %04x", offset); + // _currentString = "" + // _string = (const char *)_currentInstruction + offset +} + +void Interpreter::O_GETOBJDATA() { + Flags::Id flag = readScriptFlagId(); + uint16 obj = readScriptFlagValue(); + int16 objOffset = readScriptFlagValue(); + debugInterpreter("O_GETOBJDATA flag %d, obj %d, objOffset %d", flag, obj, objOffset); +} + +void Interpreter::O_SETOBJDATA() { + uint16 obj = readScriptFlagValue(); + int16 objOffset = readScriptFlagValue(); + uint16 value = readScriptFlagValue(); + debugInterpreter("O_SETOBJDATA obj %d, objOffset %d, value %d", obj, objOffset, value); +} + +void Interpreter::O_SWAPOBJECTS() { + uint16 obj1 = readScript<uint16>(); + uint16 obj2 = readScript<uint16>(); + debugInterpreter("O_SWAPOBJECTS obj1 %d, obj2 %d", obj1, obj2); +} + +void Interpreter::O_CHANGEHEROSET() { + uint16 hero = readScriptFlagValue(); + uint16 heroSet = readScriptFlagValue(); + debugInterpreter("O_CHANGEHEROSET hero %d, heroSet %d", hero, heroSet); +} + +void Interpreter::O_ADDSTRING() { + uint16 value = readScriptFlagValue(); + debugInterpreter("O_ADDSTRING value %d", value); + // _string += value +} + +void Interpreter::O_SUBSTRING() { + uint16 value = readScriptFlagValue(); + debugInterpreter("O_SUBSTRING value %d", value); + // _string -= value +} + +void Interpreter::O_INITDIALOG() { + debugInterpreter("O_INITDIALOG"); +} + +void Interpreter::O_ENABLEDIALOGOPT() { + uint16 opt = readScriptFlagValue(); + debugInterpreter("O_ENABLEDIALOGOPT opt %d", opt); +} + +void Interpreter::O_DISABLEDIALOGOPT() { + uint16 opt = readScriptFlagValue(); + debugInterpreter("O_DISABLEDIALOGOPT opt %d", opt); +} + +void Interpreter::O_SHOWDIALOGBOX() { + uint16 box = readScriptFlagValue(); + debugInterpreter("O_SHOWDIALOGBOX box %d", box); +} + +void Interpreter::O_STOPSAMPLE() { + uint16 slot = readScriptFlagValue(); + debugInterpreter("O_STOPSAMPLE slot %d", slot); + _vm->stopSample(slot); +} + +void Interpreter::O_BACKANIMRANGE() { + uint16 slotId = readScriptFlagValue(); + uint16 animId = readScript<uint16>(); + uint16 low = readScriptFlagValue(); + uint16 high = readScriptFlagValue(); + + if (animId != 0xFFFF) { + if (animId & InterpreterFlags::FLAG_MASK) { + animId = _flags->getFlagValue((Flags::Id)animId); + } + } + + debugInterpreter("O_BACKANIMRANGE slotId %d, animId %d, low %d, high %d", slotId, animId, low, high); + _result = 1; +} + +void Interpreter::O_CLEARPATH() { + debugInterpreter("O_CLEARPATH"); + // Fill Sala with 255 +} + +void Interpreter::O_SETPATH() { + debugInterpreter("O_SETPATH"); + // CopyPath +} + +void Interpreter::O_GETHEROX() { + uint16 heroId = readScriptFlagValue(); + Flags::Id flagId = readScriptFlagId(); + + debugInterpreter("O_GETHEROX heroId %d, flagId %d", heroId, flagId); +} + +void Interpreter::O_GETHEROY() { + uint16 heroId = readScript<uint16>(); + Flags::Id flagId = readScriptFlagId(); + + debugInterpreter("O_GETHEROY heroId %d, flagId %d", heroId, flagId); +} + +void Interpreter::O_GETHEROD() { + uint16 heroId = readScriptFlagValue(); + Flags::Id flagId = readScriptFlagId(); + + debugInterpreter("O_GETHEROD heroId %d, flagId %d", heroId, flagId); +} + +void Interpreter::O_PUSHSTRING() { + debugInterpreter("O_PUSHSTRING"); + // push on the stack + // _currentString + // _dialogData + // _string +} + +void Interpreter::O_POPSTRING() { + debugInterpreter("O_POPSTRING"); + // pop from the stack + // _currentString + // _dialogData + // _string +} + +void Interpreter::O_SETFGCODE() { + int32 offset = readScript<uint32>(); + _fgOpcodePC = _currentInstruction + offset - 4; + + debugInterpreter("O_SETFGCODE next %08x, offset %08x", _fgOpcodePC, offset); +} + +void Interpreter::O_STOPHERO() { + uint16 heroId = readScriptFlagValue(); + + debugInterpreter("O_STOPHERO heroId %d", heroId); + + // clear move steps for hero +} + +void Interpreter::O_ANIMUPDATEOFF() { + uint16 slotId = readScript<uint16>(); + debugInterpreter("O_ANIMUPDATEOFF slotId %d", slotId); +} + +void Interpreter::O_ANIMUPDATEON() { + uint16 slotId = readScriptFlagValue(); + debugInterpreter("O_ANIMUPDATEON slotId %d", slotId); +} + +void Interpreter::O_FREECURSOR() { + debugInterpreter("O_FREECURSOR"); + // Change cursor to 0 + // free inv cursor 1 +} + +void Interpreter::O_ADDINVQUIET() { + uint16 heroId = readScriptFlagValue(); + uint16 itemId = readScriptFlagValue(); + + debugInterpreter("O_ADDINVQUIET heorId %d, itemId %d", heroId, itemId); +} + +void Interpreter::O_RUNHERO() { + uint16 heroId = readScriptFlagValue(); + uint16 x = readScriptFlagValue(); + uint16 y = readScriptFlagValue(); + uint16 dir = readScriptFlagValue(); + + debugInterpreter("O_RUNHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir); +} + +void Interpreter::O_SETBACKANIMDATA() { + uint16 animId = readScriptFlagValue(); + uint16 animOffset = readScriptFlagValue(); + uint16 wart = readScriptFlagValue(); + + debugInterpreter("O_SETBACKANIMDATA animId %d, animOffset %d, wart %d", animId, animOffset, wart); +} + +void Interpreter::O_VIEWFLC() { + uint16 animNr = readScriptFlagValue(); + debugInterpreter("O_VIEWFLC animNr %d", animNr); + _vm->loadAnim(animNr, false); +} + +void Interpreter::O_CHECKFLCFRAME() { + uint16 frameNr = readScriptFlagValue(); + + debugInterpreter("O_CHECKFLCFRAME frame number %d", frameNr); + + if (_vm->_flicPlayer.getCurFrame() != frameNr) { + // Move instruction pointer before current instruciton + // must do this check once again till it's false + _currentInstruction -= 2; + _opcodeNF = 1; + } +} + +void Interpreter::O_CHECKFLCEND() { + + //debugInterpreter("O_CHECKFLCEND"); + + const Video::FlicDecoder &flicPlayer = _vm->_flicPlayer; + + //debug("frameCount %d, currentFrame %d", flicPlayer.getFrameCount(), flicPlayer.getCurFrame()); + + if (flicPlayer.getFrameCount() - flicPlayer.getCurFrame() > 1) { + // Move instruction pointer before current instruciton + // must do this check once again till it's false + _currentInstruction -= 2; + _opcodeNF = 1; + } +} + +void Interpreter::O_FREEFLC() { + debugInterpreter("O_FREEFLC"); +} + +void Interpreter::O_TALKHEROSTOP() { + uint16 heroId = readScriptFlagValue(); + debugInterpreter("O_TALKHEROSTOP %d", heroId); +} + +void Interpreter::O_HEROCOLOR() { + uint16 heroId = readScriptFlagValue(); + uint16 kolorr = readScriptFlagValue(); + debugInterpreter("O_HEROCOLOR heroId %d, kolorr %d", heroId, kolorr); +} + +void Interpreter::O_GRABMAPA() { + debugInterpreter("O_GRABMAPA"); +} + +void Interpreter::O_ENABLENAK() { + uint16 nakId = readScriptFlagValue(); + debugInterpreter("O_ENABLENAK nakId %d", nakId); +} + +void Interpreter::O_DISABLENAK() { + uint16 nakId = readScriptFlagValue(); + debugInterpreter("O_DISABLENAK nakId %d", nakId); +} + +void Interpreter::O_GETMOBNAME() { + uint16 war = readScriptFlagValue(); + debugInterpreter("O_GETMOBNAME war %d", war); +} + +void Interpreter::O_SWAPINVENTORY() { + uint16 heroId = readScriptFlagValue(); + debugInterpreter("O_SWAPINVENTORY heroId %d", heroId); +} + +void Interpreter::O_CLEARINVENTORY() { + uint16 heroId = readScriptFlagValue(); + debugInterpreter("O_CLEARINVENTORY heroId %d", heroId); +} + +void Interpreter::O_SKIPTEXT() { + debugInterpreter("O_SKIPTEXT"); +} + +void Interpreter::SetVoice(uint32 sampleSlot) { + uint16 slot = readScriptFlagValue(); + _vm->loadVoice( + slot, + sampleSlot, + Common::String::format( + "%03d-%02d.WAV", + _currentString, + _flags->getFlagValue(Flags::VOICE_H_LINE) + ) + ); +} + +void Interpreter::O_SETVOICEH() { + static const uint32 VOICE_H_SLOT = 28; + SetVoice(VOICE_H_SLOT); +} + +void Interpreter::O_SETVOICEA() { + static const uint32 VOICE_A_SLOT = 29; + SetVoice(VOICE_A_SLOT); +} + +void Interpreter::O_SETVOICEB() { + static const uint32 VOICE_B_SLOT = 30; + SetVoice(VOICE_B_SLOT); +} + +void Interpreter::O_SETVOICEC() { + static const uint32 VOICE_C_SLOT = 31; + SetVoice(VOICE_C_SLOT); +} + +void Interpreter::O_SETVOICED() { + static const uint32 VOICE_D_SLOT = 32; + SetVoice(VOICE_D_SLOT); +} + +void Interpreter::O_VIEWFLCLOOP() { + uint16 value = readScriptFlagValue(); + debugInterpreter("O_VIEWFLCLOOP animId %d", value); + + _vm->loadAnim(value, true); +} + +void Interpreter::O_FLCSPEED() { + uint16 speed = readScriptFlagValue(); + debugInterpreter("O_FLCSPEED speed %d", speed); +} + +void Interpreter::O_OPENINVENTORY() { + debugInterpreter("O_OPENINVENTORY"); + _opcodeNF = 1; + // _showInventoryFlag = true +} + +void Interpreter::O_KRZYWA() { + debugInterpreter("O_KRZYWA"); +} + +void Interpreter::O_GETKRZYWA() { + debugInterpreter("O_GETKRZYWA"); + // _flags->setFlagValue(Flags::TORX1, krzywa[_krzywaIndex++]) + // _flags->setFlagValue(Flags::TORY1, krzywa[_krzywaIndex++]) + // Check _krzywaIndex +} + +void Interpreter::O_GETMOB() { + Flags::Id flagId = readScriptFlagId(); + uint16 mx = readScriptFlagValue(); + uint16 my = readScriptFlagValue(); + debugInterpreter("O_GETMOB flagId %d, mx %d, my %d", flagId, mx, my); + // check if current mob pos = (mx, my) +} + +void Interpreter::O_INPUTLINE() { + debugInterpreter("O_INPUTLINE"); +} + + +void Interpreter::O_BREAK_POINT() { + debugInterpreter("O_BREAK_POINT"); +} + +Interpreter::OpcodeFunc Interpreter::_opcodes[NUM_OPCODES] = { + &Interpreter::O_WAITFOREVER, + &Interpreter::O_BLACKPALETTE, + &Interpreter::O_SETUPPALETTE, + &Interpreter::O_INITROOM, + &Interpreter::O_SETSAMPLE, + &Interpreter::O_FREESAMPLE, + &Interpreter::O_PLAYSAMPLE, + &Interpreter::O_PUTOBJECT, + &Interpreter::O_REMOBJECT, + &Interpreter::O_SHOWANIM, + &Interpreter::O_CHECKANIMEND, + &Interpreter::O_FREEANIM, + &Interpreter::O_CHECKANIMFRAME, + &Interpreter::O_PUTBACKANIM, + &Interpreter::O_REMBACKANIM, + &Interpreter::O_CHECKBACKANIMFRAME, + &Interpreter::O_FREEALLSAMPLES, + &Interpreter::O_SETMUSIC, + &Interpreter::O_STOPMUSIC, + &Interpreter::O__WAIT, + &Interpreter::O_UPDATEOFF, + &Interpreter::O_UPDATEON, + &Interpreter::O_UPDATE , + &Interpreter::O_CLS, + &Interpreter::O__CALL, + &Interpreter::O_RETURN, + &Interpreter::O_GO, + &Interpreter::O_BACKANIMUPDATEOFF, + &Interpreter::O_BACKANIMUPDATEON, + &Interpreter::O_CHANGECURSOR, + &Interpreter::O_CHANGEANIMTYPE, + &Interpreter::O__SETFLAG, + &Interpreter::O_COMPARE, + &Interpreter::O_JUMPZ, + &Interpreter::O_JUMPNZ, + &Interpreter::O_EXIT, + &Interpreter::O_ADDFLAG, + &Interpreter::O_TALKANIM, + &Interpreter::O_SUBFLAG, + &Interpreter::O_SETSTRING, + &Interpreter::O_ANDFLAG, + &Interpreter::O_GETMOBDATA, + &Interpreter::O_ORFLAG, + &Interpreter::O_SETMOBDATA, + &Interpreter::O_XORFLAG, + &Interpreter::O_GETMOBTEXT, + &Interpreter::O_MOVEHERO, + &Interpreter::O_WALKHERO, + &Interpreter::O_SETHERO, + &Interpreter::O_HEROOFF, + &Interpreter::O_HEROON, + &Interpreter::O_CLSTEXT, + &Interpreter::O_CALLTABLE, + &Interpreter::O_CHANGEMOB, + &Interpreter::O_ADDINV, + &Interpreter::O_REMINV, + &Interpreter::O_REPINV, + &Interpreter::O_OBSOLETE_GETACTION, + &Interpreter::O_ADDWALKAREA, + &Interpreter::O_REMWALKAREA, + &Interpreter::O_RESTOREWALKAREA, + &Interpreter::O_WAITFRAME, + &Interpreter::O_SETFRAME, + &Interpreter::O_RUNACTION, + &Interpreter::O_COMPAREHI, + &Interpreter::O_COMPARELO, + &Interpreter::O_PRELOADSET, + &Interpreter::O_FREEPRELOAD, + &Interpreter::O_CHECKINV, + &Interpreter::O_TALKHERO, + &Interpreter::O_WAITTEXT, + &Interpreter::O_SETHEROANIM, + &Interpreter::O_WAITHEROANIM, + &Interpreter::O_GETHERODATA, + &Interpreter::O_GETMOUSEBUTTON, + &Interpreter::O_CHANGEFRAMES, + &Interpreter::O_CHANGEBACKFRAMES, + &Interpreter::O_GETBACKANIMDATA, + &Interpreter::O_GETANIMDATA, + &Interpreter::O_SETBGCODE, + &Interpreter::O_SETBACKFRAME, + &Interpreter::O_GETRND, + &Interpreter::O_TALKBACKANIM, + &Interpreter::O_LOADPATH, + &Interpreter::O_GETCHAR, + &Interpreter::O_SETDFLAG, + &Interpreter::O_CALLDFLAG, + &Interpreter::O_PRINTAT, + &Interpreter::O_ZOOMIN, + &Interpreter::O_ZOOMOUT, + &Interpreter::O_SETSTRINGOFFSET, + &Interpreter::O_GETOBJDATA, + &Interpreter::O_SETOBJDATA, + &Interpreter::O_SWAPOBJECTS, + &Interpreter::O_CHANGEHEROSET, + &Interpreter::O_ADDSTRING, + &Interpreter::O_SUBSTRING, + &Interpreter::O_INITDIALOG, + &Interpreter::O_ENABLEDIALOGOPT, + &Interpreter::O_DISABLEDIALOGOPT, + &Interpreter::O_SHOWDIALOGBOX, + &Interpreter::O_STOPSAMPLE, + &Interpreter::O_BACKANIMRANGE, + &Interpreter::O_CLEARPATH, + &Interpreter::O_SETPATH, + &Interpreter::O_GETHEROX, + &Interpreter::O_GETHEROY, + &Interpreter::O_GETHEROD, + &Interpreter::O_PUSHSTRING, + &Interpreter::O_POPSTRING, + &Interpreter::O_SETFGCODE, + &Interpreter::O_STOPHERO, + &Interpreter::O_ANIMUPDATEOFF, + &Interpreter::O_ANIMUPDATEON, + &Interpreter::O_FREECURSOR, + &Interpreter::O_ADDINVQUIET, + &Interpreter::O_RUNHERO, + &Interpreter::O_SETBACKANIMDATA, + &Interpreter::O_VIEWFLC, + &Interpreter::O_CHECKFLCFRAME, + &Interpreter::O_CHECKFLCEND, + &Interpreter::O_FREEFLC, + &Interpreter::O_TALKHEROSTOP, + &Interpreter::O_HEROCOLOR, + &Interpreter::O_GRABMAPA, + &Interpreter::O_ENABLENAK, + &Interpreter::O_DISABLENAK, + &Interpreter::O_GETMOBNAME, + &Interpreter::O_SWAPINVENTORY, + &Interpreter::O_CLEARINVENTORY, + &Interpreter::O_SKIPTEXT, + &Interpreter::O_SETVOICEH, + &Interpreter::O_SETVOICEA, + &Interpreter::O_SETVOICEB, + &Interpreter::O_SETVOICEC, + &Interpreter::O_VIEWFLCLOOP, + &Interpreter::O_FLCSPEED, + &Interpreter::O_OPENINVENTORY, + &Interpreter::O_KRZYWA, + &Interpreter::O_GETKRZYWA, + &Interpreter::O_GETMOB, + &Interpreter::O_INPUTLINE, + &Interpreter::O_SETVOICED, + &Interpreter::O_BREAK_POINT, +}; + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/script.h b/engines/prince/script.h new file mode 100644 index 0000000000..d51e01b559 --- /dev/null +++ b/engines/prince/script.h @@ -0,0 +1,321 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PRINCE_SCRIPT_H +#define PRINCE_SCRIPT_H + +#include "common/random.h" +#include "common/endian.h" +#include "common/array.h" + +#include "prince/flags.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Prince { + +class PrinceEngine; + +namespace Detail { + template <typename T> T LittleEndianReader(void *data); + template <> inline uint8 LittleEndianReader<uint8>(void *data) { return *(uint8*)(data); } + template <> inline uint16 LittleEndianReader<uint16>(void *data) { return READ_LE_UINT16(data); } + template <> inline uint32 LittleEndianReader<uint32>(void *data) { return READ_LE_UINT32(data); } +} + +class Room { +public: + Room(); + + bool loadFromStream(Common::SeekableReadStream &stream); + +private: + + typedef void (Room::*LoadingStep)(Common::SeekableReadStream &stream); + + void nextLoadStep(Common::SeekableReadStream &stream, LoadingStep step); + + void loadMobs(Common::SeekableReadStream &stream); + void loadBackAnim(Common::SeekableReadStream &stream); + void loadObj(Common::SeekableReadStream &stream); + void loadNak(Common::SeekableReadStream &stream); + void loadItemUse(Common::SeekableReadStream &stream); + void loadItemGive(Common::SeekableReadStream &stream); + void loadWalkTo(Common::SeekableReadStream &stream); + void loadExamine(Common::SeekableReadStream &stream); + void loadPickup(Common::SeekableReadStream &stream); + void loadUse(Common::SeekableReadStream &stream); + void loadPushOpen(Common::SeekableReadStream &stream); + void loadPullClose(Common::SeekableReadStream &stream); + void loadTalk(Common::SeekableReadStream &stream); + void loadGive(Common::SeekableReadStream &stream); +}; + + +class Script { +public: + Script(); + ~Script(); + + bool loadFromStream(Common::SeekableReadStream &stream); + + template <typename T> + T read(uint32 address) { + assert((_data + address + sizeof(T)) <= (_data + _dataSize)); + return Detail::LittleEndianReader<T>(&_data[address]); + } + + // Some magic numbers for now, data stored in header + uint32 getRoomTableOffset() { return read<uint32>(0); } + uint32 getStartGameOffset() { return read<uint32>(4); } + + const char *getString(uint32 offset) { + return (const char *)(&_data[offset]); + } + +private: + uint8 *_data; + uint32 _dataSize; + Common::Array<Room> _roomList; +}; + +class InterpreterFlags { +public: + InterpreterFlags(); + + void setFlagValue(Flags::Id flag, uint16 value); + uint16 getFlagValue(Flags::Id flag); + + void resetAllFlags(); + + static const uint16 FLAG_MASK = 0x8000; + +private: + static const uint16 MAX_FLAGS = 2000; + int16 _flags[MAX_FLAGS]; +}; + +class Interpreter { +public: + Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags); + + void stopBg() { _bgOpcodePC = 0; } + + void step(); + +private: + PrinceEngine *_vm; + Script *_script; + InterpreterFlags *_flags; + + uint32 _currentInstruction; + + uint32 _bgOpcodePC; + uint32 _fgOpcodePC; + + uint16 _lastOpcode; + uint32 _lastInstruction; + byte _result; + + bool _opcodeNF; // break interpreter loop + + static const uint32 _STACK_SIZE = 500; + uint32 _stack[_STACK_SIZE]; + uint8 _stacktop; + //uint8 _savedStacktop; + uint32 _waitFlag; + + const byte *_string; + uint32 _currentString; + const char *_mode; + + // Helper functions + uint32 step(uint32 opcodePC); + + uint16 readScriptFlagValue(); + Flags::Id readScriptFlagId(); + + // instantiation not needed here + template <typename T> T readScript(); + + void debugInterpreter(const char *s, ...); + void SetVoice(uint32 slot); + + typedef void (Interpreter::*OpcodeFunc)(); + static OpcodeFunc _opcodes[]; + + // Keep opcode handlers names as they are in original code + // it easier to switch back and forth + void O_WAITFOREVER(); + void O_BLACKPALETTE(); + void O_SETUPPALETTE(); + void O_INITROOM(); + void O_SETSAMPLE(); + void O_FREESAMPLE(); + void O_PLAYSAMPLE(); + void O_PUTOBJECT(); + void O_REMOBJECT(); + void O_SHOWANIM(); + void O_CHECKANIMEND(); + void O_FREEANIM(); + void O_CHECKANIMFRAME(); + void O_PUTBACKANIM(); + void O_REMBACKANIM(); + void O_CHECKBACKANIMFRAME(); + void O_FREEALLSAMPLES(); + void O_SETMUSIC(); + void O_STOPMUSIC(); + void O__WAIT(); + void O_UPDATEOFF(); + void O_UPDATEON(); + void O_UPDATE (); + void O_CLS(); + void O__CALL(); + void O_RETURN(); + void O_GO(); + void O_BACKANIMUPDATEOFF(); + void O_BACKANIMUPDATEON(); + void O_CHANGECURSOR(); + void O_CHANGEANIMTYPE(); + void O__SETFLAG(); + void O_COMPARE(); + void O_JUMPZ(); + void O_JUMPNZ(); + void O_EXIT(); + void O_ADDFLAG(); + void O_TALKANIM(); + void O_SUBFLAG(); + void O_SETSTRING(); + void O_ANDFLAG(); + void O_GETMOBDATA(); + void O_ORFLAG(); + void O_SETMOBDATA(); + void O_XORFLAG(); + void O_GETMOBTEXT(); + void O_MOVEHERO(); + void O_WALKHERO(); + void O_SETHERO(); + void O_HEROOFF(); + void O_HEROON(); + void O_CLSTEXT(); + void O_CALLTABLE(); + void O_CHANGEMOB(); + void O_ADDINV(); + void O_REMINV(); + void O_REPINV(); + void O_OBSOLETE_GETACTION(); + void O_ADDWALKAREA(); + void O_REMWALKAREA(); + void O_RESTOREWALKAREA(); + void O_WAITFRAME(); + void O_SETFRAME(); + void O_RUNACTION(); + void O_COMPAREHI(); + void O_COMPARELO(); + void O_PRELOADSET(); + void O_FREEPRELOAD(); + void O_CHECKINV(); + void O_TALKHERO(); + void O_WAITTEXT(); + void O_SETHEROANIM(); + void O_WAITHEROANIM(); + void O_GETHERODATA(); + void O_GETMOUSEBUTTON(); + void O_CHANGEFRAMES(); + void O_CHANGEBACKFRAMES(); + void O_GETBACKANIMDATA(); + void O_GETANIMDATA(); + void O_SETBGCODE(); + void O_SETBACKFRAME(); + void O_GETRND(); + void O_TALKBACKANIM(); + void O_LOADPATH(); + void O_GETCHAR(); + void O_SETDFLAG(); + void O_CALLDFLAG(); + void O_PRINTAT(); + void O_ZOOMIN(); + void O_ZOOMOUT(); + void O_SETSTRINGOFFSET(); + void O_GETOBJDATA(); + void O_SETOBJDATA(); + void O_SWAPOBJECTS(); + void O_CHANGEHEROSET(); + void O_ADDSTRING(); + void O_SUBSTRING(); + void O_INITDIALOG(); + void O_ENABLEDIALOGOPT(); + void O_DISABLEDIALOGOPT(); + void O_SHOWDIALOGBOX(); + void O_STOPSAMPLE(); + void O_BACKANIMRANGE(); + void O_CLEARPATH(); + void O_SETPATH(); + void O_GETHEROX(); + void O_GETHEROY(); + void O_GETHEROD(); + void O_PUSHSTRING(); + void O_POPSTRING(); + void O_SETFGCODE(); + void O_STOPHERO(); + void O_ANIMUPDATEOFF(); + void O_ANIMUPDATEON(); + void O_FREECURSOR(); + void O_ADDINVQUIET(); + void O_RUNHERO(); + void O_SETBACKANIMDATA(); + void O_VIEWFLC(); + void O_CHECKFLCFRAME(); + void O_CHECKFLCEND(); + void O_FREEFLC(); + void O_TALKHEROSTOP(); + void O_HEROCOLOR(); + void O_GRABMAPA(); + void O_ENABLENAK(); + void O_DISABLENAK(); + void O_GETMOBNAME(); + void O_SWAPINVENTORY(); + void O_CLEARINVENTORY(); + void O_SKIPTEXT(); + void O_SETVOICEH(); + void O_SETVOICEA(); + void O_SETVOICEB(); + void O_SETVOICEC(); + void O_VIEWFLCLOOP(); + void O_FLCSPEED(); + void O_OPENINVENTORY(); + void O_KRZYWA(); + void O_GETKRZYWA(); + void O_GETMOB(); + void O_INPUTLINE(); + void O_SETVOICED(); + void O_BREAK_POINT(); + +}; + +} + +#endif + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/sound.cpp b/engines/prince/sound.cpp new file mode 100644 index 0000000000..af139f708e --- /dev/null +++ b/engines/prince/sound.cpp @@ -0,0 +1,222 @@ +/* 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. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "prince/prince.h" +#include "prince/sound.h" +#include "prince/musNum.h" + +#include "common/config-manager.h" +#include "common/memstream.h" +#include "common/archive.h" +#include "audio/decoders/raw.h" +#include "audio/audiostream.h" + +namespace Prince { + +const char * MusicPlayer::_musTable[] = { + "", + "Battlfld.mid", + "Cave.mid", + "Cemetery.mid", + "Credits.mid", + "Fjord.mid", + "Guitar.mid", + "Hell.mid", + "Jingle.mid", + "Main.mid", + "Night.mid", + "Reality.mid", + "Sunlord.mid", + "Tavern.mid", + "Temple.mid", + "Boruta.mid", + "Intro.mid" +}; + +const uint8 MusicPlayer::_musRoomTable[] = { + 0, + ROOM01MUS, + ROOM02MUS, + ROOM03MUS, + ROOM04MUS, + ROOM05MUS, + ROOM06MUS, + ROOM07MUS, + ROOM08MUS, + ROOM09MUS, + ROOM10MUS, + ROOM11MUS, + ROOM12MUS, + ROOM13MUS, + ROOM14MUS, + ROOM15MUS, + ROOM16MUS, + ROOM17MUS, + ROOM18MUS, + ROOM19MUS, + ROOM20MUS, + ROOM21MUS, + ROOM22MUS, + ROOM23MUS, + ROOM24MUS, + ROOM25MUS, + ROOM26MUS, + ROOM27MUS, + ROOM28MUS, + ROOM29MUS, + ROOM30MUS, + ROOM31MUS, + ROOM32MUS, + ROOM33MUS, + ROOM34MUS, + ROOM35MUS, + ROOM36MUS, + ROOM37MUS, + ROOM38MUS, + ROOM39MUS, + ROOM40MUS, + ROOM41MUS, + ROOM42MUS, + ROOM43MUS, + 0, + 0, + ROOM46MUS, + ROOM47MUS, + ROOM48MUS, + ROOM49MUS, + ROOM50MUS, + ROOM51MUS, + ROOM52MUS, + ROOM53MUS, + ROOM54MUS, + ROOM55MUS, + ROOM56MUS, + ROOM57MUS, + ROOM58MUS, + ROOM59MUS, + ROOM60MUS, + ROOM61MUS +}; + + +MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) { + _data = NULL; + _isGM = false; + + MidiPlayer::createDriver(); + + int ret = _driver->open(); + if (ret == 0) { + if (_nativeMT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); + + // TODO: Load cmf.ins with the instrument table. It seems that an + // interface for such an operation is supported for AdLib. Maybe for + // this card, setting instruments is necessary. + + _driver->setTimerCallback(this, &timerCallback); + } +} + +MusicPlayer::~MusicPlayer() { + killMidi(); +} + +void MusicPlayer::killMidi() { + Audio::MidiPlayer::stop(); + + free(_data); + _data = NULL; +} + +void MusicPlayer::loadMidi(const char * name) { + Common::SeekableReadStream * stream = SearchMan.createReadStreamForMember(name); + if (!stream) { + debug("Can't load midi stream %s", name); + return; + } + + // Stop any currently playing MIDI file + killMidi(); + + // Read in the data for the file + _dataSize = stream->size(); + _data = (byte *)malloc(_dataSize); + stream->read(_data, _dataSize); + + delete stream; + + // Start playing the music + sndMidiStart(); +} + +void MusicPlayer::sndMidiStart() { + _isGM = true; + + MidiParser *parser = MidiParser::createParser_SMF(); + if (parser->loadMusic(_data, _dataSize)) { + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(_driver->getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + + _parser = parser; + + syncVolume(); + + // Al the tracks are supposed to loop + _isLooping = true; + _isPlaying = true; + } +} + +void MusicPlayer::send(uint32 b) { + if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) { + b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; + } + + Audio::MidiPlayer::send(b); +} + +void MusicPlayer::sendToChannel(byte channel, uint32 b) { + if (!_channelsTable[channel]) { + _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + // If a new channel is allocated during the playback, make sure + // its volume is correctly initialized. + if (_channelsTable[channel]) + _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255); + } + + if (_channelsTable[channel]) + _channelsTable[channel]->send(b); +} + +} // End of namespace CGE + +/* vim: set tabstop=4 expandtab!: */ diff --git a/engines/prince/sound.h b/engines/prince/sound.h new file mode 100644 index 0000000000..07ac9f38d9 --- /dev/null +++ b/engines/prince/sound.h @@ -0,0 +1,74 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef PRINCE_SOUND_H +#define PRINCE_SOUND_H + +#include "audio/audiostream.h" +#include "audio/decoders/wave.h" +#include "audio/fmopl.h" +#include "audio/mididrv.h" +#include "audio/midiparser.h" +#include "audio/midiplayer.h" +#include "audio/mixer.h" +#include "common/memstream.h" + +namespace Prince { + +class PrinceEngine; + +class MusicPlayer: public Audio::MidiPlayer { +private: + PrinceEngine *_vm; + byte *_data; + int _dataSize; + bool _isGM; + + // Start MIDI File + void sndMidiStart(); + + // Stop MIDI File + void sndMidiStop(); +public: + MusicPlayer(PrinceEngine *vm); + ~MusicPlayer(); + + void loadMidi(const char *); + void killMidi(); + + virtual void send(uint32 b); + virtual void sendToChannel(byte channel, uint32 b); + + static const char * _musTable[]; + static const uint8 _musRoomTable[]; +}; + +} // End of namespace Prince + +#endif + +/* vim: set tabstop=4 expandtab!: */ diff --git a/engines/prince/variatxt.cpp b/engines/prince/variatxt.cpp new file mode 100644 index 0000000000..4270444793 --- /dev/null +++ b/engines/prince/variatxt.cpp @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "prince/variatxt.h" +#include "common/debug.h" + +namespace Prince { + +VariaTxt::VariaTxt() : _dataSize(0), _data(NULL) { +} + +VariaTxt::~VariaTxt() { + _dataSize = 0; + delete[] _data; + _data = NULL; +} + + +bool VariaTxt::loadFromStream(Common::SeekableReadStream &stream) { + _dataSize = stream.size(); + _data = new byte [_dataSize]; + stream.read(_data, _dataSize); + return true; +} + +const char * VariaTxt::getString(uint32 stringId) { + uint32 stringOffset = READ_LE_UINT32(_data + stringId); + + if (stringOffset > _dataSize) { + assert(false); + } + + debug("VariaTxt::getString %04X %04X", stringId, stringOffset); + + return (const char *)_data + stringOffset; +} + +} + +/* vim: set tabstop=4 noexpandtab: */ diff --git a/engines/prince/variatxt.h b/engines/prince/variatxt.h new file mode 100644 index 0000000000..dcdba7bd8a --- /dev/null +++ b/engines/prince/variatxt.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/stream.h" + +namespace Prince { + +class VariaTxt { +public: + VariaTxt(); + + ~VariaTxt(); + + bool loadFromStream(Common::SeekableReadStream &stream); + + const char * getString(uint32 stringId); + +private: + uint32 _dataSize; + byte *_data; +}; + +} + +/* vim: set tabstop=4 noexpandtab: */ |